Pages

Showing posts with label i2c. Show all posts
Showing posts with label i2c. Show all posts

Saturday, July 4, 2015

Greenhouse: Phase 3, Sensors Working

It has been a while since I posted, but a lot has been going on.

As far as this project is concerned, the barometer ended up being a real pain. I was using the Adafruit MPL3115A2 breakout board and, as you can see from the previous post, I tied it in on the same I2C bus as one of the AM2315 Temperature and Humidity Sensors on the DUE. I modified the Adafruit library for the MPL3115A2 in the same way I modified the AM2315 to work on any I2C bus I want it to and fired everything up.

Nothing. Not a peep from the sensor.

I tried it on the second I2C bus.

Nothing.

Now that's annoying. I checked the wiring a bunch of times, checked my code, and yet... nothing.

I then dug out an Arduino UNO to try it out on and everything worked perfectly.

I wrote a post on the forums at Adafruit to see if anyone had any ideas. Someone else tried the MPL3115A2 on a DUE and also never got it to work. So I went over to Sparkfun and bought their same board. I know, kinda silly, but I was hoping it was something about the Adafruit board and that the Sparkfun board would just work. But no, it was not to be and the Sparkfun board remained silent on the DUE. Ultimately the folks at Adafruit decided that something was odd about the DUE I2C libraries just for the barometer board, perhaps a timing issue or something, even if it was working with the temperature/humidity sensors.

Poking around, I found the Teensy 3.1 has 2 I2C buses so gave it a try. Everything worked the first time, though the Teensy libraries do not use the I2C interfaces from twi.h, and I found they had their own I2C library called i2c_t3. So much for uniform library naming.

My final modifications for the Adafruit libraries for the AM2315 and the MPL3115A are found here and here, respectively.

Here is a picture of the final breadboard. I am leaving it as a breadboard for the next year in case I want to add in other sensors. I left it with the Sparkfun barometer board, which is on the right. The left side is the Teensy 3.1.




Below is the Fritzing diagram of the circuit. I couldn't find a part that shows the pins on the underside of the Teensy so just drew the wires with a note to label them. You can see the wires coming out from under the Teensy on its right side in the above picture.




My Arduino sketch is still not sending the binary data to the host processor, but here is the current code.



#include <i2c_t3.h>
#include <Adafruit_AM2315.h>
#include <Adafruit_MPL3115A2.h>

// The inside AM2315 temperature and humidity sensor.
Adafruit_AM2315 am2315Inside(&Wire1);

Adafruit_MPL3115A2 barometric(&Wire1);


// The outside AM2315 temperature and humidity sensor.
Adafruit_AM2315 am2315Outside(&Wire);

// The sensor data packet containing all data to be transmitted
// to the host.
typedef struct _SenseData {
  float temperatureInside;
  float humidityInside;
  float temperatureOutside;
  float humidityOutside;
  float altitude;
  float barometricPressure;
  float barometicTemp;
} SenseData;;

SenseData senseData;

void setup() {
  Serial.begin(9600);
}

void loop() {
 if (am2315Outside.begin()) {
    am2315Outside.readTemperatureAndHumidity(senseData.temperatureOutside, senseData.humidityOutside);
    Serial.print("Outside Hum: "); Serial.println(senseData.humidityOutside);
    Serial.print("Outside Temp: "); Serial.println(senseData.temperatureOutside);
  } else {
    Serial.println("Cannot see outside AM2315");
  }

  if (am2315Inside.begin()) {
    am2315Inside.readTemperatureAndHumidity(senseData.temperatureInside, senseData.humidityInside);
    Serial.print("Inside Hum: "); Serial.println(senseData.humidityInside);
    Serial.print("Inside Temp: "); Serial.println(senseData.temperatureInside);
  } else {
    Serial.println("Cannot see inside AM2315");
  }
 
  if (barometric.begin()) {
    senseData.barometricPressure = barometric.getPressure();
    Serial.print(senseData.barometricPressure/3377); Serial.println(" Inches (Hg)");

    senseData.altitude = barometric.getAltitude();
    Serial.print(senseData.altitude); Serial.println(" meters");

    senseData.barometicTemp = barometric.getTemperature();
    Serial.print(senseData.barometicTemp); Serial.println("*C");
  } else {
    Serial.println("Couldnt find barametric sensor");
  }

  delay(1000);
}

You may notice the conditionals inside the loop that are constantly calling the begin() method for the sensor. I did this so that if a physical sensor is removed, the other sensors can continue to report their data. The else section will probably set those fields to minus infinity or NaN if the sensor is not read.

When I am finally ready to send this to the host computer, I will use a line like

Serial.write(&senseData, sizeof(senseData);

This line will send out the packet with the data in the order that the fields are defined in the structure SenseData above.

In the next installment of the Greenhouse Saga, I will show the Java end that will read the data from the sensor and place it in an Interactive Spaces activity.


Tuesday, May 5, 2015

Greenhouse Phase 2: Temperature and Humidity Sensors

The next phase of the greenhouse is to add some sensors to the mix. The initial round will be for measuring temperature and humidity both inside and outside of the greenhouse and measure windspeed outside the greenhouse. Windspeed measurements in the greenhouse would hopefully be pretty boring data, except perhaps if someone left the door open.

The greenhouse was initially meant to be mostly underground, what is called a walipini, but as they were digging they hit bedrock rather soon. If we had done that we would have had a reasonably temperature constant greenhouse as the temperature stays reasonably constant when underground. Instead we ended up with a climate battery. The concept here is to pump heat into the ground during the day when it is warm, or at least not too cold, and heat up the ground, and then release that heat back into the greenhouse at night. This is accomplished by having a fan that blows air into a series of tubes buried in the ground of the greenhouse.

I am very curious to see how well the climate battery works, so want to capture temperature and humidity data for a few weeks with the climate battery off and then turn it on and see how much the temperature and humidity profiles smooth out.

After some searching, I decided to use the AM2315 temperature and humidity sensor from Adafruit. The sensor comes in a case that protects the inside sensors. The description on Adafruit says that it isn't really rated for being outdoors, but I have read about a lot of people using them that way so I will give it a try.

One immediate complication is that the AM2315 is an I2C device. For those unfamiliar with I2C, this is a two wire protocol for communicating with a series of devices on a serial bus, one wire for a clock and a second wire for data. Each I2C device has an address and you can read or write to the devices by giving the address of the device you want to read or write from. Unfortunate the AM2315 has a fixed I2C address (0x5C), so if you want to use 2 of them, you need 2 independent I2C buses.

My initial design used 2 Arduino Unos, once for each AM2315. I am using Arduinos for now as I want to experiment over time with which sensors I am going to use and want to be able to easily throw in other sensors on a breadboard. Then, at some point in the future, I can built something a little more permanent. 2 Arduinos means 2 USB ports to get the data out to a host for processing, so I decided after a while to go with the Arduino DUE, which is the only Arduino with 2 I2C buses on it.

I got the Adafruit AM2315 from its git repository at https://github.com/adafruit/Adafruit_AM2315 and wired the AM2315 to the I2C bus at pins 20 and 21 on the DUE. A quick check and everything was working just fine.

That second AM2315 ended up being more of an issue. The Adafruit library only supports the I2C bus on pins 20 and 21 and I wanted to use the code on both buses. I took a look at the source of the library and found that the Wire instance variable was hardcoded directly into the AM2315 code, so modified it to allow the user to specify which bus to use.

The initial class definition in Adafruit_AM2315.h had

class Adafruit_AM2315 {
 public:
  Adafruit_AM2315();

and I changed it to

class Adafruit_AM2315 {
 public:
  Adafruit_AM2315(TwoWire* w=&Wire);

This allows the usage Adafruit_AM2315 foo() to still go with Wire, but I can now also specify if I want Wire or Wire1, though with a slightly more complicated syntax.

I also needed to add a private instance variable of TwoWire* wire to the class definition.

Adafruit_AM2315 foo(&Wire1);

This required some changes to the Adafruit_AM2315.cpp code, I did a replacement of Wire. to wire-> throughout the source and modified the Adafruit AM2315 constructor from


Adafruit_AM2315::Adafruit_AM2315() {
}

to

Adafruit_AM2315::Adafruit_AM2315(TwoWire *w): wire{w} {
}

You can find the modified library at my github repo https://github.com/kmhughes/Adafruit_AM2315.

The circuit for both AM2315s, the anemometer, and a barometric pressure sensor (which should be ignored for now) is as follows.


Note the 10k pullup resistors on the I2C lines, the Arduino will not see the AM2315s if these resistors are missing.

The Arduino code to read the sensors is


#include <Wire.h>
#include <Adafruit_AM2315.h>
#include <Adafruit_MPL3115A2.h>

// The inside AM2315 temperature and humidity sensor.
Adafruit_AM2315 am2315Inside(&Wire);

// The outside AM2315 temperature and humidity sensor.
Adafruit_AM2315 am2315Outside(&Wire1);

// The sensor data packet containing all data to be transmitted
// to the host.
typedef struct {
  float temperatureInside;
  float humidityInside;
  float temperatureOutside;
  float humidityOutside;
  int windSpeed;
} SenseData;

SenseData senseData;

void setup() {
  Serial.begin(9600);

  if (! am2315Outside.begin()) {
     Serial.println("Outside AM2315 sensor not found, check wiring & pullups!");
     while (1);
  }

  if (! am2315Inside.begin()) {
     Serial.println("Inside AM2315 sensor not found, check wiring & pullups!");
     while (1);
  }
  
  // TODO(keith): initialize barametric sensors
}

void loop() {
  am2315Outside.readTemperatureAndHumidity(senseData.temperatureOutside, senseData.humidityOutside);
  am2315Inside.readTemperatureAndHumidity(senseData.temperatureInside, senseData.humidityInside);

  senseData.windSpeed = analogRead(0);
  
  // TODO(keith): Remove when sending data to host
  Serial.print("Outside Hum: "); Serial.println(senseData.humidityOutside);
  Serial.print("Outside Temp: "); Serial.println(senseData.temperatureOutside);
  Serial.print("Inside Hum: "); Serial.println(senseData.humidityInside);
  Serial.print("Inside Temp: "); Serial.println(senseData.temperatureInside);

  Serial.print("Wind Speed: "); Serial.println(senseData.windSpeed);
  
  // TODO(keith): Write data to host computer
  
  // TODO(keith): change sample rate to every 5 minutes or so
  delay(1000);
}

Here you can see that the inside AM2315 is on the first I2C bus on pins 20 and 21 and the outside AM2315 is on the additional bus. The anemometer is connected to analog 0 on the Arduino.

You may wonder why am I using a struct to store the sensor data? As you will see, once the code is complete, this will make it very easy to write all of my sensor data in a single line to the host computer. But for now I am debugging, so will leave the Serial prints in and have the code look annoyingly complicated.

This code can be found at https://github.com/kmhughes/robotbrains-smartspaces/blob/master/arduino/GreenhouseSensors/GreenhouseSensors.ino

One thing I discovered is that even if the AM2315s are sitting physically next to each other, they give different temperature values. So I will have to calibrate them and subtract an offset from both values calculated from a known accurate sensor.

At the moment I cannot get the barometer, which is also an I2C device, working on the DUE though I did make it work on an UNO. Once I sort that out I will modify the code and post the host side that will be capturing the data and storing it for later graphing and analysis and show the wiring inside and outside the greenhouse.