If you are building a fire-detection prototype, the standard 4-pin KY-026 flame sensor connects to an Arduino Uno R3 via VCC to 5V, GND to GND, D0 to Pin 2, and A0 to Pin A0. The sensor detects infrared light between 760nm and 1100nm, using an LM393 comparator to output both an analog voltage and a digital HIGH/LOW signal based on a physical threshold potentiometer.

Safety Caveat: This guide is for hobbyist prototyping and educational embedded projects. According to NFPA 72 (National Fire Alarm and Signaling Code), life-safety fire detection requires UL-listed, hardwired heat and smoke detectors. Never use an Arduino-based flame sensor as a sole life-safety alarm in a residential or commercial building.

Project Overview & Target Hardware

This guide targets the Arduino Uno R3 (ATmega328P). While the logic applies to the Nano and Mega, the Uno R3's 5V logic and standard analog pin mapping (A0-A5) make it the baseline for this specific code. If you are using an ESP32 or a 3.3V board, pay close attention to the debugging section regarding logic level shifting and pin definition errors.

Difficulty Rating: Beginner (2/5)
Estimated Time: 20 minutes for wiring and baseline calibration
Primary Use Case: Line-following robots (detecting candle flames), automated fire-suppression triggers for small scale models, or environmental data logging.

Parts List & Sensor Specifications

Cheap sensor modules often suffer from poor solder joints or mismatched pull-up resistors. Here is exactly what to buy and what the silicon actually does.

ComponentExact Variant / ModelEstimated Cost (2026)Key Specification
MicrocontrollerArduino Uno R3 (ATmega328P)$14.00 (Clone) / $27.00 (Genuine)5V Logic, 10-bit ADC
Flame SensorKY-026 or generic 4-pin IR module$1.50 - $3.00760nm - 1100nm wavelength
Comparator ICTI LM393 (Dual Differential)Included on moduleOpen-collector output, 2mV offset
Wiring22 AWG solid core jumper wires$5.00 / spoolFits standard 0.1" breadboards

The heart of this module isn't the photodiode itself, but the LM393 comparator. The photodiode operates in reverse-bias; when IR photons hit the junction, leakage current increases, dropping the voltage on the comparator's inverting input. When that voltage drops below the reference voltage set by the blue trim potentiometer, the LM393 pulls the digital output (D0) LOW.

Pin Mapping & Wiring Steps

The 4-pin module provides both raw analog data and a threshold-based digital signal. For robust fire detection, we wire both.

Sensor PinArduino Uno R3 PinWire Color (Recommended)Function
VCC5VRedPower (3.3V to 5V tolerant)
GNDGNDBlackCommon Ground
D0Pin 2 (Interrupt capable)YellowDigital HIGH/LOW threshold output
A0Pin A0BlueAnalog raw intensity (0-1023)
  1. De-energize the board: Ensure the Arduino is unplugged from USB before routing wires to prevent accidental shorts on the 5V rail.
  2. Connect Power and Ground: Route VCC to the 5V pin and GND to any ground pin. Do not use the 3.3V pin for VCC; the LM393 and the onboard pull-up resistors perform best at 5V.
  3. Wire the Digital Output: Connect D0 to Digital Pin 2. Pin 2 supports hardware interrupts on the ATmega328P, which is useful if you want the flame detection to immediately wake the microcontroller from sleep.
  4. Wire the Analog Output: Connect A0 to Analog Pin A0.
  5. Calibrate the Trim Pot: Power on the board. Strike a lighter roughly 12 inches away from the sensor. Using a small Phillips or flathead screwdriver, turn the blue potentiometer until the onboard LED toggles exactly at your desired detection distance. Turning clockwise generally increases sensitivity (lowers the threshold voltage).

Complete Arduino Code with Noise Filtering

Cheap flame sensors are notorious for picking up 50/60Hz electromagnetic interference from nearby AC mains wiring, causing the analog read to flutter. This code implements a simple moving average filter and hysteresis to prevent the serial monitor and your downstream logic from flickering.

/*
 * Flame Sensor Arduino Project
 * Target Board: Arduino Uno R3 (ATmega328P)
 * Sensor: KY-026 4-pin IR Flame Sensor
 */

// --- Pin Definitions ---
#define FLAME_DIGITAL_PIN 2
#define FLAME_ANALOG_PIN  A0
#define STATUS_LED_PIN    13 // Built-in LED

// --- Configuration & Thresholds ---
const int SAMPLE_SIZE = 10;       // Number of samples for moving average
const int FLAME_THRESHOLD = 850;  // Analog threshold (adjust based on serial monitor)
const int HYSTERESIS_BAND = 50;   // Prevents rapid toggling at the threshold edge

// --- State Variables ---
int analogSamples[SAMPLE_SIZE];
int sampleIndex = 0;
bool flameDetected = false;

void setup() {
  Serial.begin(115200);
  pinMode(FLAME_DIGITAL_PIN, INPUT);
  pinMode(STATUS_LED_PIN, OUTPUT);
  
  // Initialize sample array
  for (int i = 0; i < SAMPLE_SIZE; i++) {
    analogSamples[i] = 0;
  }
  
  Serial.println("Flame Sensor Initialized. Calibrating baseline...");
  delay(1000); // Allow sensor and ADC to stabilize
}

void loop() {
  // 1. Read Raw Analog Value
  int rawValue = analogRead(FLAME_ANALOG_PIN);
  
  // 2. Apply Moving Average Filter (Handles 50/60Hz mains noise)
  analogSamples[sampleIndex] = rawValue;
  sampleIndex = (sampleIndex + 1) % SAMPLE_SIZE;
  
  long sum = 0;
  for (int i = 0; i < SAMPLE_SIZE; i++) {
    sum += analogSamples[i];
  }
  int avgValue = sum / SAMPLE_SIZE;
  
  // Note: On these modules, HIGHER analog values usually mean LESS IR light.
  // When fire is present, voltage drops, so analogRead value drops.
  // Check your specific module; some invert the output. 
  // We assume rawValue drops below threshold when fire is near.
  
  // 3. Hysteresis Logic for State Management
  if (!flameDetected && avgValue < FLAME_THRESHOLD) {
    flameDetected = true;
    Serial.println("[ALERT] Flame Detected! (Analog avg: " + String(avgValue) + ")");
    digitalWrite(STATUS_LED_PIN, HIGH);
  } 
  else if (flameDetected && avgValue > (FLAME_THRESHOLD + HYSTERESIS_BAND)) {
    flameDetected = false;
    Serial.println("[CLEAR] Flame Extinguished. (Analog avg: " + String(avgValue) + ")");
    digitalWrite(STATUS_LED_PIN, LOW);
  }
  
  // 4. Read Digital Pin (Optional cross-check)
  int digitalState = digitalRead(FLAME_DIGITAL_PIN);
  
  // 5. Diagnostic Output (Throttled to prevent serial buffer flooding)
  static unsigned long lastPrint = 0;
  if (millis() - lastPrint > 500) {
    Serial.print("Raw: ");
    Serial.print(rawValue);
    Serial.print(" | Avg: ");
    Serial.print(avgValue);
    Serial.print(" | D0: ");
    Serial.println(digitalState == HIGH ? "HIGH (No Fire)" : "LOW (Fire)");
    lastPrint = millis();
  }
  
  delay(20); // Small delay for ADC settling
}

Debugging: False Triggers & Compilation Errors

When a flame sensor fails, it rarely fails silently. It usually spams your serial monitor or throws a compiler error when you try to port the code. Here is how to diagnose the exact failure mode.

The First 3 Things to Check When It Fails

  1. The Blue Trim Potentiometer: If D0 is stuck HIGH or LOW, the physical threshold is misconfigured. Turn the pot fully counter-clockwise, then slowly clockwise while watching the onboard LED. If the LED never toggles, the potentiometer's wiper is likely disconnected (common on $1 clones).
  2. IR Photodiode Orientation: The black IR photodiode is highly directional. It has a narrow 60-degree detection cone. If it is pointing at the ceiling or shielded by the module's own header pins, it will read zero IR light. Ensure the clear/black bulb is facing your target.
  3. VCC Voltage Sag: If powering via a 9V battery clipped to the barrel jack, the onboard linear regulator may sag under load, causing the LM393 reference voltage to drift. Power via USB or a regulated 5V supply for stable baselines.

Compilation Error: Porting to ESP32

If you adapt the code above for an ESP32 (like the ESP32-WROOM-32 DevKit V1), you will immediately hit this exact compiler error:

error: 'A0' was not declared in this scope

Ranked Causes & Fixes:

  1. Missing Analog Pin Aliases (Most Likely): The ESP32 Arduino core does not map `A0` to a GPIO by default in older board packages. Fix: Change #define FLAME_ANALOG_PIN A0 to #define FLAME_ANALOG_PIN 34 (GPIO 34 is an input-only ADC pin on the ESP32).
  2. Wrong Board Selected in IDE: You are compiling for an AVR board but have ESP32 hardware connected. Fix: Verify Tools > Board matches your physical silicon.
  3. ADC Resolution Mismatch: The Uno uses a 10-bit ADC (0-1023). The ESP32 uses a 12-bit ADC (0-4095). Fix: If porting, multiply your FLAME_THRESHOLD by 4, or use analogReadResolution(10) in the ESP32 setup block.

Extending and Simplifying the Build

To Simplify: If you only need a binary "fire / no fire" alert and don't care about proximity or intensity, delete all analog code. Wire only VCC, GND, and D0. Use a basic digitalRead() with an internal pull-up resistor. This frees up an ADC channel and reduces code footprint.

To Extend:

  • Add an I2C OLED Display: Wire an SSD1306 128x64 OLED to the A4/A5 I2C pins to display a real-time bar graph of the IR intensity. This is invaluable for field-calibrating the threshold without needing a laptop.
  • Drive a Relay for Suppression: Use the digital output to trigger a 5V relay module connected to a 12V solenoid valve or a PC cooling fan to physically blow out a candle in a robotics competition. Always use a flyback diode across the relay coil to protect the Arduino's ATmega328P from inductive voltage spikes.

Frequently Asked Questions

How far can an Arduino flame sensor detect fire?

Under ideal, dark conditions, the KY-026 can detect a standard lighter flame from about 1.5 to 2 feet (45-60 cm) away. However, the detection range follows the inverse-square law for light intensity. A larger fire (like a campfire) will be detected from several feet away, while a small match might only trigger the sensor at 6 inches. The 60-degree detection angle also means off-axis flames require significantly closer proximity.

Why does my flame sensor trigger on sunlight or incandescent bulbs?

The sensor's IR photodiode detects wavelengths between 760nm and 1100nm. While it is tuned for the specific emission spectrum of a hydrocarbon fire, standard incandescent bulbs and direct sunlight emit massive amounts of broadband infrared radiation. If your sensor faces a window or a heat lamp, the IR saturation will drop the analog voltage below your threshold. To fix this, shield the sensor with a small piece of heat-shrink tubing or a 3D-printed hood to limit its field of view, and increase the hysteresis band in your code.

Can I use a flame sensor Arduino setup outdoors?

You can, but it requires heavy filtering. Outdoors, the sensor will be bombarded by solar IR, which will max out the analog reading (or min it out, depending on module inversion). Furthermore, ambient temperature changes can slightly alter the LM393's offset voltage. For outdoor use, you must physically shroud the sensor from direct sunlight and implement a software baseline calibration routine that runs on startup to account for the current ambient IR "noise" floor.