Siddhant Kumar
Project 086 · Automotive

Driver Drowsiness Alert.

Watches a driver's eyes and head for the signs of fatigue — prolonged eye closure, nodding, slow blinks — and warns before drowsiness becomes a crash.

Advanced 14–22 hours 29 min read VisionSafetyAlerts
Jump to source Bill of materials
Driver Drowsiness Alert — reference build illustration MCU VCC · GND · SIG · NC
Difficulty
Advanced
Build time
14–22 hours
Indicative cost
₹3,000 – ₹6,000
Platform
ESP32-S3 DevKitC-1
Category
Automotive
Last updated
28 July 2026
Contents — 27 sections

Project Overview

Watches a driver's eyes and head for the signs of fatigue — prolonged eye closure, nodding, slow blinks — and warns before drowsiness becomes a crash.

Drowsy driving is a leading cause of serious crashes, and its danger is that the driver is the last to know — fatigue impairs the very judgement needed to recognise it, and a microsleep of a few seconds at highway speed covers the length of a football field with no one at the controls. The visible signs of that creeping fatigue, though, are readable on the driver's face and head: the eyes start to close for longer, blinks slow, the gaze drifts, and the head begins to nod. This project builds a system that watches for those signs with a camera and warns the driver before drowsiness becomes a crash.

The core is computer vision on the driver's face. A camera watches the driver; the system detects the face and eyes and measures the tell-tale signals of fatigue: how open the eyes are (the eye-aspect ratio), how long they stay closed, the blink rate and duration, and the head pose (nodding forward). The single most validated measure is PERCLOS — the proportion of time the eyes are closed over a window — which correlates strongly with drowsiness; combined with prolonged-closure detection (a microsleep) and head-nod detection, it gives a robust read on the driver's state. When the signs cross a threshold, the system issues an immediate, attention-grabbing alert (a loud tone, a voice, a seat/vibration) to rouse the driver.

The value is catching fatigue before the driver would — an objective observer that does not itself get tired. It runs on the edge (an ESP32-S3 or a small single-board computer with a camera) so the video and analysis stay in the vehicle for privacy. It is honest about hard limits: it works best with a clear view of the face, is challenged by darkness (needs IR), sunglasses, and awkward angles; it detects signs of drowsiness, not the internal state itself, so it can miss or false-alarm; and it is a warning aid, not a substitute for the real fix — a rested driver who stops and sleeps. But as a fatigue-monitoring alert that reads the eyes and head and warns in time, it addresses one of the deadliest and most under-detected causes of road crashes with exactly the objective vigilance a drowsy driver lacks.

The dashboard of a modern car
A camera watches the driver for the eye and head signs of fatigue the driver cannot detect in themselves. Photograph sourced from Wikimedia Commons — Car dashboard.jpg. Reused under the licence stated on that page; please check it before republishing.

What this project does

  • Watches the driver's face with a camera
  • Measures eye openness (eye-aspect ratio) and prolonged closure
  • Tracks blink rate/duration and head pose (nodding)
  • Computes PERCLOS (proportion of eye closure), the key drowsiness measure
  • Warns the driver immediately when fatigue signs cross a threshold
  • Runs on the edge (video stays in-vehicle) for privacy
  • Catches fatigue before the impaired driver would

Real-World Applications

SettingHow it is used
Driver fatigue warningAlerting drivers to drowsiness before a crash — cars, trucks, buses.
Commercial/long-haul safetyFatigue monitoring for professional drivers on long routes.
Fleet safety systemsDrowsiness alerts as part of driver-safety programmes.
Research / educationStudying fatigue detection (PERCLOS, EAR) and alerting.

Deployment contexts where a build of this kind earns its keep.

Features & Capabilities

  • Eye-aspect-ratio and prolonged-closure (microsleep) detection
  • PERCLOS — the validated drowsiness measure
  • Head-nod detection
  • Immediate attention-grabbing alert
  • Edge/on-device (privacy)
  • Objective vigilance a tired driver lacks
  • Honest: warning aid, needs clear view, not a substitute for rest

Difficulty, Time & Required Skills

AttributeValue
Difficulty levelAdvanced
Estimated completion time14–22 hours
Indicative build cost₹3,000 – ₹6,000
Primary disciplineAutomotive
Reference platformESP32-S3 DevKitC-1

Skills you should have (or will pick up)

  • Face/eye detection and landmark tracking
  • Eye-aspect ratio, PERCLOS, blink and head-pose measures
  • Edge computer vision (ESP32-S3/Pi)
  • Alerting and thresholds
  • Privacy-preserving on-device processing

Bill of Materials

Every part below is commonly available from Indian and international hobby-electronics suppliers. Prices are indicative 2026 retail figures in Indian rupees and will drift — treat them as a budgeting guide, not a quotation.

ComponentKey specificationQtyApprox. cost
ESP32-S3 DevKitC-1
The vector extensions roughly triple TinyML inference speed over the original ESP32.
Dual-core Xtensa LX7 @ 240 MHz, 512 KB SRAM + 8 MB PSRAM, vector instructions for ML, Wi-Fi + BLE 51₹900
ESP32-CAM (AI-Thinker) + OV2640
No USB-serial on board — needs an FTDI/CP2102 adapter to flash.
ESP32-S chip, 4 MB PSRAM, 2 MP OV2640 camera, microSD slot, on-board LED flash1₹620
Raspberry Pi 4 Model B (4 GB)
Use an official 5 V 3 A supply — brown-outs from phone chargers corrupt SD cards.
Quad-core Cortex-A72 @ 1.8 GHz, 4 GB LPDDR4, Gigabit Ethernet, Wi-Fi 5, BT 5.0, 2× USB 3.0, 40-pin GPIO1₹5,800
Active piezo buzzer 5 V
Active buzzers make tone on DC; passive ones need a PWM carrier.
85 dB at 10 cm, 2.3 kHz resonance, 12 mm diameter1₹25
microSD card 32 GB A1 class
For 24/7 loggers buy a high-endurance card — normal cards die in months.
A1 rated, 10 MB/s random write, UHS-I, endurance-grade recommended1₹450
5 V 3 A regulated SMPS adapter
Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A.
100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection1₹350
Driver-facing camera + IR
IR is essential for darkness
Camera aimed at the driver with IR for night operation1₹600
Compute (ESP32-S3 or Pi)
Pi affords fuller models; ESP32-S3 a lightweight one
Edge compute for face/eye analysis1
Alert (loud + haptic)
Must reliably rouse a drowsy driver
Loud tone/voice and seat/steering vibration1₹300
In-vehicle mountPositioned for a clear, unobtrusive view of the face1₹200

Estimated total: ₹9,245, excluding tools, shipping and consumables.

Tools and consumables

  • Soldering iron (temperature controlled, 350 °C) with 0.8 mm 60/40 or lead-free solder
  • Digital multimeter — continuity, DC volts and current ranges
  • Wire strippers, flush cutters and a small set of precision screwdrivers
  • Heat-shrink tubing and a heat gun (or a lighter, carefully)
  • A laptop with a USB port and the toolchain listed above

Hardware Specifications

PartSpecificationSupplyInterfaceReference
ESP32-S3 DevKitC-1Dual-core Xtensa LX7 @ 240 MHz, 512 KB SRAM + 8 MB PSRAM, vector instructions for ML, Wi-Fi + BLE 53.3 V logic / 5 V USBUSB-OTG, SPI, I²C, I²S, LCD/camera busDatasheet
ESP32-CAM (AI-Thinker) + OV2640ESP32-S chip, 4 MB PSRAM, 2 MP OV2640 camera, microSD slot, on-board LED flash5 V in / 3.3 V logicUART (programmer required), SPI, I²CDatasheet
Raspberry Pi 4 Model B (4 GB)Quad-core Cortex-A72 @ 1.8 GHz, 4 GB LPDDR4, Gigabit Ethernet, Wi-Fi 5, BT 5.0, 2× USB 3.0, 40-pin GPIO5 V / 3 A USB-CGPIO, SPI, I²C, UART, CSI, DSIDatasheet
Active piezo buzzer 5 V85 dB at 10 cm, 2.3 kHz resonance, 12 mm diameter3–5 VDigital / PWMDatasheet
microSD card 32 GB A1 classA1 rated, 10 MB/s random write, UHS-I, endurance-grade recommended3.3 VSDIO / SPIDatasheet
5 V 3 A regulated SMPS adapter100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection5 VDC barrel / USBDatasheet

Consolidated electrical and interface specifications for every active part in the build.

Power Budget & Supply Sizing

Add up the typical active current of every part, then size the supply with at least 50 % headroom so transmit bursts and motor inrush never brown out the controller.

LoadSupply railTypical current (mA)Notes
ESP32-S3 DevKitC-13.3 V logic / 5 V USB180The vector extensions roughly triple TinyML inference speed over the original ESP32.
ESP32-CAM (AI-Thinker) + OV26405 V in / 3.3 V logic220No USB-serial on board — needs an FTDI/CP2102 adapter to flash.
Raspberry Pi 4 Model B (4 GB)5 V / 3 A USB-C1200Use an official 5 V 3 A supply — brown-outs from phone chargers corrupt SD cards.
Active piezo buzzer 5 V3–5 V30Active buzzers make tone on DC; passive ones need a PWM carrier.
microSD card 32 GB A1 class3.3 V100For 24/7 loggers buy a high-endurance card — normal cards die in months.
5 V 3 A regulated SMPS adapter5 V3000Measure the real output — many "3 A" adapters sag below 4.7 V at 2 A.

Summed typical draw is 4730 mA. With a 1.5× design margin the supply should deliver at least 7100 mA continuously at the stated rail voltage.

Software Requirements & Development Environment

Reference toolchain: Arduino IDE 2.3.x with the ESP32 board package 3.x (or PlatformIO on VS Code). Anything newer normally works; anything older may lack the board definitions used here.

  • Install the Arduino IDE 2.3.x (or PlatformIO if you prefer a real editor and dependency locking).
  • Add https://espressif.github.io/arduino-esp32/package_esp32_index.json under File → Preferences → Additional Board Manager URLs, then install esp32 from the Boards Manager.
  • Set the correct port under Tools → Port. On Linux add yourself to the dialout group: sudo usermod -aG dialout $USER and log out and back in.
  • Open the Serial Monitor at 115200 baud — every sketch here logs its state there.
  • Keep File → Preferences → Show verbose output during: compilation switched on while you are debugging build errors.

Required libraries

LibraryWhy it is neededInstall
Python 3.11+Runtime for the analysis, training and service code.sudo apt install python3 python3-venv python3-pip
OpenCV 4.10+Frame capture, colour conversion, drawing and classical CV operators.pip install opencv-python
MediaPipe 0.10+Pre-trained hand, pose and face landmark graphs that run on CPU.pip install mediapipe
TensorFlow Lite for Microcontrollers 2.4.0-alphaInt8 neural-network inference inside 200 KB of RAM.Library Manager → "TensorFlowLite_ESP32"
NumPy 1.26+Vectorised array maths underpinning every other library here.pip install numpy

Block Diagram

The block diagram shows the functional decomposition of the system — what senses, what decides, what acts, and where the data ends up.

Driver Drowsiness Alert — system block diagramFunctional block diagram of the Driver Drowsiness Alert system. WatchCamera + IRdriver faceMeasureFace/eyesEAR, closurePERCLOS/headdrowsinessDecideEdgethresholdWarnAlertloud+hapticBefore crashin timerightrightnone
Driver Drowsiness Alert — system block diagram

Circuit Diagram & Wiring

Every signal line in the build is shown below, followed by a pin-by-pin connection table you can work through with a multimeter in hand.

Driver Drowsiness Alert — wiring schematicConnection schematic showing which controller pin drives each peripheral. Sensors / InputsControllerActuators / OutputsESP32-S3 DevKitC-13.3 V logic / 5 V USBCamera + IRDriver faceAlert (buzzer/voice)GPIOWarn driverHapticGPIOSeat/steeringvibrationStorage (opt)Event log(in-vehicle)SupplyPower
Driver Drowsiness Alert — wiring schematic
PeripheralPeripheral pinController pinSignal
Camera + IRCSI/DVPDriver face
Alert (buzzer/voice)INGPIOWarn driver
HapticINGPIOSeat/steering vibration
Storage (opt)SDEvent log (in-vehicle)
Supply12V/5VPower

Wire one row at a time and tick it off — most "it does not work" reports trace back to a single swapped pair.

Wiring explanation

  • Aim the camera at the driver's face with a clear, unobtrusive view; add IR for night operation (darkness needs IR).
  • Process on the edge (ESP32-S3/Pi) so video and analysis stay in the vehicle — a privacy requirement for a driver-facing camera.
  • Provide a loud and haptic alert that reliably rouses a drowsy driver.
  • Handle sunglasses/angles/occlusion gracefully; it detects signs, not the internal state.
  • This is a warning aid — it does not replace stopping and resting.
A wrist-worn fitness tracker
Edge computer vision measures eye-aspect ratio, PERCLOS and head-nod on-device (video stays in-vehicle). Photograph sourced from Wikimedia Commons — Fitness tracker.jpg. Reused under the licence stated on that page; please check it before republishing.

System Architecture

Read the stack from the bottom up: physical hardware, the firmware that drives it, the transport that moves data off the device, and the software a human actually looks at.

Driver Drowsiness Alert — architecture stackLayered architecture from hardware to user interface. Hardware layerESP32-S3 DevKitC-1 · sensors and actuatorsDriver layerpython · opencv · mediapipe · tflmicroApplication logicsampling loop · filtering · thresholds · state machinePresentation layerlocal display · serial console · logged output
Driver Drowsiness Alert — architecture stack

Working Principle

Drowsy driving is uniquely dangerous because the driver cannot reliably detect it in themselves — fatigue impairs the judgement needed to notice fatigue, and the failure mode is the microsleep, a brief involuntary lapse of a few seconds during which no one is driving. At highway speed that is a long, unguided distance. So the value of an external monitor is precisely that it is an objective observer that does not get tired: it watches for the signs the driver is missing and warns while there is still time to act.

Those signs are readable on the face and head, which is why computer vision is the right tool. As fatigue sets in, the eyes close for longer, blinks become slower and longer, the gaze drifts, and the head begins to nod forward. The system detects the face and eyes and quantifies these: the eye-aspect ratio (EAR) measures how open the eyes are (it drops toward zero as the eyes close), from which prolonged closure — a likely microsleep — and slow blinks are detected; head-pose estimation catches nodding. The most validated single measure is PERCLOS, the proportion of time the eyes are closed over a rolling window, which correlates strongly with drowsiness because it captures the sustained, creeping eye-closure of fatigue rather than a single blink. Combining PERCLOS with prolonged-closure and head-nod detection gives a robust, multi-signal read on the driver's state.

When the signals cross a threshold, the response is an immediate, unmissable alert designed to rouse a drowsy person — a loud tone or voice, ideally reinforced by haptic feedback (a vibrating seat or steering wheel), because a subtle warning may not penetrate the very fatigue it is warning about. Timing is everything: the alert must fire on the early signs (rising PERCLOS, the first prolonged closures) to give the driver time to respond — pull over, take a break — before the fatigue becomes a lapse at the wheel. Catching it before the impaired driver would is the whole point.

The design is honest about its limits and its place, which matters for a safety system. It detects signs of drowsiness, not the internal state itself, so it can both miss real fatigue (a stoic driver) and false-alarm (someone squinting in sun), and it depends on a clear view of the face — darkness requires IR illumination, and sunglasses, awkward angles and occlusion degrade it. It runs on the edge (an ESP32-S3 or a small SBC with the camera) so the driver-facing video and its analysis stay in the vehicle, a real privacy requirement for a camera pointed at a person. And above all, it is a warning aid, not a cure: the only real remedy for drowsiness is to stop and rest, and the system exists to prompt exactly that, not to license driving tired. Within those honest bounds, it does something genuinely valuable against one of the deadliest, most under-detected crash causes — it provides the objective, tireless vigilance a fatigued driver has lost, and warns them in time.

The maths behind it

Eye-aspect ratio (EAR)

plainEye-aspect ratio (EAR)
From eye landmarks (vertical vs horizontal distances):

  EAR = (‖p2−p6‖ + ‖p3−p5‖) / (2·‖p1−p4‖)

High when open, drops toward 0 as the eye closes.
Prolonged EAR < threshold ⇒ eyes closed (microsleep).

PERCLOS (drowsiness measure)

plainPERCLOS (drowsiness measure)
Proportion of time eyes are closed over a window T:

  PERCLOS = (time eyes closed) / T

Strongly correlated with drowsiness. Alert when PERCLOS
exceeds a threshold (rising with fatigue).

Multi-signal drowsiness + timing

plainMulti-signal drowsiness + timing
drowsy if:
  PERCLOS > P_thresh
  OR prolonged closure > t_micro (microsleep)
  OR sustained head-nod

Alert on EARLY signs → time to pull over. Loud + haptic to
rouse. It is a WARNING AID, not a substitute for rest.

Program Flowchart

The firmware is a single cooperative loop. Nothing blocks for long, so networking, sensing and the user interface all stay responsive.

Driver Drowsiness Alert — firmware flowchartControl flow through the main program loop. Capture driver frameDetect face/eyesEAR/closure + head poseUpdate PERCLOSDrowsiness signs overthreshold?Alert driver (loud+haptic)ContinueAlert driver (loud+haptic)Continue
Driver Drowsiness Alert — firmware flowchart

Assembly Instructions

Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.

  1. Set up the driver-facing camera + IR

    Aim a camera at the driver's face with a clear, unobtrusive view and IR for night. Process on the edge (ESP32-S3/Pi) so video stays in the vehicle.

  2. Detect eyes and measure fatigue signals

    Detect face/eyes, compute EAR and prolonged closure, blink rate, head pose, and PERCLOS over a rolling window.

  3. Alert in time

    Warn immediately with a loud and haptic alert when the multi-signal drowsiness threshold is crossed, on early signs.

Step-by-Step Implementation Guide

Work through these in order. Each step ends in something you can observe, so a failure is always localised to the step you just finished.

  1. Compute EAR and PERCLOS and decide

    Measure eye-aspect ratio per frame, track closed frames for PERCLOS and prolonged closure, add head-nod, and alert when drowsiness signs cross the threshold.

    pythondrowsiness.py
    import numpy as np
    
    def ear(eye):                              # eye landmarks p1..p6
        v = np.linalg.norm(eye[1]-eye[5]) + np.linalg.norm(eye[2]-eye[4])
        h = 2.0*np.linalg.norm(eye[0]-eye[3])
        return v/h                             # high=open, low=closed
    
    class Drowsiness:
        def __init__(self, ear_thresh=0.20, window=1800):  # ~60s at 30fps
            self.ear_thresh, self.window = ear_thresh, window
            self.closed = []                    # rolling closed/open flags
            self.closed_run = 0                 # consecutive closed frames
    
        def update(self, ear_val, head_nod):
            closed = ear_val < self.ear_thresh
            self.closed.append(closed)
            if len(self.closed) > self.window: self.closed.pop(0)
            self.closed_run = self.closed_run+1 if closed else 0
    
            perclos = sum(self.closed)/len(self.closed)     # proportion closed
            microsleep = self.closed_run > 45               # ~1.5s eyes closed
            return {"perclos": perclos, "microsleep": microsleep, "nod": head_nod,
                    "drowsy": perclos > 0.15 or microsleep or head_nod}
    def ear(eye):The eye-aspect ratio drops as the eye closes, giving a per-frame measure of eye openness from face landmarks.
    perclos = sum(self.closed)/len(self.closed)PERCLOS — the proportion of recent frames with eyes closed — is the most validated drowsiness measure, capturing sustained fatigue rather than a single blink.
    microsleep = self.closed_run > 45A run of consecutive closed frames flags a prolonged closure — a likely microsleep, the acute danger.
    "drowsy": perclos > 0.15 or microsleep or head_nodThe decision fuses PERCLOS, microsleep and head-nod, so drowsiness is caught from multiple signs on the early side.
  2. Warn and keep it private

    On a drowsy verdict, fire a loud + haptic alert immediately; keep all video and analysis on-device, and remind that the real fix is to stop and rest.

Complete Source Code

The listing below is complete and compiles as written — there are no elided sections. Read the annotations under each block before you upload it.

pythondriver_drowsiness_alert.py
#!/usr/bin/env python3
"""
Driver Drowsiness Alert — edge (Pi/ESP32-S3) computer vision

Watches the driver's face; measures eye-aspect ratio, PERCLOS, prolonged
closure (microsleep) and head-nod; warns (loud+haptic) on early signs.
Edge/on-device (video stays in-vehicle). A WARNING AID, not a substitute
for stopping and resting.
"""
import cv2, numpy as np
from face import detect_face_landmarks   # face/eye landmark detector
from alert import warn_driver            # loud + haptic

EAR_THRESH = 0.20
class Monitor:
    def __init__(self, fps=30, window_s=60):
        self.window = fps*window_s; self.closed=[]; self.run=0

    def ear(self, eye):
        v = np.linalg.norm(eye[1]-eye[5]) + np.linalg.norm(eye[2]-eye[4])
        return v/(2.0*np.linalg.norm(eye[0]-eye[3]))

    def step(self, frame):
        lm = detect_face_landmarks(frame)      # on-device; video stays local
        if lm is None: return None             # no clear face view
        left, right, nod = lm.left_eye, lm.right_eye, lm.head_nod
        e = (self.ear(left) + self.ear(right)) / 2.0
        closed = e < EAR_THRESH
        self.closed.append(closed)
        if len(self.closed) > self.window: self.closed.pop(0)
        self.run = self.run+1 if closed else 0

        perclos = sum(self.closed)/len(self.closed)
        microsleep = self.run > 45              # ~1.5s closed
        drowsy = perclos > 0.15 or microsleep or nod
        return {"ear": e, "perclos": perclos, "microsleep": microsleep,
                "nod": nod, "drowsy": drowsy}

def main():
    cap = cv2.VideoCapture(0)                   # IR camera for night
    mon = Monitor()
    while True:
        ok, frame = cap.read()
        if not ok: continue
        r = mon.step(frame)
        if r and r["drowsy"]:
            warn_driver(loud=True, haptic=True)  # rouse the driver, in time
        # NOTE: video never leaves the device (privacy)

if __name__ == "__main__":
    main()
lm = detect_face_landmarks(frame) # on-device; video stays localFace/eye detection runs on the edge, so the driver-facing video and its analysis never leave the vehicle — a privacy requirement.
if lm is None: return None # no clear face viewWith no clear view of the face (darkness, sunglasses, angle) the system does not fabricate a result — it detects signs and degrades honestly.
perclos = sum(self.closed)/len(self.closed)PERCLOS over the rolling window is the primary drowsiness measure driving the decision.
if r and r["drowsy"]: warn_driver(loud=True, haptic=True)A drowsy verdict triggers an immediate loud and haptic alert designed to rouse a fatigued driver in time.
# NOTE: video never leaves the device (privacy)The privacy property is explicit: the camera feed stays on-device, only the alert acts.

Configuration & Calibration

Configuration steps

  • Configure the camera/IR and edge compute; set EAR and PERCLOS thresholds and the window.
  • Set microsleep/head-nod thresholds and the alert (loud+haptic) behaviour.
  • Keep processing on-device (video in-vehicle) for privacy.
  • Handle no-clear-view cases gracefully.

Calibration procedure

An uncalibrated sensor produces confident, precise, wrong numbers. Do this once per physical unit and record the constants.

  1. EAR/PERCLOS

    Tune the EAR threshold per driver/camera and the PERCLOS/microsleep thresholds so real drowsiness is caught early without excessive false alarms.

  2. Night/IR

    Verify detection under IR at night and handle glasses/angles; reject no-clear-view frames.

  3. Alert

    Confirm the loud + haptic alert reliably rouses and is timely.

Dataset, Model & Training

Dataset

The system uses face/eye landmark detection (to compute EAR and head pose) and thresholds/PERCLOS; a learned drowsiness classifier can be trained on labelled drowsy/alert driver imagery for a more robust verdict.

Datasets of driver faces with drowsiness labels (and night-IR imagery) help tune thresholds and train models to real conditions.

DatasetSizeLicenceUse here
Driver drowsiness datasets (e.g. NTHU-DDD)Many subjectsResearch (check terms)Train/validate drowsiness detection
Face-landmark datasetsLargeVariesEye/head landmark models
Your-vehicle set (night/IR)Hundreds+In-vehicleAdapt to camera/lighting

Data preprocessing

  • Detect the face and eye/facial landmarks; compute EAR and head pose per frame.
  • Handle IR imagery for night; reject frames with no clear face view.
  • Aggregate EAR into PERCLOS over a rolling window.
Driver Drowsiness Alert — ML pipelineFrom raw data through training to deployed inference. 1Camera (IR)driver face2Face/landmarkseyes/head3EAR/head poseper frame4PERCLOS/microsleepwindow5Drowsy decisionthreshold/model
Driver Drowsiness Alert — ML pipeline

Model architecture

A landmark model (e.g. a lightweight face-mesh) yields eye/head geometry, feeding EAR/PERCLOS thresholds. Optionally a small classifier (CNN or on the temporal signals) predicts drowsiness for robustness.

On a Pi, fuller models are feasible; on ESP32-S3, a tiny landmark/eye-state model gated to real time.

Layer / stageShape or configurationPurpose
Face/landmarkslightweight face meshEye/head geometry
EAR/PERCLOSgeometric + windowValidated drowsiness measures
Classifier (opt)small CNN/temporalRobust drowsy/alert verdict
Runtimeedge (Pi/ESP32-S3)Real-time, video stays local

Hyperparameters

HyperparameterValueWhy
EAR threshold~0.20Eye-closed cutoff; tune per subject/camera
PERCLOS threshold~0.15Drowsiness alert level
microsleep frames~1.5 sProlonged-closure alarm
window~60 sPERCLOS averaging window

Training process

  • Tune EAR/PERCLOS thresholds on labelled data and per driver/camera; optionally train a classifier on drowsy/alert sequences.
  • Include night-IR, glasses and angle variation so the system is robust to real conditions.
  • Validate on held-out drivers; weigh missed-drowsiness (dangerous) heavily.

Evaluation, Metrics & Deployment

The decisive trade-off is catching real drowsiness (few misses) without excessive false alarms that get the system ignored.

MetricValueWhat it tells you
Drowsiness detection ratehigh (target)Catch real fatigue early
False-alarm ratelow (target)Or drivers ignore it
PERCLOS correlationstrongValidated drowsiness measure
Latencyreal-timeAlert in time to act

Figures from the reference training run described above — reproduce them before trusting your own changes.

Detection by condition (illustrative)Clear-face detection is strong; darkness/glasses/angle challenge it. Clear face, day92 %Night + IR82 %Sunglasses/angle55 %
Detection by condition (illustrative)

Deployment

  • Run on the edge (Pi/ESP32-S3) with the camera; keep video and analysis in-vehicle.
  • Alert loud + haptic on early signs; degrade honestly when the face view is poor.
  • Present as a warning aid; never a substitute for rest.

Inference example

pythoninfer.py
def is_drowsy(frame, monitor):
    r = monitor.step(frame)            # EAR/PERCLOS/microsleep/nod (edge)
    if r is None:                      # no clear face view
        return False
    return r["drowsy"]                 # loud+haptic alert if True

Testing Procedure & Expected Output

Test from the bottom up. Confirm power, then each sensor in isolation, then the integrated loop — the first failing step tells you exactly where to look.

TestWhat you should see
Close eyes for >1.5 sMicrosleep detected; alert
Simulate rising PERCLOS (frequent closures)Drowsy verdict; alert on early signs
Nod the headHead-nod contributes to drowsy verdict
Night with IRDetection works; without IR it degrades
Sunglasses/angleDegrades honestly (no clear view) rather than fabricating
Confirm privacyVideo stays on-device; only the alert acts

Bench-test checklist. If a row fails, stop and fix it before moving on.

Expected output

In-vehicle: an immediate loud + haptic alert on drowsiness; optionally an in-vehicle log of PERCLOS/events (no video leaves the device).

jsondrowsy-event.json
{
  "ear": 0.12,
  "perclos": 0.22,
  "microsleep": true,
  "nod": false,
  "drowsy": true
}

Low EAR (0.12), high PERCLOS (0.22) and a microsleep → a drowsy verdict and an immediate alert to rouse the driver in time; all computed on-device, with the video never leaving the vehicle.

An ESP32 development board with the ESP-WROOM-32 module and USB connector
A loud, haptic alert rouses the driver in time — a warning aid, never a substitute for stopping and resting. Photograph sourced from Wikimedia Commons — ESP32 Espressif ESP-WROOM-32 Dev Board.jpg. Reused under the licence stated on that page; please check it before republishing.

Troubleshooting: Common Errors & Fixes

Misses drowsiness

Likely cause. Thresholds too lax / poor view

Fix. Tune EAR/PERCLOS; ensure a clear face view and IR at night; weigh misses heavily

Too many false alarms

Likely cause. Thresholds too strict / squinting

Fix. Tune thresholds; use PERCLOS window; add head-nod for corroboration

Fails at night

Likely cause. No IR

Fix. Add IR illumination; validate under IR

Glasses/angle break it

Likely cause. No clear view

Fix. Position camera well; degrade honestly (no fabricated result)

Privacy concern

Likely cause. Video leaving device

Fix. Process on the edge; keep video in-vehicle; only the alert acts

The sketch will not upload — "Failed to connect" or "avrdude: stk500_recv()"

Likely cause. The bootloader is not being reached: wrong port, wrong board, a serial monitor holding the port open, or a USB cable that only carries power.

Fix. Close every serial monitor, confirm Tools → Board and Port, and swap to a known data-capable USB cable. On an ESP32 hold BOOT while the IDE prints "Connecting…", then release. If a peripheral is wired to the UART pins (GPIO 1/3 on ESP32, D0/D1 on Uno) unplug it — it fights the programmer.

The board resets in a loop, or the serial monitor prints "Brownout detector was triggered"

Likely cause. The supply cannot deliver peak current. Wi-Fi transmit bursts, relay coils and servos all pull far more than their average draw.

Fix. Power peripherals from a separate regulated supply with a common ground rather than from the board 5 V pin. Add a 470–1000 µF electrolytic capacitor across the supply near the load, and use a real power adapter rather than a laptop USB port.

Serial monitor shows garbage characters

Likely cause. Baud rate mismatch between Serial.begin() and the monitor, or a floating/shared UART line.

Fix. Set the monitor to 115200 to match the sketch. If it still garbles, the crystal or the USB bridge is being confused by noise — shorten the cable and keep motor wiring away from the USB lead.

Performance Optimisation

  • Run detection in real time on the edge; keep video local.
  • Use PERCLOS over a window plus microsleep/head-nod for a robust, early verdict.
  • Alert immediately (loud+haptic) on early signs.
  • Degrade honestly when the face view is poor.
  • Replace every delay() with a millis() comparison — blocking delays are the single most common cause of dropped readings.
  • Sample sensors on a fixed cadence and publish on a slower one; you almost never need to transmit at the sampling rate.
  • Move networking into its own FreeRTOS task so a slow DNS lookup cannot stall the control loop.
  • Use uint8_t / uint16_t where the range allows; on an 8-bit AVR a 32-bit add costs four times as much.
  • For battery builds use deep sleep between samples: an ESP32 drops from ~160 mA awake to about 10 µA asleep, which is the difference between days and months of runtime.
  • Profile before optimising — print micros() deltas around each stage and fix the slowest one first.

Safety Precautions

  • This detects SIGNS of drowsiness, not the internal state — it can miss or false-alarm, and it is a WARNING AID, not a substitute for stopping and resting.
  • The only real fix for drowsiness is to stop and sleep — the alert exists to prompt that.
  • Keep the driver-facing video on-device (privacy); do not use it for other surveillance.
  • Position the camera without obstructing driving; do not rely on it to drive tired.
  • Wear eye protection when soldering or cutting, and solder in a ventilated space — rosin flux fumes are a respiratory irritant.
  • Power the circuit through a bench supply with a current limit while you are testing. A 300 mA limit turns a wiring mistake into a beep instead of a dead board.
  • Disconnect power before changing any wiring. Hot-plugging a sensor onto a live bus is the fastest way to lose a controller.

Maintenance

  • Re-tune thresholds per driver/camera and validate night/IR.
  • Verify the alert rouses reliably.
  • Keep processing on-device; confirm privacy.
  • Improve models with in-vehicle-condition data (kept local).
  • Re-check every screw terminal and header after the first week — thermal cycling loosens connections that felt tight on day one.
  • Rotate the microSD card annually and keep an image of the working system. Cards used as loggers wear out silently.
  • Recalibrate at the interval given in the calibration section, and keep the constants in a text file next to the firmware — not only in flash.
  • Keep a short logbook of firmware versions and what changed. Six months later you will not remember why that constant is 1.083.

Future Improvements & Upgrades

A working v1 is a platform, not a finish line. These are the upgrades that add the most capability for the least rework.

  • Add gaze/attention (distraction) detection.
  • Add a trained temporal drowsiness model for robustness.
  • Integrate with vehicle systems (lane, speed) for corroboration.
  • Add fatigue trend/rest-break recommendations.
  • Design a proper PCB. Once the breadboard version has run for a month, moving to a two-layer board removes the intermittent-contact failures that dominate prototype faults.
  • Add connectivity — an ESP32 and an MQTT publish turn a local gadget into something you can graph, alert on and analyse over months.
  • Add persistent local storage (microSD or the on-chip flash) so a network outage does not create a hole in your data.
  • Move configuration out of the source: a captive-portal setup page or a JSON config file makes the build reusable without a recompile.
  • Add a battery and solar option so the unit survives a power cut and can be sited away from a socket.
  • Write a small test harness that feeds synthetic sensor values through the decision logic, so you can validate thresholds without physically triggering the event.

Frequently Asked Questions

Why can't drivers just notice they're drowsy?

Because fatigue impairs the judgement needed to notice fatigue, and it fails via microsleeps — brief involuntary lapses. An external monitor that does not get tired watches for the signs the driver is missing and warns in time.

What is PERCLOS?

The proportion of time the eyes are closed over a window — the most validated drowsiness measure, because it captures the sustained, creeping eye-closure of fatigue rather than a single blink.

Does it work at night or with sunglasses?

It needs a clear view of the face. Darkness requires IR illumination; sunglasses, awkward angles and occlusion degrade it. It detects signs, not the internal state, so it degrades honestly rather than fabricating a result.

Is it a substitute for resting?

No — emphatically. It is a warning aid whose purpose is to prompt the only real fix: stop and sleep. It must never be used to license driving tired.

Where does the video go?

Nowhere — it is processed on the edge and stays in the vehicle. Only the alert acts. Keeping a driver-facing camera's video local is a privacy requirement.

References & Learning Resources

These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.

  1. Drowsy drivingReference
  2. PERCLOS drowsiness measureReference
  3. Eye-aspect ratio / blink detectionReference
  4. Driver monitoring systemsReference
  5. Facial landmark detectionReference