MQ-8 hydrogen sensor calibration

Hello,
I guess I need some help with MQ-8. So this is my circuit:

And I have tried to calibrate it using this code (taken from MQ-8 Hydrogen/H2 Sensor Module | Sandbox Electronics):

/*******************Demo for MQ-8 Gas Sensor Module V1.0*****************************
Contact: support[at]sandboxelectronics.com

Lisence: Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0)

Note:    This piece of source code is supposed to be used as a demostration ONLY. More
         sophisticated calibration is required for industrial field application. 

                                                    Sandbox Electronics    2014-02-03
************************************************************************************/

/************************Hardware Related Macros************************************/
#define         MQ_PIN                       (0)     //define which analog input channel you are going to use
#define         RL_VALUE                     (10)    //define the load resistance on the board, in kilo ohms
#define         RO_CLEAN_AIR_FACTOR          (9.21)  //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
                                                     //which is derived from the chart in datasheet

/***********************Software Related Macros************************************/
#define         CALIBARAION_SAMPLE_TIMES     (20)    //define how many samples you are going to take in the calibration phase
#define         CALIBRATION_SAMPLE_INTERVAL  (200)   //define the time interal(in milisecond) between each samples in the
                                                     //cablibration phase
#define         READ_SAMPLE_INTERVAL         (50)    //define how many samples you are going to take in normal operation
#define         READ_SAMPLE_TIMES            (5)     //define the time interal(in milisecond) between each samples in 
                                                     //normal operation

/**********************Application Related Macros**********************************/
#define         GAS_H2                      (0)

/*****************************Globals***********************************************/
float           H2Curve[3]  =  {2.3, 0.93,-1.44};    //two points are taken from the curve in datasheet. 
                                                     //with these two points, a line is formed which is "approximately equivalent" 
                                                     //to the original curve. 
                                                     //data format:{ x, y, slope}; point1: (lg200, lg8.5), point2: (lg10000, lg0.03) 

float           Ro           =  10;                  //Ro is initialized to 10 kilo ohms

void setup()
{
  Serial.begin(9600);                                //UART setup, baudrate = 9600bps
  Serial.print("Calibrating...\n");                
  Ro = MQCalibration(MQ_PIN);                        //Calibrating the sensor. Please make sure the sensor is in clean air 
                                                     //when you perform the calibration                    
  Serial.print("Calibration is done...\n"); 
  Serial.print("Ro=");
  Serial.print(Ro);
  Serial.print("kohm");
  Serial.print("\n");
}

void loop()
{
   Serial.print("H2:"); 
   Serial.print(MQGetGasPercentage(MQRead(MQ_PIN)/Ro,GAS_H2) );         //H2 in ppm
   Serial.print( "ppm" );
   Serial.print("\n");
   delay(200);
}

/****************** MQResistanceCalculation ****************************************
Input:   raw_adc - raw value read from adc, which represents the voltage
Output:  the calculated sensor resistance
Remarks: The sensor and the load resistor forms a voltage divider. Given the voltage
         across the load resistor and its resistance, the resistance of the sensor
         could be derived.
************************************************************************************/ 
float MQResistanceCalculation(int raw_adc)
{
  return ( ((float)RL_VALUE*(1023-raw_adc)/raw_adc));
}

/***************************** MQCalibration ****************************************
Input:   mq_pin - analog channel
Output:  Ro of the sensor
Remarks: This function assumes that the sensor is in clean air. It use  
         MQResistanceCalculation to calculates the sensor resistance in clean air 
         and then divides it with RO_CLEAN_AIR_FACTOR. RO_CLEAN_AIR_FACTOR is about 
         10, which differs slightly between different sensors.
************************************************************************************/ 
float MQCalibration(int mq_pin)
{
  int i;
  float val=0;

  for (i=0;i<CALIBARAION_SAMPLE_TIMES;i++) {            //take multiple samples
    val += MQResistanceCalculation(analogRead(mq_pin));
    delay(CALIBRATION_SAMPLE_INTERVAL);
  }
  val = val/CALIBARAION_SAMPLE_TIMES;                   //calculate the average value

  val = val/RO_CLEAN_AIR_FACTOR;                        //divided by RO_CLEAN_AIR_FACTOR yields the Ro 
                                                        //according to the chart in the datasheet 

  return val; 
}
/*****************************  MQRead *********************************************
Input:   mq_pin - analog channel
Output:  Rs of the sensor
Remarks: This function use MQResistanceCalculation to caculate the sensor resistenc (Rs).
         The Rs changes as the sensor is in the different consentration of the target
         gas. The sample times and the time interval between samples could be configured
         by changing the definition of the macros.
************************************************************************************/ 
float MQRead(int mq_pin)
{
  int i;
  float rs=0;

  for (i=0;i<READ_SAMPLE_TIMES;i++) {
    rs += MQResistanceCalculation(analogRead(mq_pin));
    delay(READ_SAMPLE_INTERVAL);
  }

  rs = rs/READ_SAMPLE_TIMES;

  return rs;  
}

/*****************************  MQGetGasPercentage **********************************
Input:   rs_ro_ratio - Rs divided by Ro
         gas_id      - target gas type
Output:  ppm of the target gas
Remarks: This function passes different curves to the MQGetPercentage function which 
         calculates the ppm (parts per million) of the target gas.
************************************************************************************/ 
int MQGetGasPercentage(float rs_ro_ratio, int gas_id)
{
  if ( gas_id == GAS_H2) {
     return MQGetPercentage(rs_ro_ratio,H2Curve);
  }  
  return 0;
}

/*****************************  MQGetPercentage **********************************
Input:   rs_ro_ratio - Rs divided by Ro
         pcurve      - pointer to the curve of the target gas
Output:  ppm of the target gas
Remarks: By using the slope and a point of the line. The x(logarithmic value of ppm) 
         of the line could be derived if y(rs_ro_ratio) is provided. As it is a 
         logarithmic coordinate, power of 10 is used to convert the result to non-logarithmic 
         value.
************************************************************************************/ 
int  MQGetPercentage(float rs_ro_ratio, float *pcurve)
{
  return (pow(10,( ((log(rs_ro_ratio)-pcurve[1])/pcurve[2]) + pcurve[0])));
}

I'm getting weird output, like:

Calibrating...
Calibration is done...
Ro=1.66kohm              //<-- This should be 10k
H2:25ppm
H2:25ppm
H2:25ppm
H2:25ppm
*continues to print 25ppm, value drops to ~8ppm after few minutes*

or:

Calibrating...
Calibration is done...
Ro=3.36kohm              //<-- Again, this should be 10k
H2:25ppm
H2:25ppm
H2:25ppm
H2:25ppm
*continues to print 25ppm, value drops to ~8ppm after few minutes*

Seems like it doesn't read resistance properly (random value each time I launch serial window) and I don't understand why. Is there something wrong with my circuit?

Are you sure it’s hooked up correctly? From the output, it seems as if it isn’t.

Yes, i checked circuitry several times.

I don't know how this thing works or how the calibration works but run the [u]Analog Read Serial Example[/u] to see if you are getting stable "raw" readings.

If the readings are not stable, maybe you're not letting the heater warm-up long enough.

Also check if the raw readings are "reasonable". If the readings are near zero you'll loose resolution. If the readings are too high (near 1023) you are in danger of hitting the upper limit and getting meaningless readings. ...But I don't know if your raw calibration readings are supposed to be low or high.

... If you are reading in normal air you should have near zero PPM. There is lots of H20 in the air, but almost no H2. (Wikipedia says 1ppm.) But the sensor is only rated down to 100 ppm.

Do you have a link to the data sheet and how to connect the thing? The "datasheet" link on the page you linked to doesn't give me the MQ-8 datasheet, it links to something else.

wvmarle:
Do you have a link to the data sheet and how to connect the thing? The "datasheet" link on the page you linked to doesn't give me the MQ-8 datasheet, it links to something else.

I believe it's the breakout board the OP has.

Here is the datasheet for the sensor itself. I wonder how long the device wasexposed to air before it was finally turned on? This could be the reason for the incorrect behavior:

The datasheet:
2.3 Long time storage
The sensors resistance will drift reversibly if it’s stored for long time without electrify, this drift is related with storage conditions. Sensors should be stored in airproof bag without volatile silicon compound. For the sensors with long time storage but no electrify, they need long galvanical aging time for stability before using. The suggested aging time as follow:

Storage Time              Suggested aging time


Less than one month       No less than 48 hours
1 ~ 6 months              No less than 72 hours
More than six months      No less than 168 hours

@emce97: this might be the problem. You should turn it on and let it run continuously for a week before calibrating it.

Hi,
The data sheet shows ALL pins being used.
mq8circ.jpg

Note that gnd of the Arduino connected to the gnd circuit of the MQ8.
Note that sandbox quote heater as 31K when it is really 29Ohms +/- 3 Ohms.

If the OP is using the breakout PCB, how do you use the onboard potentiometer, I cannot find a circuit of the breakout to show how it is involved in the circuit.

Tom... :slight_smile:

Based on the description given of the breakout board, I would guess that this pot goes in place of R1 (probably with an extra resistor to have minimum resistance there).

That 31k for the heater (at room temperature, they added), maybe that is the resistance between A and B? Indeed an 800 mW heater can not have that high a resistance.

TomGeorge:
The data sheet shows ALL pins being used.

Note that gnd of the Arduino connected to the gnd circuit of the MQ8.
Note that sandbox quote heater as 31K when it is really 29Ohms +/- 3 Ohms.

If the OP is using the breakout PCB, how do you use the onboard potentiometer, I cannot find a circuit of the breakout to show how it is involved in the circuit.

  1. There is a connection between 1-3 and 4-6 pins so it is not necessary to use them all.
  2. Yeah, I have common GND.
  3. I don't have any potentiometer, just resistor, as in datasheet. I've got just an MQ-8 in metal case without any PCB.

So I guess I should replace R1 with a potentiometer, like on the pic below, right?

Hi,
I think the burn in time appears to be the solution, you don't know how long its been stored in inventory, and inactive.
I think each time you ran the code the resistance was getting bigger.

So you may have to leave it running for at least a couple of days to burn it in.

Tom... :slight_smile:

Already started to burning it out, but the resistance isn't getting bigger, it oscillates around 1-4 kohm.

emce97:
Already started to burning it out, but the resistance isn't getting bigger, it oscillates around 1-4 kohm.

Just let it run for a week (168 hours.) Then set it up & calibrate.