|
Gas Sensor Practice: MQ Series for Alcohol, Smoke, and Carbon Monoxide Detection - Safety Monitoring DIY Solution

Gas Sensor Practice: MQ Series for Alcohol, Smoke, and Carbon Monoxide Detection - Safety Monitoring DIY Solution

Why Are MQ Series Sensors Still in Use?

MQ series gas sensors have been around for over twenty years - cheap, easy to buy, and simple to use. Although their accuracy can’t match industrial-grade equipment, they’re perfectly adequate for home smoke alarms, alcohol detection, and carbon monoxide monitoring.

Today I’ll walk through the three most commonly used sensors with Arduino: MQ-2 (smoke/combustible gas), MQ-3 (alcohol), and MQ-7 (carbon monoxide), covering everything from wiring to calibration to alarm systems.

Hardware List

ModuleModelPrice (approx.)Description
Gas sensorMQ-2¥8-15Smoke, LPG, methane detection
Gas sensorMQ-3¥6-12Alcohol/ethanol detection
Gas sensorMQ-7¥10-18Carbon monoxide detection
Main boardArduino Uno R3¥15-25ESP32 also works
Breadboard830 holes¥5-10For wiring
BuzzerActive 5V¥2-5Alarm sound
LED1 each of red/yellow/green¥0.5Status indication
Resistors220Ω + 10kΩ¥1Current limiting and voltage divider
Jumper wiresMale-to-male/Male-to-female¥3Connection wires

Total cost: about ¥50-90, cheaper than buying a finished smoke alarm.

Sensor Principle Quick Overview

The core of MQ series is a SnO₂ (tin dioxide) sensitive material whose resistance changes with surrounding gas concentration when heated:

  • In clean air, oxygen adsorbs on the SnO₂ surface, resistance is higher

  • When encountering reducing gases (smoke, alcohol, CO), oxygen is consumed, resistance drops

  • The higher the gas concentration, the lower the resistance, the higher the output voltage

Key parameter: heating time. Each MQ sensor needs to preheat for 24-48 hours after power-on to reach stable state (some models can be shortened to a few minutes for quick testing, but accuracy will be compromised). In actual projects, it’s recommended to preheat for at least 30 minutes before starting to read values.

Wiring Scheme

The wiring for all three sensors is basically the same, all have 4 pins: VCC, GND, AOUT (analog output), DOUT (digital output, some modules have it).

Arduino Uno
├── 5V ────→ Sensor VCC
├── GND ────→ Sensor GND
├── A0  ────→ Sensor AOUT (analog signal)
├── D2  ────→ Buzzer positive (through 220Ω resistor)
└── GND ────→ Buzzer negative

If you’re using a module with a comparator (most on Taobao have it), there will be an additional DOUT pin, which can adjust the digital threshold through the onboard potentiometer, directly outputting high/low levels. However, I recommend using AOUT analog output for higher precision and more flexible threshold adjustment in code.

Complete Code

// MQ Series Gas Sensors - Multi-channel Detection + Alarm System
// Supports MQ-2 (smoke), MQ-3 (alcohol), MQ-7 (carbon monoxide)

#define MQ2_PIN A0      // MQ-2 smoke sensor
#define MQ3_PIN A1      // MQ-3 alcohol sensor
#define MQ7_PIN A2      // MQ-7 carbon monoxide sensor
#define BUZZER_PIN 2    // Buzzer
#define LED_RED 3       // Red LED - danger
#define LED_YELLOW 4    // Yellow LED - warning
#define LED_GREEN 5     // Green LED - normal

// Alarm thresholds (need to be adjusted based on actual calibration)
#define MQ2_SMOKE_THRESHOLD 300    // MQ-2 smoke alarm value
#define MQ3_ALCOHOL_THRESHOLD 250  // MQ-3 alcohol alarm value
#define MQ7_CO_THRESHOLD 200       // MQ-7 CO alarm value

// Preheat time (milliseconds) - sensors need time to stabilize
#define WARMUP_TIME 180000  // 3 minutes minimum preheat

unsigned long warmupStart;
bool sensorReady = false;

void setup() {
  Serial.begin(115200);
  pinMode(BUZZER_PIN, OUTPUT);
  pinMode(LED_RED, OUTPUT);
  pinMode(LED_YELLOW, OUTPUT);
  pinMode(LED_GREEN, OUTPUT);

  // All LEDs off
  digitalWrite(LED_RED, LOW);
  digitalWrite(LED_YELLOW, LOW);
  digitalWrite(LED_GREEN, LOW);
  digitalWrite(BUZZER_PIN, LOW);

  warmupStart = millis();
  Serial.println("=== MQ Gas Sensor System Starting ===");
  Serial.print("Preheating... Estimated ");
  Serial.print(WARMUP_TIME / 60000);
  Serial.println(" minutes");
}

void loop() {
  // Preheat check
  if (!sensorReady) {
    unsigned long elapsed = millis() - warmupStart;
    if (elapsed >= WARMUP_TIME) {
      sensorReady = true;
      Serial.println("✅ Preheat complete, sensors ready!");
      digitalWrite(LED_GREEN, HIGH);
    } else {
      Serial.print("Preheat progress: ");
      Serial.print(elapsed / 1000);
      Serial.print(" / ");
      Serial.print(WARMUP_TIME / 1000);
      Serial.println(" seconds");
      delay(5000);
      return;
    }
  }

  // Read sensor values
  int mq2Value = analogRead(MQ2_PIN);
  int mq3Value = analogRead(MQ3_PIN);
  int mq7Value = analogRead(MQ7_PIN);

  // Print data
  Serial.print("MQ-2(Smoke): ");
  Serial.print(mq2Value);
  Serial.print(" | MQ-3(Alcohol): ");
  Serial.print(mq3Value);
  Serial.print(" | MQ-7(CO): ");
  Serial.println(mq7Value);

  // Determine status and control output
  bool alarm = false;
  bool warning = false;

  // Smoke detection
  if (mq2Value > MQ2_SMOKE_THRESHOLD) {
    Serial.println("⚠️ Smoke detected!");
    alarm = true;
  } else if (mq2Value > MQ2_SMOKE_THRESHOLD * 0.7) {
    warning = true;
  }

  // Alcohol detection
  if (mq3Value > MQ3_ALCOHOL_THRESHOLD) {
    Serial.println("⚠️ Alcohol vapor detected!");
    alarm = true;
  } else if (mq3Value > MQ3_ALCOHOL_THRESHOLD * 0.7) {
    warning = true;
  }

  // Carbon monoxide detection
  if (mq7Value > MQ7_CO_THRESHOLD) {
    Serial.println("🚨 Carbon monoxide detected! Danger!");
    alarm = true;
  } else if (mq7Value > MQ7_CO_THRESHOLD * 0.7) {
    warning = true;
  }

  // Control LEDs and buzzer
  if (alarm) {
    digitalWrite(LED_RED, HIGH);
    digitalWrite(LED_YELLOW, LOW);
    digitalWrite(LED_GREEN, LOW);
    digitalWrite(BUZZER_PIN, HIGH);  // Buzzer sounds
  } else if (warning) {
    digitalWrite(LED_RED, LOW);
    digitalWrite(LED_YELLOW, HIGH);
    digitalWrite(LED_GREEN, LOW);
    digitalWrite(BUZZER_PIN, LOW);
  } else {
    digitalWrite(LED_RED, LOW);
    digitalWrite(LED_YELLOW, LOW);
    digitalWrite(LED_GREEN, HIGH);
    digitalWrite(BUZZER_PIN, LOW);
  }

  delay(2000);  // Read once every 2 seconds
}

Calibration Method: This Step Cannot Be Skipped

MQ sensor values are not absolute, greatly affected by temperature, humidity, and individual sensor differences. Calibration is mandatory.

// Read 100 times in known clean air, take average as baseline
float getBaseline(int pin) {
  long sum = 0;
  for (int i = 0; i < 100; i++) {
    sum += analogRead(pin);
    delay(10);
  }
  return sum / 100.0;
}

void calibrate() {
  Serial.println("Calibrating... Please ensure clean air environment");
  delay(5000);
  
  float mq2Baseline = getBaseline(MQ2_PIN);
  float mq3Baseline = getBaseline(MQ3_PIN);
  float mq7Baseline = getBaseline(MQ7_PIN);
  
  Serial.print("MQ-2 Baseline: "); Serial.println(mq2Baseline);
  Serial.print("MQ-3 Baseline: "); Serial.println(mq3Baseline);
  Serial.print("MQ-7 Baseline: "); Serial.println(mq7Baseline);
}

Method 2: Standard Gas Calibration (Professional)

If you have access to standard gas (like 50ppm CO standard gas):

// Calculate sensitivity coefficient
float calculateSensitivity(int pin, float knownPPM) {
  float sensorValue = analogRead(pin);
  float baseline = getBaseline(pin);
  
  // Rs/R0 ratio
  float rs_r0 = (1023.0 - sensorValue) / (1023.0 - baseline);
  
  // Calculate sensitivity coefficient (specific formula varies by sensor model)
  // Take MQ-7 as example: lg(Rs/R0) = -0.35 * lg(ppm) + 0.55
  float sensitivity = pow(10, (-0.35 * log10(knownPPM) + 0.55));
  
  return sensitivity;
}

Threshold Setting Strategy

Don’t just copy threshold values from datasheets! Adjust based on actual environment:

// Dynamic threshold adjustment
void adjustThresholds() {
  // Read current environment baseline
  float currentBaseline = getBaseline(MQ2_PIN);
  
  // Set threshold as 2x baseline (adjustable)
  #define THRESHOLD_MULTIPLIER 2.0
  
  int newThreshold = currentBaseline * THRESHOLD_MULTIPLIER;
  
  Serial.print("Adjusted MQ-2 threshold: ");
  Serial.println(newThreshold);
}

Recommended threshold ranges:

SensorClean air baselineWarning thresholdAlarm threshold
MQ-2100-150250-300400+
MQ-380-120200-250350+
MQ-750-100150-200300+

Power Supply Considerations

MQ sensor heating element consumes considerable power:

  • Single sensor heating current: 80-120mA
  • Three sensors simultaneously: 240-360mA

Power supply recommendations:

  • Use independent 5V/2A power supply
  • Don’t power from USB (current insufficient)
  • Add 100μF electrolytic capacitor at power input for filtering
// Power management: heat sensors sequentially
void powerManagement() {
  // Control sensor power via MOSFET
  digitalWrite(MQ2_POWER, HIGH);
  delay(5000);  // MQ-2 heats for 5 seconds
  int mq2Value = analogRead(MQ2_PIN);
  digitalWrite(MQ2_POWER, LOW);
  
  digitalWrite(MQ3_POWER, HIGH);
  delay(5000);
  int mq3Value = analogRead(MQ3_PIN);
  digitalWrite(MQ3_POWER, LOW);
  
  // ...
}

Home Assistant Integration

Upload data to MQTT server for Home Assistant monitoring:

#include <WiFi.h>
#include <PubSubClient.h>

// WiFi and MQTT configuration
const char* wifi_ssid = "YOUR_WIFI";
const char* mqtt_server = "192.168.1.100";

WiFiClient espClient;
PubSubClient client(espClient);

void setup() {
  WiFi.begin(wifi_ssid, "YOUR_PASSWORD");
  while (WiFi.status() != WL_CONNECTED) delay(500);

  client.setServer(mqtt_server, 1883);
  client.connect("gas-sensor");
}

void loop() {
  if (client.connected()) {
    int mq2Value = analogRead(MQ2_PIN);
    client.publish("sensor/gas/mq2", String(mq2Value).c_str());
  }
  delay(5000);
}

Add in Home Assistant’s configuration.yaml:

sensor:
  - platform: mqtt
    name: "Kitchen Smoke Sensor"
    state_topic: "sensor/gas/mq2"
    unit_of_measurement: "ppm"
    device_class: "gas"

Summary

Although MQ series sensors are old, they excel in being cheap and easy to use. Perfectly adequate for home safety monitoring, laboratory gas detection, or simple DIY projects.

Core points review:

  • Preheat first, at least 30 minutes

  • Must calibrate, clean air baseline is the simplest method

  • Power supply must be stable, heating element consumes significant power

  • Thresholds need adjustment based on actual environment, don’t just copy datasheets

  • For safety-related applications (especially CO detection), recommend dual protection with commercial equipment

Hope this blog post is helpful to you!