Roni Bandini β Buenos Aires, Argentina Project started November 2024 Β· inference sketch January 2025
HR-HRV is an experimental wearable Machine Learning project that classifies worker stress from ECG signals directly on an Arduino Portenta H7.
The signal is acquired with a SparkFun AD8232 Single Lead Heart Rate Monitor and processed using the Edge Impulse HR/HRV Features block.
The resulting physiological features feed a neural-network classifier with two output classes:
stress
working
Inference runs locally on the Portenta H7. The onboard RGB LEDs provide immediate visual feedback.
Experimental project for exploring ECG, HR/HRV feature extraction and Edge Machine Learning. It is not intended as a medical diagnostic device.
- β€οΈ Single-lead ECG acquisition
- π§ On-device stress classification
- π Edge Impulse HR/HRV DSP block
- β±οΈ 40-second inference window
- π 50 Hz ECG acquisition
- π¬ HR and interbeat-interval feature extraction
- π¨ 85% stress confidence threshold
- π΄ Red LED for detected stress
- π’ Green LED for normal working state
- π¦ Compiled Arduino HR library included
- π Leads-off electrode detection
- π§ͺ Alternative Elemyo ECG implementation included
flowchart LR
BODY["β€οΈ ECG Electrodes"]
AD["AD8232 ECG Front End"]
PORTENTA["Arduino Portenta H7"]
HRV["Edge Impulse<br/>HR / HRV DSP"]
NN["π§ Neural Network"]
CLASS{"Classification"}
RED["π΄ Stress"]
GREEN["π’ Working"]
BODY --> AD
AD -->|"A0"| PORTENTA
PORTENTA --> HRV
HRV --> NN
NN --> CLASS
CLASS -->|"stress > 85%"| RED
CLASS -->|"otherwise"| GREEN
The complete inference pipeline executes on the Portenta H7 without requiring remote inference.
The project uses the Arduino Portenta H7.
| Specification | Value |
|---|---|
| MCU | STM32H747XI |
| Main CPU | Cortex-M7 @ 480 MHz |
| Secondary CPU | Cortex-M4 @ 240 MHz |
| Internal Flash | 2 MB |
| Internal RAM | 1 MB |
| External Flash | 16 MB |
| External SDRAM | 8 MB |
| Wireless | Wi-Fi + Bluetooth |
| USB | USB-C |
Its Cortex-M7 provides enough processing power to run the HR/HRV feature extraction and classifier locally.
The original version uses the:
π SparkFun Single Lead Heart Rate Monitor β AD8232
The AD8232 amplifies and filters the small electrical signals captured by three ECG electrodes.
The project uses:
OUTPUT β A0
LO- β D2
LO+ β D3
The LO+ and LO- outputs detect disconnected electrodes.
| AD8232 | Portenta H7 |
|---|---|
| OUTPUT | A0 |
| LO- | D2 |
| LO+ | D3 |
| GND | GND |
| 3.3 V | 3.3 V |
Electrode placement used in the original experiment:
Yellow β Left
Red β Right
Green β Below red
Complete reference:
π Wearable for Monitoring Worker Stress β Edge Impulse
Training acquisition sketch:
π acquisition.ino
The sketch defines:
#define FREQUENCY_HZ 50and streams the analog ECG value:
Serial.println(
analogRead(A0)
);only while both leads-off inputs indicate a valid electrode connection.
Serial speed:
Serial.begin(115200);The onboard LEDs also indicate electrode state.
After uploading acquisition.ino, run:
edge-impulse-data-forwarderThe expected acquisition frequency is:
50 Hz
The original workflow collected approximately:
10β20 samples per class
120 seconds per sample
10% reserved for testing
Typical classes:
working
stress
Official walkthrough:
π ECG HR/HRV Portenta Tutorial
The project uses the Edge Impulse HR/HRV Features block.
HR is the number of heartbeats per minute.
HRV describes variations between consecutive beats β the interbeat interval / RR interval.
ECG waveform
β
R peaks
β
Interbeat intervals
β
HR / HRV features
β
Machine Learning
The Edge Impulse block can produce features including:
HR Mean
HR Slope
IBI Slope
RMSSD
RMSSD Slope
AVNN
SDNN
Range NN
MAD NN
pNN50
VLF Energy
LF Energy
HF Energy
Total Energy
Relative VLF / LF / HF
LF/HF Ratio
Peak VLF / LF / HF
The configuration used by this project is intentionally compact:
Signal: ECG
Filter preset: 1
Window: 40 seconds
HRV feature group: none
The HR-derived features are then passed to the classifier.
Public project:
π Heart Rate Analysis β Edge Impulse Project #558080
Current impulse:
| Parameter | Value |
|---|---|
| Input | ECG |
| Frequency | 50 Hz |
| Window | 40,000 ms |
| Window stride | 40,000 ms |
| Classes | stress, working |
| Input features to NN | 20 |
| Validation accuracy | 89.3% |
| Test accuracy | 94.4% |
Current reported Portenta H7 performance for the float32 model:
| Metric | Value |
|---|---|
| Latency | 11 ms |
| Peak RAM | 17.7 KB |
| Flash | 14 KB |
The custom Keras architecture is compact:
20 input features
β
Dense 20 / ReLU
β
Dense 10 / ReLU
β
2-class Softmax
Training configuration used for the published model:
Training cycles: 40
Learning rate: 0.005
Batch size: 30
Auto weighting: Disabled
The resulting validation accuracy was:
89.3%
flowchart LR
ECG["β€οΈ ECG @ 50 Hz"]
HRV["HR / HRV Block"]
FEATURES["20 Features"]
NN["Dense Neural Network"]
STRESS["stress"]
WORK["working"]
ECG --> HRV
HRV --> FEATURES
FEATURES --> NN
NN --> STRESS
NN --> WORK
The repository contains the compiled Arduino library:
π heart-rate-analysis-hr-library-portenta-compiled.zip
The original Edge Impulse deployment procedure is:
- Export the model as an Arduino library.
- Unzip it locally.
- Download: edgeimpulse/example-hr-lib-arm
- Copy those support files into the deployment folder.
- Zip the complete folder again.
- Install it through:
Arduino IDE
β Sketch
β Include Library
β Add .ZIP Library
The resulting library exposes:
#include <arduino-hrv.h>Current Edge Impulse documentation notes that HR/HRV block evaluation is available broadly, while hardware deployment requires Enterprise enablement.
Main application:
π ecg2.ino
The model expects:
float features[2000];corresponding to:
40 seconds Γ 50 Hz = 2000 ECG samples
The sketch continuously fills this buffer from:
analogRead(A0);and passes it to:
run_classifier(
&features_signal,
&result,
false
);The current source uses:
float threesold = 0.85;A stress event is detected when:
result.classification[ix].value > threesoldand:
result.classification[ix].label == "stress"Therefore:
stress confidence > 85%
β
STRESS
The Portenta onboard LEDs are used as the local interface.
digitalWrite(LEDR, LOW);
digitalWrite(LEDG, HIGH);Result:
π΄ Red ON
π’ Green OFF
digitalWrite(LEDG, LOW);
digitalWrite(LEDR, HIGH);Result:
π’ Green ON
π΄ Red OFF
No external screen is required.
flowchart TD
ECG["β€οΈ Read ECG"]
LEADS{"Electrodes connected?"}
BUFFER["Store in 2000-sample buffer"]
HRV["HR / HRV Processing"]
ML["π§ Classification"]
SCORE{"stress > 0.85?"}
RED["π΄ Red LED"]
GREEN["π’ Green LED"]
ECG --> LEADS
LEADS -->|"Yes"| BUFFER
LEADS -->|"No"| ECG
BUFFER --> HRV
HRV --> ML
ML --> SCORE
SCORE -->|"Yes"| RED
SCORE -->|"No"| GREEN
RED --> ECG
GREEN --> ECG
| Component | Quantity |
|---|---|
| Arduino Portenta H7 | 1 |
| SparkFun AD8232 ECG Sensor | 1 |
| ECG electrode cable | 1 |
| Disposable electrode pads | 3 |
| Female-female jumper wires | 5 |
| USB-C cable | 1 |
Machine Learning platform:
π Edge Impulse
π Arduino IDE
From Boards Manager install:
Arduino Mbed OS Portenta Boards
Select:
Arduino Portenta H7 (M7 core)
Hardware documentation:
π Arduino Portenta H7
git clone https://github.com/ronibandini/hr-hrv.git
cd hr-hrvRepository:
π github.com/ronibandini/hr-hrv
Add:
π heart-rate-analysis-hr-library-portenta-compiled.zip
through:
Sketch
β Include Library
β Add .ZIP Library
For data collection:
π acquisition.ino
For stress inference:
π ecg2.ino
Serial Monitor:
115200 baud
Startup:
Stress detection started
Roni Bandini, Jan 2025
The repository also contains a later adaptation for an Elemyo MYO-series EMG/ECG module:
π elemyo/
Files:
The acquisition version uses:
#define CSpin 7
#define sensorInPin A1and applies notch filters around:
50 Hz
100 Hz
through the Elemyo library before forwarding ECG samples.
The adaptation was added in May 2025.
hr-hrv/
β
βββ acquisition.ino
βββ ecg2.ino
βββ heart-rate-analysis-hr-library-portenta-compiled.zip
β
βββ elemyo/
β βββ acquisition3.ino
β βββ ecg3.ino
β βββ readme.txt
β
βββ README.md
βββ LICENSE
- π
acquisition.inoβ AD8232 data forwarding - β€οΈ
ecg2.inoβ on-device stress classifier - π¦ Compiled HR library β Portenta deployment
- π§ͺ
elemyo/β alternate sensor implementation - βοΈ
LICENSEβ MIT License
Complete official tutorial for this project:
π Wearable for Monitoring Worker Stress using HR/HRV DSP Block β Arduino Portenta
Dataset, impulse, HR/HRV processing block, classifier and model testing:
π Heart Rate Analysis β Project #558080
Full list of HR and HRV time-domain and frequency-domain features:
Technical background:
π Getting the Pulse: Technical Insights Into Edge Impulse's HR and HRV Blocks
Official Portenta H7 documentation:
π Arduino Portenta H7
AD8232 ECG sensor hookup, electrode placement and example waveforms:
π AD8232 Heart Rate Monitor Hookup Guide
Support library required by the original HR/HRV Arduino deployment workflow:
π edgeimpulse/example-hr-lib-arm
TinyML worker fall detection with Arduino Nano 33 BLE Sense, Edge Impulse, BLE and Raspberry Pi.
π github.com/ronibandini/BTFall
TinyML shoulder-movement recognition using accelerometer data and Edge Impulse.
π github.com/ronibandini/rotatorCuffRecovery
Contactless heart-rate and respiration monitoring with mmWave radar, UNIHIKER and ESP32-C6.
π github.com/ronibandini/heartRespirationMonitor
Motion-pattern classification using XIAO nRF52840 Sense and Edge Impulse.
π github.com/ronibandini/XIAOnRF52840TireCare
Contracultura Maker is a book by Roni Bandini about maker culture, experimental electronics, AI, physical computing and technological autonomy.
π Contracultura Maker β GitHub repository
π Download Contracultura Maker PDF
Roni Bandini Maker Β· AI Developer Β· Writer Buenos Aires, Argentina
- π GitHub β @ronibandini
- π Medium β @ronibandini
- π X / Twitter β @RoniBandini
- πΈ Instagram β @ronibandini
βΆοΈ YouTube β @RoniBandini- πΌ LinkedIn β Roni Bandini
Built with β€οΈ + ECG + HR/HRV + Edge Machine Learning.