Skip to main content
emobility.academy
B.Tech / BEEdge AI & estimationAdvanced About 7 weeksKit + add-ons

Road Surface Classifier (Smooth / Rough / Pothole) from Vibration

You build a road surface classifier that uses the kit's MPU6050 to record vibration and classifies the surface as smooth, rough or pothole, with readings logged to the SPI flash. You collect data by moving the kit on a trolley or bicycle over real surfaces, then run a classifier on the STM32.

Uses: I2C · UART · SPI

The problem

Road condition affects EV range, comfort, suspension wear and battery-pack vibration loads. Vehicles and fleet operators use vibration data to map rough roads and potholes, and the same idea helps adapt traction control and ride settings.

Objectives

  • Sample vertical acceleration at a rate high enough to capture road vibration.
  • Collect and label vibration data over smooth, rough and pothole surfaces.
  • Extract time- and frequency-domain features and train a classifier.
  • Run the classifier on the STM32 in fixed point and log events to SPI flash.
  • Report accuracy and how it changes with speed.

What you need

From the EV Embedded Development Kit

  • STM32F103C8T6 microcontroller unit (Arm Cortex-M3)
  • MPU6050 accelerometer and gyroscope
  • SPI flash memory
  • RTC with CR2032 backup cell
  • 16×2 LCD
  • RGB LEDs and a buzzer
  • Serial UART interface

Software

  • STM32CubeIDE
  • Embedded C with HAL drivers
  • Python (NumPy, SciPy, pandas, scikit-learn, matplotlib)

Extra parts

  • A USB power bank and cable suited to the kit's power port — To power the kit while it is moved over real surfaces away from a laptop.
  • A rigid mount, for example a padded tray clamped to a trolley or bicycle carrier — To hold the kit firmly so vibration reaches the MPU6050 consistently and the board is protected.

This project uses the kit's lithium cell. Respect polarity, never short the terminals, and don't leave the cell charging unattended.

Key concepts

Sampling rate and aliasing
The signal must be sampled at more than twice its highest important frequency. Road vibration of interest is mostly below about 50 Hz, so 200 Hz with the MPU6050's low-pass filter enabled is adequate.
RMS and crest factor
RMS measures overall vibration energy; crest factor (peak divided by RMS) is high for isolated shocks such as potholes.
Band energy features
The energy of the signal in frequency bands, computed with a short FFT or simple filters, separates fine surface texture from large bumps.
Speed dependence
The same road gives higher-frequency vibration at higher speed. The kit has no speed sensor, so speed is noted manually per run and treated as a recorded condition.

Step-by-step guide

  1. 1

    Plan the data collection

    Pick safe locations for each class: a smooth tiled corridor or new tarmac, a rough patch of old road or paving, and a few clear potholes or a speed bump. Plan to push a trolley or ride slowly on a bicycle in a quiet area, never in traffic. Decide on two or three steady speeds and note them manually for each run, because the kit has no speed sensor. Write a labelling method: a keypad press or button marks the start of each segment.

    Checkpoint: A data collection plan with sites, speeds, number of runs per class and a safety note.

  2. 2

    Configure the sensor and board

    Turn on the DIP switches for the MPU6050, SPI flash, RTC, LCD and UART. Configure I2C1 at 400 kHz. Wake the MPU6050 via PWR_MGMT_1, set ±8 g so pothole shocks do not clip, set the digital low-pass filter to around 44 Hz and set SMPLRT_DIV for 200 Hz. Use the MPU6050 FIFO or a timer interrupt to read accelerometer data reliably. Configure SPI for the flash and read its JEDEC ID with command 0x9F.

    Checkpoint: 200 samples per second of acceleration with no gaps, and the flash ID read correctly.

  3. 3

    Build the flash logger

    Write samples in pages to the SPI flash with a small header containing an RTC timestamp, run number, speed setting and label. Erase sectors before writing and keep a write pointer so logging can resume after power loss. Add a UART command to dump the flash to the PC as CSV. Show logging status and memory used on the LCD, and blink an LED while recording.

    Checkpoint: A five-minute test log written to flash and dumped to the PC with no missing samples and correct timestamps.

  4. 4

    Mount the kit and collect data

    Clamp the kit in a padded, rigid tray so it cannot move inside the mount but is protected from impacts. Keep the orientation fixed so the vertical axis is the same in every run. Collect at least ten runs per class per speed, plus mixed runs where the surface changes. Use the button to mark potholes as you hit them. Check the cell and connections after each session.

    Checkpoint: Labelled logs for all three classes at two or more speeds, checked for clipping and gaps.

  5. 5

    Explore the data

    In Python remove gravity from the vertical axis with a high-pass filter and plot time series and spectrograms for each class. Look at RMS, peak values and where the energy sits in frequency. Potholes show as single large shocks; rough roads as continuous higher RMS. Note how speed shifts the spectrum. This guides the choice of window length and features.

    Checkpoint: Plots for each class and speed, and a short note on which features look most useful.

  6. 6

    Design features and windows

    Use windows of about one second (200 samples) with 50% overlap. For each window compute RMS, peak-to-peak, crest factor, kurtosis, zero-crossing rate and the energy in three or four frequency bands from a 128- or 256-point FFT. Choose features that are cheap on the STM32: band energies can also come from simple IIR band-pass filters if the FFT is too slow in fixed point.

    Checkpoint: A feature table for all windows with class labels, and plots showing class separation.

  7. 7

    Train and evaluate classifiers

    Train a decision tree, a random forest and a small logistic regression in scikit-learn. Split train and test by run, not by window, so overlapping windows from one run never appear in both. Report accuracy, per-class precision and recall and the confusion matrix. Check accuracy separately for each speed. Choose the model that runs on the STM32 with acceptable accuracy.

    Checkpoint: Test results per model and per speed, with a chosen model justified.

  8. 8

    Implement on-device classification

    Port feature extraction to C in fixed point, using the CMSIS-DSP Q15 FFT functions or band-pass filters, and generate C code for the chosen tree. Feed recorded windows over UART and check that the STM32's features and predictions match Python. Measure execution time per window; it must be well under one second so classification keeps up in real time. Also record the RAM used by the FFT buffers, which is significant on a 20 KB part.

    Checkpoint: Matching predictions on replayed test data and a measured execution time per window.

  9. 9

    Run live and log events

    Run classification live during new trials. Show the current class on the LCD and RGB LED, beep on a pothole, and log each classified window and every pothole event with an RTC timestamp to the SPI flash. After each run dump the log and compare the device's events with your manual pothole markers. Note any missed or false pothole events and look at the raw vibration around them to understand why the classifier failed.

    Checkpoint: Live classification during at least five new runs, with logged pothole events matching manual marks.

  10. 10

    Report results

    Write up the method, data collection, features, model, embedded implementation and results. Present accuracy per class and per speed, and discuss the effect of speed, mounting and that real vehicles have suspension, which changes the vibration seen by the sensor. Include memory and timing figures from the firmware. Add photographs of the mount and test sites, the feature definitions and a short section on how the system could be fitted to a real vehicle.

    Checkpoint: A report with results tables, a demo video of live classification and the dataset.

Testing & validation

  • No accelerometer clipping on pothole events at the chosen range.
  • Train and test split by run, with accuracy reported per class and speed.
  • STM32 predictions match Python on replayed data.
  • Live pothole detections compared with manual markers.

Expected results

A portable vibration logger and on-device road surface classifier, a labelled dataset, and measured accuracy showing how well smooth, rough and pothole surfaces are separated at different speeds.

Take it further

  • Use the gyroscope to separate turning from bumps.
  • Add an encoder or wheel sensor add-on to measure speed and normalise features by it.
  • Add an ESP32 or a phone link through an HC-05 on the Bluetooth header to tag events with location.
  • Send road-condition messages over CAN for a traction or ride controller.

Viva and review questions

Why did you choose 200 Hz sampling?

The useful road vibration is mostly below about 50 Hz, so 200 Hz gives a margin above the Nyquist rate, and the MPU6050's low-pass filter removes higher frequencies that would alias.

Why split data by run instead of by window?

Overlapping windows from the same run are nearly identical, so a random split leaks information and inflates accuracy. Splitting by run tests on genuinely new data.

How does speed affect your classifier?

Higher speed raises vibration frequency and amplitude, so a rough road at low speed can look like smooth road at high speed. We report accuracy per speed and note that a speed sensor would let us normalise.

Related EV projects

All 100 EV projects