MQ2. Get started with gas and smoke detector and Arduino. Calibration, value reading

mq2 arduino curve reading rs r0 ratio calibration
Share on facebook
Share on twitter
Share on linkedin
Share on pinterest
Share on email
Share on whatsapp

The MQ2 is a sensor that allows gas or smoke detector at concentrations of 300 ppm to 10,000 ppm. After calibration, the MQ-2 can detect various gases such as LPG, i-butane, propane, methane, alcohol, hydrogen and fumes. It is designed for indoor use at room temperature.

 

Supplied in 5V, it has an analog output and a potentiometer sensitivity adjustment. You can also find it with a Grove interface, including the SeeedStudio manufacturer for your Intel Edisson projects. You can buy MQ2 from €2.60

Caution, do not use this detector to carry out applications that could endanger the safety of people (medical, industrial, etc.)
Warning. The sensor heats up after a few minutes of use. This is normal, it is the principle of operation of all physicochemical sensors. Take into account in designing your project.

Hardware needed to test the MQ-2 on an Arduino

For this project, you will need the following materials:

Circuit

You may encounter problems installing your MQ-2 on a breadboard. Indeed, manufacturers quite often solder angled connectors a little too far from the edge (to let the markings appear), which prevents the use of a breadboard. In this case, it is preferable to use Dupont M / F Jumpers.

Connect the 3 pins of the sensor to the Arduino (or ESP32 / ESP8266) by following the following wiring diagram

Connect the Vcc and GND pins of the sensor to the 5V and GND of the Arduino

Connect the Pin D0 of the sensor to the analog input A0 of the Arduino

 

arduino mq2 circuit wiring analog input

Basic Arduino code, how to read MQ2 analog signal

Here is the code for testing your MQ-2. By default, the analog output of the MQ-2 is connected to input A0 of the Arduino.

const int mqxPin = A0;  // La sortie analogique du détecteur MQx est reliée au Pin analogique A0 de l'Arduino

void setup()
{
    Serial.begin(9600); // Initialise le port série à 9600 bps // 
}

void loop()
{
    Serial.println(analogRead(mqxPin));
    delay(1000);        // Imprime une mesure chaque seconde
}

How to determine the pollutant concentration with an MQ-2

To detect the presence of a pollutant (gas or smoke), we calculate the ratio between the initial resistance (R0) and the resistance (the analog signal read by the Arduino) that the MQ2 sends back at any time (Rs).

Knowing this ratio, we use the theoretical curve below to determine the quantity of each pollutant.

mq2 mq-2 sensitivity sensor for lpg co alcohol propane fumes hydrogen

Here for example, the ratio Rs / R0 = 2, we read a smoke concentration of 800ppm on the red curve.

mq2 arduino curve reading rs r0 ration

It is preferable to determine the R0 each time the sensor is turned on. In fact, the resistance of MQxx sensors can change over time because the active surface of the sensor can change (presence of dust, stabilization of the ceramic, etc.).

By measuring the temperature and the humidity level, the Rs / R0 ratio can be corrected, which improves detection accuracy.

mq2 mq-2 sensitivity correction humidity temperature function

In practice, the MQ2 sends an analog signal to the Arduino. This signal will be the value of Rs

Example of Arduino code to detect the presence of LPG, CO and smoke with an MQ2

To use the MQ2, there is no need to reinvent the wheel, we will use the code made available by Sandbox Electronics which allows the sensor to be calibrated to detect the presence of LPG, CO (carbon monoxide) or fumes in the surrounding atmosphere. .

Create an Arduino project and paste the code below.

The program begins by measuring the resistance on CALIBARAION_SAMPLE_TIMES samples (measurements). We wait for CALIBRATION_SAMPLE_INTERVAL between each measurement. By default, the initial calibration of R0 lasts 2.5 seconds (5 * 500 ms).

While calibrating R0, make sure that the sensor is placed in “clean” air, ideally outdoors.

We can think of each curve as a straight line. The LPGCurve COCurve and SmokeCurve variables are used to determine the concentration of LPG, fumes and CO in the atmosphere, knowing the Rs / R0 ratio .

The MQGetGasPercentage () method allows you to find out the pollutant concentration. We must indicate the Rs / R0 ratio as well as the desired pollutant GAS_LPG, GAS_CO (carbon monoxide) or GAS_SMOKE.

To find out the presence of other gases, just add the corresponding curves in your code.

/*******************Demo for MQ-2 Gas Sensor Module V1.0*****************************
Support:  Tiequan Shao: 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    2011-04-25
************************************************************************************/

/************************Hardware Related Macros************************************/
#define         MQ_PIN                       (0)     //define which analog input channel you are going to use
#define         RL_VALUE                     (5)     //define the load resistance on the board, in kilo ohms
#define         RO_CLEAN_AIR_FACTOR          (9.83)  //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     (50)    //define how many samples you are going to take in the calibration phase
#define         CALIBRATION_SAMPLE_INTERVAL  (500)   //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_LPG                      (0)
#define         GAS_CO                       (1)
#define         GAS_SMOKE                    (2)

/*****************************Globals***********************************************/
float           LPGCurve[3]  =  {2.3,0.21,-0.47};   //two points are taken from the curve. 
                                                    //with these two points, a line is formed which is "approximately equivalent"
                                                    //to the original curve. 
                                                    //data format:{ x, y, slope}; point1: (lg200, 0.21), point2: (lg10000, -0.59) 
float           COCurve[3]  =  {2.3,0.72,-0.34};    //two points are taken from the curve. 
                                                    //with these two points, a line is formed which is "approximately equivalent" 
                                                    //to the original curve.
                                                    //data format:{ x, y, slope}; point1: (lg200, 0.72), point2: (lg10000,  0.15) 
float           SmokeCurve[3] ={2.3,0.53,-0.44};    //two points are taken from the curve. 
                                                    //with these two points, a line is formed which is "approximately equivalent" 
                                                    //to the original curve.
                                                    //data format:{ x, y, slope}; point1: (lg200, 0.53), point2: (lg10000,  -0.22)                                                     
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("LPG:"); 
   Serial.print(MQGetGasPercentage(MQRead(MQ_PIN)/Ro,GAS_LPG) );
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("CO:"); 
   Serial.print(MQGetGasPercentage(MQRead(MQ_PIN)/Ro,GAS_CO) );
   Serial.print( "ppm" );
   Serial.print("    ");   
   Serial.print("SMOKE:"); 
   Serial.print(MQGetGasPercentage(MQRead(MQ_PIN)/Ro,GAS_SMOKE) );
   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_LPG ) {
     return MQGetPercentage(rs_ro_ratio,LPGCurve);
  } else if ( gas_id == GAS_CO ) {
     return MQGetPercentage(rs_ro_ratio,COCurve);
  } else if ( gas_id == GAS_SMOKE ) {
     return MQGetPercentage(rs_ro_ratio,SmokeCurve);
  }    

  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])));
}

The other detectors of the MQ-xx family

The MQ-2 belongs to a family of sensors dedicated to gas detection. It is the most versatile detector, the others are specialized in one or two molecules. You can purchase them separately. It is very often found in sensor kits. You can use the same code as before to test them, you will have to adjust the calibration according to the chosen sensor.

See more kits

Click to rate this post!
[Total: 0 Average: 0]

Are you having a problem with this topic?

Maybe someone has already found the solution, visit the forum before asking your question
Ask your question

Share on facebook
Share on twitter
Share on linkedin
Share on pinterest
Share on email
Share on whatsapp

Did you like this project ? Don't miss any more projects by subscribing to our weekly newsletter!

4 Comments
  1. the coding has a erro at the void…line 46

  2. Hi all,
    first off thanks for the awesome tutorial. One question though, in line 166 the function log is used which is base e and pow(10, …) which is base 10. Is there a reason for this? Should both not be using the same base? Switching to log10 leads to more plausible results in my case although I have not been able to verify since I do not possess any real CO measurement equipment.

    Best regards,

    Sebastian

  3. Hi sir, may i know how to get the value LPGCurve[3] = {2.3,0.21,-0.47}; ——–2.3 and 0.21?

    Leave a Reply

    DIY Projects
    %d bloggers like this: