Draadloze ECG-hartslagmonitor: weerebaar ontwerp met Arduino Nano & nRF24
Onderdelen en benodigdheden
| Onderdeel | Aantal | Opmerking |
|---|---|---|
| uECG-apparaat | 1 | Voor daadwerkelijke BPM-meting. Stuurt data via nRF24-compatibel protocol |
| Arduino Nano R3 | 1 | |
| nRF24-module (generiek) | 1 | Elke module werkt. Ontvangt BPM-data van uECG |
| Adafruit NeoPixel-ring: WS2812 5050 RGB LED (16 LEDs) | 1 | |
| LiPo-accu (200+ mAh) | 1 |
Benodigde tools en machines
- Solderbout (standaard)
Over dit project
Dit is de tweede iteratie van mijn hartslagmonitorproject. De vorige toonde hartslagen op de borst en was via draad verbonden met de uECG. Dat ziet er cool uit, maar is niet praktisch: je ziet niet goed hoeveel LEDs branden, het zit buiten je zichtveld, en de draad veroorzaakt problemen voor de sensor tijdens het rennen.
Deze versie lost alle problemen op: hij zit op de pols, dus je kunt ernaar kijken terwijl je op de weg let, en hij is draadloos, dus geen verstoring van de metingen. Het werkt echt tijdens het rennen en laat je de hartslagbelasting volgen.

1. Onderdelen
Hetzelfde als in het vorige project: al het zware werk wordt gedaan door de uECG – hij meet data en berekent BPM onboard. In "direct link mode" stuurt hij alle informatie (inclusief hoog-resolutie ECG-data, die we hier niet gebruiken) via een radioprotocoll compatibel met generieke nRF24-chips. De tweede cruciale component is dus de nRF24-module. De Arduino Nano heeft de juiste grootte om onder een kleine LED-ring te passen, dus ik gebruik hem als controller (maar eender wat zou werken).
2. Schema
De nRF24-module aansturen is niet simpel: je moet alle SPI-draden (MISO, MOSI, SCK, CS), chip enable, en voeding aansluiten. Voor een compacte vorm moeten alle pinheaders verwijderd worden en draden direct op de pads gesoldeerd worden. Alleen de nRF24 kost al 7 draden, 14 solderpunten. Het goede nieuws: de rest is simpel: LED-ring vereist 1 data-draad en 2 voedingsdraden, en 2 voedingsdraden voor de accu-connector.

Aansluitlijst:
- nRF24 pin 1 (GND) → Arduino GND
- nRF24 pin 2 (Vcc) → Arduino 3.3V
- nRF24 pin 3 (Chip Enable) → Arduino D9
- nRF24 pin 4 (SPI:CS) → Arduino D8
- nRF24 pin 5 (SPI:SCK) → Arduino D13
- nRF24 pin 6 (SPI:MOSI) → Arduino D11
- nRF24 pin 7 (SPI:MISO) → Arduino D12
- LED-ring Power → Arduino 5V
- LED-ring GND → Arduino GND
- LED-ring DI → Arduino D5
- Accu plus (rood) → Arduino 5V
- Accu min (zwart) → Arduino GND
- (Let op: accu vereist connector voor opladen)
Belangrijk: MOSI, MISO, SCK mogen niet op andere Arduino-pinnen aangesloten worden. SPI-hardware zit op D11, D12, D13 en werkt niet op andere pinnen. Alle andere pinnen kunnen gewijzigd worden (met bijbehorende code-aanpassingen).
3. Programma
Het enge ingewikkelde aan de software is de RF-kanaalconfiguratie. Ik besteedde veel tijd eraan voordat ik ontdekte dat uECG en nRF24 een andere bitvolgorde voor het pipe-adres gebruiken. Toen ik dat had opgelost, werkte alles direct :). Basis: we lezen binnenkomende pakketten, gebruiken de 5e byte als BPM, en filteren (RF-kanaal is ruisgevoelig, dus ab en toe krijg je een willekeurige waarde in plaats van de juiste meting, en hardware CRC is uitgeschakeld voor compatibiliteit). Vervolgens wordt BPM omgezet in kleur en aantal actieve pixels.
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#include <SPI.h>
#include <RF24.h>
#include <RF24_config.h>
#include <nRF24L01.h>
int rf_cen = 9; // nRF24 chip enable pin
int rf_cs = 8; // nRF24 CS pin
RF24 rf(rf_cen, rf_cs);
// Pipe-adres - hardcoded op uECG-zijde
uint8_t pipe_rx[8] = {0x0E, 0xE6, 0x0D, 0xA7, 0, 0, 0, 0};
#define PIN 5 // Arduino-pin verbonden met NeoPixels
#define NUMPIXELS 16 // Aantal NeoPixels
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
uint8_t swapbits(uint8_t a) { // uECG pipe-adres gebruikt omgekeerde bitvolgorde
uint8_t v = 0;
if(a & 0x80) v |= 0x01;
if(a & 0x40) v |= 0x02;
if(a & 0x20) v |= 0x04;
if(a & 0x10) v |= 0x08;
if(a & 0x08) v |= 0x10;
if(a & 0x04) v |= 0x20;
if(a & 0x02) v |= 0x40;
if(a & 0x01) v |= 0x80;
return v;
}
void setup() {
pixels.begin();
for(int i=0; i 0)
rf_bpm = bb;
}
long ms = millis();
if(ms - last_pix_upd > 10) { // Update pixels niet te vaak
int r, g, b;
last_pix_upd = ms;
int bpm = rf_bpm;
int max_bright = 160; // Max helderheid (max 255)
float dd = 25; // BPM-verandering per kleurtoon (blauw→groen→geel→roze→rood)
float t1 = 90, t2, t3, t4; // t1 = "basis" BPM, lager = blauw
t2 = t1 + dd;
t3 = t2 + dd;
t4 = t3 + dd;
// Kleur berekenen op basis van BPM-bereik
if(bpm < t1) { r = 0; g = 0; b = max_bright; }
else if(bpm < t2) { r = 0; g = max_bright * (bpm-t1)/dd; b = max_bright - g; }
else if(bpm < t3) { r = max_bright * (bpm-t2)/dd; g = max_bright - r; b = r/4; }
else if(bpm < t4) { r = max_bright; g = 0; b = max_bright/2 - max_bright * (bpm-t3)/(2*dd); }
else { r = max_bright; g = 0; b = 0; }
int on_pixels = (bpm-80)/8; // Voer niets onder 80 BPM (voor lopen), gevoeliger in hoge belasting
for(int i=0; i
4. Polsband monteren
Als alle draden gesoldeerd zijn, de code geüpload, en je bevestigd hebt dat uECG-data ontvangen wordt, is het tijd om alles te monteren.


Ik koos een simpele manier: warmteplak. Omdat de onderdelen al bijna passen (Nano past in de outer ring, nRF24 in de inner ring, accu past ergens ertussen) plakte ik alles vast. Vervolgens naaide ik het aan een willekeurige polsband (overgebleven van soldeerstation, een band voor aarding tijdens solderen). En klaar!

5. Testen
Voor de test ging ik rennen, en het werkte prima – behalve één verrassing. Ik had ingesteld dat bij 192 BPM alle LEDs aan gingen, omdat die hartslag te hoog is voor mijn parameters. De verrassing: ik overschreed dit in enkele minuten rennen, zonder het door te hebben. Ik dacht aan sensorfout, maar toen ik stopte, daalde het niet direct, maar rustte langzaam af (sensor is 100% betrouwbaar zonder veel beweging). Dus ik train een tijdje boven mijn gezonde drempel (volgens standaarden voor mijn leeftijd/gewicht).
Interessant: ik doe al van kind af aan sport, maar had hartenproblemen in mijn pubertijd die leken overgegaan. Ik wist uit ervaring dat elke belasting sneller dan wandelen heel zwaar was, toch bleef ik trainen – en dat verhoogde mijn limiet tot nu, waar ik mezelf redelijk fit vind. Vraag: is mijn BPM hoger door die jeugdproblemen, of train ik te zwaar zonder het te merken? Ik moet er iets aan doen: of de max BPM op de monitor verhogen, of minder intens trainen. :)
P.S. Verrassend genoeg werkte uECG ook goed als EMG-sensor – lees erover in mijn Robotic Hand Control-project.
Code
bpm_watch.ino (Arduino)
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#include <SPI.h>
#include <RF24.h>
#include <RF24_config.h>
#include <nRF24L01.h>
int rf_cen = 9;
int rf_cs = 8;
RF24 rf(rf_cen, rf_cs);
uint8_t pipe_rx[8] = {0x0E, 0xE6, 0x0D, 0xA7, 0, 0, 0, 0};
#define PIN 5
#define NUMPIXELS 16
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
uint8_t swapbits(uint8_t a) {
uint8_t v = 0;
if(a & 0x80) v |= 0x01;
if(a & 0x40) v |= 0x02;
if(a & 0x20) v |= 0x04;
if(a & 0x10) v |= 0x08;
if(a & 0x08) v |= 0x10;
if(a & 0x04) v |= 0x20;
if(a & 0x02) v |= 0x40;
if(a & 0x01) v |= 0x80;
return v;
}
void setup() {
pixels.begin();
for(int i=0; i 0)
rf_bpm = bb;
}
long ms = millis();
if(ms - last_pix_upd > 10) {
int r, g, b;
last_pix_upd = ms;
int bpm = rf_bpm;
int max_bright = 160;
float dd = 25;
float t1 = 90, t2, t3, t4;
t2 = t1 + dd;
t3 = t2 + dd;
t4 = t3 + dd;
if(bpm < t1) { r = 0; g = 0; b = max_bright; }
else if(bpm < t2) { r = 0; g = max_bright * (bpm-t1)/dd; b = max_bright - g; }
else if(bpm < t3) { r = max_bright * (bpm-t2)/dd; g = max_bright - r; b = r/4; }
else if(bpm < t4) { r = max_bright; g = 0; b = max_bright/2 - max_bright * (bpm-t3)/(2*dd); }
else { r = max_bright; g = 0; b = 0; }
int on_pixels = (bpm-80)/8;
for(int i=0; i
Schema's
Geen document beschikbaar.
nrf24_led_ring_o2Gij5oigT.fzz
Productieproces
- Bouw Een Raspberry Pi Luchtkwaliteit & Weerstation Met InfluxDB & Grafana
- Een externe temperatuursensor bouwen met Raspberry Pi en Python – Stap-voor-stap handleiding
- Je huis temperatuur monitoren met een Raspberry Pi-dashboard
- Remote Hartslagmonitoringssysteem met AWS IoT-waarschuwingen
- Bouw een indrukwekkend monitor Ambilight-systeem met Arduino
- Een slimme voltmeter bouwen met Arduino en smartphone – Eenvoudig DIY-project
- Real-time IoT hartslagmonitor met Arduino en MAX30100
- Bouw een nauwkeurige hartslagmonitor met een fotoweerstand en Arduino
- CNC-bewerking: precisiefabricatie van materialen en componenten
- Renesas & Altran lanceren eerste low-rate-pulse UWB polsband voor sociale distancing
- Geïntegreerde hartslagsensoren in slimme kleding: betrouwbare draagbare monitoring