Detecting LPG, Propane & Butane

As I previously mentioned, I got a number of gas sensors. The intention is to use one to build a gas leak detector for a neighbour who has no sense of smell and runs a burger van. After reading the datasheets for a number of possible sensors including the MQ-2, MQ-5 and MQ-6, I decided to use the MQ-6 as it seemed best suited. The MQ-2 is sensitive to smoke, which rules it out and the MQ-6 appears to be more sensitive to LPG than the MQ-5, judging by the datasheets. The sensors I have come on breakout boards. My MQ-6 board is powered from 5v and has a digital output with the threshold set by a potentiometer on the board in addition to the analogue output. The on board comparator (I’ve not looked into what form it takes) lights an LED when the gas concentration exceeds the level set by the potentiometer, but be aware that a digital LOW corresponds to a positive identification of gas, and a digital HIGH corresponds to the concentration being lower than the set threshold. The datasheet states that the sensor consumes <750mW, mine seems to be using something between 400 and 500mW.

MQ-6 Gas Sensor

I have been using an Arduino Pro Micro board because they are convenient for prototyping in breadboard as they have a built in USB port and a DIL layout. I may switch to a ATTiny85 or a ATMega328 in the future. The Pro Micro is built around the ATMega32u4 chip and can be bought cheaply from alibaba, or almost as cheaply using paypal from banggood.

Arduino Pro Micro

After writing some comments in an empty sketch to give me the structure of what I wanted to do, I wired up the sensor, along with an LED (unfortunately the Pro Micro only has LEDs for power, TX and RX) and a push-to-make switch to act as an “action” button. I later added a 2N7000 MOSFET, which I am using to switch power to the sensor – this is being used to reduce the power consumption after 10 minutes and reduce battery usage should someone forget to turn the device off!

20160206_144747

Quick diagram (ignore the colours in the photo, they’re misleading) :

Screenshot from 2016-02-06 18:14:43

The sensor seems to need bedding in and so the values I’ve used for alarm thresholds are only temporary. Once it stabilises (it is referred to as a “burning in” period elsewhere), I’ll re-visit the values.

The current code is as follows :

// LPG Gas Detector
// 
// Using the MQ-6, although with changes to detection values,
// you could easily use the MQ-5, or perhaps the MQ-2.
// No responsibility is taken for failure to detect gas.
// Samplerates are approximate for simplicity.
// 6th Feb 2016 version 0.1



int heaterPin = 9; // connect a MOSFET or transistor to this pin to
                      // drive the Heater
int DIn = 10; // connect the digital trigger from the sensor

int AIn = A0; // connect the analogue input from the sensor

int LED1 = 2; // LED

int action = 7; // action button

unsigned long stopTime;
byte heaterOffMinutes = 10;// time before auto power down heater
byte heaterDelayMinutes = 3;// time to wait for heater to start
//byte heaterDelayMinutes = 1;// time to wait for heater to start
byte samplesPerMinute = 30;// number of samples in a minute
byte reheatDelayMinutes = 1;// Time to reheat after low power mode. Should really be 3 minutes.

boolean debug = true;

int lowAlarm = 250;
int medAlarm = 375;
int highAlarm = 500;

void setup() {
  unsigned long heaterOff = heaterOffMinutes*60L*1000L;// min*seconds*ms
  int heaterDelay = heaterDelayMinutes*60L;// min*seconds

  if(debug){
    Serial.begin(115200);
  }
  
  delay(3000);

  if(debug){
    Serial.println("Setting up pins...");
  }
  
  pinMode(DIn,INPUT);
  pinMode(AIn, INPUT);
  pinMode(LED1, OUTPUT);
  pinMode(heaterPin, OUTPUT);
  pinMode(action, INPUT);

  digitalWrite(LED1, LOW);

  if(debug){
    Serial.println("Turning on heater...");
  }
  
  // Turn on heater
  digitalWrite(heaterPin, HIGH);

  if(debug){
    Serial.println("Waiting for heater to warm up...");
  }
  
  // Wait Three minutes before giving readings
  heat(heaterDelay);//heaterDelay in seconds

  // Record target stop time for auto heater off (save the battery!)
  stopTime = millis()+heaterOff;
  if(debug){
    Serial.println("Heater will stop at : " + String(stopTime,DEC));
  }
  
}

void loop() {
  // Go to sleep after 10 minutes? At least turn off heater.
  if(millis() < stopTime){
      if(debug){
        Serial.println(String((stopTime-millis())/1000, DEC) + " seconds until sleep. Taking Reading...");
      }
      int AVal = analogRead(AIn);
      boolean DVal = !digitalRead(DIn);// 0 is high
      if(debug){
        Serial.println("Digital is : " + String(DVal, DEC));
      }
      if(debug){
        Serial.println("Analogue is : " + String(AVal, DEC));
      }
      if(AVal > lowAlarm){
        if(AVal > medAlarm){
          if(AVal > highAlarm){
            //HighAlarm
            digitalWrite(LED1, HIGH);
            if(debug){
              Serial.println("Alarm! High");
            }
          }else{
            //MedAlarm
            if(debug){
              Serial.println("Alarm! Medium");
            }
            digitalWrite(LED1, LOW);
            delay(10);
            digitalWrite(LED1, HIGH);
            delay(50);
            digitalWrite(LED1, LOW);
            delay(200);
            digitalWrite(LED1, HIGH);
            delay(50);
            digitalWrite(LED1, LOW);
            delay(200);
            digitalWrite(LED1, HIGH);
            delay(50);
            digitalWrite(LED1, LOW);
          }
        }else{
          //LowAlarm
          if(debug){
              Serial.println("Alarm! Low");
            }
          digitalWrite(LED1, LOW);
          delay(10);
          digitalWrite(LED1, HIGH);
          delay(50);
          digitalWrite(LED1, LOW);
          delay(200);
          digitalWrite(LED1, HIGH);
          delay(50);
          digitalWrite(LED1, LOW);
        }
      }else{
        //NoAlarm
        digitalWrite(LED1, LOW);
      }

  
  
  }// end of stopTime if
  else{
    if(debug){
      Serial.println("Low Power mode");
    }
    //sleep mode instead of delay?
    digitalWrite(heaterPin, LOW);
    int y = 0;
    for(int x=0; x<30; x++){
      if(digitalRead(action)){
        y++;
      }else{
        y=0;
      }
      if(y>2){
        // Record target stop time for auto heater off (save the battery!)
        digitalWrite(heaterPin, HIGH);
        while(digitalRead(action)){
          //do nothing
          delay(100);
        }
        heat(reheatDelayMinutes*60L);
        stopTime = millis()+(heaterOffMinutes*60L*1000L);
        x = 30;
        if(debug){
          Serial.println("Heater will stop at : " + String(stopTime,DEC));
        }
      }
      delay(2000);
    }
    
  }
  delay(60000L/samplesPerMinute);

  digitalWrite(LED1, LOW);
  delay(10);
  digitalWrite(LED1, HIGH);
  delay(10);
  digitalWrite(LED1, LOW);
}

void heat(int heaterDelay){ // heaterDelay in seconds
  for(int x = 0; x< heaterDelay; x++){
    boolean btn = false;
    if(debug){
      Serial.println("Readings start in... " + String(heaterDelay-x,DEC)+ " seconds");
    }
    //Serial.println(String(x, DEC) + " of " + String(heaterDelay, DEC));
    digitalWrite(LED1, !digitalRead(LED1));
    if(digitalRead(action)){
      btn = true;
    }
    delay(1000);
    if(digitalRead(action) && btn){
      x = heaterDelay;
      if(debug){
        Serial.println("Warm up skipped...");
      }
    }
  }
}

If you spot any errors, please drop me a message!

As always, the most difficult part of this project seems to be identifying a suitable power source and box. I’ve been using my USB meter to gauge how much energy the circuit uses – I estimate that I  can run it with the heater on for 10 hours off four AA batteries. I’m struggling to identify a box that would easily allow the end user to change the battery without being forced to use a PP6 battery, which would be a waste of 4v. I’m not sure how accurate my little USB meter is, but it is very useful as I power a lot of my projects off computer USB ports or my USB battery packs!

USB Meter

My USB Voltage and Current Meter.

Leave a Reply