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.
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
| Setting | How it is used |
|---|---|
| Driver fatigue warning | Alerting drivers to drowsiness before a crash — cars, trucks, buses. |
| Commercial/long-haul safety | Fatigue monitoring for professional drivers on long routes. |
| Fleet safety systems | Drowsiness alerts as part of driver-safety programmes. |
| Research / education | Studying 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
| Attribute | Value |
|---|---|
| Difficulty level | Advanced |
| Estimated completion time | 14–22 hours |
| Indicative build cost | ₹3,000 – ₹6,000 |
| Primary discipline | Automotive |
| Reference platform | ESP32-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.
| Component | Key specification | Qty | Approx. 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 5 | 1 | ₹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 flash | 1 | ₹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 GPIO | 1 | ₹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 diameter | 1 | ₹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 recommended | 1 | ₹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 protection | 1 | ₹350 |
| Driver-facing camera + IR IR is essential for darkness | Camera aimed at the driver with IR for night operation | 1 | ₹600 |
| Compute (ESP32-S3 or Pi) Pi affords fuller models; ESP32-S3 a lightweight one | Edge compute for face/eye analysis | 1 | — |
| Alert (loud + haptic) Must reliably rouse a drowsy driver | Loud tone/voice and seat/steering vibration | 1 | ₹300 |
| In-vehicle mount | Positioned for a clear, unobtrusive view of the face | 1 | ₹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
| Part | Specification | Supply | Interface | Reference |
|---|---|---|---|---|
| ESP32-S3 DevKitC-1 | Dual-core Xtensa LX7 @ 240 MHz, 512 KB SRAM + 8 MB PSRAM, vector instructions for ML, Wi-Fi + BLE 5 | 3.3 V logic / 5 V USB | USB-OTG, SPI, I²C, I²S, LCD/camera bus | Datasheet |
| ESP32-CAM (AI-Thinker) + OV2640 | ESP32-S chip, 4 MB PSRAM, 2 MP OV2640 camera, microSD slot, on-board LED flash | 5 V in / 3.3 V logic | UART (programmer required), SPI, I²C | Datasheet |
| 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 GPIO | 5 V / 3 A USB-C | GPIO, SPI, I²C, UART, CSI, DSI | Datasheet |
| Active piezo buzzer 5 V | 85 dB at 10 cm, 2.3 kHz resonance, 12 mm diameter | 3–5 V | Digital / PWM | Datasheet |
| microSD card 32 GB A1 class | A1 rated, 10 MB/s random write, UHS-I, endurance-grade recommended | 3.3 V | SDIO / SPI | Datasheet |
| 5 V 3 A regulated SMPS adapter | 100–240 VAC in, 5 V ±5 % out, 3 A, short-circuit and over-voltage protection | 5 V | DC barrel / USB | Datasheet |
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.
| Load | Supply rail | Typical current (mA) | Notes |
|---|---|---|---|
| ESP32-S3 DevKitC-1 | 3.3 V logic / 5 V USB | 180 | The vector extensions roughly triple TinyML inference speed over the original ESP32. |
| ESP32-CAM (AI-Thinker) + OV2640 | 5 V in / 3.3 V logic | 220 | No USB-serial on board — needs an FTDI/CP2102 adapter to flash. |
| Raspberry Pi 4 Model B (4 GB) | 5 V / 3 A USB-C | 1200 | Use an official 5 V 3 A supply — brown-outs from phone chargers corrupt SD cards. |
| Active piezo buzzer 5 V | 3–5 V | 30 | Active buzzers make tone on DC; passive ones need a PWM carrier. |
| microSD card 32 GB A1 class | 3.3 V | 100 | For 24/7 loggers buy a high-endurance card — normal cards die in months. |
| 5 V 3 A regulated SMPS adapter | 5 V | 3000 | Measure 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.jsonunder 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
dialoutgroup:sudo usermod -aG dialout $USERand 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
| Library | Why it is needed | Install |
|---|---|---|
| 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-alpha | Int8 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.
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.
| Peripheral | Peripheral pin | Controller pin | Signal |
|---|---|---|---|
| Camera + IR | CSI/DVP | — | Driver face |
| Alert (buzzer/voice) | IN | GPIO | Warn driver |
| Haptic | IN | GPIO | Seat/steering vibration |
| Storage (opt) | SD | — | Event log (in-vehicle) |
| Supply | 12V/5V | — | Power |
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.
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.
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)
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)
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
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.
Assembly Instructions
Build on a breadboard first and only commit to solder once the whole system has run for an hour without a fault.
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.
Detect eyes and measure fatigue signals
Detect face/eyes, compute EAR and prolonged closure, blink rate, head pose, and PERCLOS over a rolling window.
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.
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.pyimport 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.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.
#!/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()
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.
EAR/PERCLOS
Tune the EAR threshold per driver/camera and the PERCLOS/microsleep thresholds so real drowsiness is caught early without excessive false alarms.
Night/IR
Verify detection under IR at night and handle glasses/angles; reject no-clear-view frames.
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.
| Dataset | Size | Licence | Use here |
|---|---|---|---|
| Driver drowsiness datasets (e.g. NTHU-DDD) | Many subjects | Research (check terms) | Train/validate drowsiness detection |
| Face-landmark datasets | Large | Varies | Eye/head landmark models |
| Your-vehicle set (night/IR) | Hundreds+ | In-vehicle | Adapt 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.
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 / stage | Shape or configuration | Purpose |
|---|---|---|
| Face/landmarks | lightweight face mesh | Eye/head geometry |
| EAR/PERCLOS | geometric + window | Validated drowsiness measures |
| Classifier (opt) | small CNN/temporal | Robust drowsy/alert verdict |
| Runtime | edge (Pi/ESP32-S3) | Real-time, video stays local |
Hyperparameters
| Hyperparameter | Value | Why |
|---|---|---|
| EAR threshold | ~0.20 | Eye-closed cutoff; tune per subject/camera |
| PERCLOS threshold | ~0.15 | Drowsiness alert level |
| microsleep frames | ~1.5 s | Prolonged-closure alarm |
| window | ~60 s | PERCLOS 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.
| Metric | Value | What it tells you |
|---|---|---|
| Drowsiness detection rate | high (target) | Catch real fatigue early |
| False-alarm rate | low (target) | Or drivers ignore it |
| PERCLOS correlation | strong | Validated drowsiness measure |
| Latency | real-time | Alert in time to act |
Figures from the reference training run described above — reproduce them before trusting your own changes.
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
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.
| Test | What you should see |
|---|---|
| Close eyes for >1.5 s | Microsleep detected; alert |
| Simulate rising PERCLOS (frequent closures) | Drowsy verdict; alert on early signs |
| Nod the head | Head-nod contributes to drowsy verdict |
| Night with IR | Detection works; without IR it degrades |
| Sunglasses/angle | Degrades honestly (no clear view) rather than fabricating |
| Confirm privacy | Video 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).
{
"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.
Troubleshooting: Common Errors & Fixes
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 amillis()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_twhere 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
References & Learning Resources
These are the primary sources worth reading in full. Manufacturer datasheets always outrank forum posts when the two disagree.
- Drowsy drivingReference
- PERCLOS drowsiness measureReference
- Eye-aspect ratio / blink detectionReference
- Driver monitoring systemsReference
- Facial landmark detectionReference