Analog CO2 Sensor for LoPy, can 5v pin power it?



  • Hello,
    I have a lopy with the pycom lopy expansion board that I am connecting an analog CO2 sensor to. This is a SEN0219 Gravity Analog Infrared CO2 sensor, more HERE

    The sensor specification:
    Gas Detection: Carbon Dioxide (CO2)
     Operating Voltage: 4.5 ~ 5.5V DC
     Average Current: <60mA @ 5V
     Peak Current: 150mA @ 5V
     Output Signal: Analog output (0.4 ~ 2V)
     Measuring Range: 0 ~ 5000ppm
     Accuracy: ± (50ppm + 3% reading)
     Preheating Time: 3min
     Response Time: 120s
     Operating Temperature: 0 ~ 50 Ԩ
     Operating Humidity: 0 ~ 95% RH (no condensation)
     Service Life: >5 years
     Size: 37mm * 69mm

    Vendor states this can be used in a 3.3V system as long as you power it with 5VDC. On the LoPy pin out diagram, the 3.3V pin states an absolute max of 1.2-A max load capability. Does this apply to the 5V pin as well? I assumed so, but I may not be getting enough amps.

    CO2 sensor connection: I have the sensor power plugged into the 5vdc pin, the gnd to the gnd and the signal (sensor output) to pin 16.

    When I run
    adc = machine.ADC() # create an ADC object
    apin = adc.channel(pin='P16') # create an analog pin on P16 & connect CO2 sensor
    value = apin()
    print("ADC count = %d" %(value))

    I get an ADC count = 1988

    Why is this so high?
    If I run the same code without anythign connected I get an ACD count of 4095...

    I need to set the attinuation level to 3.3v, but the syntax from the documentation does not work. I tried:

    apin = adc.channel(pin='P16', attn=ADC.ATTN_11DB)

    But get the error: Traceback (most recent call last) File "stdin", line 1, in <module> ValueError: invalid argument(s) value

    While this works:
    apin = adc.channel(pin='P16')

    How do I properly set the attinuation?



  • @ledbelly2142 said in Analog CO2 Sensor for LoPy, can 5v pin power it?:

    @bmarkus
    The COZIR sensors look nice. Are they in the sub $100 range?

    First hit of Google search gives $109 USD

    https://www.co2meter.com/products/cozir-0-2-co2-sensor

    As an indication you can visit the webshop of ChipCAD, a Hungarian distributor

    https://shop.chipcad.hu/Welcome/Default.aspx?scenarioID=360&pid=1878

    Prices are in HUF (Hungarian Forint), VAT not included. At the moment 1 USD = 262.6 HUF

    But it may vary by distributor, quantity, shipping conditions, custom, etc. and model. You can ask GSS to advice where to buy it, they are good.



  • Here's the updated code for this sensor with everyone's help. @jmarcelino @robert-hh
    In testing it, the results seem reasonable. Not super accurate but enough within 100ppm. Digy-Key has them for $58

    import machine
    from machine import ADC
    
    adc = machine.ADC()               # create an ADC object
    apin = adc.channel(pin='P16', attn=ADC.ATTN_11DB)   # create an analog pin on P16 & connect CO2 sensor
    
    print("")
    print("CO2 sensor Warming Up")
    #need initial delay (180) # CO2 sensor needs 3 minutes to warm up
    print("Reading CO2 Sensor...")
    value = apin()
    print("ADC count = %d" %(value))
    
    # LoPy  has 1.1 V input range for ADC
    co2 = (value-400) * (3900/4096.0)
    print("CO2 Level = %5.1f ppm" % (co2))
    


  • @bmarkus
    The COZIR sensors look nice. Are they in the sub $100 range? I also have CO2 sensors from co2meter.com, the K30. But they are a pain to work with and give very little support. At some point I wanted to create an I2C driver for micropython, but put it off because of the support. Another IoT option for low power gas sensors is Spec-Sensors We have used some of their stuff in the past, but they don't have CO2.

    Thanks!



  • Analog CO2 sensors does not really fit to todays IoT environment specially low power battery operated devices due to high power consumption and slow operation, long settle time. Take a look on Gas Sensing Solutions sensors. They are fast low power devices with digital interface. It is the data sheet of model I'm using with a LoRaWAN sensor (not PyCom), connected via serial line:

    https://www.gassensing.co.uk/media/1050/cozir_ambient_datasheet_gss.pdf



  • @jmarcelino
    Thank you, makes sense now. Really appreciate it.
    Cheers



  • @ledbelly2142
    I can't find any proper datasheet for your sensor but this plot shows everything you need to know:

    0_1501027117716_Screen Shot 2017-07-26 at 00.57.27.png

    At 0 ppm the sensor outputs 0.4v so you you need to subtract 400 (in millivolts) from your voltage reading (the voltage_diference in that formula)

    Then you know that 0.4 volts to 2.0 volts (a 1.6 volt range or 0 to 1600 in your voltage_diference from above) equates to a range of 0 to 5000 ppm.



  • @jmarcelino
    Thanks for your reply and help, I appreciate it. I understand the ADC bit range to 3900 instead of 3300--makes sense.

    I am missing the voltage reading completely :( I was going on the ADC example code and explanations. It's gotta be in the documentation somewhere that I can't find. Even when I search the docs for 'voltage', only DAC shows up, not in ADC.

    Why do we need the voltage difference -400 value?

    How do I apply the concentration to get the value?
    is that something like:

    int voltage_diference=voltage-400
    float concentration=voltage_diference*50.0/16.0
    value = apin()
    co2 = value * concentration(3900/4096.0)
    

    Or would it just be

    co2 = value * concentration
    

    Thanks



  • @ledbelly2142
    The ADC is 12 bit so the range is 0..4095 as @robert-hh explained. The reference is 1.1 Volts.

    At ATTN_11DB the full scale goes to 3.9V: 1.1 * math.pow(10.0, 11.0/20.0) so a more correct formula is value * (3900/4096)

    Finally the sample code you linked doesn't just use the voltage reading (what you have now) as the concentration, it takes a few extra calculations.

        int voltage_diference=voltage-400;
        float concentration=voltage_diference*50.0/16.0;
    

    I haven't read the datasheet but I guess you'll need to do the same in your code.



  • Here is what I used for this sensor:

    import machine
    from machine import ADC
    
    adc = machine.ADC()               # create an ADC object
    apin = adc.channel(pin='P16', attn=ADC.ATTN_11DB)   # create an analog pin on P16 & connect CO2 sensor
    
    print("")
    print("CO2 sensor Warming Up")
    #time.sleep(180) # CO2 sensor needs 3 minutes to warm up
    print("Reading CO2 Sensor...")
    value = apin()
    print("ADC count = %d" %(value))
    
    # LoPy  has 1.1 V input range for ADC
    co2 = value * (3300/4096.0)
    print("CO2 Level = %5.1f ppm" % (co2))
    
    


  • @robert-hh
    Thanks, I could not find where in the documentation the ADC range?

    The vendor of the CO2 sensor used the formula to get CO2 ppm:
    value*(3300/1024)

    I think there are 1024 is the steps on an arduino for the analog in.

    So I think the step function to interpret the ppm should be:
    value*(3300/4096) which would put us in the range of 711 ppm of CO2. Which sounds about right given that is on my desk right in front of me.

    Thanks!



  • @ledbelly2142 The range of the ADC is 0..4096. With an attenuation of 11DB, the reading of 883 tells 883*3.3/4096V = 0.71V



  • @jmarcelino
    Thanks! yes, I only had 'import macine'
    Now I get a reading, but it does not look like the sensor is working correctly. I am using ATTN_11DB to make the math conversion easier value * (3300/1024.0)
    The raw ADC count is still high, at 883 and its not changing much.

    Perhaps I am missing something in the documentation, is the ADC count a division of something? e.g. 883 count = 0.83v?

    Thanks



  • @ledbelly2142 The 5V pin is connected to the USB 5V or Vin. So it should source enough power to run the sensor. In you example, to use the attenuator, the syntach is:

    adc = machine.ADC() # create an ADC object
    apin = adc.channel(pin='P16', attn=machine.ADC.ATTN_11DB) # create an analog pin on P16 & connect CO2 sensor
    value = apin()
    print("ADC count = %d" %(value))
    

    The value will never be 0, since the output of the sensor is in the range of 0.4..2 V. The esp32 is quite noisy, so you should average over a handful samples, like 10.



  • @ledbelly2142
    To use ADC.ATTN_11DB you must declare what ADC is with

    from machine import ADC

    I think in your code you must have used import machine instead. Alternatively you can also use machine.ADC.ATTN_11DB but it's longwinded and unusual.

    As for the values the data sheet you linked to suggests the maximum output signal is 2V so you can use ADC.ATTN_6DB (half) instead.
    This brings down the signal from 0-2V to the 0-1V the ADC expects, you definitely need the attenuation.

    Finally note the internal ADC currently suffers from calibration issues so don't expect much accuracy from the results.



Pycom on Twitter