Before I started this project, I thought the hard part would be the hardware — wiring sensors, getting the ESP32 to read data correctly, building a reliable alert system. The hardware was actually the easy part. The hard part was the algorithm, and specifically, the impossibility of making it simultaneously sensitive and specific.

What I thought a fall looked like

My initial model was simple: a fall produces free-fall (very low acceleration), then an impact (very high acceleration). Detect both in sequence, within a short time window, and you've detected a fall.

This is approximately correct. The problem is that real human motion is much messier than this model suggests. Sitting down quickly. Dropping something heavy nearby. Bending over fast. Jumping. All of these produce acceleration signatures that overlap with the edges of a fall signature.

The polling rate problem

The free-fall phase of a fall — the moment before impact — typically lasts between 50 and 200 milliseconds, depending on height. My initial polling loop ran every 100ms. That meant I was sometimes polling once during the entire free-fall phase, and sometimes missing it entirely depending on timing.

When I increased the polling rate, I reduced missed detections — but I also started capturing more noise in the signal. Faster sampling of a noisy signal gives you noisier data. I hadn't understood that the polling rate and the signal quality were coupled problems, not independent ones.

Threshold tuning felt like guessing

I spent a long time adjusting the free-fall threshold (below which we call it free-fall) and the impact threshold (above which we call it an impact). Every adjustment that reduced false positives also reduced true positive detections, and vice versa.

This is the sensitivity/specificity tradeoff. I had read about it in the context of machine learning classifiers. I had not expected to experience it so viscerally while watching a device on my wrist fire an alert every time I sat down quickly.

A threshold-based classifier on noisy real-world data has a fundamental ceiling on performance. You can tune it, but you cannot eliminate the tradeoff. The only way past it is better data or a better model — preferably both.

What I'd do differently

The correct approach, which I understand now and didn't when I started, is interrupt-driven sampling. The MPU-6050 has a hardware interrupt that fires when acceleration crosses a configurable threshold — this removes the polling latency problem entirely and lets the microcontroller stay in low-power mode between events.

For the classifier, I'd collect real labeled data — actual falls (simulated safely) and non-fall motions — and train a lightweight ML model that could run on the ESP32 using something like TensorFlow Lite for Microcontrollers. A learned classifier would handle the variability in human motion much better than hand-tuned thresholds.

The broader lesson

Building something that has to make decisions about the real world — in real time, on cheap hardware — forces you to understand the limits of your approach very quickly. Textbook solutions work in controlled conditions. Real conditions are not controlled.

I came out of this project with a much cleaner understanding of what "embedded systems design" actually means — and a healthy skepticism of algorithms that look elegant but haven't been tested on real signal data.


← AV: Why It Failed Next: Autism Platform →