Composants · 20 min de lecture

Capteur de pouls Arduino : BPM avec Pulse Sensor et KY-039

Capteur de pouls Arduino : câblage du Pulse Sensor et du KY-039, BPM avec PulseSensorPlayground, onde dans le traceur série, écran OLED, code ESP32 et Pico.

Un capteur de pouls Arduino, aussi appelé capteur de fréquence cardiaque, est un petit module qui suit le flux sanguin dans le bout de ton doigt ou dans le lobe de ton oreille grâce à la lumière et mesure combien de fois ton cœur bat par minute, c'est-à-dire les BPM (battements par minute). Les deux modèles les plus répandus en électronique amateur sont le Pulse Sensor à carte ronde et le KY-039 à LED infrarouge. Les deux se branchent avec trois fils et se lisent sur une seule broche analogique, mais ils diffèrent beaucoup par la qualité du signal et par la difficulté à écrire un code fiable.

Dans ce guide, tu vas apprendre pas à pas sur quel principe physique repose un capteur de pouls, comment voir une vraie onde de pouls dans le traceur série (Serial Plotter), comment calculer les BPM avec la bibliothèque PulseSensorPlayground, comment traiter le signal faible du KY-039 avec un algorithme sans bibliothèque et comment afficher le résultat sur un écran OLED avec une icône de cœur. Tu trouveras aussi du code pour l'ESP32 et le Raspberry Pi Pico, les facteurs qui faussent la mesure et la différence avec le MAX30102. Une remarque importante dès le départ : ces capteurs ne sont pas des dispositifs médicaux et ne doivent servir à aucune décision liée à la santé.

Capteur de pouls Pulse Sensor avec câble de connexion
Module Pulse Sensor : une carte ronde d'environ 16 mm de diamètre qui réunit une LED verte, un capteur de lumière et le circuit qui amplifie le signal ; il est livré avec un câble à 3 broches.

Comment fonctionne un capteur de pouls ? La photopléthysmographie (PPG)

Tous les capteurs de pouls fonctionnent avec une méthode appelée photopléthysmographie (PPG). À chaque contraction, le cœur envoie une onde de sang dans les artères ; quand cette onde atteint les petits vaisseaux du bout du doigt, le volume de sang dans les tissus augmente brièvement. Comme l'hémoglobine du sang absorbe la lumière, plus il y a de sang, moins la lumière est renvoyée par les tissus ou les traverse. Le capteur éclaire les tissus avec une LED et un capteur de lumière mesure la lumière qui revient ; cette petite variation régulière de la quantité de lumière, c'est le pouls lui-même.

La difficulté, c'est que presque toute la lumière mesurée est constante. La peau, les muscles, les os et le sang des veines absorbent en permanence la même quantité de lumière ; c'est la composante continue (DC) du signal. La composante alternative (AC), qui varie à chaque battement, ne représente généralement que 1 à 2 % de la lumière totale. Le vrai travail du capteur consiste donc à extraire et amplifier une petite onde posée sur un niveau élevé et stable. Une onde PPG montre d'abord une montée rapide jusqu'à un pic (le pic systolique), puis une descente lente ; la petite encoche au milieu de la descente et la petite bosse juste après (l'incisure dicrote) viennent de la fermeture de la valve aortique. Un bon algorithme compte chaque battement une seule fois et ne prend pas cette encoche pour un second battement.

La façon dont la lumière est envoyée dans les tissus compte aussi. Le Pulse Sensor utilise la méthode par réflexion : la LED et le capteur de lumière sont sur la même face et mesurent la lumière rétrodiffusée par la peau. Sa lumière verte est fortement absorbée par l'hémoglobine et donne un signal net provenant des vaisseaux situés juste sous la peau ; c'est aussi pour cela que l'on voit des LED vertes au dos des montres connectées. Le KY-039 fonctionne par transmission : une LED infrarouge éclaire un côté du doigt et un phototransistor placé de l'autre côté mesure la lumière qui le traverse. La lumière infrarouge pénètre plus profondément dans les tissus, mais comme le KY-039 n'a aucun circuit d'amplification, l'onde obtenue est très petite.

CaractéristiqueValeur du Pulse Sensor
Méthode de mesurePPG par réflexion
Source lumineuseLED verte
Capteur de lumièreAPDS-9008, sensibilité maximale à 565 nm
Alimentation3–5 V
ConsommationEnviron 4 mA (sous 5 V)
SortieAnalogique ; au repos, la moitié de la tension d'alimentation (~2,5 V sous 5 V, ~512 sur l'Uno)
Diamètre de la carteEnviron 16 mm (0,625 pouce)
FilsSur l'original : rouge +, noir GND, violet signal ; les couleurs peuvent changer sur les clones

Pulse Sensor, KY-039 et MAX30102 : les différences

Capteur de battements cardiaques KY-039 (LED infrarouge et phototransistor)
KY-039 : en haut, la LED infrarouge pliée au-dessus du phototransistor ; en bas, le phototransistor. Le doigt se place entre les deux. La carte n'a pas d'amplificateur, le signal va donc directement à la broche analogique.
CaractéristiquePulse SensorKY-039MAX30102
MéthodePPG par réflexionPPG par transmission (doigt entre les deux)PPG par réflexion
LumièreLED verteLED infrarougeRouge (660 nm) + infrarouge (880 nm)
Amplificateur et filtreOui (ampli op)NonADC 18 bits intégré, suppression de la lumière ambiante
SortieAnalogiqueAnalogique (très faible)Numérique, I2C (adresse 0x57)
Alimentation3–5 V3,3–5 V3,3–5 V selon le module
Qualité du signalBonneFaible, sensible au bruitTrès bonne
SpO2 (oxygène)NonNonOui (par algorithme)
BibliothèquePulseSensor PlaygroundPas de bibliothèque prêteSparkFun MAX3010x

Si tu débutes et que tu veux seulement mesurer ton pouls, le Pulse Sensor est le choix le plus simple : comme le signal est amplifié et filtré sur la carte, tu verras une onde nette dans le traceur série dès le premier essai. L'ampli op au dos de la carte porte cette minuscule variation à un niveau que l'Arduino peut lire ; tu peux tester le calcul d'un tel gain avec l'outil Ampli op. Le KY-039 est bon marché et se trouve dans la plupart des kits de capteurs, mais sa sortie ne varie que de quelques pas de l'ADC, si bien qu'un code simple à seuil fixe ne donne pas de résultats fiables. Si tu veux aussi mesurer la saturation en oxygène du sang (SpO2), le bon choix est le MAX30102 ; nous lui consacrons une section plus bas.

Branchement du capteur de pouls : Arduino Uno, ESP32 et Pico

Broche du capteurArduino UnoESP32Raspberry Pi Pico
+ (VCC, rouge)5V3V33V3(OUT), broche 36
− (GND, noir)GNDGNDGND, broche 38
S (signal, violet)A0GPIO 34 (ADC1)GP26 (ADC0), broche 31
LED de battement (facultative)D13 (LED intégrée)GPIO 2 (LED intégrée)LED de la carte
Les entrées analogiques de l'ESP32 et de la Pico supportent au maximum 3,3 V. Comme la sortie du Pulse Sensor peut monter jusqu'à la tension d'alimentation, sur ces cartes alimente le capteur par la broche 3V3, pas par 5V ni VBUS. Sur les cartes clones, l'ordre des broches et les couleurs des fils peuvent différer ; lis toujours les marquages S, + et − de la carte avant de la brancher.

Le même tableau vaut pour le KY-039 : la broche S va à l'entrée analogique, + à l'alimentation et − à GND. Vérifie que la LED infrarouge est pliée au-dessus du phototransistor et que ton doigt passe entre les deux. Les composants au dos du Pulse Sensor sont à nu ; si un doigt ou une surface humide de sueur touche cette face, cela crée du bruit. C'est donc une bonne habitude de coller l'autocollant transparent fourni avec le kit sur la face avant et de recouvrir le dos de colle chaude. Si tu utilises une LED externe, calcule sa résistance avec l'outil Résistance de LED ; le brochage de ta carte se trouve dans l'outil Pinout.

Premier test : voir l'onde de pouls brute dans le traceur série

Avant de passer aux BPM, vérifie que le capteur voit vraiment un pouls. Le code ci-dessous n'utilise aucune bibliothèque ; il lit le signal 100 fois par seconde et l'envoie au traceur série. Téléverse le code, ouvre Outils > Traceur série dans l'Arduino IDE et règle la vitesse sur 115200 bauds. Si tu n'as jamais utilisé le traceur série, l'article Moniteur série Arduino explique comment fonctionne la fenêtre.

C++ (Arduino IDE)
1// Nabız sensörü ham sinyal testi (Seri Çizici) / Pulse sensor raw signal test (Serial Plotter)
2const int PULSE_PIN = A0;              // sensörün S (mor) kablosu / sensor S (purple) wire
3const unsigned long PERIOD_MS = 10;    // 10 ms = saniyede 100 örnek / 10 ms = 100 samples per second
4
5unsigned long lastSample = 0;
6
7void setup() {
8  Serial.begin(115200);                // Seri Çizici'de de 115200 seç / pick 115200 in the Serial Plotter too
9  lastSample = millis();
10}
11
12void loop() {
13  if (millis() - lastSample >= PERIOD_MS) {
14    lastSample += PERIOD_MS;           // sabit aralıkla örnekle / sample at a fixed interval
15    int raw = analogRead(PULSE_PIN);   // 0-1023 arası değer / value between 0 and 1023
16    Serial.print("Sinyal:");
17    Serial.print(raw);
18    Serial.println(",Orta:512");       // boştaki orta seviye çizgisi / idle midpoint line
19  }
20}

Sans doigt, la ligne du Pulse Sensor reste plate autour de 512 avec un léger tremblement ; c'est la moitié de l'alimentation, et cela montre que le capteur est bien branché. Quand tu poses légèrement le bout du doigt sur le capteur, une onde apparaît en quelques secondes : elle monte vite et redescend lentement à chaque battement, avec une amplitude généralement comprise entre 100 et 300 pas. Si tu ne vois pas l'onde, ne passe pas au code BPM : corrige d'abord le câblage, l'alimentation et la pression du doigt. Si les pics se transforment en une ligne plate collée à 0 ou à 1023, le signal est écrêté ; en général le doigt bouge ou le capteur est trop serré. Si tu te demandes d'où vient la plage 0–1023 d'une lecture analogique, consulte l'article l'ADC et la conversion analogique-numérique.

Mesurer les BPM avec PulseSensorPlayground

  1. Ouvre le gestionnaire de bibliothèques de l'Arduino IDE, cherche PulseSensor Playground et installe-la. Pour plus de détails sur l'installation des bibliothèques, vois l'article ajouter une bibliothèque Arduino.
  2. Branche le capteur comme dans le tableau : + sur 5V, − sur GND et S sur A0.
  3. Téléverse le code ci-dessous et ouvre le traceur série à 115200 bauds ; la première courbe montre le signal brut et la seconde la valeur des BPM.
  4. Pose ton doigt sur le capteur, appuie ta main sur la table et reste immobile pendant 10 secondes ; la bibliothèque stabilise sa moyenne sur les premiers battements.
  5. Si tu préfères voir les chiffres ligne par ligne dans le moniteur série, passe la constante PLOTTER du code à false ; les BPM et le temps entre deux battements (IBI) s'affichent alors à chaque battement.
C++ (Arduino IDE)
1// PulseSensor Playground ile BPM ölçme / Measuring BPM with PulseSensor Playground
2#include <PulseSensorPlayground.h>
3
4const int PULSE_PIN = A0;              // sensörün S (mor) kablosu / sensor S (purple) wire
5const int LED_PIN = LED_BUILTIN;       // her atışta yanan LED (D13) / LED lit on each beat (D13)
6const int THRESHOLD = 550;             // başlangıç eşiği, boşta ~512 / starting threshold, idle ~512
7const bool PLOTTER = true;             // true: Seri Çizici, false: Seri Monitör / true: Serial Plotter, false: Serial Monitor
8
9PulseSensorPlayground pulseSensor;     // kütüphane nesnesi / library object
10unsigned long lastPrint = 0;
11
12void setup() {
13  Serial.begin(115200);
14  pulseSensor.analogInput(PULSE_PIN);
15  pulseSensor.blinkOnPulse(LED_PIN);
16  pulseSensor.setThreshold(THRESHOLD);
17  if (!pulseSensor.begin()) {          // 2 ms'lik zamanlayıcıyı başlatır / starts the 2 ms timer
18    Serial.println(F("PulseSensor baslatilamadi / could not start"));
19    while (true) {}
20  }
21}
22
23void loop() {
24  // Atış anı: BPM ve atışlar arası süre / moment of a beat: BPM and inter-beat interval
25  if (pulseSensor.sawStartOfBeat() && !PLOTTER) {
26    Serial.print(F("BPM: "));
27    Serial.print(pulseSensor.getBeatsPerMinute());
28    Serial.print(F("  IBI: "));
29    Serial.print(pulseSensor.getInterBeatIntervalMs());
30    Serial.println(F(" ms"));
31  }
32
33  // 20 ms'de bir çizim satırı / one plotter line every 20 ms
34  if (PLOTTER && millis() - lastPrint >= 20) {
35    lastPrint = millis();
36    Serial.print(F("Sinyal:"));
37    Serial.print(pulseSensor.getLatestSample());
38    Serial.print(F(",BPM:"));
39    Serial.println(pulseSensor.getBeatsPerMinute());
40  }
41}
FonctionRôle
analogInput(pin)Choisit la broche analogique où est branché le capteur (A0 par défaut)
blinkOnPulse(pin)Allume la LED de cette broche tant que le signal dépasse le seuil, c'est-à-dire pendant chaque battement
fadeOnPulse(pin)Allume la LED d'une broche PWM à chaque battement puis l'éteint progressivement
setThreshold(valeur)Seuil de départ ; si aucun battement n'est trouvé, le seuil revient à cette valeur
begin()Lance l'échantillonnage ; renvoie true en cas de succès
sawStartOfBeat()Renvoie true si un nouveau battement a commencé depuis le dernier appel
getBeatsPerMinute()BPM calculés à partir de la moyenne des 10 derniers intervalles entre battements
getInterBeatIntervalMs()Temps entre les deux derniers battements (IBI), en millisecondes
getLatestSample()La dernière valeur brute lue (0–1023)
isInsideBeat()Renvoie true tant que le signal est au-dessus du seuil

La bibliothèque lit le capteur en arrière-plan grâce à une interruption de timer toutes les 2 ms (500 fois par seconde), si bien que l'échantillonnage reste régulier même si tu fais des tâches longues dans loop(). À chaque battement, elle enregistre le pic et le creux de l'onde et place le seuil exactement à mi-chemin entre les deux ; la valeur que tu passes à setThreshold() n'est donc qu'un point de départ. Elle ignore les montées qui arrivent moins de 250 ms après le battement précédent ou avant que les trois cinquièmes du dernier intervalle se soient écoulés, pour que l'incisure dicrote ne compte pas comme un second battement. Les BPM sont calculés à partir de la moyenne des 10 derniers intervalles entre battements ; si aucun battement n'est trouvé pendant 2,5 secondes, tout est remis à zéro et getBeatsPerMinute() renvoie 0.

Choisis le seuil de départ en regardant le signal brut : 30 à 50 pas au-dessus de la valeur la plus haute atteinte par la ligne sans doigt est un bon point de départ (entre 530 et 600 sur la plupart des capteurs). Si le seuil est trop bas, le bruit est compté comme des battements même sans doigt ; s'il est trop haut, les pouls faibles sont manqués. Autre mise en garde : sur l'Arduino Uno, la bibliothèque utilise le Timer1 pour l'échantillonnage, donc analogWrite() ne fonctionne pas sur les broches 9 et 10. Si tu ajoutes la bibliothèque Servo à ton projet, la bibliothèque passe au Timer2 ; ce sont alors le PWM des broches 3 et 11 et la fonction tone() qui sont affectés.

Pour une mesure juste : pression du doigt, lumière ambiante et mouvement

La plupart des choses qui faussent une mesure de pouls tiennent à la manière de tenir le capteur, pas au code. Essaie les points suivants un par un avec le traceur série ouvert ; voir comment chacun modifie l'onde est le moyen le plus rapide de comprendre le capteur.

  • Pression du doigt : appuie légèrement mais de façon constante. Si tu le touches trop doucement, chaque petit mouvement du doigt crée un bruit plus grand que l'onde ; si tu appuies trop fort, tu écrases les capillaires, le flux sanguin diminue et l'onde s'aplatit, voire disparaît. Les meilleurs résultats s'obtiennent en fixant le capteur autour du doigt avec une bande velcro.
  • Lumière ambiante : le soleil et les lampes s'infiltrent dans le capteur par les côtés. Sur un réseau à 50 Hz, comme en France, beaucoup de lampes scintillent 100 fois par seconde et ce scintillement se retrouve dans le signal. Couvre complètement les abords du capteur avec ton doigt ou enroule une bande sombre par-dessus.
  • Mouvement : un câble qui se balance, parler, bouger le doigt ou marcher produisent des signaux bien plus grands que le pouls. Appuie ta main sur la table et reste immobile pendant la mesure.
  • Mains froides : dans un doigt froid, les vaisseaux se resserrent et le signal faiblit. Réchauffe tes mains ou place le capteur sur le lobe de l'oreille, qui est aussi moins sensible aux mouvements.
  • Sueur et sébum : une peau humide diffuse la lumière différemment et salit la surface du capteur. Utilise l'autocollant protecteur transparent sur la face avant et essuie le capteur de temps en temps avec un chiffon sec.
  • Temps de stabilisation : pendant les 5 à 10 premières secondes après avoir posé le doigt, le signal se stabilise et la moyenne se remplit ; ne tiens pas compte des valeurs affichées pendant ce temps.
Il existe un moyen simple de savoir si ton capteur mesure correctement : compte ton pouls au poignet ou au cou pendant 30 secondes, multiplie par 2 et compare avec les BPM à l'écran. Au repos, un écart de 3 à 5 BPM est normal ; s'il est plus grand, corrige d'abord la pression du doigt et la lumière ambiante, puis ajuste le seuil.

Affichage du pouls sur un écran OLED

Le traceur série suffit sur un bureau, mais un cardiofréquencemètre portable a besoin d'un petit écran. Le code ci-dessous affiche, en haut d'un écran OLED SSD1306 de 0,96 pouce, les BPM en grands chiffres et un cœur qui grossit à chaque battement, et en bas une onde de pouls en direct qui défile de gauche à droite. Branche l'OLED sur les broches A4 (SDA) et A5 (SCL) de l'Uno et son alimentation sur 5V et GND ; l'installation de la bibliothèque de l'écran et le réglage de l'adresse sont détaillés dans l'article Utiliser un écran OLED (SSD1306).

C++ (Arduino IDE)
1// Pulse Sensor + 0,96" OLED: BPM, kalp simgesi ve nabız dalgası / BPM, heart icon and pulse wave
2#include <Wire.h>
3#include <Adafruit_GFX.h>
4#include <Adafruit_SSD1306.h>
5#include <PulseSensorPlayground.h>
6
7Adafruit_SSD1306 display(128, 64, &Wire, -1);  // 128x64, reset pini yok / no reset pin
8PulseSensorPlayground pulseSensor;
9
10const int PULSE_PIN = A0;              // sensörün S pini / sensor S pin
11const int THRESHOLD = 550;             // başlangıç eşiği / starting threshold
12const int GRAPH_TOP = 24;              // dalga alanının üst kenarı / top edge of the wave area
13const int GRAPH_H = 40;                // dalga alanının yüksekliği / height of the wave area
14
15int x = 0;                             // tarama sütunu (0-127) / sweep column (0-127)
16int lastY = GRAPH_TOP + GRAPH_H / 2;   // önceki noktanın y'si / y of the previous point
17int lo = 1023, hi = 0;                 // bu taramadaki en küçük/büyük değer / min/max in this sweep
18int scaleLo = 400, scaleHi = 624;      // çizimde kullanılan aralık / range used for drawing
19unsigned long lastDraw = 0, beatTime = 0;
20
21// İki daire ve bir üçgenle kalp çiz / draw a heart from two circles and a triangle
22void drawHeart(int cx, int cy, bool big) {
23  int r = big ? 6 : 4;                 // atış anında büyük kalp / bigger heart on a beat
24  display.fillCircle(cx - r, cy - r / 2, r, SSD1306_WHITE);
25  display.fillCircle(cx + r, cy - r / 2, r, SSD1306_WHITE);
26  display.fillTriangle(cx - 2 * r, cy, cx + 2 * r, cy, cx, cy + 2 * r, SSD1306_WHITE);
27}
28
29void setup() {
30  Serial.begin(115200);
31  if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {  // I2C adresi 0x3C / I2C address 0x3C
32    Serial.println(F("SSD1306 allocation failed"));
33    while (true) {}
34  }
35  display.clearDisplay();
36  pulseSensor.analogInput(PULSE_PIN);
37  pulseSensor.setThreshold(THRESHOLD);
38  pulseSensor.begin();                 // örnekleme kesmeyle sürer / sampling runs in an interrupt
39}
40
41void loop() {
42  if (pulseSensor.sawStartOfBeat()) beatTime = millis();  // atış anını sakla / store the beat time
43
44  if (millis() - lastDraw < 40) return; // saniyede 25 kare / 25 frames per second
45  lastDraw = millis();
46
47  // Alt bölüm: soldan sağa taranan nabız dalgası / bottom: pulse wave swept left to right
48  int s = pulseSensor.getLatestSample();
49  if (s < lo) lo = s;
50  if (s > hi) hi = s;
51  int y = map(constrain(s, scaleLo, scaleHi), scaleLo, scaleHi, GRAPH_TOP + GRAPH_H - 1, GRAPH_TOP);
52  display.drawFastVLine(x, GRAPH_TOP, GRAPH_H, SSD1306_BLACK);              // eski sütunu sil / erase the old column
53  display.drawFastVLine((x + 1) % 128, GRAPH_TOP, GRAPH_H, SSD1306_BLACK);  // önündeki boşluk / gap ahead
54  if (x > 0) display.drawLine(x - 1, lastY, x, y, SSD1306_WHITE);
55  lastY = y;
56  if (++x >= 128) {                    // tarama bitti: ölçeği yenile / sweep done: refresh the scale
57    x = 0;
58    if (hi - lo > 20) { scaleLo = lo; scaleHi = hi; }
59    lo = 1023;
60    hi = 0;
61  }
62
63  // Üst bölüm: kalp ve BPM / top: heart and BPM
64  display.fillRect(0, 0, 128, GRAPH_TOP, SSD1306_BLACK);
65  drawHeart(14, 10, millis() - beatTime < 150);
66  int bpm = pulseSensor.getBeatsPerMinute();
67  display.setTextColor(SSD1306_WHITE);
68  display.setTextSize(3);
69  display.setCursor(40, 0);
70  if (bpm > 0) display.print(bpm);
71  else display.print(F("--"));         // parmak yok / no finger
72  display.setTextSize(1);
73  display.setCursor(104, 14);
74  display.print(F("BPM"));
75  display.display();                   // tamponu ekrana gönder / push the buffer to the screen
76}

Le code rafraîchit l'écran 25 fois par seconde et ajoute un point à l'onde à chaque image, si bien que la largeur de l'écran montre environ 5 secondes d'enregistrement du pouls. À la fin de chaque balayage, l'onde est remise à l'échelle selon la valeur minimale et maximale de ce balayage, pour qu'un signal faible comme un signal fort tienne à l'écran. Envoyer une image à l'écran par I2C prend environ 25 à 30 ms, mais comme la bibliothèque échantillonne par interruption, aucun battement n'est perdu pendant ce temps. Sur l'Uno, le tampon d'image de l'écran occupe 1 Ko de RAM ; comme le code dessine l'onde directement à l'écran sans la stocker dans un tableau, la mémoire suffit, même s'il ne reste qu'environ 450 octets libres.

Mesurer le pouls avec le KY-039

Sur le KY-039, le phototransistor est monté en série avec une résistance et la tension de sortie varie selon la lumière reçue : plus de lumière donne une tension plus basse, moins de lumière une tension plus haute. Il n'y a ni amplificateur ni filtre entre les deux. Avec le doigt en place, un battement ne fait généralement varier cette tension que de 2 à 10 pas de l'ADC, soit environ 10 à 50 mV ; même un petit changement de lumière ambiante est plus grand que cela. C'est pourquoi le code écrit pour le Pulse Sensor et un seuil fixe comme 550 ne fonctionnent pas avec le KY-039 ; il faut d'abord nettoyer le signal, puis utiliser un seuil qui s'adapte à la taille de l'onde elle-même.

Le code ci-dessous le fait en quatre étapes. D'abord, il lit la broche analogique sans arrêt pendant 20 ms (environ 175 lectures) et en fait la moyenne ; cela réduit le bruit aléatoire et, comme 20 ms correspondent exactement à une période du réseau à 50 Hz, supprime presque entièrement le scintillement des lampes. Ensuite, il lisse le signal avec un léger filtre passe-bas et retire le niveau continu avec une moyenne glissante très lente, pour ne garder que l'onde de pouls. À la troisième étape, il calcule deux enveloppes qui suivent les pics et les creux de l'onde et place le seuil au milieu. Enfin, un battement est compté quand le signal franchit le seuil vers le haut, et les BPM sont tirés de la moyenne des 8 derniers intervalles.

C++ (Arduino IDE)
1// KY-039 ile nabız ölçme (kütüphanesiz) / Heart rate with the KY-039 (no library)
2const int SENSOR_PIN = A0;             // KY-039 S pini / KY-039 S pin
3const int LED_PIN = LED_BUILTIN;       // atışta yanan LED / LED lit on each beat
4const bool PLOTTER = true;             // true: Seri Çizici, false: Seri Monitör / true: Serial Plotter, false: Serial Monitor
5const unsigned long WINDOW_US = 20000; // 20 ms = 50 Hz şebekenin bir periyodu / one period of 50 Hz mains
6const float MIN_AMP = 1.2;             // tepe-tepe gürültü sınırı (ADC birimi) / peak-to-peak noise limit (ADC units)
7const int AVG_BEATS = 8;               // BPM için ortalanan aralık sayısı / intervals averaged for BPM
8
9float smooth, baseline;                // süzülmüş sinyal ve DC seviye / filtered signal and DC level
10float posEnv = 0, negEnv = 0;          // tepe ve çukur zarfları / peak and trough envelopes
11bool armed = true;                     // yeni atışa hazır mı / ready for a new beat
12unsigned long lastBeat = 0;            // son atışın zamanı / time of the last beat
13unsigned int ibi[AVG_BEATS];           // atışlar arası süreler (ms) / inter-beat intervals (ms)
14int ibiCount = 0, ibiIndex = 0, bpm = 0;
15
16// 20 ms boyunca okuyup ortalama al / read for 20 ms and average
17float readWindow() {
18  unsigned long start = micros();
19  long sum = 0;
20  int n = 0;
21  while (micros() - start < WINDOW_US) {
22    sum += analogRead(SENSOR_PIN);
23    n++;
24  }
25  return (float)sum / n;
26}
27
28float averageIbi() {
29  if (ibiCount == 0) return 500.0;     // geçmiş yoksa 120 BPM varsay (ilk bekleme 350 ms) / assume 120 BPM without history (first wait 350 ms)
30  unsigned long sum = 0;
31  for (int i = 0; i < ibiCount; i++) sum += ibi[i];
32  return (float)sum / ibiCount;
33}
34
35void addInterval(unsigned int ms) {
36  ibi[ibiIndex] = ms;                  // halka tampon / ring buffer
37  ibiIndex = (ibiIndex + 1) % AVG_BEATS;
38  if (ibiCount < AVG_BEATS) ibiCount++;
39  bpm = (int)(60000.0 / averageIbi() + 0.5);
40}
41
42void setup() {
43  Serial.begin(115200);
44  pinMode(LED_PIN, OUTPUT);
45  smooth = baseline = readWindow();    // başlangıç seviyesi / starting level
46}
47
48void loop() {
49  float x = readWindow();              // saniyede 50 örnek / 50 samples per second
50  unsigned long now = millis();
51
52  smooth += (x - smooth) * 0.5;        // hafif alçak geçiren süzgeç / light low-pass filter
53  baseline += (smooth - baseline) * 0.05;  // yavaş DC takibi (~0,4 s) / slow DC tracking (~0.4 s)
54  float ac = smooth - baseline;        // yalnız nabız dalgası / pulse wave only
55
56  // Zarflar: uçları hemen yakala, yavaşça bırak / envelopes: catch extremes fast, release slowly
57  posEnv = (ac > posEnv) ? ac : posEnv * 0.99;
58  negEnv = (ac < negEnv) ? ac : negEnv * 0.99;
59  float amp = posEnv - negEnv;         // tepe-tepe genlik / peak-to-peak amplitude
60  float mid = (posEnv + negEnv) / 2;   // eşik: dalganın ortası / threshold: middle of the wave
61
62  unsigned long sinceBeat = now - lastBeat;
63  float refractory = constrain(averageIbi() * 0.7, 250.0, 600.0);  // dikrotik çentiği atla / skip the dicrotic notch
64
65  if (armed && amp > MIN_AMP && ac > mid && sinceBeat > refractory) {
66    armed = false;                     // atış bulundu / beat found
67    digitalWrite(LED_PIN, HIGH);
68    if (sinceBeat < 2000) addInterval(sinceBeat);  // 30 BPM'den yavaşı alma / ignore gaps slower than 30 BPM
69    lastBeat = now;
70    if (!PLOTTER && bpm > 0) {
71      Serial.print(F("BPM: "));
72      Serial.println(bpm);
73    }
74  }
75  if (!armed && ac < mid - amp * 0.25) {  // dalga yeterince indi: yeniden hazır / wave fell enough: re-arm
76    armed = true;
77    digitalWrite(LED_PIN, LOW);
78  }
79  if (sinceBeat > 2500 && ibiCount > 0) {  // 2,5 s atış yok: sıfırla / no beat for 2.5 s: reset
80    ibiCount = 0;
81    bpm = 0;
82  }
83
84  if (PLOTTER) {
85    Serial.print(F("Nabiz:"));
86    Serial.print(ac);
87    Serial.print(F(",Esik:"));
88    Serial.println(mid);
89  }
90}
Constante / valeurRôle
WINDOW_US = 20000Fenêtre de moyenne ; supprime le scintillement du réseau à 50 Hz (mets 16667 dans les pays à 60 Hz)
0.5 (smooth)Léger filtre passe-bas ; adoucit les sauts brusques
0.05 (baseline)Suit le niveau continu en environ 0,4 seconde ; élimine les variations lentes de la pression du doigt
0.99 (enveloppes)Vitesse de retombée des enveloppes de pics et de creux (environ 2 secondes)
MIN_AMP = 1.2Une onde en dessous de cette amplitude crête à crête est considérée comme du bruit
refractory70 % de l'intervalle moyen actuel (250–600 ms ; 350 ms tant qu'il n'y a pas d'historique, pour ne pas rater un pouls rapide) ; empêche l'incisure dicrote de compter comme un second battement
mid - amp * 0.25Niveau de réarmement ; aucun nouveau battement n'est cherché tant que l'onde n'est pas assez redescendue

Une fois le code téléversé et le traceur série ouvert, tu vois deux courbes : Nabiz (pouls) montre l'onde nettoyée et Esik (seuil) le seuil adaptatif qui passe en son milieu. Regarde de combien la courbe Nabiz bouge sans doigt et règle MIN_AMP un peu au-dessus de cette valeur crête à crête ; baisse-le si ton signal est très faible. Pour en savoir plus sur le lissage des signaux, consulte l'article filtrer les données d'un capteur. Le même code fonctionne aussi avec le Pulse Sensor ; il suffit alors de monter MIN_AMP à environ 20.

Capteur de pouls avec l'ESP32

Sur l'ESP32, alimente le capteur par la broche 3V3 et relie le signal à GPIO 34. Cette broche fait partie du groupe ADC1 ; les broches ADC2 ne peuvent pas être lues quand le Wi-Fi est actif, donc si tu comptes envoyer les données de pouls sur Internet, tu dois choisir une broche ADC1 (GPIO 32–39). L'ADC de l'ESP32 est sur 12 bits (0–4095) et, alimenté en 3,3 V, le Pulse Sensor donne au repos une valeur d'environ 2000.

Les versions récentes de PulseSensorPlayground prennent aussi en charge l'ESP32, mais la bibliothèque utilise les fonctions de timer de la version 3.x du paquet de cartes ESP32 et ne compile pas avec la version 2.x. Dans ses exemples, elle réduit l'ADC à 10 bits avec analogReadResolution(10), si bien que le seuil s'exprime sur la même échelle 0–1023 que sur l'Uno (685 dans l'exemple ESP32). Pour ne pas dépendre des différences de version, voici ci-dessous un sketch sans bibliothèque qui reprend l'algorithme de la section KY-039 ; il fonctionne avec les deux versions du paquet de cartes.

C++ (Arduino IDE)
1// ESP32 + Pulse Sensor: kütüphanesiz BPM / BPM without a library
2const int SENSOR_PIN = 34;             // ADC1 pini, Wi-Fi açıkken de çalışır / ADC1 pin, works with Wi-Fi on
3const int LED_PIN = 2;                 // çoğu DevKit'te dahili LED / built-in LED on most DevKits
4const unsigned long PERIOD_MS = 10;    // saniyede 100 örnek / 100 samples per second
5const float MIN_AMP = 80;              // 12 bitte tepe-tepe gürültü sınırı / peak-to-peak noise limit in 12-bit units
6const int AVG_BEATS = 8;               // BPM için ortalanan aralık sayısı / intervals averaged for BPM
7
8float smooth, baseline, posEnv = 0, negEnv = 0;
9bool armed = true;
10unsigned long lastSample = 0, lastBeat = 0;
11unsigned long ibi[AVG_BEATS];
12int ibiCount = 0, ibiIndex = 0, bpm = 0;
13
14// 8 okumanın ortalaması: ESP32 ADC'si gürültülüdür / average of 8 reads: the ESP32 ADC is noisy
15float readSensor() {
16  long sum = 0;
17  for (int i = 0; i < 8; i++) sum += analogRead(SENSOR_PIN);
18  return sum / 8.0;
19}
20
21float averageIbi() {
22  if (ibiCount == 0) return 500.0;     // geçmiş yoksa 120 BPM varsay (ilk bekleme 350 ms) / assume 120 BPM without history (first wait 350 ms)
23  unsigned long sum = 0;
24  for (int i = 0; i < ibiCount; i++) sum += ibi[i];
25  return (float)sum / ibiCount;
26}
27
28void setup() {
29  Serial.begin(115200);
30  pinMode(LED_PIN, OUTPUT);
31  analogReadResolution(12);            // 0-4095 arası değer / values from 0 to 4095
32  smooth = baseline = readSensor();
33  lastSample = millis();
34}
35
36void loop() {
37  if (millis() - lastSample < PERIOD_MS) return;
38  lastSample += PERIOD_MS;             // sabit aralıkla örnekle / sample at a fixed interval
39  unsigned long now = millis();
40
41  float x = readSensor();
42  smooth += (x - smooth) * 0.3;        // alçak geçiren süzgeç (~6 Hz) / low-pass filter (~6 Hz)
43  baseline += (smooth - baseline) * 0.02;  // DC takibi (~0,5 s) / DC tracking (~0.5 s)
44  float ac = smooth - baseline;
45
46  posEnv = (ac > posEnv) ? ac : posEnv * 0.995;  // tepe zarfı / peak envelope
47  negEnv = (ac < negEnv) ? ac : negEnv * 0.995;  // çukur zarfı / trough envelope
48  float amp = posEnv - negEnv;
49  float mid = (posEnv + negEnv) / 2;
50
51  unsigned long sinceBeat = now - lastBeat;
52  float refractory = constrain(averageIbi() * 0.7, 250.0, 600.0);
53
54  if (armed && amp > MIN_AMP && ac > mid && sinceBeat > refractory) {
55    armed = false;
56    digitalWrite(LED_PIN, HIGH);
57    if (sinceBeat < 2000) {            // 30-240 BPM aralığı / 30-240 BPM range
58      ibi[ibiIndex] = sinceBeat;
59      ibiIndex = (ibiIndex + 1) % AVG_BEATS;
60      if (ibiCount < AVG_BEATS) ibiCount++;
61      bpm = (int)(60000.0 / averageIbi() + 0.5);
62      Serial.printf("BPM: %d  IBI: %lu ms\n", bpm, sinceBeat);
63    }
64    lastBeat = now;
65  }
66  if (!armed && ac < mid - amp * 0.25) {
67    armed = true;
68    digitalWrite(LED_PIN, LOW);
69  }
70  if (sinceBeat > 2500 && ibiCount > 0) {  // parmak çekildi / finger removed
71    ibiCount = 0;
72    bpm = 0;
73    Serial.println("Parmak yok / no finger");
74  }
75}

Dans ce code, le signal est lu 100 fois par seconde et, comme l'ADC de l'ESP32 est bruité, chaque échantillon est la moyenne de 8 lectures. Le seuil et les enveloppes sont réglés pour l'échelle 12 bits, d'où MIN_AMP à 80 (environ 65 mV). Le vrai point fort de l'ESP32, c'est le Wi-Fi : tu peux envoyer les BPM en direct vers une page web par WebSocket, envoyer un message Telegram quand le pouls dépasse une limite ou enregistrer tes mesures dans Google Sheets.

Mesurer le pouls avec le Raspberry Pi Pico et MicroPython

Sur le Raspberry Pi Pico, relie la broche + du capteur à 3V3(OUT) (broche 36), − à GND (broche 38) et S à GP26 (ADC0, broche 31). En MicroPython, read_u16() renvoie une valeur de 0 à 65535 ; le code la décale de 4 bits vers la droite pour la ramener à la même échelle 0–4095 que l'ESP32, si bien que les seuils restent identiques sur les deux cartes. Si tu enregistres le code sur la Pico sous le nom main.py depuis Thonny, il démarre tout seul à chaque mise sous tension.

MicroPython
1# Raspberry Pi Pico + Pulse Sensor: MicroPython ile BPM / BPM with MicroPython
2from machine import ADC, Pin
3import time
4
5sensor = ADC(26)                   # GP26 = ADC0, sensörün S pini / sensor S pin
6led = Pin("LED", Pin.OUT)          # kartın üzerindeki LED / on-board LED
7
8PERIOD_MS = 10                     # saniyede 100 örnek / 100 samples per second
9MIN_AMP = 80                       # 12 bitte tepe-tepe gürültü sınırı / peak-to-peak noise limit (12-bit)
10AVG_BEATS = 8                      # BPM için ortalanan aralık / intervals averaged for BPM
11
12def read12():
13    # 4 okumanın ortalaması, 0-4095 / average of 4 reads, 0-4095
14    s = 0
15    for _ in range(4):
16        s += sensor.read_u16() >> 4
17    return s / 4
18
19smooth = baseline = read12()
20pos_env = neg_env = 0.0
21armed = True
22ibis = []
23bpm = 0
24last_beat = time.ticks_ms()
25next_t = time.ticks_ms()
26
27while True:
28    while time.ticks_diff(time.ticks_ms(), next_t) < 0:
29        pass                       # bir sonraki örnek zamanını bekle / wait for the next sample time
30    next_t = time.ticks_add(next_t, PERIOD_MS)
31    now = time.ticks_ms()
32
33    x = read12()
34    smooth += (x - smooth) * 0.3            # alçak geçiren süzgeç / low-pass filter
35    baseline += (smooth - baseline) * 0.02  # DC takibi / DC tracking
36    ac = smooth - baseline
37
38    pos_env = ac if ac > pos_env else pos_env * 0.995
39    neg_env = ac if ac < neg_env else neg_env * 0.995
40    amp = pos_env - neg_env
41    mid = (pos_env + neg_env) / 2
42
43    since = time.ticks_diff(now, last_beat)
44    avg_ibi = sum(ibis) / len(ibis) if ibis else 500   # geçmiş yoksa 120 BPM varsay / assume 120 BPM without history
45    refractory = min(max(avg_ibi * 0.7, 250), 600)   # dikrotik çentiği atla / skip the dicrotic notch
46
47    if armed and amp > MIN_AMP and ac > mid and since > refractory:
48        armed = False
49        led.on()
50        if since < 2000:                    # 30 BPM'den yavaşı alma / ignore gaps slower than 30 BPM
51            ibis.append(since)
52            if len(ibis) > AVG_BEATS:
53                ibis.pop(0)
54            bpm = round(60000 / (sum(ibis) / len(ibis)))
55            print("BPM:", bpm, "IBI:", since)
56        last_beat = now
57    if not armed and ac < mid - amp * 0.25:
58        armed = True
59        led.off()
60    if since > 2500 and ibis:               # parmak çekildi / finger removed
61        ibis = []
62        bpm = 0
63        print("Parmak yok / no finger")

Le code suit la même logique que la version ESP32 : il prend un échantillon toutes les 10 ms, retire le niveau continu, détecte le battement avec un seuil adaptatif et calcule les BPM à partir de la moyenne des 8 derniers intervalles. À chaque battement, la LED de la carte s'allume et les BPM ainsi que l'intervalle entre battements s'affichent dans la fenêtre Shell de Thonny. Si la syntaxe Python est nouvelle pour toi, l'article les bases de MicroPython est un bon point de départ.

La différence avec le MAX30102 : mesurer l'oxygène du sang (SpO2)

Le MAX30102 est un capteur monopuce conçu par Analog Devices (anciennement Maxim Integrated) pour mesurer la fréquence cardiaque et la saturation en oxygène du sang. Il contient deux LED, rouge (660 nm) et infrarouge (880 nm), une photodiode, un circuit de suppression de la lumière ambiante et un ADC 18 bits. Il effectue la mesure lui-même, stocke les échantillons dans une mémoire de 32 valeurs (FIFO) et les envoie sous forme de nombres sur le bus I2C (adresse 0x57). Comme le bruit capté par les fils analogiques et la limite de l'ADC 10 bits de l'Arduino disparaissent, son signal est bien plus propre que celui du Pulse Sensor.

Le secret de la mesure de la SpO2, c'est d'utiliser de la lumière de deux couleurs différentes. L'hémoglobine chargée d'oxygène absorbe davantage la lumière infrarouge et moins la rouge ; l'hémoglobine qui a libéré son oxygène fait l'inverse. Le capteur mesure les composantes alternative et continue de l'onde de pouls pour les deux lumières et calcule le rapport R = (AC_rouge / DC_rouge) / (AC_infrarouge / DC_infrarouge) ; la SpO2 s'en déduit grâce à une courbe d'étalonnage empirique. Le Pulse Sensor et le KY-039 n'utilisent qu'une seule couleur de lumière : ils ne peuvent pas calculer ce rapport, donc pas mesurer l'oxygène. La bibliothèque Arduino la plus utilisée pour le MAX30102 est SparkFun MAX3010x ; son exemple Example5_HeartRate calcule la fréquence cardiaque et Example8_SPO2 la saturation en oxygène.

Sur certaines cartes MAX30102 bon marché, les résistances de tirage (pull-up) de l'I2C sont reliées à 1,8 V ; un Arduino Uno en 5 V ne reconnaît pas ce niveau comme HIGH et le capteur n'est pas détecté. Si ta carte possède un pont de soudure pour choisir entre 1,8 V et 3,3 V, place-le du côté 3,3 V. Ces modules sont eux aussi très sensibles à la pression du doigt et aux mouvements.

Un capteur de pouls n'est pas un dispositif médical

Les montages et le code de cet article sont destinés à l'apprentissage et au loisir. Les modules Pulse Sensor, KY-039 et MAX30102 n'ont pas été testés ni homologués comme dispositifs médicaux ; ne pose aucun diagnostic et ne prends aucune décision de médicament ou de traitement à partir de leurs valeurs. Si tu ressens une douleur thoracique, des palpitations, des vertiges, un malaise ou un essoufflement, ne te fie pas à un capteur : consulte immédiatement un professionnel de santé et, en cas d'urgence, appelle le 15 ou le 112.

Il y a des raisons concrètes à cela. Les oxymètres de pouls et cardiofréquencemètres médicaux sont étalonnés selon des limites de précision définies et testés sur différentes couleurs de peau, avec un faible débit sanguin et en mouvement ; les modules amateurs et les algorithmes que nous écrivons ne passent pas ces tests. De plus, mesurer le pouls n'est pas la même chose qu'évaluer le rythme cardiaque : pour comprendre les troubles du rythme, il faut un ECG, qui enregistre le signal électrique du cœur. À titre d'information générale, la fréquence cardiaque au repos d'un adulte se situe le plus souvent entre 60 et 100 battements par minute ; chez les personnes qui font régulièrement du sport, elle peut descendre à 40–60. Si ta mesure sort de cette plage, vérifie d'abord le capteur et le code ; si tu restes inquiet, parles-en à un médecin.

Idées de projets avec un capteur de pouls

  • Lumière qui bat au rythme du cœur : à chaque battement, allume en rouge un anneau de LED WS2812B et éteins-le progressivement ; fais passer la couleur du bleu au rouge quand les BPM augmentent.
  • Cardiofréquencemètre qui bipe : joue un bip court sur un buzzer chaque fois que sawStartOfBeat() renvoie true ; un projet amusant qui imite le son des moniteurs d'hôpital.
  • Cardiofréquencemètre portable : place le code OLED dans un boîtier avec une batterie et un circuit de charge ; éteins l'écran à la fin de la mesure pour prolonger l'autonomie.
  • Test de récupération après l'effort : mesure juste à la fin de ton entraînement et calcule de combien de battements ton pouls baisse pendant la première minute ; note la valeur chaque jour et suis tes progrès.
  • Enregistreur de pouls : écris les BPM avec l'heure sur une carte SD ou envoie-les vers Excel pour en tracer le graphique.
  • Jeu de respiration : montre à l'écran comment ton pouls change quand tu respires lentement et profondément ; tu gagnes quand tu fais descendre ton pouls sous une valeur cible.

Erreurs fréquentes et solutions

SymptômeCause probableSolution
BPM toujours à 0 ou "--"Aucun battement détecté : seuil trop haut, pas de doigt ou broche S sur la mauvaise entréeVérifie l'onde avec le sketch du signal brut ; place le seuil au milieu de l'onde
BPM très élevés, vers 150–220Le bruit ou l'incisure dicrote est compté comme un second battementMonte le seuil, stabilise le doigt, bloque la lumière ambiante
Des BPM s'affichent même sans doigtSeuil sous le bruit au repos ; le scintillement des lampes entre dans le signalPlace le seuil 30 à 50 pas au-dessus de la valeur maximale au repos, couvre le capteur
Signal plat bloqué à 0 ou à 1023+ et − inversés, fil coupé, broche S mal branchée ou capteur défectueuxVérifie le câblage avec le tableau ; utilise 3V3 sur l'ESP32 et la Pico
Il y a une onde, mais elle se déforme sans cesseLe doigt bouge ou la pression changeFixe le capteur avec une bande velcro, appuie ta main sur la table et ne bouge plus
Aucune onde avec le KY-039LED non pliée au-dessus du phototransistor ou forte lumière ambiante qui sature le phototransistorPlie la LED pour qu'elle soit au-dessus du doigt, utilise le capteur à l'ombre, baisse MIN_AMP
"too few arguments to function 'hw_timer_t* timerBegin(uint8_t, uint16_t, bool)'" sur l'ESP32PulseSensorPlayground est compilée avec la version 2.x du paquet de cartes ESP32Mets à jour le paquet de cartes en 3.x ou utilise le code ESP32 sans bibliothèque de cet article
analogWrite() ne fonctionne pas sur la broche 9 ou 10La bibliothèque utilise le Timer1 sur l'UnoUtilise les broches 3, 5, 6 ou 11 pour le PWM
Pour chercher une panne, commence toujours par le code le plus simple : si le test du signal brut montre une onde propre, le matériel va bien et le problème vient du seuil ou du code ; s'il n'y a pas d'onde, changer le code ne servira à rien, corrige donc d'abord le câblage et le contact du capteur avec le doigt.

Le capteur de pouls fait partie de ces rares projets qui, avec une seule broche analogique, t'apprennent à la fois la lecture analogique, le filtrage du signal, les interruptions de timer et le tracé en temps réel, et dont tu vois le résultat sur ton propre corps. Si tu cherches un projet d'initiation qui mesure lui aussi la lumière, la photorésistance LDR est une bonne étape suivante. Dans l'application BlueGrays, tu trouveras des projets qui utilisent les composants de cet article, comme la lecture de l'intensité lumineuse avec une LDR, le buzzer, des projets ESP32 avec écran OLED et un effet de respiration PWM sur la Pico, avec schémas de câblage et code pas à pas.

Questions fréquentes

Quelle est la précision d'un capteur de pouls Arduino ?

Bien tenu et avec une personne immobile, un Pulse Sensor mesure en général le pouls au repos à quelques BPM près. Le mouvement, la lumière ambiante, les mains froides et la pression du doigt augmentent vite l'erreur. Le signal du KY-039 est beaucoup plus faible, ses valeurs varient donc davantage ; aucun de ces capteurs ne convient à une mesure médicale.

Quelle différence entre le Pulse Sensor et le KY-039 ?

Le Pulse Sensor utilise une LED verte et la méthode par réflexion, amplifie et filtre le signal avec un ampli op sur la carte et se place au repos à la moitié de l'alimentation. Le KY-039 mesure la lumière infrarouge qui traverse le doigt, n'a pas d'amplificateur et sa sortie ne varie que de quelques pas de l'ADC. C'est pourquoi le Pulse Sensor fonctionne facilement avec une bibliothèque toute prête, alors que le KY-039 demande un filtrage et un seuil adaptatif.

Peut-on mesurer l'oxygène du sang (SpO2) avec un capteur de pouls ?

Pas avec le Pulse Sensor ni le KY-039, car le calcul de la SpO2 repose sur la comparaison de deux longueurs d'onde, le rouge et l'infrarouge. Il faut pour cela un capteur à deux LED comme le MAX30102. Même la valeur du MAX30102 reste une estimation non étalonnée qui ne remplace pas un oxymètre médical.

Pourquoi mon capteur de pouls affiche-t-il des valeurs très élevées ou instables ?

La cause la plus fréquente est que le bruit ou l'incisure dicrote de l'onde de pouls est compté comme un second battement ; les BPM sortent alors à environ deux fois la valeur réelle. Monte le seuil, fixe ton doigt avec une bande velcro et protège le capteur de la lumière. Regarder l'onde brute dans le traceur série montre tout de suite l'origine du problème.

Le Pulse Sensor fonctionne-t-il avec l'ESP32 et le Raspberry Pi Pico ?

Oui, mais sur les deux cartes tu dois alimenter le capteur par la broche 3V3, car leurs entrées analogiques ne supportent pas plus de 3,3 V. Sur l'ESP32, utilise une broche ADC1 comme GPIO 34 pour éviter tout conflit avec le Wi-Fi ; sur la Pico, GP26, GP27 ou GP28. PulseSensorPlayground exige la version 3.x du paquet de cartes ESP32 ; en MicroPython, tu écris ton propre algorithme comme dans cet article.

Quelle est la fréquence cardiaque normale ?

Chez l'adulte au repos, le pouls se situe le plus souvent entre 60 et 100 battements par minute ; chez les sportifs réguliers, il peut être de 40–60, et il est plus élevé chez l'enfant. Le pouls augmente naturellement avec l'effort, le stress, la caféine et la fièvre. Ce sont des informations générales ; parle de tes mesures ou de tes symptômes à un médecin.

Voir tous les projets
Mesurer l'intensité lumineuse avec une LDR
#11Débutant

Mesurer l'intensité lumineuse avec une LDR

Envie de voir en chiffres à quel point ta chambre est lumineuse ? Le LDR, une petite pièce sensible à la lumière, mesure la lumière ambiante, et l'Arduino écrit la valeur sur l'écran de ton ordinateur

4.6(81)
139
Mesure de l'intensité lumineuse avec le module LDR ESP32
#113Débutant

Mesure de l'intensité lumineuse avec le module LDR ESP32

Suivi en temps réel sur le moniteur série de la valeur brute de l'ADC du module LDR et du pourcentage relatif de luminosité calculé à partir de références dans l'obscurité et à la lumière. Ce pourcentage n'est pas une mesure en lux. Permet de comprendre le principe de calibrage du module. Il est préférable de réaliser cet exercice avant le projet 10, car il sert à déterminer la valeur seuil.

4.6(36)
55
Utilisation du buzzer
#13Débutant

Utilisation du buzzer

Tu t'es déjà demandé comment une sonnette ou une alarme produit son son ? L'Arduino fait biper un petit buzzer à intervalles courts : bip, silence, bip, silence. Tu vois comment l'électricité devient

4.7(89)
161
Température et humidité avec DHT11
#55Intermédiaire

Température et humidité avec DHT11

Quelle température fait-il dans ta chambre, et l'air est-il humide ou sec ? Le capteur DHT11 mesure la température et l'humidité, et l'Arduino affiche les valeurs sur un écran LCD à deux lignes, mises

4.7(47)
73
Voltmètre numérique avec écran LCD
#56Intermédiaire
Premium

Voltmètre numérique avec écran LCD

Découvre quelle tension fournit une pile ou un adaptateur avec un appareil de mesure fait maison. Un diviseur de deux résistances abaisse la tension élevée à un niveau que la carte peut lire, et l'Ard

4.5(27)
36
ESP32 HTTPClient + API météo (avec écran OLED SSD1306)
#134Avancé
Premium

ESP32 HTTPClient + API météo (avec écran OLED SSD1306)

Dans ce projet, nous effectuons un appel à l'API REST de la météo (wttr.in) via Internet à l'aide de l'ESP32 et de la bibliothèque HTTPClient.h. Contrairement à la version précédente avec écran LCD I2C, nous utilisons ici un écran OLED SSD1306 (128×64) — ce qui permet d’afficher une police de grande taille, des icônes vectorielles et une présentation visuelle riche sur un seul écran. Sept icônes vectorielles différentes représentant les conditions météorologiques (ensoleillé, partiellement nua

4.3(10)
19
Mode veille profonde de l'ESP32 — Économie de batterie (OLED + compteur RAM RTC)
#135Avancé
Premium

Mode veille profonde de l'ESP32 — Économie de batterie (OLED + compteur RAM RTC)

Le mode « Deep Sleep » de l'ESP32 réduit la consommation de courant à environ 10 µA en désactivant le processeur et la plupart des périphériques, ce qui revêt une importance cruciale pour les appareils IoT fonctionnant sur batterie. Dans ce projet, nous utilisons trois sources de réveil différentes : une minuterie (timer, 15 s), une broche externe (EXT0 — bouton GPIO 33) et un capteur tactile (T0/GPIO 4). Les variables marquées avec RTC_DATA_ATTR sont conservées pendant le mode Deep Sleep — le

4.3(10)
16
Raspberry Pi Pico PWM LED Fade (Effet Respiration)
#160Débutant

Raspberry Pi Pico PWM LED Fade (Effet Respiration)

La LED ne clignote plus — elle respire ! Grâce au PWM (modulation de largeur d'impulsion) du Raspberry Pi Pico, la luminosité monte puis descend lentement. Apprends la classe machine.PWM, duty_u16() (luminosité 16 bits 0–65535), la fréquence PWM, les boucles range() et la sortie quasi analogique. Base du mélange de couleurs RGB, du contrôle moteur, des servos et du buzzer.

0.0(0)
4