MQ2 Sensor and Fire Prevention

This project strives to help my aging grandparents. Age makes us forgetful enough to meddle with our routines and priorities. My grandparents seldom tend to leave the stove turned on without the flame being lit, and that could be a potential hazard. So I decided to address the issue with an Arduino project. Of course the credibility of the project could be questioned considering the finantial inputs involved, but its still better than nothing.

So this one involves a basic MQ2 methane and flamable gas sensor (questionably) calibrated to contextual environment and hardware values (RO and Load Resistance and the likes). The hardware involved is:

Arduino Mini Pro 5v/16Mhz
MQ2 Gas Sensor
SSD1306 OLED
DS18B20 Onewire Temperature Sensor
RTC DS3231
Relay 5v
Buzzer
Momentary Switches

Objective: To detect an unmediated escalation of flamable gases or rise in temperature and offer a warning combined with countermeasures (turn on the air ventilator?).

Setup:

+Arduino → 5v through Ground and Raw
+MQ2 → Connected at A0 of Arduino
+OLED → Shares the same 5v supply and data to A4 and A5
+DS18B20 → Pin 3
+RTC DS3231 → Pin A4 and A5
+Relay → Pin 7
+Buzzer (not yet implimented)
+Momentary Switch → Pin 6. The switch is intended to toggle between Auto/Manual control of air ventilator.

Issues:

  1. Momentary Switch: The switch is meant to offer an option to either automate the activation of air ventilator based upon either gas concentration or elevated temperatures (the rise in temperature is calculated with referenced with internal temperature sensor on RTC DS3231), or act as manual On/Off switch. So it will cycle through Auto>On>Off modes. But here lies the problem. A case based selection menu was implimented, but it seldom works. Sometimes the button push is detected, and ignored on other occaisions. And for some reasons, the button ceases to make a difference after 2-3 changes of mode. I sincerely need help here.

  2. “Ro = MQCalibration(MQ_PIN);”: This statement needs to be run to calibrate the sensor. Is there any way to reflect that on the Display? A statement like “Calibrating” would be better since with the present code, the deplay remains blank for the duration of calibration, which makes it appear as if its not responding.

  3. A way to replace ‘delay’ from the MQ2 sensor calculation algorithm, so that it does not affect the flow of the entire process. Perhaps this could help me to opt for a more conservative and less memory intesive display buffer mode (NONAME_1_HW_I2C, instead of NONAME_F_HW_I2C).

  4. Please bear with my inexperience in this domain :slight_smile:

Code is attached as the post had reached the word limit. Please take a look, thank you!

MQ2_Gas_Sensor_U8G2.ino (7.79 KB)

Here’s the code for a quick lookup. I would apreciate any help in this regard. Thanks.

// Updated on 10 NOV 2017
#include <U8g2lib.h>
#ifdef U8X8_HAVE_HW_SPI
#include <SPI.h>
#endif
#ifdef U8X8_HAVE_HW_I2C
#include <Wire.h>
#endif

#include "DHT.h"
#include <MQ135.h>
#include "RTClib.h"
#include <OneWire.h>
#include <DallasTemperature.h>
RTC_DS3231 rtc;

#define ONE_WIRE_BUS 3 // Data wire is plugged into pin 3 on the Arduino
OneWire oneWire(ONE_WIRE_BUS); // Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature.
#define RELAY1  7 // Relay Pin
char daysOfTheWeek[7][12] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};

#define         MQ_PIN                       (0)     //define which analog input channel you are going to use
#define         RL_VALUE                     (2.4)     //define the load resistance on the board, in kilo ohms
#define         RO_CLEAN_AIR_FACTOR          (13.9)  //RO_CLEAR_AIR_FACTOR=(Sensor resistance in clean air)/RO,
#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 
#define         GAS_LPG                      (0)
#define         GAS_CO                       (1)
#define         GAS_SMOKE                    (2)
float           LPGCurve[3]  =  {3.3, 0.72, -0.47};
float           COCurve[3]  =  {2.3, 0.72, -0.34};
float           SmokeCurve[3] = {2.3, 0.53, -0.44};
float           Ro           =  10;                 //Ro is initialized to 10 kilo ohms
byte AlarmPlayed = false; // Variable to control Alarm occurrence
byte FanState = false;
int buzzPin = 9; // Buzzer Pin
int switchPin = 6; // Mode Switch Pin
int val;                        // variable for reading the pin status
int val2;                       // variable for reading the delayed status
int buttonState = 0;
int Mode = 0;


U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);

float MQResistanceCalculation(int raw_adc)
{
  return ( ((float)RL_VALUE * (1023 - raw_adc) / raw_adc));
}

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


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


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


int  MQGetPercentage(float rs_ro_ratio, float *pcurve)
{
  return (pow(10, ( ((log(rs_ro_ratio) - pcurve[1]) / pcurve[2]) + pcurve[0])));
}



void setup(void) {

  Serial.begin(9600);                               //UART setup, baudrate = 9600bps
  pinMode(switchPin, INPUT);
  buttonState = digitalRead(switchPin);
  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");


  u8g2.begin();
}

void loop(void) {
  u8g2.firstPage();
  do {

    // TIME
    DateTime now = rtc.now();
    u8g2.drawRBox(0, 0, 128, 14, 0); // Header Frame
    u8g2.setColorIndex(0);
    // Display Time
    u8g2.setFont(u8g2_font_7x14B_mr);
    u8g2.setCursor(1, 12);
    if (now.hour() < 10) {      // Zero padding if value less than 10 ie."09" instead of "9"
      u8g2.print("0"); u8g2.print(now.hour(), DEC);
    }
    else {
      u8g2.print(now.hour(), DEC);
    }
    u8g2.print(':');
    if (now.minute() < 10) {      // Zero padding if value less than 10 ie."09" instead of "9"
      u8g2.print("0"); u8g2.print(now.minute(), DEC);
    }
    else {
      u8g2.print(now.minute(), DEC);
    }

    // TEMPERATURE
    sensors.begin(); // Initialize Dallas One Wire Sensor
    float RTCTemp = rtc.getTemperature() - 1.6;
    sensors.requestTemperatures(); // Send the command to get temperatures
    u8g2.print(" "); u8g2.print(sensors.getTempCByIndex(0), 1); u8g2.print(char(247)); u8g2.print("C"); u8g2.print(RTCTemp, 1);
    u8g2.drawVLine(39, 0, 15); // Virtical Divider


    u8g2.setColorIndex(1);
    // TIME

    // POLLUTION DATA
    u8g2.setFont(u8g_font_5x8);
    u8g2.setCursor(45, 23);
    u8g2.print("CONTAMINATION");
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(0, 33);
    u8g2.print(analogRead(MQ_PIN)); //Substracts X from value offered by sensorValue
    //u8g2.drawVLine(37,16,19);
    //u8g2.drawFrame(0,16,36,21);
    u8g2.drawFrame(45, 28, 60, 6);
    u8g2.drawBox(45, 28, analogRead(MQ_PIN) / 16, 6);

    u8g2.setFont(u8g_font_5x8);
    u8g2.setCursor(45, 45);
    u8g2.print("LPG GAS PPM");
    u8g2.setFont(u8g2_font_logisoso16_tr);
    u8g2.setCursor(0, 55);
    u8g2.print((MQGetGasPercentage(MQRead(MQ_PIN) / Ro, GAS_LPG))); //Substracts X from value offered by sensorValue
    u8g2.drawFrame(45, 49, 60, 6);
    u8g2.drawBox(45, 49, (MQGetGasPercentage(MQRead(MQ_PIN) / Ro, GAS_LPG)) / 16, 6);

    // FAN Control. Three Modes are intended. Mode0 is Automatic based upon environmental factors, The other two modes will toggle the Relay state.

    val = digitalRead(switchPin);      // read input value and store it in val
    delay(10);                         // 10 milliseconds is a good amount of time
    val2 = digitalRead(switchPin);     // read the input again to check for bounces
    if (val == val2) {                 // make sure we got 2 consistant readings!
      if (val != buttonState) {          // the button state has changed!
        if (val == LOW) {                // check if the button is pressed
          if (Mode == 0) {
            Mode = 1;
          } else {
            if (Mode == 1) {
              Mode = 2;
            } else if (Mode == 2) {
              Mode = 0;
            }
          }
        }
      }
      buttonState = val;                 // save the new state in our variable
    }

    // Now do whatever the lightMode indicates


    if (Mode == 0) { // Auto

      pinMode(RELAY1, OUTPUT); //Define Relay Pin Mode (whether input or output)
      if (sensors.getTempCByIndex(0) > RTCTemp + 2) // Check if the Temperature is high enough to turn on Fan
      {
        digitalWrite(RELAY1, 0); // Turn Relay On
      }
      else
      {
        digitalWrite(RELAY1, 1); // Turn Relay Off
      }

    }

    if (Mode == 1) {
      digitalWrite(RELAY1, 1);
    }

    if (Mode == 2) {
      if (digitalRead(7) == LOW)
      {
        digitalWrite(RELAY1, 0);
      }

    }

    // Read the state of Arduino pin that controls the Air Ventilator and display 'F' when active.
    if (digitalRead(6) == LOW) {
      u8g2.drawFrame(112, 45, 16, 16); // FanBox
      u8g2.setFont(u8g_font_7x14);
      u8g2.setCursor(117, 58);
      u8g2.print("F");
    }

  }


  while ( u8g2.nextPage() );
  //`delay(100);

}

I'm hopeful, someone will help.

I really can't help much with your code. A lot to learn for me yet.

But I would seriously put thought into a professionally designed commercially available setup. You're talking about people's lives if something doesn't do what you expect it to. Just my 2 cents.

+1 for the professional alarm. In particular LPG alarms are not expensive and are properly calibrated to give warning about dangerous quantities of gas.

I would not trust the cheap, unreliable and indiscriminate MQ series of sensors for anything to do with personal safety.

DangerToMyself:
I really can't help much with your code. A lot to learn for me yet.

But I would seriously put thought into a professionally designed commercially available setup. You're talking about people's lives if something doesn't do what you expect it to. Just my 2 cents.

I would not trust the cheap, unreliable and indiscriminate MQ series of sensors for anything to do with personal safety.

Thanks, I guess it would be a wise idea to seek out credible products. It would be helpful if you could cite some examples as such products are not available in domestic market in India. Further, I have little faith in chinese contraptions that Aliexpress offers. Platforms like Amazon would be preferable as they ship here.

Amazon has a search function.

jremington:
Amazon has a search function.

I know. I was looking for suggestions since I do not know if ratings indeed translate into reliability. At least that is not that case here. If I am investing into something like this, it might as well serve better.

Well, I rummaged the entire Amazon and couldn't find anything that works for sure. Most of them have almost equal contradictory customer experiences. The one with most positive reviews, the Safe-T-Alert, expires in 5 years and is sold with a manufacturing date of 2015. One of the bestselling ones like the Universal, has the most contrary reviews. The industry is known to fabricate narratives that seldom agree with truth. The 'best' is hardly average in pragmatic scenario. In this case, even an MQ2 based prototype, if rightfully calibrated is more reliable since its imperfections are known unlike consumer electronics which are technological black holes.

Please, someone with experience in this technology point me in the right direction.

Sometimes the button push is detected, and ignored on other occaisions.

This sounds like a floating pin problem.

  pinMode(switchPin, INPUT);

This does nothing to assure me that you have, indeed, incorporated a pullup or pulldown resistor so that the pin is always in a known state.

Just how IS your switch wired?

    float RTCTemp = rtc.getTemperature() - 1.6;
    sensors.requestTemperatures(); // Send the command to get temperatures

Why do you get the temperature BEFORE you tell the sensors to get ready?

    val = digitalRead(switchPin);      // read input value and store it in val
    delay(10);                         // 10 milliseconds is a good amount of time
    val2 = digitalRead(switchPin);     // read the input again to check for bounces

Why do these variables need to be global? Does ANY other function care?

Do you really count this way? Uh-huh, two, three? What's wrong with the more conventional one, two, three?

In this case, even an MQ2 based prototype, if rightfully calibrated is more reliable

How would you know that? In my experience, MQ series detectors drift so badly as to be useless.

If you have the equipment to "rightfully calibrate" an MQ2 detector, which involves making accurate measurements of gas concentrations, then you have no need for the detector. But do let us know what you learn.

By the way, Amazon is an agency aimed at high volume mail order sales. The "whole of Amazon" is not "the world of gas detectors". Quality is expensive! One source of certified explosive gas leak detectors: http://www.gasleaksensors.com/lel-gas-detectors.html

jremington:
+1 for the professional alarm. In particular LPG alarms are not expensive and are properly calibrated to give warning about dangerous quantities of gas.

I would not trust the cheap, unreliable and indiscriminate MQ series of sensors for anything to do with personal safety.

I just finished a somewhat exhaustive search on Google to find these reliability issues you mention.
Unfortunately, I can't say I found a single one.

I do not doubt your word, but where can I find this information you speak of for myself?

I even searched on MQ2+Unreliable......no results that show this propensity.

I did discover that there is a "burn-In" process required to make them more consistent and reliable.
I'm wondering if that's what your results were lacking?

Thanks

quamikazee:
I just finished a somewhat exhaustive search on Google to find these reliability issues you mention.
Unfortunately, I can't say I found a single one.

I do not doubt your word, but where can I find this information you speak of for myself?

I even searched on MQ2+Unreliable......no results that show this propensity.

I did discover that there is a "burn-In" process required to make them more consistent and reliable.
I'm wondering if that's what your results were lacking?

Thanks

I believe what is being referred here is calibration of MQ Sensors before any implementation. The sensors themselves are indescminate towards gases they detect. Mostly, people deploy sensitivity curve to defferentiate between gases. If concentration (PPM) is of importance, then these sensors need to be professionally calibrated. If only a gas mixture is to be detected, DOUT on the sensor board is helpful. I'm using MQ2 to detect propane and use the DOUT to detect its presence.

jremington:
How would you know that? In my experience, MQ series detectors drift so badly as to be useless.

If you have the equipment to "rightfully calibrate" an MQ2 detector, which involves making accurate measurements of gas concentrations, then you have no need for the detector. But do let us know what you learn.

By the way, Amazon is an agency aimed at high volume mail order sales. The "whole of Amazon" is not "the world of gas detectors". Quality is expensive! One source of certified explosive gas leak detectors: http://www.gasleaksensors.com/lel-gas-detectors.html

Yes, precision calls for substantial investments. Although I have seen some consumer oriented products use MQ sensors, though they may be well calibrated. Even Grove Multichannel Gas Sensor has garnered mixed response.