A wearable posture sensor, from a TinyML classifier running on an IMU board to ESP32 firmware for a strain-gauge patch.
Real-time posture classification on a microcontroller. An Arduino Nano 33 BLE Sense Rev2 reads its onboard IMU, runs a small neural network with TensorFlow Lite Micro, and reports a smoothed good/bad posture percentage over serial. A small Python app turns that stream into a live, colour-coded display.
This is the first prototype of PosturePatch, a wearable posture sensor. The firmware for the next phase, which reads strain gauges through an HX711 on an ESP32-C3, is in PosturePatchFirmware.
BMI270 IMU ──> 6 features ──> MLP 6-16-8-1 ──> 25-sample ──> serial ──> Visualizer
(accel xyz, (TFLite Micro, history "Good: 72.4%
gyro xyz) ~3 KB model) Bad: 27.6%"
Visualizer/posture_gui.py parses the serial output and shows
the good-posture percentage on a background that fades from red to green.| Path | Purpose |
|---|---|
Posture/ |
Main sketch: inference, 25-sample smoothing, serial output at 115200 baud |
TensorML/TensorML.ino |
Earlier sketch: one classification every 500 ms, no smoothing |
TensorML/model_data.* |
The trained model as a C array, used by TensorML.ino |
TensorML/excess/ |
Data collection, preparation, training and conversion scripts, plus the datasets |
posture model v1/ |
The trained model in Keras (.h5), TFLite and C-header form |
Visualizer/ |
Tkinter app that displays the live posture percentage |
All of these live in TensorML/excess/.
sketch_may13a.txt is an Arduino sketch that prints raw IMU
readings as CSV at about 10 Hz.data_creation.py reads that stream over serial and saves 300
labelled samples (about 30 seconds) per run. Set label to good_posture
or bad_posture and the serial port to match your board.prepare_data.py merges the two recordings, shuffles them,
standardises each feature with scikit-learn's StandardScaler, and writes
posture_train_data.npz. The combined set, posture_dataset.csv, holds
600 samples, 300 per class.train_model.py trains the network with Adam and binary
cross-entropy for 30 epochs, holding out 20% for validation, and saves
posture_model.h5.convert_tflite.py converts it to TensorFlow Lite with the
default optimisations, giving a 3,092-byte .tflite file. That file is then
embedded in the sketch as a C array, for example with xxd -i.Board. Arduino Nano 33 BLE Sense Rev2. Install the Arduino_BMI270_BMM150
library and a TensorFlow Lite Micro library for Arduino, then upload
Posture/Posture.ino and open the serial monitor at 115200 baud.
Visualizer. Needs Python 3 with pyserial and Tkinter.
pip install pyserial
python Visualizer/posture_gui.py
It asks for the serial port, for example COM3 or /dev/ttyACM0.
Retraining. Needs pyserial, pandas, scikit-learn, numpy and
tensorflow. Run the pipeline scripts above in order.
Posture.ino. The model has a single sigmoid output,
the probability of bad posture (labels are good_posture = 0 and
bad_posture = 1). Posture.ino reads two outputs, [bad, good], so
output->data.f[1] falls outside the output tensor. It should compare
output->data.f[0] against 0.5, as TensorML.ino does.PosturePatch moves from an IMU on a development board to strain gauges on a patch worn on the back. Phase 1 of that firmware, a raw HX711 data stream on an ESP32-C3, is in PosturePatchFirmware.