smart helmet for accident prevention using esp32

Smart Helmet for Accident Detection 🪖 Full ESP32 Tutorial with OLED Display, Circuit, Code & Wokwi Simulation
🪖🔒

Smart Helmet for Accident Detection

ESP32 project: helmet check, alcohol lock, crash detection & OLED display — all in one!

📋 What We're Making

This Smart Helmet system does four jobs at once: it checks if the rider is wearing the helmet (using a PIR sensor), checks if the rider has been drinking using a gas/alcohol sensor (MQ2), and only allows the bike to start (via a relay controlling the ignition) if both checks pass. An MPU6050 accelerometer/gyroscope watches for sudden crashes using a 3-level trigger system and sounds a buzzer alert. And now, a new SSD1306 OLED display shows the live status of everything right on the helmet! 🛵🪖📟

  1. Gather the Parts
  2. Wire Up the Circuit
  3. SSD1306 OLED Display (New!)
  4. Step-by-Step Assembly
  5. Upload the Code
  6. See the Serial Output
  7. Try it in Wokwi (no hardware!)
  8. Test & Fix Problems
  9. Cool Upgrades

🧰 Parts You'll Need

🧠ESP32 Dev Board
📐MPU6050 Accelerometer/Gyro
👤PIR Motion Sensor (helmet check)
🍺MQ2 Gas/Alcohol Sensor
Relay Module (ignition control)
🔔Buzzer + 100Ω Resistor
📟SSD1306 OLED Display (128×64, I2C)
🔋Battery / Power Supply
🔗Jumper Wires + Breadboard

🔌 The Circuit Diagram

The ESP32 connects to all five sensors/modules at once! The OLED display shares the I2C bus (GPIO 21 & 22) with the MPU6050 — they just need different I2C addresses. ⚡

🔧 Full Circuit: ESP32 + MQ2 + PIR + Relay + MPU6050 + SSD1306 OLED + Buzzer

📐 MPU6050 (Crash Sensor) → ESP32

MPU6050 PinESP32 Pin
VCC3V3
GNDGND
SDAGPIO 21
SCLGPIO 22

👤 PIR Motion Sensor (Helmet Worn Check) → ESP32

PIR PinESP32 Pin
VCC3V3
GNDGND
OUTGPIO 2

🍺 MQ2 Gas/Alcohol Sensor → ESP32

MQ2 PinESP32 Pin
VCC3V3
GNDGND
AOUTGPIO 34 (Analog)

⚡ Relay Module (Ignition Lock) → ESP32

Relay PinESP32 Pin
VCC3V3
GNDGND
INGPIO 12

🔔 Buzzer (Crash Alert) → ESP32

Buzzer PinESP32 Pin
Positive (via 100Ω resistor)GPIO 14
NegativeGND

📟 SSD1306 OLED Display → ESP32 NEW

OLED PinESP32 PinNotes
VCC3V3Use 3.3V — most SSD1306 modules are 3.3V tolerant
GNDGNDCommon ground
SDAGPIO 21Shared with MPU6050 on I2C bus
SCLGPIO 22Shared with MPU6050 on I2C bus
The SSD1306 OLED and MPU6050 both use I2C — they share GPIO 21 (SDA) and GPIO 22 (SCL). They work together because they have different I2C addresses: MPU6050 is 0x68 and OLED is 0x3C. No extra wires needed!

📟 SSD1306 OLED Display NEW

The 128×64 SSD1306 OLED display acts as the helmet's dashboard — showing real-time helmet status, alcohol level, ignition state, and crash alerts without needing to check a phone or serial monitor. Here's what it looks like while the system is running: 👇

🖥️ Normal Riding Mode (Helmet On, Sober)

SMART HELMET
Helmet: WORN [OK]
Alcohol: OK (420)
Ignition: ON [SAFE]
Accel: 7 Ang: 2
Monitoring...

🚨 Accident Detected Mode

SMART HELMET
Helmet: WORN [OK]
Alcohol: OK (420)
Ignition: ON [SAFE]
Accel: 15 Ang: 85
!! ACCIDENT !!

🔒 Locked Mode (Helmet Off or Drunk)

SMART HELMET
Helmet: NOT WORN [!!]
Alcohol: HIGH! (3510)
Ignition: LOCKED
Accel: 1 Ang: 0
Monitoring...

📚 Extra Library to Install

In addition to the existing libraries, you'll need one more for the OLED:

  • Adafruit MPU6050 (already needed)
  • Adafruit Unified Sensor (already needed)
  • Adafruit SSD1306 ← Add this one!
  • Adafruit GFX Library ← Required by SSD1306!
In Arduino IDE: go to Sketch → Include Library → Manage Libraries, then search "Adafruit SSD1306" and install it. It will automatically prompt you to install the GFX dependency — say yes!

🛠️ Step-by-Step Build

Step 1: Wire the Crash Sensor 📐
Connect the MPU6050 to the ESP32's I2C pins (SDA=21, SCL=22). This sensor watches for sudden jerks and orientation changes.
Step 2: Wire the Helmet Sensor 👤
Connect the PIR sensor's OUT pin to GPIO 2. When the helmet is worn snugly, the PIR detects the rider's presence (HIGH signal).
Step 3: Wire the Alcohol Sensor 🍺
Connect the MQ2 sensor's analog output (AOUT) to GPIO 34. This reads a value from 0–4095 — higher means more alcohol detected.
Step 4: Wire the Relay (Ignition) ⚡
Connect the relay's IN pin to GPIO 12. The relay acts as a switch for the bike's ignition circuit — only closing when it's safe to ride.
Step 5: Wire the Buzzer 🔔
Connect the buzzer through a 100Ω resistor to GPIO 14. This sounds an alert when a crash is detected.
Step 6: Wire the OLED Display 📟 NEW
Connect the SSD1306 OLED's SDA to GPIO 21 and SCL to GPIO 22 — the same I2C lines as the MPU6050. Connect VCC to 3V3 and GND to GND. Both devices share the bus peacefully using their different I2C addresses.
Step 7: Power Everything 🔋
Power all sensors from the ESP32's 3V3 pin and connect every GND together for a common ground.
Step 8: Install Libraries & Upload the Code 💻
Install Adafruit MPU6050, Adafruit Unified Sensor, Adafruit SSD1306, and Adafruit GFX Library via the Library Manager, then upload the code below.
Step 9: Open Serial Monitor + Watch OLED 🖥️
Open the Serial Monitor at 115200 baud. Simultaneously, the OLED display will show live helmet/alcohol/crash status — no PC needed in the field!
When wiring the relay to a real ignition circuit, make sure you understand your bike's wiring and use a relay rated for the correct voltage/current. When in doubt, test with an LED first instead of the actual ignition!

💻 The Code

📚 Libraries to Install

  • Adafruit MPU6050
  • Adafruit Unified Sensor
  • Adafruit SSD1306 ← New!
  • Adafruit GFX Library ← New!

🪖 Smart Helmet: Full Code with OLED Display

#include <Wire.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_SSD1306.h>

Adafruit_MPU6050 mpu;

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// Pins
#define PIR_PIN 2          // Helmet detection
#define MQ2_PIN 34         // Alcohol detection (analog)
#define RELAY_PIN 12       // Ignition control
#define BUZZER_PIN 14      // Crash alert

int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;
float ax = 0, ay = 0, az = 0, gx = 0, gy = 0, gz = 0;
boolean accident = false;
boolean trigger1 = false;
boolean trigger2 = false;
boolean trigger3 = false;
byte trigger1count = 0;
byte trigger2count = 0;
byte trigger3count = 0;
int angleChange = 0;

void setup() {
  Serial.begin(115200);

  pinMode(PIR_PIN, INPUT);
  pinMode(RELAY_PIN, OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);

  digitalWrite(RELAY_PIN, LOW);
  digitalWrite(BUZZER_PIN, LOW);

  // Initialize OLED
  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println("SSD1306 OLED not found. Check wiring.");
    while (1);
  }
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(20, 20);
  display.println("Smart Helmet");
  display.setCursor(25, 36);
  display.println("Initializing...");
  display.display();
  delay(1500);

  // Initialize MPU6050
  if (!mpu.begin()) {
    Serial.println("MPU6050 not found. Check connections.");
    display.clearDisplay();
    display.setCursor(0, 24);
    display.println("MPU6050 ERROR!");
    display.display();
    while (1);
  }

  Serial.println("Smart Helmet System Initialized.");
  display.clearDisplay();
  display.setCursor(20, 24);
  display.println("System Ready!");
  display.display();
  delay(1000);
}

void updateOLED(bool helmetWorn, bool sober, int alcoholLevel,
                int amp, bool accidentDetected) {
  display.clearDisplay();

  // Title bar
  display.setTextSize(1);
  display.setCursor(25, 0);
  display.println("SMART HELMET");
  display.drawLine(0, 9, 127, 9, SSD1306_WHITE);

  // Helmet status
  display.setCursor(0, 12);
  display.print("Helmet: ");
  if (helmetWorn) {
    display.println("WORN  [OK]");
  } else {
    display.println("NOT WORN [!!]");
  }

  // Alcohol status
  display.setCursor(0, 22);
  display.print("Alcohol: ");
  if (sober) {
    display.print("OK (");
    display.print(alcoholLevel);
    display.println(")");
  } else {
    display.print("HIGH! (");
    display.print(alcoholLevel);
    display.println(")");
  }

  // Ignition status
  display.setCursor(0, 32);
  display.print("Ignition: ");
  if (helmetWorn && sober) {
    display.println("ON  [SAFE]");
  } else {
    display.println("LOCKED");
  }

  // Crash detection row
  display.drawLine(0, 42, 127, 42, SSD1306_WHITE);
  display.setCursor(0, 45);
  display.print("Accel: ");
  display.print(amp);
  display.print("  Ang: ");
  display.println(angleChange);

  // Bottom status / accident alert
  if (accidentDetected) {
    display.fillRect(0, 55, 128, 9, SSD1306_WHITE);
    display.setTextColor(SSD1306_BLACK);
    display.setCursor(15, 56);
    display.print("!! ACCIDENT !!");
    display.setTextColor(SSD1306_WHITE);
  } else {
    display.setCursor(0, 56);
    display.println("Monitoring...");
  }

  display.display();
}

void loop() {
  bool helmetWorn = digitalRead(PIR_PIN);
  int alcoholLevel = analogRead(MQ2_PIN);
  bool sober = alcoholLevel < 3000;

  if (helmetWorn && sober) {
    digitalWrite(RELAY_PIN, HIGH);
    Serial.println("Helmet worn and sober - Ignition ON");
  } else {
    digitalWrite(RELAY_PIN, LOW);
    if (!helmetWorn) Serial.println("Helmet not detected - Ignition locked");
    if (!sober) Serial.println("Alcohol detected - Ignition locked");
  }

  // Crash Detection
  mpu_read();
  ax = (AcX - 2050) / 16384.00;
  ay = (AcY - 77) / 16384.00;
  az = (AcZ - 1947) / 16384.00;
  gx = (GyX + 270) / 131.07;
  gy = (GyY - 351) / 131.07;
  gz = (GyZ + 136) / 131.07;

  float Raw_Amp = pow(pow(ax, 2) + pow(ay, 2) + pow(az, 2), 0.5);
  int Amp = Raw_Amp * 10;
  Serial.println(Amp);

  if (Amp <= 2 && trigger2 == false) {
    trigger1 = true;
    Serial.println("Level 1 Trigger");
  }
  if (trigger1 == true) {
    trigger1count++;
    if (Amp >= 12) {
      trigger2 = true;
      Serial.println("Level 2 Trigger");
      trigger1 = false; trigger1count = 0;
    }
  }
  if (trigger2 == true) {
    trigger2count++;
    angleChange = pow(pow(gx, 2) + pow(gy, 2) + pow(gz, 2), 0.5);
    Serial.println(angleChange);
    if (angleChange >= 30 && angleChange <= 400) {
      trigger3 = true; trigger2 = false; trigger2count = 0;
      Serial.println(angleChange);
      Serial.println("Level 3 Trigger");
    }
  }
  if (trigger3 == true) {
    trigger3count++;
    if (trigger3count >= 10) {
      angleChange = pow(pow(gx, 2) + pow(gy, 2) + pow(gz, 2), 0.5);
      Serial.println(angleChange);
      if ((angleChange >= 0) && (angleChange <= 10)) {
        accident = true; trigger3 = false; trigger3count = 0;
        Serial.println(angleChange);
      } else {
        trigger3 = false; trigger3count = 0;
        Serial.println("TRIGGER 3 DEACTIVATED");
      }
    }
  }
  if (accident == true) {
    Serial.println("ACCIDENT DETECTED");
    // Flash OLED alert + buzzer 3 times
    for (int i = 0; i < 3; i++) {
      updateOLED(helmetWorn, sober, alcoholLevel, Amp, true);
      digitalWrite(BUZZER_PIN, HIGH);
      delay(300);
      digitalWrite(BUZZER_PIN, LOW);
      delay(300);
    }
    accident = false;
    Serial.println("Accident Alert!! Send SMS");
    delay(2000);
  }
  if (trigger2count >= 6) {
    trigger2 = false; trigger2count = 0;
    Serial.println("TRIGGER 2 DEACTIVATED");
  }
  if (trigger1count >= 6) {
    trigger1 = false; trigger1count = 0;
    Serial.println("TRIGGER 1 DEACTIVATED");
  }

  // Update OLED with latest readings
  updateOLED(helmetWorn, sober, alcoholLevel, Amp, false);

  delay(1000);
}

void mpu_read() {
  AcX = Wire.read() << 8 | Wire.read();
  AcY = Wire.read() << 8 | Wire.read();
  AcZ = Wire.read() << 8 | Wire.read();
  Tmp = Wire.read() << 8 | Wire.read();
  GyX = Wire.read() << 8 | Wire.read();
  GyY = Wire.read() << 8 | Wire.read();
  GyZ = Wire.read() << 8 | Wire.read();
}
The SMS-sending lines are commented out — to make accident alerts actually send, add a GSM module (like SIM800L) and uncomment those lines with your modem setup code!

🖥️ Serial Monitor Output

Here's what you'll see in the Serial Monitor while the system runs. The OLED mirrors this information visually on the helmet itself! 👇

Serial monitor output showing Helmet not detected, Alcohol detected, Ignition locked, and Level 1 Trigger messages
📟 Live Serial Monitor Output
  • "Helmet not detected – Ignition locked" → PIR sensor reads LOW, ignition stays off. OLED shows "NOT WORN [!!]"
  • "Alcohol detected – Ignition locked" → MQ2 reading is 3000 or higher. OLED shows "HIGH! (xxxx)"
  • "1" → Calculated Amplitude (Amp) value from the MPU6050, shown on OLED as "Accel: 1"
  • "Level 1 Trigger" → Amp dropped to 2 or below — system watching for a possible crash
  • "ACCIDENT DETECTED" → All 3 triggers fired! OLED flashes "!! ACCIDENT !!" and buzzer beeps

🌐 Try It Online with Wokwi (No Hardware Needed!)

Don't have the parts yet? Simulate this entire circuit online for free using Wokwi! The updated diagram.json below includes the SSD1306 OLED wired up and ready to go.

⬇️ Download diagram.json ⬇️ Download smart_helmet.ino

📥 How to Use It

  1. Go to wokwi.com and create a new ESP32 project
  2. Paste in the code from above into sketch.ino
  3. Replace the auto-generated diagram.json with the one you downloaded
  4. Click the green ▶️ Play button to run the simulation
  5. Watch the OLED display update live as you interact with sensors!
  6. Click on sensors to interact — toggle the PIR, drag the gas sensor slider, and tilt the MPU6050!
In the simulation, the SSD1306 OLED renders in real time — you can see the display update as sensor values change. The OLED and MPU6050 both auto-detect on the shared I2C bus.

🧪 Testing & Troubleshooting

🎯 Calibration Tips

  • Adjust the 3000 threshold in bool sober = alcoholLevel < 3000; based on your MQ2 sensor's baseline readings in clean air.
  • The crash detection uses three trigger levels — test by gently shaking, then flipping the MPU6050 to simulate a fall, and watch the OLED and Serial Monitor.
  • If "ACCIDENT DETECTED" never triggers, try adjusting the threshold values (2, 12, 30–400, 0–10) to match your sensor's real-world readings.

🔧 Quick Fix Table

Problem 😟Solution 😊
"MPU6050 not found" on startupCheck SDA/SCL wiring (21/22) and that VCC is 3.3V
"SSD1306 OLED not found" on startupCheck SDA/SCL wiring (21/22), VCC is 3.3V, and I2C address is 0x3C (or try 0x3D)
OLED shows garbage / frozenCheck common GND; try power-cycling; ensure SSD1306 library version matches
Ignition never turns onCheck PIR is detecting HIGH and MQ2 reading is below threshold
Relay clicks randomlyAdd a flyback diode and ensure stable power supply
Amp value always 0Replace raw Wire.read() calls with mpu.getEvent() for real hardware
Buzzer doesn't soundCheck resistor value and buzzer polarity on pin 14

🚀 Cool Upgrades to Try

  • 📡 Add a GPS + GSM module to send the real accident location via SMS (the code already has commented-out SMS lines!)
  • 📱 Add a Telegram or WhatsApp alert using Wi-Fi instead of (or alongside) SMS
  • 🔆 Add an LED indicator strip showing helmet/alcohol/ignition status at a glance
  • 🗣️ Add a small speaker for spoken warnings ("Please wear your helmet")
  • 📊 Log all sensor data to an SD card or cloud dashboard for analysis
  • 🔋 Add a rechargeable battery pack with solar charging for the helmet unit
  • 🌡️ Use the MPU6050's built-in temperature sensor to display the ambient temp on the OLED!
  • 🎨 Add icons to the OLED using Adafruit GFX's bitmap drawing functions

🎉 You Did It!

You've built a Smart Helmet system that checks safety gear, blocks drunk riding, watches for crashes, and now shows everything live on an OLED display — all in one ESP32! Stay safe, ride smart! 🪖💛📟

Comments

Product Cards
Buddy Bot eBook
⭐ New 2026 Release
Build Your
Own Robot!
3D design, wiring &
Arduino coding.
Young inventors love it!
🖨️
3D Print
All parts
Wire it
Circuit guide
💻
Code it
Arduino IDE
🤖
Watch it
Walk & react
📋 Your Details
Enter your name
Valid 10-digit no.
Enter a valid email
Special Website Offer
₹499 300
🌍 International: $5 USD
One-time · Instant digital delivery
🔒 Secured by Razorpay · Your data is safe
📄 Download Free Sample Copy
🔒 Secured by Razorpay · Your data is safe
🍓
Raspberry Pi Pico Mastery
21 Projects
⚡ Launch Price — 80% OFF
Learn Pico
Build 21 Projects!
MicroPython · Wokwi
IoT · Certificate
Perfect for beginners!
🖥️
Wokwi
No hardware
🐍
MicroPy
From zero
🔨
21 Projects
IoT + sensors
📄
Certificate
Verified cert
📋 Your Details
Enter your name
Valid 10-digit no.
Enter a valid email
Special Launch Offer
₹999 200 80% OFF
🌍 International: $5 USD
One-time · Lifetime access · No subscription
🔒 Secured by Razorpay · UPI · Cards · NetBanking
🎉

You're in!

Payment successful! Your Buddy Bot eBook is ready. Time to build!

📖 Access Your eBook Now
🎉

Enrolled!

Payment successful! Lifetime access to all 21 Pico Projects is yours!

🍓 Go to My Course