RepGuard is a wearable gym movement form corrector: a forearm-worn ESP32 + gyroscope unit that classifies each exercise repetition as correct or incorrect form in real time, gives instant LED feedback, and streams live data to a laptop/phone dashboard.
It's a software implementation of the Gym Movement Form Corrector system designed by Tiya Agarwal, Komal Jha, and Selvakumara Rajkumar for the BCSE315L Wearable Computing course at VIT Vellore, under the guidance of Prof. Dr. Jafar Ali Ibrahim S. — built out from the project report into a runnable codebase.
MPU6050 gyro → ESP32 (rep segmentation + on-device ML) → white LED (1 blink = correct, 2 = incorrect)
│
└── TCP (JSON) ──→ dashboard/server.py → web UI (laptop/phone browser)
- Firmware (
firmware/) samples the gyroscope at 50Hz, segments each repetition with a motion-threshold/debounce state machine, extracts 12 statistical features from the rep window, and runs an on-device Random Forest classifier (no cloud, no network round-trip needed for the LED feedback) to label the rep correct/incorrect. - ML pipeline (
ml/) trains that Random Forest offline in Python (scikit-learn) and exports it directly to a C header the firmware includes — so there's no ML runtime on the microcontroller, just plain if/else comparisons. - Dashboard (
dashboard/) receives the streamed samples and rep events over TCP and serves a live web UI — a scrolling gyro graph, correct/incorrect rep counters, and a calorie estimate — to any browser on the same network.
cd ml
pip install -r requirements.txt
python3 generate_dataset.py # writes data/synthetic_reps.csv
python3 train_model.py # trains + evaluates + writes ../firmware/RepGuard/model.hThis repo ships with a synthetic dataset (three exercises × correct/incorrect, parametric waveforms + noise) so the pipeline runs out of the box — see Collecting real data to retrain on real participants like the original project did (85% accuracy on real gyroscope data, per the report).
cd dashboard
pip install -r requirements.txt
python3 server.pyOpen http://<this-machine's-local-IP>:8000 on your laptop or phone (same Wi-Fi network). No dedicated access point or router setup needed beyond your existing network.
Don't have the hardware handy? Exercise the dashboard with synthetic rep data:
python3 simulate_esp32.py- Open
firmware/RepGuard/RepGuard.inoin the Arduino IDE (board: ESP32 Dev Module). - Install the MPU6050 library (Electronic Cats / i2cdevlib) via Library Manager.
- Edit
firmware/RepGuard/config.h: your Wi-Fi SSID/password and the dashboard machine's local IP. - Wire per
firmware/wokwi/diagram.json(MPU6050 over I2C on pins 21/22, white LED + 220Ω resistor on pin 5). - Flash to an ESP32, or paste the sketch into wokwi.com with
firmware/wokwi/diagram.jsonto simulate first — the original project validated its logic this way before building physical hardware.
firmware/
RepGuard/
RepGuard.ino # main sketch: sampling, rep segmentation, LED, TCP streaming
features.h # on-device feature extraction (must match ml/features.py)
model.h # generated by ml/train_model.py — the trained classifier as C
config.h # Wi-Fi/dashboard/threshold constants
wokwi/
diagram.json # Wokwi simulation wiring (ESP32 + MPU6050 + LED)
libraries.txt
ml/
features.py # shared feature spec (12 values per rep window)
generate_dataset.py # synthetic labelled dataset generator
train_model.py # trains the Random Forest, prints metrics, exports model.h
export_model.py # sklearn tree → C code exporter
dashboard/
server.py # TCP listener (ESP32) + Flask HTTP server (web UI)
simulate_esp32.py # sends synthetic sample/rep data for testing without hardware
templates/, static/ # dependency-free frontend (canvas graph, polls a JSON endpoint)
To match the original project's real-world accuracy, replace the synthetic dataset with real capture:
- Add a
Serial.printline in the firmware to log each rep's raw(gx, gy, gz)samples, or log them from the dashboard'ssamplemessages. - Label each captured rep as correct (1) or incorrect (0) — the original project had participants perform both deliberately.
- Write the rows to a CSV with the same columns as
ml/generate_dataset.pyproduces (ml/features.py'sFEATURE_NAMES+exercise+label), or feed raw windows throughextract_features()yourself. - Point
train_model.py --data your_file.csvat it and retrain.
A single white LED (not red/green) was a deliberate accessibility choice — usable by colorblind users — with blink count as the signal: one blink for correct form, two for incorrect. The buzzer/audio alert is routed through the connected laptop rather than an onboard speaker, keeping the wearable itself minimal.
MIT.