Digital Racing

Saturday, September 24, 2011

Arduino-based Nitrox analyzer

In an earlier post, I described the common method of making a nitrox analyzer out of a typical digital voltmeter and an oxygen sensor.  It works well, lots of people have made them.

But I just picked up a nice programmable microcontroller.  It's called Arduino- and is cheap.  Here's my plan for using it as a nitrox analyzer.

  • Be able to adjust to any type of oxygen sensor
  • Compensate for relative humidity (when you want to use it an an input to a nitrox stick)
  • Calibrate meter on 100% O2 and/or 20.9% (air)
  • Auto shutoff
  • Battery Meter
It was roughly possible to do this with a pure hardware-based system.  You put a potentiometer on the reading circuit to change the voltage divider and you can adjust.  Relative humidity, you had to fake it out by reading the RH and then adjusting down 

For me, I'm going to try to have it all built-in.  First thing is first- we need to read the value coming out of an oxygen sensor.  I'm going to use the common sensor we see, which is a Teledyne R-17.  In 100% O2, it reads 62mV, and in 20.9% (air) it reads around 10mV.

First thing's first- get a sensor, get an Arduino.

I got my Arduino for $25 at TechShopRDU which is a local hobbyist center.  It is an amazing place, and it was great to pick up one of these off the shelf.

Looking at the Arduino, it can read analog voltage of 0-5V in 1024 increments, or 5mV per increment.  Not enough detail!  But.. you can reset that voltage.  By setting the input range to 1.1, you get 1024 increments or each value is about 1mv.

This is done by:
void setup() {
Serial.begin(9600);

// Set the reference voltage to be 1.1V to get more resolution
analogReference(INTERNAL);
}
Except.. it didn't work. It should have reduced the range and increased the resolution.  I tested my sensor in air and got 11mV.  But when I let the arduino read it, I only get 7mV.  That's pretty far off.   One thing I'm considering is using an opamp to up the gain on the sensor.  Something like this:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1272911672/all

I don't know anything about op amps.  But I found one on my desk.  Weird, eh?  It was leftover from when a local RadioShack was closing- I bought a lot of stuff, and this was like in the 10c bin.   I need to see if it is applicable to my circuit.

One biggie that is going to interfere with my design is that op amps seem to require positive and negative voltage. Some designs just use a couple of 9v batteries, one flipped to give negative voltage.  This page gives a history (the designer of the modern op amp retired at age 30) and sample designs, as well as a dual 12v power supply.

But I don't want dual power supplies.  In the Ti link above, you can fake a negative power supply by using a single power supply and creating a virtual ground with a voltage divider.

Finally, after seeing that an LM324 is a commonly available quad op-amp (Radio Shack, $3), I found a project that used one... and it hooked up to an Arduino. Perfect.  http://www.practicalarduino.com/projects/water-tank-depth-sensor

 
Off to RadioShack to get the the LM324, then time for some breadboarding.

(several days of design and breadboading)

This morning, I cam up with this circuit:




Stef says "that's the best circuit I've ever seen".  I was quite proud!  So tonight, I wired it up.  I calculated the gain needed to be about 40x, so that my Rg (variable resistor) should be 800ohms or so.   The LM324 is actually four op-amps in a single IC.  You can wire it up a bunch of different ways, but I chose an instrumentation amplifier as it was close to the Practical Arduino book above.   But it didn't work.  I got 3.62v as the output when compared to ground.  Which should have been nicely in range.  However, the signal didn't vary as I blew on the sensor.  I went and tested the voltage at pins 1 and 7 and got nice variance (about 300mv) between them, but for some reason actually amplifying that difference got me nothing.  It could be that the feedback circuits were overcompensating and driving the difference down, or it could be simply that I was using cheapo 5% resistance capacitors and it was making my readings meaningless.  Using a simple amp (one of the 4 op amps) could work, I'd get a lot of variance, but I'm bummed that my fancy circuit failed.  So, I did research and found that they have ICs that have the three op-amps in them already with 0.1% resistors built-in.  They're more expensive than the LM324 I paid a couple of bucks for, but they'd be far less than having to source fancy resistors.  And even better, I found the AD623 off Ebay for $3 shipped.  I chose the AD623 because it is a single-supply amplifier (like the LM324) and the only piece I need to do a 40x amplification is a 2.5kOhm precision resistor (and I can probably skip a high precision resistor as I'm going to have the arduino do the tare-ing of steady-state)

The AD623 experiment was a failure- I did not get the result I planned.  I got a high voltage without even any input.

And then, last night I figured out what I was doing wrong.  Let me help those of you who are playing with an IC.  The pins are numbered starting next to the 'dot' as pin 1.  This is on the side with the divot.  And then, the numbers are COUNTERCLOCKWISE around the chip.  Notice the ALLCAPS.  They are not numbered top-to-bottom, left to right.  On an 8-pin chip, pin 5 is across pin 4, not pin 1 (that would be pin 8).  I feel pretty stupid.

I made a simple differential op-amp using a single amp from the LM324, but really any single-sided op-amp would work.

It only needs four resistors and I got a nice linear increase in my sensor.  To make it really simple, just use Rg=Rf and R1=R2, and the gain becomes Rf/R1.  The reason I went with a differential sensor is that my sensor isn't a voltage to ground, but rather a voltage difference.    I'm using 44k for my Rf and 1k for my R1 values which gives it 44x and my measured difference was 43.7.  Close enough!

Since I learned to count again, I also rewired my single-supply instrumentation amp (AD623AN).  And I got strange results.  It only requires a single resistor, which at 2000Ohms would give it a 50x gain.  But instead, it got a 27x gain.  And it wasn't linear- at higher inputs, the gain went up to almost 40x.  Something was very strange.  And I used two different 623s and got the same results.  I even built a voltage divider and tried to add in a reference voltage.  Somewhere buried in the datasheet is probably the reason, and it has something to do with how much gain it can give close to the 'rails' (p.20).  But it seems the issue only occurs <10mV of the bottom rail (which extends below zero) to 4.9V on the top end.  But since it is really three op-amps in a single package, there's a table of min/max values.  The max gain could be as low as 18x, and for my situation might top out at 49x. Hmmm.  I may play with it some more, because the 623 sounds like the perfect chip!

The AD623 is a bizarre chip.  I could not get it to amplify linearly.   The trick I tried was to force one of my sensor sides to ground (through a 10k resistor) so it didn't float.  I got solid reliable readings on the sensor side.  And at the low end of the scale, I got my  expected 50x gain.  However, when I upped the values coming from the sensor to 53mV, I only got  a 29x gain on the high end.  There was a blurb in the datasheet about a max gain in the 40s in certain situations, so I changed the gain to 35 by going to a 3k resister- and at the low end I got the expected gain, but at the high end, it went down into the 20s.  I gave up.

I went back to the LM324, using only a single op amp as a differential amp.

Here's my final circuit:

I still have three op-amps available for use for something else if needed.  And here it is on the breadboard:


Once I get my other components I'll move the design to a veloboard to make it somewhat permanent.  I've ordered a temperature/humidity sensor and now I'm back to doing some coding for Android (in Java) while I wait on some components to arrive.

I just got a new sensor- a Teledyne R-17 clone and I wired it into my circuit.  It reads 13.8mV in air, and I up it 44x to get it into a range usable by the analog read of the Arduino.  I wrote Arduino code to wait for the user to sample air (assumed to be 20.93) and then press a button.  I take 10 quick readings, then average the result.   This sample voltage becomes my calibration using math- no resistors needed!

After the calibration is set, the user can press the button again to get a reading (I do the 10x average again).  I do a simple  (readingV/calibrationV * 20.93) to get the percentage of O2.

Press button when sensor is in air
sensor value = 109.00:V = 532.23
Calibrated voltage is: 532.23
sensor value = 109.00:V = 532.23
Oxygen percentage:20.93
sensor value = 109.00:V = 532.23
Oxygen percentage:20.93
sensor value = 110.00:V = 537.11
Oxygen percentage:21.12
sensor value = 115.00:V = 561.52
Oxygen percentage:22.08
sensor value = 202.00:V = 986.33
Oxygen percentage:38.79
sensor value = 501.00:V = 2446.29
Oxygen percentage:96.20

I notice that my value at near 100% is only half the available range (1024), so I can choose a lower voltage (or higher amplification) to get greater resolution.



Cost of the project:
Arduino: $25
Veloboard: $3
Resistors: $2 (Radio Shack)
LM324:$3 (Radio Shack)
Sensor: $65

After speaking with another hobbyist about how he did his micro-controller sensor, he said you really need an ADC to do it right.  The built-in analog-to-digital controller on the Arduino is simply too coarse to get good readings.  I've ordered an ADS1115 for $15 to add to my Arduino to see if I can get better readings.

The next step is to hook up a display and give it an independent power supply (9v battery).