Gas Sensor

How does it work?

Gas sensors serve to measure the concentration of gases in the environment. There are many different types depending on what you want to measure. In this case, the MQ-4 gas sensor can measure Liquefied Petroleum Gas (LPG), Methane (CH4), Hydrogen (H2), Carbon Monoxide (CO), alcohol, and smoke concentrations.

The sensor has a built in variable resistor that changes its value according to the concentration of gas. If the concentration is high, the resistance decreases. If the concentration is low, the resistance increases. Besides the built in resistor, it is necessary to include a load resistor. This resistor serves to adjust the sensor’s sensitivity and accuracy. The value can range anywhere from 2k Ohms to 47k Ohms. The higher the value, the more sensitive the sensor becomes.

The value depends on whether you want to measure high concentrations of gas or not. If you choose to measure high concentrations of gas, but choose a high value for the load resistor, then the readings won't be very accurate. Lastly, there is another built-in resistor used for the heater of the sensor. The heater is used to provide the temperature that the sensor needs to work properly. In the end, we have a circuit like this:

Circuit.jpg

Figure 1: Sensor Circuit

Which can also be seen as this:

Circuit3.JPG

Figure 2: Sensor Circuit

Where H, A, and B are the pins of the sensor.  

pins.JPG

Figure 3: Sensor Pinout (Bottom View)

Even though the sensor has six pins in total, pins A and pins B are connected together, leaving us with four connections.

pins2.JPG

Figure 4: Sensor Pins combined

Between A and B there is the built-in resistor that varies depending on the gas concentration. Between H and H there is the built-in resistor for the heater.  

How do we calculate gas concentrations from the variation of resistance? Here is where the data sheet comes in handy:

http://www.jayconsystems.com/fileuploader/download/download/?d=1&file=custom%2Fupload%2FFile-1341960991.pdf

Graph.JPG

Figure 5: MQ-4 Sensitivity Characteristics

Figure 5 tells us the concentration of a gas in part per million (ppm) according to the resistance ratio of the sensor (RS/R0). RS is the resistance of the sensor that changes depending on the concentration of gas, and R0 is the resistance of the sensor at a known concentration without the presence of other gases, or in fresh air.   

Calculations

We can derive a formula to find RS using Ohm's Law:

 
V = I x R
 

Where V is voltage, I is current, and R is resistance. Looking back at the circuit from Figure 1, we can see that RS, which is the resistor between pins A and B, and RL are in series. Thus, we can simplify the circuit as shown below:

Circuit2.JPG

Figure 6: Sensor Circuit Simplified

Now we combine the two resistors in series

1.JPG

Figure 7: RS and RL combined

From Ohm’s Law, we can derive I as follows:

 
I = V / R 
 

Which in our circuit is equal to:

 
I = VC / (RS+RL)
 

Going back to our original circuit from Figure 6, we can obtain the output voltage at the load resistor using the value obtained for I and Ohm’s Law.

 
V = I x R 
 
VRL = [VC / (RS + RL)] x RL 
 
VRL = (VC x RL) / (RS + RL) 
 

So now we solve for RS:

 
VRL x (RS + RL) = VC x RL
 
(VRL x RS) + (VRL x RL) = VC x RL 
 
(VRL x RS) = (VC x RL) - (VRL x RL)
 
RS = [(VC x RL) - (VRL x RL)] / VRL
 
RS = [(VC x RL) / VRL] - RL
 

This formula will help us find the values of the sensor resistance for different gases.

From the graph, we can see that the resistance ratio in fresh air is a constant:

 
RS / R0 = 4.4 ppm
 

To calculate R0 we will need to find the value of the RS in fresh air. This will be done by taking the analog average readings from the sensor and converting it to voltage. Then we will use the RS formula to find R0. We will show you how to do this in the Arduino IDE after the wiring setup.

Now let’s analyze the graph:

  1. The scale of the graph is log-log. This means that in a linear scale, the behavior of the gas concentration with respect to the resistance ratio is exponential.

  2. The data for gas concentration only ranges from 200 ppm to 10000 ppm.

  3. Even though the relation between resistance ratio and gas concentration may seem linear, in reality, it is not.

First of all, we will treat the lines as if they were linear. This way we can use one formula that linearly relates the ratio and the concentration. By doing so, we can find the concentration of a gas at any ratio value even outside of the graph’s boundaries. The formula we will be using is the equation for a line, but for a log-log scale. The formula for a line is:

 
y = mx + b 
 

Where:

 
y: X value 
 
x: X value 
 
m: Slope of the line 
 
b: Y intercept  
 

For a log-log scale, the formula looks like this:  

 
log(y) = m*log(x) + b
 

Note: the log is base 10.

Okay, let’s find the slope. To do so, we need to choose 2 points from the graph. In our case, we chose the points (200,2.6) and (10000,0.75) from the LPG line. The formula to calculate m is the following:

 
m = [log(y) - log(y0)] / [log(x) - log(x0)]
 

If we apply the logarithmic quotient rule we get the following:

 
m = log(y/y0) / log(x/x0)
 

Now we substitute the values for x, x0, y, and y0:

 
m = log(0.75/2.6) / log(10000/200)
 
m = -0.318 
 

Now that we have m, we can calculate the y intercept. To do so, we need to choose one point from the graph (once again from the LPG line). In our case, we chose (5000,0.9)

 
log(y) = m*log(x) + b
 
b = log(y) - m*log(x)
 
b = log(0.9) - (-0.318)*log(5000)
 
b = 1.13
 

Now that we have m and b, we can find the gas concentration for any ratio with the following formula:

log(x) = [log(y) - b] / m

However, in order to get the real value of the gas concentration according to the log-log plot we need to find the inverse log of x:

x = 10 ^ {[log(y) - b] / m}

If you are not sure how logarithms work, you can refer to this link:

http://www.rapidtables.com/math/algebra/Logarithm.htm

Materials

Now that we have the necessary background, we can start working on the tutorial. We will calculate the gas concentration of LPG (butane) in the air and display it on an OLED screen. If the concentration is too high, a red LED will be turned on, and a buzzer will be activated. These are the materials required for this project:

Wiring

Solder some wires to the gas sensor’s pins and add heat shrinking tubing:

MethaneSensor_2.jpg

In our case, the orange wires represent A, the blue wires represent B, and the red wires represent H. If you want, you can make the blue wires A and the orange wires B, there is no polarity in these pins.

Wire the sensor to the Arduino as follows:

 

Gas sensor

Arduino Pro Mini

A

VCC

B

Pin A0

H

VCC

H

GND

 

Connect a 10k ohm resistor from A0 to ground:

MethaneSensor_9.jpg

Connect the OLED to the Arduino as shown below:

MethaneSensor_6.jpg

MethaneSensor_7.jpg

OLED

Arduino Pro Mini

SDA

Pin 4

SCL

Pin 5

RES

Pin 11

GND

GND

VCC

VCC

Connect anode side of LED to Arduino’s pin 10 and cathode side to a 330 ohm resistor. Connect the other end of the 330 ohm resistor to GND.

MethaneSensor_4.jpg

MethaneSensor_5.jpg

 

Connect positive side of buzzer to Arduino’s pin 9. The positive side is marked by “+” on the buzzer. Connect the negative side of the buzzer to GND.

MethaneSensor_1.jpg

MethaneSensor_0.jpg

Code to Calculate R0
  void setup() {  Serial.begin(9600); //Baud rate }   void loop() {  float sensor_volt; //Define variable for sensor voltage  float RS_air; //Define variable for sensor resistance  float R0; //Define variable for R0  float sensorValue; //Define variable for analog readings  for(int x = 0 ; x < 500 ; x++) //Start for loop  {    sensorValue = sensorValue + analogRead(A0); //Add analog values of sensor 500 times  }  sensorValue = sensorValue/500.0; //Take average of readings  sensor_volt = sensorValue*(5.0/1023.0); //Convert average to voltage  RS_air = ((5.0*10.0)/sensor_volt)-10.0; //Calculate RS in fresh air  R0 = RS_air/4.4; //Calculate R0    Serial.print("R0 = "); //Display "R0"  Serial.println(R0); //Display value of R0  delay(1000); //Wait 1 second }  

Code Explanation

 
void setup() {
  Serial.begin(9600); //Baud rate 
}
 

The setup section starts serial communication at 9600 bits per second.

 
void loop() {
  float sensor_volt; //Define variable for sensor voltage 
  float RS_air; //Define variable for sensor resistance in air
  float R0; //Define variable for R0
  float sensorValue; //Define variable for analog readings 
 

Here we are defining the variables that will be used to calculate R0.

 
  for(int x = 0 ; x < 500 ; x++) //Start for loop 
  {
    sensorValue = sensorValue + analogRead(A0); //Add analog values of sensor 500 times 
  }
 

The “for loop” is used to add 500 samples of the analog readings from the sensor.  

 
  sensorValue = sensorValue/500.0; //Take average of readings
  sensor_volt = sensorValue*(5.0/1023.0); //Convert average to voltage 
  RS_air = ((5.0*10.0)/sensor_volt)-10.0; //Calculate RS in fresh air 
  R0 = RS_air/4.4; //Calculate R0
 

In this section, we calculate the average of the analog readings. Then we convert the value to voltage (the value will range from 0-5V). This voltage represents Vout in Figure 2. Next we calculate RS in fresh air using the formula derived in the Calculations section. Lastly we calculate R0 based on the value of RS and the ratio constant obtained from the graph.

 
  Serial.print("R0 = "); //Display "R0"
  Serial.println(R0); //Display value of R0  
  delay(1000); //Wait 1 second 
 

Once we find R0, we display its value in the serial monitor. Let the code run for some time until the sensor stabilizes. Also, take note of the value since it will be used in the next code.

 

Code to Calculate Gas Concentration

 
#include <SPI.h> //Library for SPI interface 
#include <Wire.h> //Library for I2C interface 
#include <Adafruit_GFX.h> //Core graphic library for displays 
#include <Adafruit_SSD1306.h> //Library for OLED display
 
#define OLED_RESET 11 //Reset pin 
Adafruit_SSD1306 display(OLED_RESET); //Set Reset pin for OLED display 
 
int led = 10; //LED pin 
int buzzer = 9; //Buzzer pin 
int gas_sensor = A0; //Sensor pin 
float m = -0.318; //Slope 
float b = 1.133; //Y-Intercept 
float R0 = 11.820; //Sensor Resistance in fresh air from previous code
 
void setup() {
  Serial.begin(9600); //Baud rate 
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Initialize screen 
  display.setTextColor(WHITE); //Set text color 
  display.setTextSize(3); //Set text size 
  pinMode(led, OUTPUT); //Set LED as output 
  digitalWrite(led, LOW); //Turn LED off 
  pinMode(buzzer, OUTPUT); //Set buzzer as output 
  digitalWrite(buzzer, LOW); // Turn buzzer off 
  pinMode(gas_sensor, INPUT); //Set gas sensor as input 
}
 
void loop() {  
  display.clearDisplay(); //Clear display 
  display.setCursor(0,5); //Place cursor in (x,y) location 
  float sensor_volt; //Define variable for sensor voltage 
  float RS_gas; //Define variable for sensor resistance  
  float ratio; //Define variable for ratio
  float sensorValue = analogRead(gas_sensor); //Read analog values of sensor  
  sensor_volt = sensorValue*(5.0/1023.0); //Convert analog values to voltage 
  RS_gas = ((5.0*10.0)/sensor_volt)-10.0; //Get value of RS in a gas
  ratio = RS_gas/R0;  // Get ratio RS_gas/RS_air
 
  double ppm_log = (log10(ratio)-b)/m; //Get ppm value in linear scale according to the the ratio value  
  double ppm = pow(10, ppm_log); //Convert ppm value to log scale 
  double percentage = ppm/10000; //Convert to percentage 
  display.print(percentage); //Load screen buffer with percentage value 
  display.print("%"); //Load screen buffer with "%"
  display.display(); //Flush characters to screen 
  
  if(ppm>2000){ //Check if ppm value is greater than 2000 
    digitalWrite(led, HIGH); //Turn LED on 
   digitalWrite(buzzer, HIGH); //Turn buzzer on  }  else{ //Case ppm is not greater than 2000    digitalWrite(led, LOW); //Turn LED off    digitalWrite(buzzer, LOW); //Turn buzzer off  }   }  

Code Explanation

 
#include <SPI.h> //Library for SPI interface 
#include <Wire.h> //Library for I2C interface 
#include <Adafruit_GFX.h> //Core graphic library for displays 
#include <Adafruit_SSD1306.h> //Library for OLED display
#define OLED_RESET 11 //Reset pin 
Adafruit_SSD1306 display(OLED_RESET); //Set Reset pin for OLED display
 

We start by including the libraries required for I2C and SPI communication (OLED displays use either SPI or I2C interface). We also include the libraries required to control the OLED display. You can download such libraries here:

https://github.com/adafruit/Adafruit-GFX-Library

https://github.com/adafruit/Adafruit_SSD1306

Then we assign an Arduino pin to reset the OLED screen, and let the SSD1306 library know what pin we are using.

 
int led = 10; //LED pin 
int buzzer = 9; //Buzzer pin 
int gas_sensor = A0; //Sensor pin 
float m = -0.318; //Slope 
float b = 1.133; //Y-Intercept 
float R0 = 11.820; //Sensor Resistance in fresh air 
 

Here we assign the corresponding Arduino’s pins to the LED, buzzer, and sensor. We also define our slope, y-intercept, and R0. R0 is the value obtained from the previous code.

 
void setup() {
  Serial.begin(9600); //Baud rate 
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C); //Initialize screen 
  display.setTextColor(WHITE); //Set text color 
  display.setTextSize(3); //Set text size 
  pinMode(led, OUTPUT); //Set LED as output 
  digitalWrite(led, LOW); //Turn LED off 
  pinMode(buzzer, OUTPUT); //Set buzzer as output 
  digitalWrite(buzzer, LOW); // Turn buzzer off 
  pinMode(gas_sensor, INPUT); //Set gas sensor as input 
}
 

In the setup section, we initialize the OLED screen and set the color and size of the text that will be displayed on our screen. We also set the buzzer and LED as outputs and turned them off. Lastly we set the sensor as input.

 
void loop() {  
  display.clearDisplay(); //Clear display 
  display.setCursor(0,5); //Place curson in (x,y) location 
  float sensor_volt; //Define variable for sensor voltage 
  float RS_gas; //Define variable for sensor resistance  
  float ratio; //Define variable for ratio
  float sensorValue = analogRead(gas_sensor); //Read analog values of sensor  
  sensor_volt = sensorValue*(5.0/1023.0); //Convert analog values to voltage
  RS_gas = ((5.0*10.0)/sensor_volt)-10.0; //Get value of RS in a gas
  ratio = RS_gas/R0;  // Get ratio RS_gas/RS_air
 

In the loop, we erase everything that the screen is displaying. Then we set the cursor at the beginning of the screen and somewhat centered in the y-axis. Next we define the variables that will be used to calculate RS in the presence of a gas. Then we read the analog values obtained from the sensor, convert them to voltage, calculate RS using the derived formula, and find the resistance ratio.

 
  double ppm_log = (log10(ratio)-b)/m; //Get ppm value in linear scale according to the the ratio value  
  double ppm = pow(10, ppm_log); //Convert ppm value to log scale 
  double percentage = ppm/10000; //Convert to percentage 
  display.print(percentage); //Load screen buffer with percentage value 
  display.print("%"); //Load screen buffer with "%"
  display.display(); //Flush characters to screen 
 

Once we have the ratio, we find its corresponding value of gas concentration according to the graph. Then we convert the concentration to percentage using the following formula:

 
x(%) = x(ppm) / 10000

Once we have the percentage, we display it on our screen.

 if(ppm>2000){ //Check if ppm value is greater than 2000 
    digitalWrite(led, HIGH); //Turn LED on 
    digitalWrite(buzzer, HIGH); //Turn buzzer on 
  }
  else{ //Case ppm is not greater than 2000
    digitalWrite(led, LOW); //Turn LED off
    digitalWrite(buzzer, LOW); //Turn buzzer off
  }
 

According to this document http://nj.gov/health/eoh/rtkweb/documents/fs/1118.pdf exposure to 2000 ppm of LPG gas is immediatly dangerous to life and health. In this section, we are constantly checking if there is more than 2000 ppm of LPG in the air. If the case is true, then we turn on the LED and buzzer to alert that there is a high concentration of LPG.

Results

The percentage readings obtained are only approximations of the real values. If you want to get more accurate results, then you can do the following:

  • Since the heater of the sensor draws a lot of current and the sensor needs 5V to work properly, it is better if you use an external power supply that assures you a voltage input of 5V with enough current for the heater (The Arduino provided a little less than 4.6V when tested). The Arduino Mini Pro has an internal 5V regulator, so you can connect an external power supply (no more than 12V) to the Raw pin. Alternatively, this tutorial shows you how to setup a 5V regulated power supply:
  • When getting the R0 value, do it in a clean environment where no other gases are present.
  • The datasheet recommends to calculate R0 in an environment that has 10000 ppm of methane. If you can simulate such environment, calculate R0 under these conditions.
  • Let the sensor preheat for a good amount of time (48 hours according to the datasheet), so that the readings stabilize. The longer it preheats, the more accurate readings you will get.