Trying to "calibrate" a heart rate sensor so values aren't skewed

So I am making a project that measures biometrics during exercise and outputs them both to the serial monitor as well as to a set of external speakers for use by athletes with visual impairments. I have a problem where the heart rate sensor I am using (Default one from Pulsesensor.com) reads the first few beats as being super high (~160-250BPM) or low (~20-40BPM).

Is there some kind of "calibration" sequence I can add to the setup function to get a few values processed before it goes to the loop I have below? I already tried to implement one, as you can see but the program just skips to the loop when it doesn't immediately detect a heartbeat. Code is below.


#define USE_ARDUINO_INTERRUPTS true // Set-up low-level interrupts for most accurate BPM math
#include "DallasTemperature.h"
#include "OneWire.h"
#include "PulseSensorPlayground.h"
#include "Talkie.h"
#include "Vocab_US_Large.h"
#include "Vocab_Special.h"
#include <Wire.h>
#include "Adafruit_TPA2016.h"

Adafruit_TPA2016 audioamp = Adafruit_TPA2016();

Talkie voice;

const int PulseWire = 0;       // PulseSensor PURPLE WIRE connected to ANALOG PIN 0
const int LED = LED_BUILTIN;          // The on-board Arduino LED, close to PIN 13.
int Threshold = 550;           // Determine which Signal to "count as a beat" and which to ignore.
int ZoneThresholdHigh, ZoneThresholdLow; //defines the ZoneThreshold variables for use in the setup and loop funcitons                             
int waitForInput() { //This loop accounts for the repeated waiting and retrieving of user-entered Data
  while (!Serial.available()) { //While the serial monitor is active and waiting for input
    delay(500);
  }
  return (Serial.readStringUntil('\n')).toInt(); //Returns the serial monitor input "readStringUntil" the enter "\n" key is pressed, and sets the input to an integer "toInt"
} 
#define ONE_WIRE_BUS 13     // Data wire is plugged into pin 13 on the Arduino


PulseSensorPlayground pulseSensor;
// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass the oneWire reference to Dallas Temperature
DallasTemperature sensors(&oneWire);

void setup() {   
  audioamp.begin();
  audioamp.enableChannel(true, true);
  audioamp.setGain(20);
  Serial.begin(9600);
  sensors.begin();
    // Variable definitions first
  // Ask for age
  Serial.println("Bootup");
  Serial.println("------------------------------");
  Serial.println("Please enter your age");
  int AGE = 16;
  //delay(5000);
  Serial.println("------------------------------");
  // Ask for resting heart rate
  Serial.println("Please enter your resting heart rate: ");
  int RESTING = 60;
  //delay(5000);
  Serial.println("------------------------------");
  // Ask for workout zone
  Serial.println("Please enter your desired workout zone (1-4, or 5 for a resting benchmark): ");
  int WorkoutZone = waitForInput();
  //delay(5000);
  Serial.println("------------------------------");
  Serial.println("You selected these values:");
  Serial.println("Age: ");
  Serial.println(AGE);
  Serial.println("Resting HR: ");
  Serial.println(RESTING);
  Serial.println("Workout Zone: ");
  Serial.println(WorkoutZone);
  Serial.println("------------------------------");
  Serial.println("Your Heart Rate information is being calculated");
  int HRMAX = (207-(0.7*(AGE))); 
  int HRR = ((HRMAX)-(RESTING));
  Serial.println("Maximum Heart Rate: ");
  Serial.println(HRMAX);
  Serial.println("Heart Rate Reserve: ");
  Serial.println(HRR);

  if (WorkoutZone == 1) {
    //55-65%
    ZoneThresholdLow = (((HRR)*0.55)+(RESTING));
    ZoneThresholdHigh = (((HRR)*0.65)+(RESTING));
  }
    if (WorkoutZone == 2) {
    //65-75%
    ZoneThresholdLow = (((HRR)*0.65)+(RESTING));
    ZoneThresholdHigh = (((HRR)*0.75)+(RESTING));
  }
    if (WorkoutZone == 3) { 
    //75-80%
    ZoneThresholdLow = (((HRR)*0.75)+(RESTING));
    ZoneThresholdHigh = (((HRR)*0.80)+(RESTING));
  }
    if (WorkoutZone == 4) {
    //80-88%
    ZoneThresholdLow = (((HRR)*0.80)+(RESTING));
    ZoneThresholdHigh = (((HRR)*0.88)+(RESTING));
  }
    if (WorkoutZone == 5) {
    //Resting Zone
    ZoneThresholdHigh = (RESTING+20);
    ZoneThresholdLow = (RESTING);
  }
  pulseSensor.analogInput(PulseWire);   
  pulseSensor.setThreshold(Threshold);   

  // Double-check the "pulseSensor" object was created and "began" seeing a signal. 
  if (pulseSensor.begin()) {
    Serial.println("Pulse Sensor is on and active!");  //This prints one time at Arduino power-up,  or on Arduino reset.  
  }
  Serial.println("----------------------------------");
  Serial.println("Maximum Heart Rate: ");
  Serial.println(ZoneThresholdHigh);
  Serial.println("----------------------------------");
  Serial.println("Minimum Heart Rate: ");
  Serial.println(ZoneThresholdLow);
  Serial.println("----------------------------------");
  delay(1000);
  Serial.println("The Pulse Sensor is now calibrating, please rest your finger with the tip touching the green light on the HR sensor.");  
  delay(1000);
  Serial.println("The high heart rate extremum will now be calibrated. Remain still.");
  if (pulseSensor.sawStartOfBeat()) {
    int SetupBPM = pulseSensor.getBeatsPerMinute();
    while ((SetupBPM) > ZoneThresholdHigh){
      delay(20);  
      Serial.println("Calibrated BPM:");
      Serial.print(SetupBPM);
    }
    if ((SetupBPM) < ZoneThresholdHigh) {
      Serial.println("High heart rate extremum calibration completed-initializing low extremum now");
      while ((SetupBPM) < ZoneThresholdLow) {
        delay(20);
        Serial.println("Calibrated BPM:");
        Serial.print(SetupBPM);  
      }
      if ((SetupBPM) > ZoneThresholdLow){
        Serial.println("Low heart rate extremum calibration completed. Workout Starting");
      }
    }
  }
}

void loop() {

  if (pulseSensor.sawStartOfBeat()) {            // Constantly test to see if "a beat happened".
    int BPM = pulseSensor.getBeatsPerMinute();  // Calls function on our pulseSensor object that returns BPM as an "int". 
    Serial.println("BPM: ");
    Serial.println(BPM);
  
  delay(20);
  if ((BPM) > ZoneThresholdHigh) { 
    Serial.println("Heart Rate above max threshold");
    Serial.println("----------------------------------");
    voice.say(spPAUSE2);
    voice.say(sp2_SPEED);
    voice.say(sp2_HIGH);
    voice.say(spPAUSE1);
    voice.say(sp2_SLOW);
    voice.say(sp5_DOWN);
    }
  if ((BPM) < ZoneThresholdLow) {
    Serial.println("Heart Rate below min threshold");
    Serial.println("----------------------------------");
    voice.say(spPAUSE2);
    voice.say(sp2_SPEED);
    voice.say(sp2_LOW);
    voice.say(spPAUSE1);
    voice.say(sp2_SPEED);
    voice.say(sp2_UP);
  }
  
  
  }
}

I would say a stop watch would be the standard. For calibration use several minutes. The first few beats should be ignored. If it varies and your heart is not the sensor is either loose or in a bad spot, either tighten the band or move the sensor.

It was a hunt, but eventually you find their library examples, with descriptions...

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.