Sunday, March 31, 2013

If it ain't broke...

I've spent weeks trying to figure out how I broke my Raspberry Pi.  Actually... How I broke two of them.

Well, I didn't actually break them.  Just the sensors attached to them.

Well, I didn't actually break them, it's just that they weren't reading correctly.

Here's the story:

I've been working on a couple of I2C sensors to tie into my Raspberry Pi.  The idea is to read the sensors at specific intervals, log the data, and then serve up some nice graphs.  I've been using the BMP085 temperature and pressure sensor, the TSL2561 light sensor, and the TMP102 temperature sensor (All those links go to the Adafruit forums specific to those sensors and the Raspberry Pi).

A group of us were collaborating on the TSL2561 (Hi, csalty!), when I upgraded to the newer version of Adafruit_I2C and the Adafruit_BMP085.  That's where everything went sideways.

I spent days looking at the datasheet and the Adafruit_BMP085 code.  Some of the stuff just doesn't make sense to me.  It doesn't make sense to the point that I wrote the devs saying "This is broken".

It's not, and that's pretty embarrassing.  It really looks like something in the Adafruit_I2C code changed how it pulls the information from the BMP085.  If you're looking for solutions, enable the debug mode, and check your calibration information.  Mine was VERY off using that version of Adafruit_I2C (Impossible temperatures and unstable in nature reading 200 degrees one minute negative 70 the next).  Once I switched some of the functions to the older version, things went well.  The kludge-version of Adafruit_I2C that I'm using is listed here: Modified Adafruit_I2C.py.

I also made a very specific change to the Adafruit_BMP085.py code.  I allowed the code to pass a specified bus number down the "stack" to the I2C code.  By default it does not specify a bus, and will allow the new I2C software to determine which version of the Raspberry Pi is being used, selecting the default GPIO header bus.  This way, all you have to do is call the BMP085.  It will fill in the default address, the default mode, and the default bus.  If you (like me) are using both I2C buses on your Raspberry Pi, then you MUST specify when you are using the "non-standard" bus.  The way the Adafruit_I2C.py code is written, it will only look for the version of the board and assign the "default" bus.  It has no way of knowing which bus you want to use.

I also set up the BMP085 code to pass the debug state down the code stack.  I figure if you're interested in debugging the BMP085, you're also going to be interested in debugging what is happening with the I2C code.  As part of the BMP085 calibration data, I also set it up to print out which I2C bus is being specified.

I need to make these changes to the TSL2561 code and the TMP102 code.  Both of these sensors appeared to be working just fine with the new Adafruit_I2C.py code (I've checked to make sure).

I've changed my project a little bit.  Now I'm running two parallel sets of sensors on the two different buses.  Each bus has a TSL2561 and a BMP085 sensor.  I'm logging the temperature, light level, and pressure every sixty seconds or so.  I'm manually able to generate all kinds of charts, but for right now I'm going to keep it manual.  I'll let the system run while I'm at work this week (four days), and if everything looks OK, I'll work on re-writing the webpage code.

5 comments:

Jawed Qadir said...

Hello,

I'm trying t use your code for TSL2561 that you posted on GitHub. I've downloaded the updated I2C Adafrurit and seem to be communicating with the sensor, but the reads comming back seem to be jumping all over the place. I'm not clear what calls I need to make to read the ambient and IR values. My datalogger will logging values of the ambient and IR level outdoor in the sunshine, so I would think I should be using auto gain ??

At end of of your code you have the following calls...

if __name__ == "__main__":
tsl=TSL2561()
print tsl.readLux()
#print "LUX HIGH GAIN ", tsl.readLux(16)
#print "LUX LOW GAIN ", tsl.readLux(1)
#print "LUX AUTO GAIN ", tsl.readLux()

Question:

- In the example you just screen print tsl.readlux() and the rest of them are commented out. Is the readlux() call using auto gain ?

- Do I need to first call __init__()

- To read IR, do I just call the tsl.readIR() ??

I tried doing the above, but the values change quite a bit from read to read.

Any help would be greatly appreciated.

Thanks,
Jay

Static said...

Thanks for posting up!
It's been awhile since I worked on this. I'm running down the documentation I did over on the Adafruit forums. It looks like we found a problem here:
http://forums.adafruit.com/viewtopic.php?f=8&t=34922&start=60


Unfortunately, I don't seem to have access to the GitHub page (bizarre). Could you provide me with a direct link?

I can answer some of the code questions, though:
In Python, the __init__ method is automatically run whenever an object of the class is instantiated. You should never have to call it manually (I don't know what happens if you try to). The short answer: You do not need to call it, Python will do it for you at runtime.

I believe that the readlux() method is using autogain. Further, there may be errors in the code that I was using. See the link above, that takes you to the Adafruit forums. If it doesn't take you directly to the page, go to Page Six, of TSL2561 and Raspberry Pi. The really good news is that there are some serious experts there that have addressed the code.

I never explicitly tested the IR reading capability. In theory, you should just have to call tsl.readIR(), but I didn't have a steady IR source to test it out.

The 'if __name__ == "main":' at the end of the code is to allow the code to either be used as a module, or to run independently. If the code is run independently (just telling python to run the code, as opposed to importing it into another code), then it sets the variable '__name__' to '__main__'. Then it will run the code within the code block. I use this as a code test during development. It lets me easily test the code while allowing me to write the code to be easily used by other programs. You can uncomment the lines with '#' in front of them, within that code block, to get the test program to report all of the values. There may be an issue with the auto-gain and integration times. Check the Adafruit link that I posted above.

Good hearing from you, let me know if I can help.


Jawed Qadir said...

Hello,

Thanks a bunch for your response; do appreciate it.

I did review the thread link you sent on Adafruit forum. "huelke" had posted a revised code of yours, but when I compared it to your "TSL2561.py" posted on GitHub, it appeared to be the same except for he renamed the Class luxmeter and you call it TSL2561 and few other label differences. Also; looking at the dates, his post was on May, 2015 and you updated your code on GitHub in July, 2014; so your GitHub code may have have his corrections.

I'm going to run your code again in a more systematic way to validate the results I'm getting. I'm really interested in the IR value as I'm looking to monitor thermal IR produced by solar for my evaporator application. I'm not a pro yet with Python so still trying to understand the code. From what I understand, if I want to place the sensor outdoors in the sun, I should use auto gain feature, do you recall if that is same as gain=0 ??

I again want to thank you for your help and I may seek more while I try to make this work :)

Greetings from Atlanta.

Jay

Static said...

I don't know if gain=0 is auto-gain. I'm going to work on getting my sensor system back up and running this weekend, so I can get things installed around the house over winter.

One big thing, I'm not sure this IR is true thermal IR. It may be a poor measure of heat (in fact, I'm almost positive it is, I just can't point you to a specific discussion about it). If you're looking to measure heat, there are I2C non-contact thermometer sensors out there.

Could you post up a link to the GitHub you're using?

Jawed Qadir said...

What I'm building is a remote datalogger for several parameters; temperature, weight scale, humidity and IR for a prototype solar water evaporator. The chemistry of the evaporator depends on the mentioned variables. I'm using TMP36 for temp, I2C humidity sensor, strain gauge for sensing the output of the liquid and TSL2561 to sense how much IR that can be utilized in evaporation process is blocked by the poly-carbonate sheet used for housing the evaporator.

The spec sheet for TSL2561 shows the sensing IR spectrum which has a peek of 8 um. Google research shows 8 -15 um as the thermal IR wavelength. Based on that I assumed this sensor would work for my application. Any thoughts/comments will be of lot of value.

I'm not using any code from GitHub other than yours. Other sensors were fairly simple to integrate and Adafruit has sample codes for them on their site.