Real-time hartslag LED-visualisator aangedreven door ECG
Onderdelen en benodigdheden
| Onderdeel | Aantal |
|---|---|
| uECG-apparaat | 1 |
| Arduino Nano R3 | 1 |
| Adafruit NeoPixel Ring: WS2812 5050 RGB LED | 1 |
| Li-Ion accu 1000 mAh | 1 |
Benodigde tools
- Solderbout
Over dit project
Jarenlang wilde ik een LED-project maken dat knippert op mijn hartslag – niet alleen stilstaand, maar ook tijdens beweging. Dat bleek verrassend lastig; ik probeerde en faalde jarenlang. Maar niet meer!
Alle zware berekeningen worden gedaan door de uECG – een kleine, open-source draagbare ECG met een Arduino-vriendelijke output-pin (hoog/laag per hartslag). Deze digitale signaalverwerking is veel simpeler dan ruwe ECG-signaalverwerking.
Update: bekijk ook de 2e iteratie die data via radiolink ontvangt.
1. Schema
Alleen digitale signalen → simpel. Voor draagbaarheid: soldeer verbindingen voor betrouwbaarheid.
- DI-pin LED-ring → pin D11 (instelbaar in code)
- DRV-pin uECG → pin D3 (instelbaar)
- Accu + → Arduino 5V en LED-ring 5V
- Accu - → Arduino GND, ring GND, uECG GND
Belangrijk: LiPo direct op 5V-pin (niet Vin!). De spanningsregelaar op Vin introduceert spanningsval; Arduino is stabiel tot 3,4V. Een volle LiPo is 4,2V, 3,4V bereikt pas bij <15% lading. Met >200 mAh heb je redelijke looptijd. Gebruik een connector voor opladen.
2. Code
Programma leest continu pin D3. Bij flank (1→0) wordt tijdstip opgeslagen in 20-elementen array. Gemiddelde tijd per slag = (laatste - eerste) / 20. BPM = 60.000 / gemiddelde tijd.
Array-grootte instelbaar: kleiner = snellere reactie, minder stabiel; groter = stabieler, langzamere reactie.
BPM wordt gemapt op kleur (blauw → groen → geel → roze → rood bij stijgende BPM) en aantal actieve LEDs (bij 80 BPM = 8 LEDs, 110 BPM = 11 LEDs). Schaal instelbaar.
Tijdens een hartslag (pin laag) = volle helderheid; ertussenin = 25% helderheid → duidelijke pulskiezen.
3. Montage als wearables
Arduino past perfect in de NeoPixel-ring. Accu ernaast. uECG op borst → draad met connectoren. Eerst uECG plaatsen, dan shirt met overige componenten, dan connector koppelen. Anders ongemakkelijk.
4. Veldtest
Getest tijdens lopen en rennen. Tijdens rennen: accu botst op ECG-sensor → vervorming. Draad te kort → trekt sensor bij elke stap. Betrouwbare meting alleen bij lopen/staan. Sensor zelf werkt wel tijdens rennen (gecheckt via app).
LEDs op borst zijn praktisch onbruikbaar (moeilijk af te lezen). Volgende iteratie: polsbandje voor feedback.
Meer over uECG: Hackaday-pagina (PCB-ontwerpen, discussie, logs).
Code
uECG_pixel_ring.ino (Arduino)
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
#include <avr/power.h>
#endif
#define PIN 11 // DI-pin LED-ring
#define NUMPIXELS 16 // Aantal pixels
int in_pin = 3; // Input-pin uECG
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#define BEAT_HIST 20
long beats[BEAT_HIST];
void push_beat(long ms) {
for (int x = 0; x < BEAT_HIST - 1; x++) beats[x] = beats[x + 1];
beats[BEAT_HIST - 1] = ms;
}
int get_bpm() {
long dt = beats[BEAT_HIST - 1] - beats[0];
return BEAT_HIST * 60000 / dt;
}
long last_pix_upd = 0;
int prev_in_state = 0;
void setup() {
pixels.begin();
pinMode(in_pin, INPUT);
digitalWrite(in_pin, 1); // Pull-up inschakelen (kritiek: uECG heeft geen interne pull-up)
}
void loop() {
long ms = millis();
int in_state = digitalRead(in_pin); // 1 = geen slag, 0 = slag
if (in_state == 1 && prev_in_state == 0) push_beat(ms);
prev_in_state = in_state;
if (ms - last_pix_upd > 10) {
last_pix_upd = ms;
int bpm = get_bpm();
int max_bright = 120;
float dd = 20;
float t1 = 90, t2 = t1 + dd, t3 = t2 + dd, t4 = t3 + dd;
int r, g, b;
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; }
if (in_state) { r *= 0.25; g *= 0.25; b *= 0.25; } // Tussen slagen: dimmen
int on_pixels = (bpm + 5) / 10;
for (int i = 0; i < NUMPIXELS; i++) {
if (i < on_pixels) pixels.setPixelColor(i, pixels.Color(r, g, b));
else pixels.setPixelColor(i, pixels.Color(0, 0, 0));
}
pixels.show();
}
}
Schema
Schema-afbeelding is bijgeleverd.
Productieproces
- Externe Defibrillator: Geschiedenis, Ontwerp en Productie
- De Deegroller: Van Etrusken tot Moderne Vakmanschap
- Kunstmatig Hart: Technologie, Geschiedenis en Toekomstperspectieven
- Kunstmatige Hartkleppen: Typen, Geschiedenis en Toekomstige Innovaties
- De Evolutie en Vakmanschap van Moderne Bowlingpinnen
- Een LED Besturen met een PIR-bewegingssensor op Raspberry Pi
- Je huis temperatuur monitoren met een Raspberry Pi-dashboard
- Remote Hartslagmonitoringssysteem met AWS IoT-waarschuwingen
- Kogelgewricht (Knuckle Joint) uitgelegd: Ontwerp, toepassingen en kernkenmerken
- Contactloze hartslagmonitoring via slimme speakers: Een revolutionair systeem
- Grafene-gebaseerd elektronisch tatoe biedt continue, nauwkeurige hartsmonitoring voor lange periodes