MQ2: gas and smoke detector (Arduino)

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.80

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

mq-2 mq2 sensor arduinoYou may run into problems installing your MQ-2 on a breadboard. Indeed, the manufacturers often quite often solder the angled connectors a little too far from the edge (to let the appearances appear) which prevents to use a breadbord. In this case, not the choice, it will be necessary to use Jumpers Dupont M/F.

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

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

Basic code

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
}

Calibrate an MQ2 to detect different gases

The above code simply reads the analog value returned by the detector. If you want to know more precisely the value of the emission level of the gas, we will have to carry out a calibration. The manufacturer has published two curves in the technical documentation to enable us to carry out the calibration.

mq2 mq-2 sensibilite capteur pour gpl co alcool propane fumées hydrogene

The second curve allows the calibration to be adjusted as a function of temperature and humidity.

mq2 mq-2 correction sensibilite fonction humidite temperature

To calibrate, we do not need to re-invent the wheel, we will use the code provided by Sandbox Electronics to calibrate the sensor to detect the presence of LPG, CO (carbon monoxide) or smoke in the surrounding atmosphere . Create an Arduino project and paste the code below. This program performs the calibration of resistance R0 alone. To do this, make sure that the sensor is placed in clean air when you start the program.

/*******************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 sensors of the MQ-xx family

The MQ-2 belongs to a family of sensors dedicated to the detection of gases. It is the most versatile detector, the others are specialized in one or two molecules. They can be obtained separately but they can also be found as an assembly of several sensors. You can use the same code as before to test them, it will be necessary to adjust the calibration according to the chosen sensor. For more information on the MQ sensor family, please see this article.

Subscribe to the weekly newsletter

No spam and no other use will be made of your email. You can unsubscribe anytime.

Tags:

  • Nur Tika

    the coding has a erro at the void…line 46

    • Hello Nur. I checked the code but did not find the error on line 46. There may be an error while copying the code in the arduino editor.

  • Sebastian Lange

    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

  • On Jian Ye

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

DIY Projects