The problem
An electric two-wheeler controller that knows whether the rider is about to accelerate, brake or corner, and whether the road is smooth, rough or broken, can shape torque, adjust regenerative braking and warn the rider. These estimates must run on low-cost controllers with tight memory and timing budgets, and must degrade safely when sensors are noisy or the classifier is unsure.
Objectives
- Design an intent model (accelerate, cruise, coast, brake, turn) and a road-condition model (smooth, rough, pothole or bump event)
- Build a labelled dataset from instrumented rides with the kit mounted on a bicycle or test cart
- Implement and compare rule-based, filter-based and small learned estimators on the STM32 in fixed point
- Quantify accuracy, detection latency, false-alarm rate, memory and CPU use, and robustness to sensor faults
What you need
From the EV Embedded Development Kit
- STM32F103C8T6 microcontroller unit (main controller)
- 3-axis accelerometer and gyroscope (MPU6050, I2C)
- Analog potentiometer input
- Serial UART interface
- SPI flash memory
- RTC with CR2032 backup cell
- 16×2 LCD
- RGB LEDs and a buzzer
Software
- STM32CubeIDE with HAL drivers
- Embedded C and FreeRTOS
- Python with pandas, NumPy, SciPy, scikit-learn and matplotlib
- TensorFlow Lite for Microcontrollers or a hand-written fixed-point inference routine
- MATLAB (optional)
Extra parts
- Rigid mounting bracket, padded enclosure and a portable low-voltage supply suited to the kit's power port — The board must ride on a bicycle or cart with its axes fixed relative to the frame for repeatable data.
- Wheel encoder or reed-switch speed sensor on the test wheel — The kit has no speed sensor; real rides need a measured speed signal. Bench experiments can use potentiometer-emulated speed instead.
- Two handlebar potentiometers or levers wired to spare ADC inputs, or the kit potentiometer used for one channel — The kit has one potentiometer; separate throttle and brake signals need a second analog input.
- Action camera or phone video synchronised to the log — Video gives ground-truth labels for intent and road events.
This project uses the kit's lithium cell. Respect polarity, never short the terminals, and don't leave the cell charging unattended.
Key concepts
- Rider intent
- A latent state inferred from control inputs and motion, such as rising throttle or a lean angle building before a turn. Early, reliable detection gives the controller time to act.
- Road-condition features
- Vertical acceleration variance, peak-to-peak values, band energy in chosen frequency bands and kurtosis over short windows separate smooth surfaces, rough surfaces and discrete impacts.
- Sensor fusion
- Combining inputs with different noise and bandwidth, here IMU, throttle, brake and speed, so that the estimate is better than any single source.
- Hidden Markov model
- A probabilistic model of states that cannot be observed directly and their transitions; useful for smoothing intent decisions so they do not flicker.
- Fixed-point inference
- Running a quantised model with integer arithmetic. On a Cortex-M3 with no FPU, int8 or Q15 maths is far faster than software floating point.
Step-by-step guide
- 1
Frame the research questions and label taxonomy
Write precise definitions for each intent class and each road class, including how a human annotator decides the label from video and logs. Decide the decision rate (for example 20 Hz) and the latency budget that would make the estimate useful for torque shaping. Review published work on two-wheeler rider modelling and road-surface classification and identify the gap your testbed targets, such as low-cost hardware, fixed-point deployment or robustness. Fix the metrics before collecting data.
Checkpoint: A protocol document defines labels, decision rate, latency budget and metrics, and the guide has signed it off.
- 2
Hardware setup and clocking
Set SYSCLK to 72 MHz in CubeMX. Enable the DIP switches for the MPU6050, potentiometer, SPI flash, RTC, LCD, LEDs and UART. Configure I2C at 400 kHz, ADC1 with DMA over the throttle and brake channels, a timer input-capture channel for the speed sensor add-on, and SPI for flash. Use the MPU6050 data-ready interrupt to trigger sampling at 200 Hz. Read the RTC over I2C after a bus scan confirms its address.
Checkpoint: A UART stream shows synchronised IMU, ADC, speed and RTC time at 200 Hz with no missing sample counters.
- 3
Mount, align and calibrate
Fix the kit in its enclosure on the bracket so that the board axes map to forward, lateral and vertical. Record the rotation matrix if the mounting is not aligned. Calibrate gyro bias at rest, calibrate accelerometer offsets with a six-position test, and calibrate throttle and brake travel to 0–100 per cent. Store calibration in SPI flash with a CRC so it survives power cycles.
Checkpoint: After calibration, the board at rest reads 1 g on the vertical axis within tolerance and the stored calibration reloads with a valid CRC.
- 4
Logging firmware under FreeRTOS
Create a high-priority sampling task triggered by the IMU interrupt, a feature task at the decision rate, and a low-priority logging task that writes 256-byte pages to SPI flash from a double buffer. Add a sync marker: a button press flashes an RGB LED and writes an event record so video can be aligned to the log. Measure stack high-water marks and CPU load with a spare timer.
Checkpoint: A 20-minute ride is logged with zero dropped records and the LED sync event is visible in both video and log.
- 5
Collect and label the dataset
Ride defined routes covering smooth tar, broken patches, speed bumps, gravel, turns and braking zones, at several speeds and with at least two riders. Label intent and road class from synchronised video using a simple annotation tool in Python. Hold out whole rides, not random windows, for testing, so the evaluation reflects new rides. Document class balance and annotation agreement between two labellers.
Checkpoint: A versioned dataset with ride-level train, validation and test splits and an annotation-agreement figure exists.
- 6
Feature extraction and baselines
Compute window features in Python first: means, variances, peak-to-peak, band energies from short FFTs, throttle and brake rates, yaw rate and lateral acceleration. Build three baselines: thresholds tuned on the validation set, a hidden Markov model over intent, and a decision tree. Evaluate per-class precision, recall and detection latency against video labels. Keep the feature code simple enough to port to fixed point later, and record the cost of each feature so expensive ones can be dropped if they add little accuracy.
Checkpoint: Baseline confusion matrices and latency histograms are produced on the held-out rides.
- 7
Learned models and quantisation
Train a small model, such as a gradient-boosted tree exported as nested comparisons or a tiny 1-D convolutional network, on the same features or raw windows. Quantise to int8 or Q15 and estimate flash and RAM from the generated tables. Keep the model within a budget that leaves room for the rest of the firmware within 64 KB flash and 20 KB RAM.
Checkpoint: The quantised model's accuracy on the test rides is within your stated tolerance of the floating-point model, and its size fits the budget.
- 8
On-target deployment
Port feature extraction and inference to the STM32 using integer arithmetic, verifying bit-exact or near-exact agreement with a Python reference by replaying logged windows over UART. Add a confidence measure and a fallback: when confidence is low or a sensor fault is detected, report 'unknown' and use conservative defaults. Show intent and road class on the LCD and drive an RGB colour per road class.
Checkpoint: Replayed windows give the same classes on target and in Python, and inference time per decision is measured with a GPIO toggle.
- 9
Robustness and fault-injection experiments
Inject faults in firmware: IMU stuck values, added noise, saturation, a missing speed signal and mounting rotation of a few degrees. Measure how accuracy and false-alarm rate degrade and whether the fallback engages correctly. Repeat on rides by an unseen rider to test generalisation. Report results per fault type and severity, and check that the system never reports a confident wrong class when its inputs are clearly invalid, since that is the most dangerous failure for a controller relying on the estimate.
Checkpoint: A table shows accuracy, false alarms and fallback rate under each injected fault.
- 10
Analysis and write-up
Compare every estimator on accuracy, latency, false-alarm rate, flash, RAM and CPU load. Use confidence intervals across rides rather than single numbers. Discuss failure cases with plots of the raw signals. Publish the dataset description, labelling protocol and firmware structure so others can reproduce the testbed. Include an ablation that removes one sensor at a time to show what each contributes, and state the conditions not covered by the dataset, such as rain, night riding or a different vehicle, so readers know where the results apply.
Checkpoint: A draft paper or thesis chapter with reproducible figures generated from the versioned dataset.
Testing & validation
- Ride-level held-out evaluation with per-class precision, recall and F1
- Detection latency measured from video-labelled event onset to estimator output
- False-alarm rate per kilometre on smooth roads
- Bit-exactness or bounded error between on-target and Python inference on replayed data
- CPU load, stack high-water marks and inference time measured on target
- Accuracy under injected sensor faults and on an unseen rider
Expected results
A mounted, logging testbed with a labelled multi-rider dataset, several intent and road-condition estimators running in fixed point on the STM32, and a quantified comparison of accuracy, latency, robustness and resource use.
Research angle for your PhD
Research questions: what is the minimum sensing and compute needed for useful intent and road estimates on a two-wheeler, and how do learned models compare with interpretable filters once quantised for a Cortex-M3? Metrics: per-class F1, detection latency, false alarms per km, flash, RAM, CPU load and degradation under faults. Baselines: thresholds, HMM and decision tree. Datasets: your own multi-rider logs with a published labelling protocol; offline comparison with any public two-wheeler or road-surface IMU dataset you can verify. Publishable contributions include a reproducible low-cost dataset, an analysis of the accuracy-latency-resource trade-off, and a safe fallback design with measured behaviour under faults.
Take it further
- Use intent output to shape a throttle map on the motor driver with a small DC motor add-on
- Estimate tyre-road friction trends from braking events
- Transmit road events as CAN frames for a crowd-sourced road-quality map via a gateway add-on
- Online adaptation of thresholds per rider
Viva and review questions
Why split the dataset by ride rather than by window?
Neighbouring windows from the same ride are highly correlated, so a random split leaks information and inflates accuracy. Ride-level splits test on genuinely new conditions.
Why quantise the model?
The Cortex-M3 has no FPU, so floating-point inference is slow; int8 or Q15 arithmetic cuts time and memory, at the cost of a small, measured accuracy loss.
What happens when the classifier is unsure?
It reports 'unknown' and the controller uses conservative default behaviour. Low confidence and detected sensor faults both trigger this fallback.
How did you get ground truth for intent?
From synchronised video and control inputs, labelled by two annotators using a written protocol, with their agreement reported.