Skip to content
Denna sida är ännu inte tillgänglig på svenska.
← Tillbaka till projekten

TinyML Arduino Posture Classifier

TinyML Arduino Posture Classifier

An Echo State Network running on Arduino Nano 33 BLE that classifies posture using IMU sensor data, with federated learning over Bluetooth Low Energy.

#tinyml#embedded#machine-learning#arduino#edge-computing#federated-learning

What We Built

We implemented a posture classification system on an Arduino Nano 33 BLE that runs an Echo State Network (ESN) entirely on-device. The system samples 9-axis IMU data, extracts statistical features, and classifies three postures: sitting, standing, and moving.

The project was part of the EITP40 course and demonstrates that you can run machine learning on a microcontroller with only 256KB of RAM and 1MB of flash - no cloud, no external server, just the device itself.

The Core Idea

An Echo State Network is a type of recurrent neural network where only the output layer is trained. The reservoir, a fixed random recurrent network, transforms the input into a high-dimensional state space. We only train the output weights using online gradient descent, which is computationally cheap and memory-efficient.

The architecture:

  • 20 reservoir neurons with random fixed weights
  • 18 input features (mean and standard deviation of 9 IMU axes)
  • 3 output classes (sitting, standing, moving)
  • 128-sample sliding window for feature extraction

Key Design Decisions

Why an ESN? Traditional RNNs require backpropagation through time, which is expensive in both compute and memory. An ESN sidesteps this by keeping the reservoir weights fixed and only training a linear output layer. Training reduces to online gradient descent, just a few matrix multiplications per sample.

Feature extraction: Instead of raw IMU values, we compute mean and standard deviation over a 128-sample window for each of the 9 axes (accelerometer X/Y/Z, gyroscope X/Y/Z, magnetometer X/Y/Z). This gives 18 features that capture both static posture and movement dynamics.

Normalization: We use Exponential Moving Average (EMA) with alpha=0.005 to normalize features. This adapts to sensor drift and device-to-device variation without requiring explicit calibration.

Federated learning: Multiple devices can share and aggregate their output weights over Bluetooth Low Energy. Each device trains locally, then exchanges weights with another device. The aggregation is a weighted average based on how many batches each device has trained on.

The Implementation

The firmware is structured as a state machine in engine.cpp that handles different commands:

  • CMD_NONE: Normal inference - sample IMU, compute features, update reservoir, predict
  • CMD_TRAIN: Collect a batch of 8 samples, get labels, normalize, train output layer
  • CMD_VAL: Run evaluation loop - collect test data, compute confusion matrix
  • CMD_INFER: Run inference on a batch and return predictions
  • CMD_PERSIST: Save weights and EMA to MbedOS KVStore
  • CMD_SHARE_WEIGHTS: Federated weight exchange over BLE
  • CMD_RESET: Clear all persisted state

Communication happens over either USB Serial or BLE, selected by button press duration at startup.

What Works

The system successfully:

  • Classifies three postures in real-time
  • Trains incrementally with new labeled data
  • Persists model state across power cycles
  • Shares weights between devices over BLE
  • Computes evaluation metrics (accuracy, precision, recall, F1)

The federated learning implementation uses a weighted average: if device A trained on 10 batches and device B trained on 5 batches, the aggregated weights give 2/3 weight to A and 1/3 to B.

Files and Structure

tinyml-arduino-posture-classifier.ino   // Entry point
engine.{cpp,h}                          // State machine, command handling
esn.{cpp,h}                             // ESN: reservoir, training, inference
imu_features.{cpp,h}                    // IMU sampling, feature extraction, EMA
eval.{cpp,h}                            // Confusion matrix, metrics
federated.{cpp,h}                       // BLE weight sharing
persistance.{cpp,h}                     // KVStore read/write
io.{cpp,h}                              // Unified I/O interface
ble.{cpp,h}                             // BLE communication
serial_protocol.{cpp,h}                 // USB Serial communication
button.{cpp,h}                          // Button input (mode selection)
led.{cpp,h}                             // LED status indicators

A Python helper script (python_helper/ble_shell.py) provides a command-line interface for BLE communication and federated learning management.