Project Overview
RT-Spark is an IoT activity recognition system that identifies walking and running using accelerometer and gyroscope readings. An STM32F407ZG reads the onboard ICM20608 motion sensor and transmits the measurements through an RW007 Wi-Fi module to a cloud server.
A Random Forest model processes the motion data, stores each prediction in SQLite, and makes the results available through an HTTPS API. An Android application displays the latest activity, prediction confidence, timestamp, and recent history.
The project demonstrates a complete path from physical movement to embedded sensing, cloud classification, and mobile monitoring.
Motivation
Motion sensors produce numerical measurements that describe acceleration and rotation. Turning those measurements into recognizable activities requires consistent sensor units, feature extraction, and a classification model.
The goal of this project is to connect these stages in a working prototype. Walking and running provide a focused starting point for exploring how an embedded device, cloud services, and an Android interface can work together.
Features
- Six-axis motion sensing using the onboard ICM20608.
- Direct Wi-Fi communication from the RT-Spark board.
- MQTT transmission over TLS with broker authentication.
- Cloud classification into WALKING and RUNNING.
- Five-reading, non-overlapping prediction windows.
- SQLite storage of activity labels, confidence values, and timestamps.
- HTTPS access to the latest prediction and activity history.
- Android Live activity and History screens.
- Automatic refresh while the app is open.
- Feed status for current data, stale readings, connection issues, and clock mismatch.
Hardware Components
- One RT-Spark board with an STM32F407ZG microcontroller.
- Onboard ICM20608 accelerometer and gyroscope.
- Onboard RW007 Wi-Fi module.
- An ST-Link programming interface and compatible USB data/power cables.
- An Android phone or Android Studio emulator.
- A Wi-Fi access point and development computer.
The IMU and Wi-Fi module are included on the RT-Spark board.
Software and Services
- PlatformIO for firmware builds and uploads.
- STM32CubeMX and STM32Cube HAL for peripheral configuration and firmware development.
- lwIP and Mbed TLS for embedded networking and TLS.
- Ubuntu on AWS EC2 for cloud hosting.
- Eclipse Mosquitto for MQTT communication.
- Python, Paho MQTT, NumPy, pandas, scikit-learn, and joblib for classification.
- SQLite for prediction storage.
- Flask, Gunicorn, and Nginx for the HTTPS API.
- Android Studio, Kotlin, and Volley for the mobile application.
We planned a system that would detect walking and running, process the motion data in the cloud, and display the results on an Android phone.
Step 2: Prepared the RT-Spark BoardWe set up the STM32Cube HAL firmware and PlatformIO build, used the CubeMX configuration as a peripheral reference, and uploaded the firmware through ST-Link.
Step 3: Read the Motion SensorWe used the onboard ICM20608 to read acceleration and rotation along three axes. We checked the readings through the serial monitor and converted them into the units expected by the classifier.
Step 4: Connected the Board to Wi-FiWe configured the onboard RW007 module to connect to Wi-Fi. The board sent its sensor readings as JSON messages using MQTT over TLS.
Step 5: Set Up the Cloud ServerWe used an Ubuntu server on AWS EC2 to host the Mosquitto MQTT broker and the Python application that received the board’s sensor messages.
Step 6: Integrated the Activity ClassifierWe connected the incoming readings to the saved Random Forest model. The classifier processed five readings at a time and predicted WALKING or RUNNING.
Step 7: Added the Database and APIWe stored each prediction, confidence value, and timestamp in SQLite. We provided Flask API endpoints for the latest prediction and history, with HTTPS access through Nginx and Gunicorn.
Step 8: Developed the Android AppWe built a Kotlin app with Live activity and History screens. The app retrieved results from the API, refreshed automatically while open, and showed when the latest reading became stale.
Step 9: Checked the Complete ConnectionWe connected the board, cloud services, and Android app. We compared prediction IDs, activity labels, confidence values, and timestamps to confirm that the phone displayed matching server records.
Step 10: Tested Walking and JoggingWe ran three walking and three jogging trials, each lasting 60 seconds, with one participant holding the board in the right hand. The recorded test correctly classified 51 of 52 eligible windows, giving 98.1% accuracy within that session.
How the System Works
1. The ICM20608 measures acceleration and angular velocity along three axes.
2. The STM32 converts the readings into the required units and formats them as JSON.
3. The RW007 sends the readings to the MQTT topic activity/sensor over TLS.
4. The cloud subscriber collects five readings and extracts motion features.
5. The Random Forest model predicts WALKING or RUNNING.
6. The prediction, confidence, and timestamp are saved in SQLite.
7. The Android app retrieves the records through the HTTPS API.
The STM32 handles sensor acquisition and transmission. Classification runs on the cloud server.
Sensor Acquisition and Firmware
The firmware uses STM32Cube HAL and a foreground loop that services networking, time synchronization, MQTT, and sensor acquisition.
The ICM20608 connects through I2C2, while the RW007 uses SPI2. The onboard signal assignments are defined in the firmware:
- ICM20608 I2C2: PF0 is SDA, and PF1 is SCL.
- RW007 SPI2: PB13 is SCK, PC2 is MISO, and PC3 is MOSI.
- RW007 control: PF10 is chip select, PG15 is reset, and PG11 is INT/BUSY.
- USART1 diagnostics: PA9 is TX, and PA10 is RX.
The driver checks the sensor identity and configures the accelerometer for ±2 g and the gyroscope for ±250 degrees per second. The application targets one reading per second.
Each message contains six fields: acceleration_x, acceleration_y, acceleration_z, gyro_x, gyro_y, and gyro_z. Acceleration is transmitted in g, and angular velocity is transmitted in radians per second. The firmware converts gyroscope measurements from degrees per second before publishing them.
Keeping these units consistent with the model input is essential for meaningful predictions. Serial diagnostics are available at 115200 baud.
MQTT Communication
The board connects to an authenticated Mosquitto listener over TLS on TCP port 8883. Sensor messages use the topic activity/sensor, QoS 1, and retain disabled.
The firmware verifies the server certificate using its configured CA and hostname. It also obtains UTC for certificate-date validation. Wi-Fi and MQTT credentials are stored in local configuration headers excluded from source control.
The cloud classifier connects to the broker's loopback listener on port 1883. After classifying a window, it saves the result and also publishes a message to activity/prediction. The Android app obtains its displayed results through the HTTPS API.
Cloud Classification
The classifier processes five readings per non-overlapping window. At the nominal one-second acquisition interval, each prediction represents approximately five seconds of motion.
For each of the six sensor channels, the feature extractor calculates the mean, standard deviation, minimum, maximum, range, and root mean square. It calculates the same statistics for acceleration magnitude and gyroscope magnitude, producing 48 features.
The training code defines a Random Forest classifier with 200 trees. The two output classes are WALKING and RUNNING.
Each prediction includes a confidence value. This value represents the model's probability estimate for that prediction; accuracy is measured separately by comparing predictions with labelled activity intervals.
The repository includes a saved model for inference. The training script expects dataset/dataset.csv, which is absent from this source snapshot. Reproducing training requires the original dataset, its provenance, label definitions, sampling rate, and units.
Database and API
SQLite stores each prediction with its record ID, activity ID, activity label, confidence, and creation time. Timestamps are stored in UTC.
The API provides two main endpoints:
- GET /api/activity/latest returns the newest prediction.
- GET /api/activity/history?limit=50 returns the newest 50 predictions, ordered by descending record ID.
The deployed arrangement uses Gunicorn to serve Flask and Nginx to provide HTTPS on port 443. Database timestamps indicate prediction completion on the server, rather than the acquisition time of individual sensor samples.
Android Application
The Android app uses Kotlin and Volley to retrieve predictions over HTTPS. Its working interface is implemented in RtsparkActivity.
The Live activity screen displays the latest activity, confidence, timestamp, prediction number, and feed status. The History screen displays the latest 50 predictions, newest first, with counts of walking and running records within that set.
While the app is open, another refresh is scheduled five seconds after the previous request cycle finishes. Actual refresh intervals also include request duration. UTC timestamps are converted to the phone's local timezone.
When the latest prediction becomes more than 20 seconds old, the app displays WAITING FOR SENSOR. During connection problems, it preserves the last received prediction and identifies the connection issue.
Build and Setup
1. Obtain the Source
Use the integration/stm32cubemx version containing firmware, cloud, android_app, and the setup documentation. The configuration procedure is documented in docs/RTSPARK_SETUP.md.
2. Configure the Firmware
Create the local configuration headers from these example files:
For Wi-Fi settings, copy firmware/include/rw007_wifi_config.example.h to firmware/include/rw007_wifi_config.h.
For MQTT settings, copy firmware/include/rtspark_private.h.example to firmware/include/rtspark_private.h.
Enter the Wi-Fi credentials, MQTT password, and a unique client ID. For a separate server, configure the broker hostname and matching trusted CA.
From the repository root, check and build the firmware:
python firmware/scripts/check_cubemx.py
pio run -d firmware
Upload through ST-Link:
pio run -d firmware -t upload
Open the serial monitor at 115200 baud using the detected port. Check sensor initialization, Wi-Fi association, DHCP, and the MQTT/TLS connection.
PlatformIO compiles the maintained firmware/src and firmware/include trees. The CubeMX .ioc is a configuration reference; regeneration follows the review procedure in firmware/README.md.
3. Prepare the Cloud Services
Configure Mosquitto with a loopback listener for the classifier and an authenticated TLS listener for the board. Use certificates matching the hostname and CA configured in the firmware and Android app.
In the project's Python environment, install the dependencies and initialize SQLite:
python -m pip install -r requirements.txt
python -m pip install gunicorn
python cloud/database/database.py
Start the classifier in one terminal or service:
python cloud/mqtt/mqtt_classifier.py
Start the API in another terminal or service:
gunicorn --bind 127.0.0.1:5000 cloud.api.app:app
Configure Nginx to serve HTTPS and forward API requests to the loopback listener. The project-specific provisioning scripts require adaptation for a different hostname, certificate setup, or server environment. Deployed service unit files and private credentials are not included in the source snapshot.
4. Run the Android App
Open android_app in Android Studio, sync the project, and run the app configuration on a compatible phone or emulator.
For a separate deployment, update the API hostname in RtsparkApi.kt, the domain in rtspark_network_security.xml, and the trusted public CA certificate. Ensure the phone can reach the server.
5. Check the Complete Pipeline
Confirm that sensor messages reach the subscriber, predictions are saved, and the API returns fresh record IDs. Compare an app prediction with the corresponding API record using its ID, label, confidence, and timestamp.
Demonstrate walking and jogging. Stop the board to check the stale-data status, then restore it and confirm that fresh predictions appear again in the setup being demonstrated.
Testing and Results
A recorded session on October 25, 2026 used six requested 60-second trials: three walking and three jogging, alternating by activity. One participant held the board in the right hand. Jogging was evaluated against the model's RUNNING class.
Eligible windows were selected using recorded activity intervals, settling time, and boundary margins. Incorrect and low-confidence predictions remained in the scoring.
Walking trials: 25 of 26 eligible windows were correctly classified as WALKING. One window was classified as RUNNING.
Jogging trials: all 26 eligible windows were correctly classified as RUNNING. No windows were classified as WALKING.
The system correctly classified 51 of 52 eligible windows, giving 98.1% accuracy within this session. This short, non-randomized test involved one participant and one board placement; it does not establish accuracy across people, placements, or environments.
Recorded eligible prediction-completion gaps were five to six seconds. These are server-record intervals rather than direct measurements of sensor acquisition timing or end-to-end latency.
Android checks included emulator and physical-phone displays. In the recorded physical-phone Live check on October 26, prediction 5167 matched its API record by ID, WALKING label, confidence of 67.5%, and timestamp. The API timestamp of 02:08:39 UTC corresponded to 10:08:39 AM in Asia/Manila.
Implementation Lessons
Sensor units and feature extraction must remain consistent with the model input. Foreground networking must also continue running while the board waits for time synchronization, TLS, or MQTT traffic.
Prediction IDs and UTC timestamps make it possible to compare the phone display with stored records. Feed status helps users understand when a displayed prediction has become stale.
Limitations and Future Improvements
The model currently recognizes WALKING and RUNNING. A stationary board still receives one of those labels because REST is not a trained class. Cloud prediction also depends on network connectivity.
Future improvements include adding a REST class, evaluating more participants and sensor placements, documenting a reproducible training dataset, assessing sampling-rate changes with retraining, and adding device IDs and buffering for broader deployment.











Comments