ESP32: Heart Rate Sensor

Introduction

In this tutorial we are going to learn how to use the ESP32 to interact with a heart rate sensor, using the Arduino core.

We will be using this sensor module, which has a simple 3 wire interface that makes the connection to a microcontroller very easy.

The tests shown in the sections below were performed on a ESP32-E FireBeetle board from DFRobot. The Arduino core version used was 2.0.0 and the Arduino IDE version was 1.8.15, working on Windows 8.1. 

The sensor

Like already mentioned, we are going to use this sensor module from DFRobot. It has a 3 wire terminal that makes the whole electric wiring very simple, as we will see in the section below.

This module is based on a SON1303 integrated circuit and it can operate on a voltage supply range from 3.3v to 6v [1]. Since we are going to attach it to the ESP32, we want to have it operating on 3.3V.

The operating principle of the sensor is based on the PPG technique [1]. To be more precise, Photoplethysmography (PPG) is a simple and inexpensive optical measurement method that is often used for heart rate monitoring purposes. PPG is a non-invasive technology that uses a light source and a photodetector at the surface of skin to measure the volumetric variations of blood circulation [2].

IMPORTANT: This sensor is not designed for medical purposes and thus it should not be used to diagnose or treat medical conditions [1].

The actual module is shown below in figures 1 and 2. Figure 1 shows the bottom of the sensor, which has the LED and the photodetector. This bottom part is the one that should be in contact with the skin. Note also the band that comes with the module and that we can use to easily attach it to the wrist or finger. For some images with examples on how to attach the sensor to a finger or wrist, please check the product Wiki.

Bottom of the Heart Rate sensor module.
Figure 1 – Bottom of the Heart Rate sensor module.

Figure 2 illustrates the top of the module. We can can clearly see the terminal for the 3 wires, which is easy to attach and detach. We can also see a switch that allows to change the sensor to operate in digital or analog mode. Note also how the band is wrapped around the sensor, to facilitate stabilizing it. Nonetheless, the band can easily be adjusted or removed.

Top of the Heart Rate sensor module.
Figure 2 – Top of the Heart Rate sensor module.

The electric diagram

The connection between the sensor and the ESP32 is quite simple, given the already mentioned 3 wire interface. Basically, it has 1 pin for VCC, one for GND and another for the signal.

We will power the sensor with 3.3V and connect its GND pin to a common GND with the ESP32. Additionally, we will connect the sensor signal pin to a pin of the ESP32 that has support for analog readings. In my case, I’ll be using pin 25.

The complete wiring diagram is shown below on figure 3.

Electric diagram between the sensor and the ESP32.
Figure 3 – Electric diagram between the sensor and the ESP32.

To confirm the order of the wires, please check the product wiki. The color of the wires should follow a pattern similar to this:

  • Black: GND
  • Red: VCC
  • Green: Signal

As already mentioned, the device has a switch that allows to operate on two modes: digital and analog [1]. In our case, we are going to work in digital mode (we will see this in the code below), so the switch should be in the “D” position. Note that even in digital mode, the Arduino core will do an Analog Read over the sensor pin, which explains why we need to wire the sensor to an analog pin.

Installing the library

To make the interaction with the sensor easier, we will use this library. To install it, we first need to locate the Arduino libraries folder in our computer. In my case, it is located on the following path (yours may differ, depending on your installation):

C:\Users\MyUserName\Documents\Arduino\libraries\

Once there, simply create a new folder, where we will place the library files. I’ve called mine heart_rate.

Then, go to the library GitHub page and download the following files to this folder:

After this, you should be able to include the library with the following line of code:

#include <DFRobot_Heartrate.h>

I also recommend you to take a look at the examples folder. The code we are going to analyze in the next section is based on this example.

The code

We will start our code with the library include.

#include <DFRobot_Heartrate.h>

After that we will define a constant to hold the number of the ESP32 pin that will be connected to the ESP32. I’ll be using pin 25.

const int sensorPin = 25;

Then we will create an object of class DFRobot_Heartrate. As input, we need to pass a constant indicating the operating mode (digital or analog). In our case we will be using the digital mode, meaning we should use the constant DIGITAL_MODE.

DFRobot_Heartrate heartrate(DIGITAL_MODE); 

Moving on to the Arduino setup, we will simply open a serial connection, to later output the heart rate measurements. Since we are going to do the measurements periodically in the main loop, our setup will just be used for opening the serial connection.

void setup() {
  Serial.begin(115200);
}

On the Arduino main loop we will start by getting a sample from the sensor with a call to the getValue method on our DFRobot_Heartrate object. As input, we need to pass the number of the ESP32 pin connected to the sensor (which we have in the previously defined global variable).

Under the hood, this method will get a measurement from the sensor and add it to an internal buffer. Although the obtained value is returned as output of the method, we will not store it anywhere.

heartrate.getValue(sensorPin);

After that we will call the getRate method on our object. This method takes no arguments and returns as output an heart rate measurement. Note that this call will take into account previous measurements and so some conversions to compute the final value. If you are interested in the details, you can check the implementation here (the link points to the method that is called by the getRate method).

The values outputted by this method are in heart beats per minute.

rateValue = heartrate.getRate();

When we call the getRate method and there is no valid value available, then the value zero is returned. As such, we will use it for error checking, and print the result to the serial port only if the value is valid.

if(rateValue>0){
  Serial.println(rateValue);
}

Finally we will introduce a small 20 milliseconds delay between each iteration of the main loop.

delay(20);

The whole loop function is shown below.

void loop() {
  int rateValue;
  
  heartrate.getValue(sensorPin);   
  rateValue = heartrate.getRate();
    
  if(rateValue>0){
    Serial.println(rateValue);
  }
  
  delay(20);
}

The complete code is shown below.

#include <DFRobot_Heartrate.h>

const int sensorPin = 25;

DFRobot_Heartrate heartrate(DIGITAL_MODE); 

void setup() {
  Serial.begin(115200);
}

void loop() {
  int rateValue;
  
  heartrate.getValue(sensorPin);   
  rateValue = heartrate.getRate();
    
  if(rateValue>0){
    Serial.println(rateValue);
  }
  
  delay(20);
}

Testing the code

Before uploading the code to the ESP32, make sure that all the wirings between the microcontroller and the sensor are correctly done. Make also sure to have the sensor properly attached to your finger or wrist.

Then, simply compile and upload the code to the ESP32, using the Arduino IDE. Once the procedure finishes, open the IDE serial monitor. You should see a result like figure 4. In my case, in the test illustrated in the figure, my heart beats were around 75 per minute, which makes sense given the fact that I was in rest.

Heart rate measurements printer to the Arduino IDE serial monitor.
Figure 4 – Heart rate measurements printer to the Arduino IDE serial monitor.

Note that you won’t immediately get heart rate measurements, as some valid samples need to be collected first. The message “Wait for valid data!” that gets printed to the monitor was not defined in our code but it is hardcoded in the library getRate method here. If you are doing an integration using the serial port and this message is complicating your implementation, you may simply remove or comment that line of code from your local copy of the library.

In terms of stability of the measurements, you should try to have the sensor as stable as possible. As the product page indicates, this sensor is designed to work when the user is not moving, which means that if used while moving it will give inaccurate results [1].

Also, in my tests, the more accurate and stable measurements seemed to be when I’ve attached the sensor to the finger.

Regarding the values obtained, they were close to some measurements I’ve done with a blood pressure monitor. Also, to see if the sensor could detect increases in the heart rate, I’ve done a test after running a bit and I could see an increase to around 120 heart beats per minute.

Regardless of how reasonable the measurements obtained are, it is important to highlight that this sensor is not intended for professional medical use and should not be used to diagnose or treat medical conditions [1].

References

[1] https://www.dfrobot.com/product-1540.html

[2] https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6426305/

Leave a Reply