Inspiration
Walk through any hackathon at 2 AM and you'll see the same silhouette: thirty heads buried in laptops, every spine curled into a question mark. We've all read the "sit up straight" advice and ignored it, because a passive reminder loses to a flow state every time. So we asked the obvious-but-cursed question: what if the reminder couldn't be ignored? What if your own body was the alarm? Posturetir is the answer — a closed-loop posture corrector that watches you with a webcam, warns you twice, and then politely zaps your shoulders if you keep slouching.
What it does
Posturetir is a Raspberry Pi 4 sitting next to your monitor with a webcam pointed at you. A YOLO11n pose model extracts your skeleton in real time, a temporal CNN classifies whether you're upright, slouching, or full "shrimp" hunched over the keyboard, and a hysteresis debouncer smooths out the noise so a single bad frame doesn't trigger anything. Once you've been slouching long enough, the system escalates: a gentle spoken warning, then a sterner one, and finally a short pulse from a TENS unit driving EMS pads on your upper back through a GPIO-gated relay. The shock is the corrective signal — you straighten up, the gate closes, the cycle resets. Everything runs on-device. No cloud, no app, no account.
How we built it
The vision side runs YOLO11n-pose for 17-keypoint skeleton extraction, feeding hand-crafted geometric features (ear-shoulder offset, shoulder tilt, head-forward distance, normalized by torso length) into a tiny 1D-conv + MLP classifier we trained on our own labeled sessions. We collected data with a hotkey-driven recorder that lets you label frames as you sit (1=upright, 2=slouch, 3=shrimp), trained on a desktop GPU with leave-one-session-out cross-validation, and exported to ONNX so the Pi only needs onnxruntime — no PyTorch on the deployment image. The runtime side is a single inference loop wired through a hysteresis debouncer, a two-stage warning escalator with audio cues, and a single-pulse-with-cooldown safety wrapper that converts each detection into one bounded gate assertion. A watchdog thread independently drops the GPIO line if the loop ever stops heartbeating. The TENS unit is gated through an opto-isolated relay driven by a single BCM pin, default active-LOW so the line idles de-energized at boot before Python even starts.
Challenges we ran into
Safety dominated the design. The very first prototype could shock you at boot, because the GPIO line floats during early boot before the runtime claims it — we fixed it by picking an active-LOW relay so the inactive level is the safe one, and by enforcing "TENS off until you hear the bootup chime." The pulser was another rabbit hole: a single inference frame is only ~50–200 ms, which clicks the relay but is too short for many TENS units to actually trigger a stim, so we added a wall-clock pulse-duration window decoupled from the inference cadence. Synchronizing the spoken warnings with the actual zap was tricky too — we ended up running audio playback on a daemon thread and using a deferred-pulse signal so the gate fires after the "zapwarn" clip finishes, not on top of it. On the ML side, our first model trivially memorized per-session lighting/camera-angle quirks, so we moved to session-aware splits and added mixup, feature-space noise, and label smoothing to actually measure cross-person generalization.
Accomplishments that we're proud of
We have a real closed-loop hardware demo that works end-to-end on a Pi 4: camera in, EMS pulse out, with audio escalation and a watchdog enforcing default-off. The codebase has a hard model/ ↔ runtime/ ↔ utils/ seam so the entire ML pipeline is unit-testable on a laptop with FakeGate / FakeSpeaker, and a dedicated dry_run.py lets us tune thresholds and see "would have zapped" log lines without ever touching real hardware. We're also genuinely happy with the training story — leave-one-session-out CV that re-derives features live from raw keypoints, so iterating on the feature set never requires re-recording any data. And the safety contract holds up: default-off at construction, watchdog on a separate thread, post-pulse cooldown, single-pulse-per-rising-edge, and a --no-self-test-able relay sanity pulse before the loop even arms.
What we learned
Hardware projects rearrange your priorities. You stop thinking "what's the happy path" and start thinking "what does this do when it crashes." Every component now has an explicit fail-safe state and a context-manager lifecycle. We learned that real-time inference on a Pi is a budget exercise, not a model-quality exercise: cutting YOLO's imgsz from 640 to 320 quadrupled our FPS with no measurable drop in keypoint quality for the body region we actually care about. We learned to keep the deployment image lean by exporting to ONNX rather than dragging PyTorch onto the Pi. And we learned (the painful way) that cv2.VideoCapture.read() returns the oldest queued frame, not the freshest — a background grab thread that always serves the latest frame is the real fix.
What's next for Posturetir
More data, more people. Our trained model is honest but small; getting it across users and lighting conditions is the next milestone, and the collector script makes that cheap. We've been eyeing a Gemma-powered coaching mode — after a sustained slouch event, asynchronously generate a short spoken hint ("try rolling your shoulders back") instead of just a generic warning clip. A small e-paper or OLED display strapped to the device for at-a-glance posture stats is another quick win. Longer term: an integrated wearable form factor, a phone-side dashboard for streaks and trends, and an opt-in "study mode" for libraries and classrooms where the audio warning escalates to the zap silently, however headphone support was built in from day one so this might be unnecessary.
Built With
- agile
- ai
- ems
- github
- machine-learning
- python
- raspberry-pi
- scrum
Log in or sign up for Devpost to join the conversation.