Giter VIP home page Giter VIP logo

pulsesensorplayground's Introduction

logo

PulseSensor.com Playground

How To Update Your Playground Code

This Playground is a collection of code for the most popular uses of PulseSensor and Arduino.  

- Use this code to get started quickly, or do advanced stuff. ๐Ÿ‘
- Playground code is already written-out and commented! ๐Ÿค˜ย 
- Switch between projects right in the Arduino IDE (software). ๐Ÿ’ป
- Contribute your project's code back to the GitHub hive-mind. ๐Ÿ

Buy Verified "PulseSensor.com"

Where to buy Verified Sensors ๐Ÿ’ฐ


Connecting the Harware ๐Ÿ˜Ž

Easy Setup

  1. Prepare the sensor, with the Kit parts.
  1. See the recommended wiring for your specific project

Loading the Playground

Steps For Loading the Playground in Arduino ๐Ÿค“

An Arduino Library is a collection of code and examples on a specific topic or device. For example, our PulseSensor Playground Library is a collection of code and projects made just for your PulseSensor and Arduino.

(NOTE If you do not have Arduino, you can download it here)

To install the PulseSensor Playground Library, in Arduino, to go Sketch > Include Library > Manage Library...

In the Library Manager: Search for and Select "PulseSensor.com

Install or update to the latest version.๐Ÿ‘

Hurray! Once this library is installed you will see our examples in Arduino's dropdown! To select an example project, go to: File > Examples > PulseSensor Playground > GettingStartedProject

More Info On Libraries in General ๐Ÿ‘‰ https://www.arduino.cc/en/Guide/Libraries.

Playground Project Descriptions:

Tinker and Experiment with Popular Projects ๐Ÿ‘ฉ๐Ÿฝโ€๐Ÿ’ป๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ”ฌ

The "Getting Started" Project: ย 

Plug your sensor in for the first time! Blink an LED with your pulse, live.


Calculate BPM:

Focus-in on the code that calculates a user's HeartRate Beats Per Minute, "BPM".
See the best practises to get the best signal.


Make A Sound to a live Heartbeat:

Transform the heartbeat into a live "beep" with a speaker.


Move a Motor to a live Heartbeat:

Make a servo motor pulse to your live heartbeat.


Connect Two (or more) Pulse Sensors:

Use 2 or more Pulse Sensors on one Arduino.


Processing Visualizer:

Get detailed visualization of the heart's pulse and behavior. Send the PulseSensor data into Processing!


Pulse Transit Time:

Use two Pulse Sensors on different parts of your body to measure Pulse Transit Time!


Developer Resources:

Troubleshooting / Issues / Function Guide

The Functions Guide

We put together a HANDY GUIDE to the function-ality of our library. Check it out if you want to dive into the inner workings!


Troubleshooting Your Signal:

Ugh, Where's the Beat ? ๐Ÿ˜ต If you're having trouble seeing a heartbeat, make sure that you are using 'Goldilocks' pressure on the Pulse Sensor: Not too hard, not too soft. Squeezing the Pulse Sensor too hard against your skin will make the heartbeat go away, and not enough pressure will cause too much noise to creep in!

If you are seeing way too many Beats Per Minute, or you are getting lots of noise, try adjusting the Threshold setting. The Threshold variable tells Arduino when to find a pulse that is legit. Adjust this number (noted below with arrows) up for less sensitivity and down for more sensitivity. In the StarterProject you can find the Threshold variable as shown in the pic below:

StarterThreshold

In the other examples, the THRESHOLD is defined at the top of the code.


Give and Get Feedback

The Issues Tab will get you the quickest answers to common techinal questions.


Legal: PulseSensor.comยฎ World Famous Electronics llc. in Brooklyn, NY. USA

pulsesensorplayground's People

Contributors

anonymous-ol avatar biomurph avatar bneedhamia avatar joelsensor avatar per1234 avatar rustynymph avatar schweinebaer avatar yury-g avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pulsesensorplayground's Issues

Sensor not sending smooth values

Hello,
So I connected my sensor and uploaded the Getting Started sketch. But as you can see I'm not getting a smooth chart, so Icannot set a threshold and calculate BPM.

image

BTW, I once got a smooth chart and it was working, but now it's not.

BPM work good and TFT work good but when I combine them, not good!

So all works good but as I said and now when I want to see BPM number on the TFT. My TFT act wired like it will print different color and the letter "B" will be removed from BPM will be missing and the 5s maybe later it will turn all white I don't know why but after long debugging I was able to find the line causing that! which is this -- >pulseSensor.analogInput(PulseWire);
However, if there is If a take the wire off from A0 things good but will print BPM: 0

#define USE_ARDUINO_INTERRUPTS true    // Set-up low-level interrupts for most acurate BPM math.
#include <PulseSensorPlayground.h>     // Includes the PulseSensorPlayground Library.   
#include <Adafruit_GFX.h>    // Core graphics library
#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include <Adafruit_ST7789.h> // Hardware-specific library for ST7789
#include <SPI.h>
#include <SD.h>

  #define TFT_CS        10
  #define TFT_RST        9 // Or set to -1 and connect to Arduino RESET pin
  #define TFT_DC         8

// OPTION 1 (recommended) is to use the HARDWARE SPI pins, which are unique
// to each board and not reassignable. For Arduino Uno: MOSI = pin 11 and
// SCLK = pin 13. This is the fastest mode of operation and is required if
// using the breakout board's microSD card.

// For 1.44" and 1.8" TFT with ST7735 (including HalloWing) use:
//Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_RST);

// For 1.54" TFT with ST7789:
//Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// OPTION 2 lets you interface the display using ANY TWO or THREE PINS,
// tradeoff being that performance is not as fast as hardware SPI above.
#define TFT_MOSI 11  // Data out
#define TFT_SCLK 13  // Clock out

Adafruit_ST7735 tft = Adafruit_ST7735(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);
float p = 3.1415926;
int Variable1;

//  Variables
int PulseWire = 0;       // PulseSensor PURPLE WIRE connected to ANALOG PIN 0
const int LED13 = 13;          // The on-board Arduino LED, close to PIN 13.
int Threshold = 550;           // Determine which Signal to "count as a beat" and which to ignore.
PulseSensorPlayground pulseSensor;  // Creates an instance of the PulseSensorPlayground object called "pulseSensor"
int myBPM = 100;
static uint32_t tsLastReport = 0;  
     
void setup(void) {
  Serial.begin(9600);
 //PulseWire = 3;
  pulseSensor.analogInput(PulseWire);   
  pulseSensor.blinkOnPulse(LED13);       //auto-magically blink Arduino's LED with heartbeat.
  pulseSensor.setThreshold(Threshold);   
  pulseSensor.begin();



  Serial.print(F("Hello! ST77xx TFT Test"));

#ifdef ADAFRUIT_HALLOWING
  // HalloWing is a special case. It uses a ST7735R display just like the
  // breakout board, but the orientation and backlight control are different.
  tft.initR(INITR_HALLOWING);        // Initialize HalloWing-oriented screen
  pinMode(TFT_BACKLIGHT, OUTPUT);
  digitalWrite(TFT_BACKLIGHT, HIGH); // Backlight on
#else
  // Use this initializer if using a 1.8" TFT screen:
 // tft.initR(INITR_BLACKTAB);      // Init ST7735S chip, black tab

  // OR use this initializer (uncomment) if using a 1.44" TFT:
  tft.initR(INITR_144GREENTAB); // Init ST7735R chip, green tab

  // OR use this initializer (uncomment) if using a 0.96" 180x60 TFT:
  //tft.initR(INITR_MINI160x80);  // Init ST7735S mini display

  // OR use this initializer (uncomment) if using a 1.54" 240x240 TFT:
  //tft.init(240, 240);           // Init ST7789 240x240
#endif

  Serial.println(F("Initialized"));

  uint16_t time = millis();
  tft.fillScreen(ST77XX_BLACK);
  time = millis() - time;
  
  Serial.println(time, DEC);
  delay(500);

  Serial.println("done");
  delay(1000);

  Variable1 = 90;
  
 
}

void loop() {
  


   int myBPM = pulseSensor.getBeatsPerMinute();  // Calls function on our pulseSensor object that returns BPM as an "int".                                 
       
      if (pulseSensor.sawStartOfBeat()) {  
     
 
         Serial.println(myBPM);                        // Print the value inside of myBPM. 
    
          } 
          
         delay(20);         

  testdrawtext(" BPM: ", ST77XX_WHITE);
  delay(600);
  tft.setTextColor(ST77XX_RED);  
  tft.setTextSize(3); 
  tft.print(myBPM); 
   delay(600);
 tft.fillScreen(ST77XX_BLACK);
  delay(500);


}


void testdrawtext(char *text, uint16_t color) {
  

  tft.setCursor(0, 0);
  //  tft.setCursor(10, 40);
  tft.setTextSize(2);
 // tft.setTextColor(color);
  tft.setTextColor(ST7735_YELLOW);
  tft.setTextWrap(true);
  tft.print(text);
}

error Scrollbar scaleBar; in Processing Part Two

I have coppied the following sketch from https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer
and when I run it I obtain the error: The class "Scrollbar" does not exist. Google has not helped.
The code:
/*
THIS PROGRAM WORKS WITH PulseSensorAmped_Arduino ARDUINO CODE
THE PULSE DATA WINDOW IS SCALEABLE WITH SCROLLBAR AT BOTTOM OF SCREEN
PRESS 'S' OR 's' KEY TO SAVE A PICTURE OF THE SCREEN IN SKETCH FOLDER (.jpg)
PRESS 'R' OR 'r' KEY TO RESET THE DATA TRACES
MADE BY JOEL MURPHY AUGUST, 2012
UPDATED BY JOEL MURPHY SUMMER 2016 WITH SERIAL PORT LOCATOR TOOL
UPDATED BY JOEL MURPHY WINTER 2017 WITH IMPROVED SERIAL PORT SELECTOR TOOL
THIS CODE PROVIDED AS IS, WITH NO CLAIMS OF FUNCTIONALITY OR EVEN IF IT WILL WORK
WYSIWYG
*/

import processing.serial.*; // serial library lets us talk to Arduino
PFont font;
PFont portsFont;
Scrollbar scaleBar;

Serial port;

int Sensor; // HOLDS PULSE SENSOR DATA FROM ARDUINO
int IBI; // HOLDS TIME BETWEN HEARTBEATS FROM ARDUINO
int BPM; // HOLDS HEART RATE VALUE FROM ARDUINO
int[] RawY; // HOLDS HEARTBEAT WAVEFORM DATA BEFORE SCALING
int[] ScaledY; // USED TO POSITION SCALED HEARTBEAT WAVEFORM
int[] rate; // USED TO POSITION BPM DATA WAVEFORM
float zoom; // USED WHEN SCALING PULSE WAVEFORM TO PULSE WINDOW
float offset; // USED WHEN SCALING PULSE WAVEFORM TO PULSE WINDOW
color eggshell = color(255, 253, 248);
int heart = 0; // This variable times the heart image 'pulse' on screen
// THESE VARIABLES DETERMINE THE SIZE OF THE DATA WINDOWS
int PulseWindowWidth = 490;
int PulseWindowHeight = 512;
int BPMWindowWidth = 180;
int BPMWindowHeight = 340;
boolean beat = false; // set when a heart beat is detected, then cleared when the BPM graph is advanced

// SERIAL PORT STUFF TO HELP YOU FIND THE CORRECT SERIAL PORT
String serialPort;
String[] serialPorts = new String[Serial.list().length];
boolean serialPortFound = false;
Radio[] button = new Radio[Serial.list().length*2];
int numPorts = serialPorts.length;
boolean refreshPorts = false;

void setup() {
size(700, 600); // Stage size
frameRate(100);
font = loadFont("Arial-BoldMT-24.vlw");
textFont(font);
textAlign(CENTER);
rectMode(CENTER);
ellipseMode(CENTER);
// Scrollbar constructor inputs: x,y,width,height,minVal,maxVal
scaleBar = new Scrollbar (400, 575, 180, 12, 0.5, 1.0); // set parameters for the scale bar
RawY = new int[PulseWindowWidth]; // initialize raw pulse waveform array
ScaledY = new int[PulseWindowWidth]; // initialize scaled pulse waveform array
rate = new int [BPMWindowWidth]; // initialize BPM waveform array
zoom = 0.75; // initialize scale of heartbeat window

// set the visualizer lines to 0
resetDataTraces();

background(0);
// DRAW OUT THE PULSE WINDOW AND BPM WINDOW RECTANGLES
drawDataWindows();
drawHeart();

// GO FIND THE ARDUINO
fill(eggshell);
text("Select Your Serial Port",245,30);
listAvailablePorts();

}

void draw() {
if(serialPortFound){
// ONLY RUN THE VISUALIZER AFTER THE PORT IS CONNECTED
background(0);
noStroke();
drawDataWindows();
drawPulseWaveform();
drawBPMwaveform();
drawHeart();
// PRINT THE DATA AND VARIABLE VALUES
fill(eggshell); // get ready to print text
text("Pulse Sensor Amped Visualizer v1.5",245,30); // tell them what you are
text("IBI " + IBI + "mS",600,585); // print the time between heartbeats in mS
text(BPM + " BPM",600,200); // print the Beats Per Minute
text("Pulse Window Scale " + nf(zoom,1,2), 150, 585); // show the current scale of Pulse Window

// DO THE SCROLLBAR THINGS
scaleBar.update (mouseX, mouseY);
scaleBar.display();

} else { // SCAN BUTTONS TO FIND THE SERIAL PORT

autoScanPorts();

if(refreshPorts){
refreshPorts = false;
drawDataWindows();
drawHeart();
listAvailablePorts();
}

for(int i=0; i<numPorts+1; i++){
button[i].overRadio(mouseX,mouseY);
button[i].displayRadio();
}

}

} //end of draw loop

void drawDataWindows(){
// DRAW OUT THE PULSE WINDOW AND BPM WINDOW RECTANGLES
noStroke();
fill(eggshell); // color for the window background
rect(255,height/2,PulseWindowWidth,PulseWindowHeight);
rect(600,385,BPMWindowWidth,BPMWindowHeight);
}

void drawPulseWaveform(){
// DRAW THE PULSE WAVEFORM
// prepare pulse data points
RawY[RawY.length-1] = (1023 - Sensor) - 212; // place the new raw datapoint at the end of the array
zoom = scaleBar.getPos(); // get current waveform scale value
offset = map(zoom,0.5,1,150,0); // calculate the offset needed at this scale
for (int i = 0; i < RawY.length-1; i++) { // move the pulse waveform by
RawY[i] = RawY[i+1]; // shifting all raw datapoints one pixel left
float dummy = RawY[i] * zoom + offset; // adjust the raw data to the selected scale
ScaledY[i] = constrain(int(dummy),44,556); // transfer the raw data array to the scaled array
}
stroke(250,0,0); // red is a good color for the pulse waveform
noFill();
beginShape(); // using beginShape() renders fast
for (int x = 1; x < ScaledY.length-1; x++) {
vertex(x+10, ScaledY[x]); //draw a line connecting the data points
}
endShape();
}

void drawBPMwaveform(){
// DRAW THE BPM WAVE FORM
// first, shift the BPM waveform over to fit then next data point only when a beat is found
if (beat == true){ // move the heart rate line over one pixel every time the heart beats
beat = false; // clear beat flag (beat flag waset in serialEvent tab)
for (int i=0; i<rate.length-1; i++){
rate[i] = rate[i+1]; // shift the bpm Y coordinates over one pixel to the left
}
// then limit and scale the BPM value
BPM = min(BPM,200); // limit the highest BPM value to 200
float dummy = map(BPM,0,200,555,215); // map it to the heart rate window Y
rate[rate.length-1] = int(dummy); // set the rightmost pixel to the new data point value
}
// GRAPH THE HEART RATE WAVEFORM
stroke(250,0,0); // color of heart rate graph
strokeWeight(2); // thicker line is easier to read
noFill();
beginShape();
for (int i=0; i < rate.length-1; i++){ // variable 'i' will take the place of pixel x position
vertex(i+510, rate[i]); // display history of heart rate datapoints
}
endShape();
}

void drawHeart(){
// DRAW THE HEART AND MAYBE MAKE IT BEAT
fill(250,0,0);
stroke(250,0,0);
// the 'heart' variable is set in serialEvent when arduino sees a beat happen
heart--; // heart is used to time how long the heart graphic swells when your heart beats
heart = max(heart,0); // don't let the heart variable go into negative numbers
if (heart > 0){ // if a beat happened recently,
strokeWeight(8); // make the heart big
}
smooth(); // draw the heart with two bezier curves
bezier(width-100,50, width-20,-20, width,140, width-100,150);
bezier(width-100,50, width-190,-20, width-200,140, width-100,150);
strokeWeight(1); // reset the strokeWeight for next time
}

void listAvailablePorts(){
println(Serial.list()); // print a list of available serial ports to the console
serialPorts = Serial.list();
fill(0);
textFont(font,16);
textAlign(LEFT);
// set a counter to list the ports backwards
int yPos = 0;
int xPos = 35;
for(int i=serialPorts.length-1; i>=0; i--){
button[i] = new Radio(xPos, 95+(yPos20),12,color(180),color(80),color(255),i,button);
text(serialPorts[i],xPos+15, 100+(yPos
20));

yPos++;
if(yPos > height-30){
  yPos = 0; xPos+=200;
}

}
int p = numPorts;
fill(233,0,0);
button[p] = new Radio(35, 95+(yPos20),12,color(180),color(80),color(255),p,button);
text("Refresh Serial Ports List",50, 100+(yPos
20));

textFont(font);
textAlign(CENTER);
}

void autoScanPorts(){
if(Serial.list().length != numPorts){
if(Serial.list().length > numPorts){
println("New Ports Opened!");
int diff = Serial.list().length - numPorts; // was serialPorts.length
serialPorts = expand(serialPorts,diff);
numPorts = Serial.list().length;
}else if(Serial.list().length < numPorts){
println("Some Ports Closed!");
numPorts = Serial.list().length;
}
refreshPorts = true;
return;
}
}

void resetDataTraces(){
for (int i=0; i<rate.length; i++){
rate[i] = 555; // Place BPM graph line at bottom of BPM Window
}
for (int i=0; i<RawY.length; i++){
RawY[i] = height/2; // initialize the pulse window data line to V/2
}
}
Any sugestion?

Is PulseSensor faking heartbeat??

So I got the following PulseSensor

Photo 14 05 19, 08 54 01
Photo 14 05 19, 08 53 51

and thought I got it to kinda work - but even though the pulse blinking seemed to be somewhat close to the pulse I felt, the blinks didn't seem to really correspond to the beats I felt by hand - so I changed the PulseSensor.cpp code to directly output the measured sensor value, as in

analogWrite(LED_PIN, analogRead(SENSOR_PIN));

and what you see on the video is the led behaviour I get WITHOUT touching the sensor (or even the cable) in any way.

ezgif-1-e64392a5bf71

Did I get a fake sensor? (it looks like it's got exactly the components it's supposed to have) - or is this the filter and amplifier "feature" of the new hardware version you guys write about on your blog?

I'm a bit bummed and wonder what's going on here

How to extract BPM value out and do calculation with it using STM32 board?

Hi, I'm currently using Nucleo64-F401RE development board to interface with pulse sensor. I wanted to design a detection system which can determine if the BPM value is less than assigned threshold, an action will be taken. Since that Nucleo board doesn't support interrupt for pulse sensor, I can't use the getbeatsperminute( ) function. May I know how can I solve this issue? Or I'll just use an Arduino board? Thank you for your attention. Much help will be appreciated.

Can't get the right values with the pulse sensor and the LM35 temperature sensor . Reading 2 anolog sesnors

I am trying to combine the two sensors (pulse sensor and LM35 temp),but there is a problem with them when is a noise at the pulse sensor .The values are fluctuates especially the LM35 it goes from 31 degrees (normal value ) to 25-50 and even the pulse one .
Here are the results .
The code is this(I got the code form the Getting_BPM_to_Monitor sketch and added the LM35 code)(board is Arduino Uno) :

#define USE_ARDUINO_INTERRUPTS true    // Set-up low-level interrupts for most acurate BPM math.
#include <PulseSensorPlayground.h>     // Includes the PulseSensorPlayground Library. 

const int sensor = A5; // Assigning analog pin A5 to variable โ€˜sensorโ€™
float tempc; //variable to store temperature in degree Celsius
float vout; //temporary variable to hold sensor reading
//  Variables
const int PulseWire = 0;       // PulseSensor PURPLE WIRE connected to ANALOG PIN 0
const int LED13 = 13;          // The on-board Arduino LED, close to PIN 13.
int Threshold = 550;           // Determine which Signal to "count as a beat" and which to ignore.
// Use the "Gettting Started Project" to fine-tune Threshold Value beyond default setting.
// Otherwise leave the default "550" value.

PulseSensorPlayground pulseSensor;  // Creates an instance of the PulseSensorPlayground object called "pulseSensor"
void setup() {
  Serial.begin(9600);          // For Serial Monitor
  // Configure the PulseSensor object, by assigning our variables to it.
  pulseSensor.analogInput(PulseWire);
  pulseSensor.blinkOnPulse(LED13);       //auto-magically blink Arduino's LED with heartbeat.
  pulseSensor.setThreshold(Threshold);
  // Double-check the "pulseSensor" object was created and "began" seeing a signal.
  if (pulseSensor.begin()) {
    Serial.println("We created a pulseSensor Object !");  //This prints one time at Arduino power-up,  or on Arduino reset.
  }
}

void loop() {
  int temp = analogTemp();
  Serial.print(temp);
  Serial.println("Temp");
  
  if (pulseSensor.sawStartOfBeat()) {            // Constantly test to see if "a beat happened".
    // Serial.println("โ™ฅ  A HeartBeat Happened ! "); // If test is "true", print a message "a heartbeat happened".
    int myBPM = pulseSensor.getBeatsPerMinute();  // Calls function on our pulseSensor object that returns BPM as an "int".
    // "myBPM" hold this BPM value now.
    Serial.print("BPM: ");                        // Print phrase "BPM: "
    Serial.print(myBPM);                        // Print the value inside of myBPM.
    Serial.println(" A HeartBeat Happened ! ");
  }
  delay(20);                    // considered best practice in a simple sketch.
}
float analogTemp() {
  vout = analogRead(sensor);
  vout = (vout * 500) / 1023;
  return vout; // Storing value in Degree Celsius

}

BPM won't go back to zero and blink pin and fade pin do not turn on although BPM is not zero

I am making a remote heart rate monitor to send BPM to an android phone. The android part works correctly. However, the BPM fails to go back to zero after I remove the finger. With the finger placed on the sensor, the system works well and the blink and fade pins work nicely as well. However, upon removing the finger, the blink pin and fade pin remain off but the BPM sent through serial is not zero. At times, pressing the return button returns BPM to zero. However, I expected that if the BPM is not zero, the blink pin should be blinking. My code pasted below;

/*
Code to detect pulses from the PulseSensor,
using an interrupt service routine.

Here is a link to the tutorial
https://pulsesensor.com/pages/getting-advanced

Copyright World Famous Electronics LLC - see LICENSE
Contributors:
Joel Murphy, https://pulsesensor.com
Yury Gitman, https://pulsesensor.com
Bradford Needham, @bneedhamia, https://bluepapertech.com

Licensed under the MIT License, a copy of which
should have been included with this software.

This software is not intended for medical use.
*/

/*
Every Sketch that uses the PulseSensor Playground must
define USE_ARDUINO_INTERRUPTS before including PulseSensorPlayground.h.
Here, #define USE_ARDUINO_INTERRUPTS true tells the library to use
interrupts to automatically read and process PulseSensor data.

See ProcessEverySample.ino for an example of not using interrupts.
*/
#define USE_ARDUINO_INTERRUPTS true
#include <SoftwareSerial.h>
#include <PulseSensorPlayground.h>

/*
The format of our output.

Set this to PROCESSING_VISUALIZER if you're going to run
the Processing Visualizer Sketch.
See https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer

Set this to SERIAL_PLOTTER if you're going to run
the Arduino IDE's Serial Plotter.
*/
const int OUTPUT_TYPE = SERIAL_PLOTTER;

/*
Pinout:
PIN_INPUT = Analog Input. Connected to the pulse sensor
purple (signal) wire.
PIN_BLINK = digital Output. Connected to an LED (and 220 ohm resistor)
that will flash on each detected pulse.
PIN_FADE = digital Output. PWM pin onnected to an LED (and resistor)
that will smoothly fade with each pulse.
NOTE: PIN_FADE must be a pin that supports PWM. Do not use
pin 9 or 10, because those pins' PWM interferes with the sample timer.
/
const int BT_RX = 3;
const int BT_TX = 4;
const int PIN_INPUT = A2;
const int PIN_BLINK = 13; // Pin 13 is the on-board LED
const int PIN_FADE = 6;
const int ALERT_PIN=10;
const int buzzer=5;
const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
int period = 100; //time to wait before printing via BT
int period2=500; //time to play alert sound and light up alert
int period3=20; // time for outputiing data to serial
unsigned long time_now = 0;// used sith period for millis timer
/

All the PulseSensor Playground functions.
*/
PulseSensorPlayground pulseSensor;
SoftwareSerial BTSerial(BT_RX, BT_TX);

void setup() {
/*
Use 115200 baud because that's what the Processing Sketch expects to read,
and because that speed provides about 11 bytes per millisecond.

 If we used a slower baud rate, we'd likely write bytes faster than
 they can be transmitted, which would mess up the timing
 of readSensor() calls, which would make the pulse measurement
 not work properly.

*/
Serial.begin(115200);
BTSerial.begin (9600);
pinMode (ALERT_PIN, OUTPUT);
pinMode (buzzer, OUTPUT);

// Configure the PulseSensor manager.

pulseSensor.analogInput(PIN_INPUT);
pulseSensor.blinkOnPulse(PIN_BLINK);
pulseSensor.fadeOnPulse(PIN_FADE);

pulseSensor.setSerial(Serial);
pulseSensor.setOutputType(OUTPUT_TYPE);
pulseSensor.setThreshold(THRESHOLD);

// Now that everything is ready, start reading the PulseSensor signal.
if (!pulseSensor.begin()) {
/*
PulseSensor initialization failed,
likely because our particular Arduino platform interrupts
aren't supported yet.

   If your Sketch hangs here, try ProcessEverySample.ino,
   which doesn't use interrupts.
*/
for(;;) {
  // Flash the led to show things didn't work.
  digitalWrite(PIN_BLINK, LOW);
  delay(50);
  digitalWrite(PIN_BLINK, HIGH);
  delay(50);
}

}
}

void loop() {

int myBPM=pulseSensor.getBeatsPerMinute ();

if (myBPM>100){
time_now = millis();
tone(buzzer, 1000); // Send 1KHz sound signal...
digitalWrite (ALERT_PIN, HIGH);
while(millis() < time_now + period2);

    }
 else if (myBPM<60){
    time_now = millis();
    tone(buzzer, 1000); // Send 1KHz sound signal...
    digitalWrite (ALERT_PIN, HIGH);
    while(millis() < time_now + period2);
 
    }
 else {
    noTone (buzzer);
    digitalWrite (ALERT_PIN, LOW);
    }

/*
Wait a bit.
We don't output every sample, because our baud rate
won't support that much I/O.
*/
if (millis() > time_now + period3){
time_now = millis();

 // write the latest sample to Serial.
 pulseSensor.outputSample();

  /*
 If a beat has happened since we last checked,
 write the per-beat information to Serial.
*/
if (pulseSensor.sawStartOfBeat()) {
    pulseSensor.outputBeat();
    }
}

if (millis() > time_now + period){
time_now = millis();
BTSerial.println(pulseSensor.getBeatsPerMinute());

}

}

PulseSensorPlayground does not work on Arduino Uno WiFi Rev2

Im trying to get a simple BPM reading using the Arduino Uno WiFi Rev2. When compiling I seem to be getting an error. I just need a serial reading. Is there a simple fix for this issue? Or do I need another Arduino board?

This is my error:

Arduino: 1.8.9 (Mac OS X), Board: "Arduino Uno WiFi Rev2, ATMEGA328"

In file included from /Users/tommaarleveld/Library/Arduino15/packages/arduino/hardware/megaavr/1.6.25/cores/arduino/Arduino.h:27:0,
                 from sketch/Getting_BPM_to_Monitor.ino.cpp:1:
/Users/tommaarleveld/Documents/Arduino/libraries/PulseSensor_Playground/src/utility/Interrupts.h: In function 'void TIMER1_COMPA_vect()':
/Users/tommaarleveld/Documents/Arduino/libraries/PulseSensor_Playground/src/utility/Interrupts.h:207:9: warning: 'TIMER1_COMPA_vect' appears to be a misspelled signal handler, missing __vector prefix [-Wmisspelled-isr]
     ISR(TIMER1_COMPA_vect)
         ^
/Users/tommaarleveld/Documents/Arduino/libraries/PulseSensor_Playground/src/utility/PulseSensor.cpp: In member function 'void PulseSensor::updateLEDs()':
/Users/tommaarleveld/Documents/Arduino/libraries/PulseSensor_Playground/src/utility/PulseSensor.cpp:221:33: error: cannot convert 'volatile boolean {aka volatile bool}' to 'PinStatus' for argument '2' to 'void digitalWrite(pin_size_t, PinStatus)'
     digitalWrite(BlinkPin, Pulse);
                                 ^
exit status 1
Error compiling for board Arduino Uno WiFi Rev2.

[Question] Is our device working properly

Hello,
We started a small project at Uni and we decided to use your device to read the heart rate of a user to trigger certain events. However we are all new to arduino and DYI electronics and were wondering if we were using / reading the graphs right. We are using the BPM code and just have the pulse sensor connected to a arduino uno board.

disconnected

When we turn on the arduino with no sensor connected.
Shouldnt this be 0 ?

measuredpulse

when we have everything connected we get a pulse.

notouch

and when we are not touching the device when its connected and let it run for a moment, we can still se some signs of a pulse even when we edit the threshold.

The serial console shows a lot of readings here.

What we are planning to do is a heart rate is above a certain level something will happem, however when we see from the console a lot of readings even when we are not touching the sensor we are not really certain we are looking at this correctly

Obtaining HRV Biofeedback from PulseSensor Serial Plotter

Antecedents.
HRV Biofeedback is becoming more and more frequent during therapy sessions. It is used to treat stress and many other illnesses. I refer you to the web for more information.
I copy here some โ€œclarificationโ€ I posted in another issue:
People are used to measure the pulse of a person in BPM (beats per minute).
This is done usually counting the beats during 15 seconds and multiplying by 4. This is an average.
The device your doctor puts in your finger also gives an average number.
The problem is that the frequency at which the heart beats is not constant, it increases during inspiration, and decreases during expiration. This is regulated by the Autonomic Nervous System. A good athlete can have a variation as large as 20 beats, meaning that when inspiring the heart accelerates to, letโ€™s say, 60, and when expires descends to 40.
This number, 20, is what is called HRV, or Heart Rate Variability.
There are many ways to measure HRV, but when Biofeedback is attempted, it is this number that is used.
When I talk about real time BPM I mean the number that one would obtain if the heart would continue beating at that frequency for one minute.
In a typical Biofeedback session, the therapist asks you to breath following a pacer, and measures the HRV for that breathing frequency. This is done during several minutes. Then the pace is changed and a new value of HRV is obtained.
The normal ranges measured is from 5 to 9 breaths per minute, and most individuals have a Maximum HRV at around 6 breaths per minute.
Many researchers have found that when breathing at this rate (the optimal) stress is reduced. You can have more information about the benefits of biofeedback in the Internet.
Now to the PulseSensor_BPM.
This is the graph obtained from the PulseSensor in the Serial Plotter:

Instead of this graph, I should like to see this:

  1. Delete the blue line. It shows the BPM of the last ten seconds. This is no good for HRV analysis.
  2. Change the upper graph (IBI) to BPM (dividing 60,000 by the value of IBI (in ms). This new โ€œstaircaseโ€ would have a horizontal length and a vertical height equal to one beat.
  3. Add a sine wave with a period of 10 s. It would serve as the breathing pacer.
    Once this is achieved, I will post more improvements that can be made.
    Anyone?

pulseSensor.sawStartOfBeat is always false

Here is my (short) sketch:

#define USE_ARDUINO_INTERRUPTS false
#include <PulseSensorPlayground.h>

PulseSensorPlayground pulseSensor;

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

	pulseSensor.analogInput(A0);

	pulseSensor.setSerial(Serial);
	pulseSensor.setOutputTypeSERIAL_PLOTTER);
	pulseSensor.setThreshold(550);

	samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;

	if (!pulseSensor.begin()) {
		Serial.println("Cannot begin.");
	}
}

void loop() {
	if (pulseSensor.sawStartOfBeat()) {
		pulseSensor.outputBeat();
	}
}

This will never output anything while previously using pulseSensor.outputSample(); would output valid bpm and a nice heartbeat to the graph.

I tested this with the serial monitor on an ESP8266.

PulseSensor with arm based device?

Hi I want to ask you if there is possible to use the library and the examples with a stm32 board (nucleo F401RE) because I saw that the libraries uses the Arduino avr interrupts, but my board is an Arm Cortex one so I cannot use the functions "cli()" and "sei()"; I already try to use "__enable_irq()" and "__disable_irq()" with the "Getting_BPM_to_Monitor" example, but the program never receive the BPM.
Is there something that i can do?

Pulse sensor amped with Teensy 3.2

I'm trying to interface Pulse sensor bpm alternative code with teensy 3.2 but the code is giving bpm value of 0 and IBI=600. what might be the possible cause of this? Can you please suggest a way to interface it on Teensy 3.2?

error โ€œunexpectedtoken:defโ€ in Processing

Antecedents.

  1. Iโ€™m receiving biofeedback therapy from an specialist and I should like to replicate his equipment so I can practice at home.
  2. He uses the Bio-Trace Nexus 10, very expensive ($5,000).
  3. The therapy sessions consist of:
    a. He attaches to me a breathing strap, two skin galvanic electrodes, one thermistor and a Blood Volume Pulse (BVP), (photoplethysmograph).
    b. Then I watch a breathing pacer and follow the breathing pattern of 6 breaths per minute for several minutes. This is the rate that is considered best to increase oneโ€™s HRV.
    c. After that I try to continue breathing at that rate, and watch the graph of my HRV, and try (subconsciously) to increase the HRV.
    d. His system records many variables, but temperature and galvanic response remain very much constant. The main part is the curve of the heart beats and how they go up and down with the breathing, and the HRV bar (that is the same thing).
  4. Other devices (phone aps) only measure HRV during several minutes, and then give the values of RMSSD, SDNN, SDANN, LF, HF, HF/LF, (from the Fourier Transforms) and Poincare plot.
  5. Most people do not understand this, and they are presented with a value that is the average over several minutes.
  6. All these applications are aimed at training and give advice as to your state of recuperation from exercise.
  7. So, I bought a PulseSensor and an Arduino. I spent the following two months studying and practicing with some Arduino projects.
  8. I assisted several times to an Arduino group in my city, but I have reached a point that I need help.
    What I have done:
  9. Run the PulseSensor_BMP and I obtain the tree curves. No problem so far.
  10. Download Processing and copied the code from Arduino IDE to Processing, changing the const int OUTPUT_TYPE = SERIAL_PLOTTER; to PROCESSING_VISUALIZER.
  11. This is the code:
  12. #define USE_ARDUINO_INTERRUPTS true
  13. #include <PulseSensorPlayground.h>
  14. /*
  15. The format of our output.
    
  16. Set this to PROCESSING_VISUALIZER if you're going to run
  17. the Processing Visualizer Sketch.
    
  18. See https://github.com/WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer
    
  19. Set this to SERIAL_PLOTTER if you're going to run
  20. the Arduino IDE's Serial Plotter.
    
  21. */
  22. const int OUTPUT_TYPE = PROCESSING_VISUALIZER;
  23. /*
  24. Pinout:
  25.  PIN_INPUT = Analog Input. Connected to the pulse sensor
    
  26.   purple (signal) wire.
    
  27.  PIN_BLINK = digital Output. Connected to an LED (and 220 ohm resistor)
    
  28.   that will flash on each detected pulse.
    
  29.  PIN_FADE = digital Output. PWM pin onnected to an LED (and resistor)
    
  30.   that will smoothly fade with each pulse.
    
  31.   NOTE: PIN_FADE must be a pin that supports PWM. Do not use
    
  32.   pin 9 or 10, because those pins' PWM interferes with the sample timer.
    
  33. */
  34. const int PIN_INPUT = A0;
  35. const int PIN_BLINK = 13; // Pin 13 is the on-board LED
  36. const int PIN_FADE = 5;
  37. const int THRESHOLD = 550; // Adjust this number to avoid noise when idle
  38. /*
  39. All the PulseSensor Playground functions.
  40. */
  41. PulseSensorPlayground pulseSensor;
  42. void setup() {
  43. /*
  44.  Use 115200 baud because that's what the Processing Sketch expects to read,
    
  45.  and because that speed provides about 11 bytes per millisecond.
    
  46.  If we used a slower baud rate, we'd likely write bytes faster than
    
  47.  they can be transmitted, which would mess up the timing
    
  48.  of readSensor() calls, which would make the pulse measurement
    
  49.  not work properly.
    
  50. */
  51. Serial.begin(115200);
  52. // Configure the PulseSensor manager.
  53. pulseSensor.analogInput(PIN_INPUT);
  54. pulseSensor.blinkOnPulse(PIN_BLINK);
  55. pulseSensor.fadeOnPulse(PIN_FADE);
  56. pulseSensor.setSerial(Serial);
  57. pulseSensor.setOutputType(OUTPUT_TYPE);
  58. pulseSensor.setThreshold(THRESHOLD);
  59. // Now that everything is ready, start reading the PulseSensor signal.
  60. if (!pulseSensor.begin()) {
  61. /*
    
  62.    PulseSensor initialization failed,
    
  63.    likely because our particular Arduino platform interrupts
    
  64.    aren't supported yet.
    
  65.    If your Sketch hangs here, try ProcessEverySample.ino,
    
  66.    which doesn't use interrupts.
    
  67. */
    
  68. for(;;) {
    
  69.   // Flash the led to show things didn't work.
    
  70.   digitalWrite(PIN_BLINK, LOW);
    
  71.   delay(50);
    
  72.   digitalWrite(PIN_BLINK, HIGH);
    
  73.   delay(50);
    
  74. }
    
  75. }
  76. }
  77. void loop() {
  78. /*
  79.  Wait a bit.
    
  80.  We don't output every sample, because our baud rate
    
  81.  won't support that much I/O.
    
  82. */
  83. delay(20);
  84. // write the latest sample to Serial.
  85. pulseSensor.outputSample();
  86. /*
  87.  If a beat has happened since we last checked,
    
  88.  write the per-beat information to Serial.
    
  89. */
  90. if (pulseSensor.sawStartOfBeat()) {
  91. pulseSensor.outputBeat();
  92. }
  93. }

When I run the sketch, I obtain the error โ€œunexpectedtoken:defโ€ and the program stops at: #define USE_ARDUINO_INTERRUPTS true.
Remember: This is Processing.
Any suggestion?
I will post now another question under another subject.

Translation

I am a teacher in Brazil, I am developing a compilation of scripts with Arduino educational practices, aimed at teachers without knowledge of Arduino and electronics. I would like to know if you allow me to translate the sketch provided by you, keeping the references and credits to you. Thank you!

Not working with Beetle Bluno

I've tried a couple of versions of your playground as well as switching between A0 and A1 and varying the threshold between 10 and 1024 without any luck. Any ideas?

Pulse Sensor priting high values

I connected the pulse sensor in my arduino, and its sending high values( From 300 to 500 bpms). I think it might be ASCII, but i'm not sure.

And I think the problem isn't the pulse sensor since I have already tested 2 different ones

`

// Variables
int PulseSensorPurplePin = 1;
int LED13 = 13;

int Signal;
int Threshold = 550;

// The SetUp Function:
void setup() {
pinMode(LED13,OUTPUT);
Serial.begin(9600);

}

// The Main Loop Function
void loop() {

Signal = analogRead(PulseSensorPurplePin);

Serial.println(Signal);

delay(100);

}
`

Pulse sensor with multiple coonections.

Hey,
Absolutely loved your product. I am currently building a project where we can detect bmp, display it on the LCD as well as send the data to the clouds via wifi module.

As the whole process is i.e detecting heartbeat, processing it, displaying it on LCD as well sending that data to the servers is generating a lot of delays. and due to which it is generating a lot of irregular bpm readings.
As uno have only serial communication line, I Tried using mega 2560 which allows me to use 2 separate baud rates (which I think can help me to get better results). but for now, pulseSensor library does not support Arduino mega 2560.

So to tackle this I am planning to use two Arduino (uno,mega) and connect them via i2c?
uno will detect the bpm and display it on LCD and mega will send that bmp to the servers.

So can you tell me is this idea viable? can this work and if not, what else do I need to do?
your input is highly appreciated.

would love to share the details of my work once completed.

Other methods of calculating BPM

Hey, I was wondering if there is another way of calculating a person's BPM without using the pulse sensor library. I know that you have to read the sensor, but I do not know how to continue after this.

getBeatsPerMinute is providing the o/p even when I am not touching the Sensor

Hi,

Issue:1
I am using the I2C 20X4 display to show the heart beat and what is happening that, first it shows 0 as heard beat, then after sometime it changes to any number up to 200+ also, even when I don't touch the sensor. My expectation is that I should have the heart beat as 0 and when I touch the sensor, then it should print the correct heartbeat on the LCD. I have used the following code and without even touching the sensor I am getting o/p on the display.

I have not included the LCD code. I did search on the internet on this issue, but I could not find any concrete solution.

Issue 2:
I am also facing an issue when I am using PulseSensor with DHT22 AM2302 3 pin sensor for Humidity. When I run the statement of pulseSensor.begin(). I am getting error on DHT sensor. If I comment the begin statement then I am able to read the DHT readings.

#define USE_ARDUINO_INTERRUPTS true
#include <PulseSensorPlayground.h>

const int PulseWire = 0;
void setup()
{
pulseSensor.analogInput(PulseWire);
pulseSensor.setThreshold(Threshold);
if (pulseSensor.begin()) {
Serial.println("We created a pulseSensor Object !");
}
}
void loop()
{

int myBPM = pulseSensor.getBeatsPerMinute();
if (pulseSensor.sawStartOfBeat()) {
Serial.println("โ™ฅ A HeartBeat Happened ! ");
Serial.print("BPM: ");
Serial.println(myBPM);
}
}

PulseSensorPlayground does not work on Arduino Mega 2650

I am using your example sketch called Getting_BPM_to_Monitor, it works on my Arduino UNO, but not on my Arduino Mega 2560. Why is that?

It does not even Serial print "We created a pulseSensor Object!" indicating that pulseSensor.begin() failed. The Serial Monitor is completely empty.

teensy 3.2

love the sensor and you library. thank you.

do you by any chance have plans to make the interrupt version work for the teensy 3.2 ?

I will give it a try myself using the IntervalTimer that ships with the teensy. But I thought you people might have something already in the pipeline.

thanks.

STOP PulseSensor.

Command PulseSensorPlayground.:begin() to START sequence.
How do I STOP the execution PulseSensor sequence?

getLastBeatTime()

Member function getLastBeatTime() is not working in arduino. While using this member function, arduino shows an error- 'class PulseSensorPlayground' has no member named 'getLastBeatTime'.I am using a arduino UNO. kindly help!

Understanding output values

on line 153 in examples/PulseSensor_BPM_alternative my serial monitar is printing 3 values separated by comma which among them is original heartbeat value

Clarification

The comments on the ATtiny need to be tidied up

#elif defined(AVR_ATtiny85)
GTCCR &= 0x81; // Disable PWM, don't connect pins to events
OCR1C = 0x7C; // Set the top of the count to 124
OCR1A = 0x7C; // Set the timer to interrupt after counting to 124
#if F_CPU == 16000000L
TCCR1 = 0x88; // Clear Timer on Compare, Set Prescaler to 128
#elif F_CPU == 8000000L
TCCR1 = 0x89; // Clear Timer on Compare, Set Prescaler to 256
#endif
bitSet(TIMSK,6); // Enable interrupt on match between TCNT1 and OCR1A
ENABLE_PULSE_SENSOR_INTERRUPTS;
return true;

nRF52832 support

Hi,

I'm trying to get the library work with my Adafruit Bluefruit Feather (nRF52832) but can't compile the sketches, I tried the PulseSensor_BPM_Alternative :

In file included from PulseSensor_Playground/src/PulseSensorPlayground.h:439:0,
                 from PulseSensor_Playground/src/PulseSensorPlayground.cpp:16:
PulseSensor_Playground/src/PulseSensorPlayground.cpp: In member function 'boolean PulseSensorPlayground::sawNewSample()':
PulseSensor_Playground/src/utility/Interrupts.h:71:45: error: 'cli' was not declared in this scope
 #define DISABLE_PULSE_SENSOR_INTERRUPTS cli()
                                             ^
PulseSensor_Playground/src/PulseSensorPlayground.cpp:105:5: note: in expansion of macro 'DISABLE_PULSE_SENSOR_INTERRUPTS'
     DISABLE_PULSE_SENSOR_INTERRUPTS;
     ^
PulseSensor_Playground/src/utility/Interrupts.h:72:44: error: 'sei' was not declared in this scope
 #define ENABLE_PULSE_SENSOR_INTERRUPTS sei()
                                            ^
PulseSensor_Playground/src/PulseSensorPlayground.cpp:108:5: note: in expansion of macro 'ENABLE_PULSE_SENSOR_INTERRUPTS'
     ENABLE_PULSE_SENSOR_INTERRUPTS;
     ^
exit status 1
Error compiling for board Adafruit Bluefruit nRF52832 Feather.

Any idea how can I get out of this ?

Cheers

High value readings when I have almost anything else in my code.

Hi - I'm trying to use the pulse sensor with a couple of other sensors and some outputs, but it seems like -- even though I am using the interrupts -- if there's anything much in the loop itself, I get very high readings. I had commented out the section reading the GSR sensor and the temp sensor and got reasonable readings, but as soon as I added it back in, they went very high again - I could see it go from 60-70 to 90 when I added additional code. Any thoughts as to what's going on? I was using it on a seeeduino lotus.

`#include <math.h>
#define USE_ARDUINO_INTERRUPTS true // Set-up low-level interrupts for most acurate BPM math.
#include <PulseSensorPlayground.h> // Includes the PulseSensorPlayground Library.

// Variables
const int PulseWire = A0; // PulseSensor PURPLE WIRE connected to ANALOG PIN 0
const int LED13 = 13; // The on-board Arduino LED, close to PIN 13.
int Threshold = 550; // Determine which Signal to "count as a beat" and which to ignore.
// Use the "Gettting Started Project" to fine-tune Threshold Value beyond default setting.
// Otherwise leave the default "550" value.
int myBPM;

PulseSensorPlayground pulseSensor; // Creates an instance of the PulseSensorPlayground object called "pulseSensor"

const int GSR = A2;
int sensorValue = 0;
int gsr_average = 0;
long gsr_timer = 0;
int gsr_reading_int = 5; //in millis
int gsr_counter = 0;
long gsr_sum = 0;

//temp sensor stuff
const int B = 4275; // B value of the thermistor
const int R0 = 100000; // R0 = 100k
const int pinTempSensor = A6; // Grove - Temperature Sensor connect to A0
int curtempreading = 0;

//other vars
long printtimer = 0;
int printinterval = 1000;
long loopmillis = 0;

void setup() {
Serial.begin(9600);

// Configure the PulseSensor object, by assigning our variables to it.
pulseSensor.analogInput(PulseWire);
pulseSensor.blinkOnPulse(LED13); //auto-magically blink Arduino's LED with heartbeat.
pulseSensor.setThreshold(Threshold);

// Double-check the "pulseSensor" object was created and "began" seeing a signal.
if (pulseSensor.begin()) {
Serial.println("We created a pulseSensor Object !"); //This prints one time at Arduino power-up, or on Arduino reset.
}
}

void loop() {
loopmillis = millis(); // so I only need to do it once per loop, I guess?
// Heart Rate
myBPM = pulseSensor.getBeatsPerMinute(); // Calls function on our pulseSensor object that returns BPM as an "int".
// "myBPM" hold this BPM value now.

/*
if (pulseSensor.sawStartOfBeat()) { // Constantly test to see if "a beat happened".
Serial.println("โ™ฅ A HeartBeat Happened ! "); // If test is "true", print a message "a heartbeat happened".
Serial.print("BPM: "); // Print phrase "BPM: "
Serial.println(myBPM); // Print the value inside of myBPM.
}*/

//GSR values

if (loopmillis > gsr_timer + gsr_reading_int) {
gsr_timer = loopmillis;
sensorValue = analogRead(GSR);
gsr_sum += sensorValue;
if (gsr_counter == 9) {
gsr_counter = 0;
gsr_average = gsr_sum / 10;
//Serial.println(gsr_average);
gsr_sum = 0;
} else {
gsr_counter++;
}

}

/*
//Temp reading
curtempreading = analogRead(pinTempSensor);

float R = 1023.0 / curtempreading - 1.0;
R = R0 * R;

float temperature = 1.0 / (log(R / R0) / B + 1 / 298.15) - 273.15; // convert to temperature via datasheet

//Serial.print("temperature = ");
//Serial.println(temperature);
*/
printinfo();

}

void printinfo() {
if(millis()>printtimer+printinterval){
printtimer = millis();
Serial.println("GSR: " + String(gsr_average) + " BPM: " + String(myBPM));
}
}
`

Any help is much appreciated, thanks!

Cannot get correct BPM while keep getting data from firebase

I am doing an IOT health alert project. However, I met a problem when keep checking the firebase data. The BPM seems become incorrect or even not detected, keep having zero. Is there any way I can modify the code to get better BPM?

#include <WiFi.h>
#include <IOXhop_FirebaseESP32.h>
#include<Wire.h>

// Set these to run example.
#define FIREBASE_HOST "xxx"
#define FIREBASE_AUTH "xxx"
#define WIFI_SSID "xxx"
#define WIFI_PASSWORD "xxx"
#define onboardLED 2

#define PROCESSING_VISUALIZER 1
#define SERIAL_PLOTTER  2

//  Variables
#define ESP32
int pulsePin = 34;                 // Pulse Sensor purple wire connected to analog pin 34 , ADC6
// Volatile Variables, used in the interrupt service routine!
volatile int BPM;                   // int that holds raw Analog in 0. updated every 2mS
volatile int Signal;                // holds the incoming raw data
volatile int IBI = 600;             // int that holds the time interval between beats! Must be seeded!
volatile boolean Pulse = false;     // "True" when User's live heartbeat is detected. "False" when not a "live beat".
volatile boolean QS = false;        // becomes true when Arduoino finds a beat.
static int outputType = SERIAL_PLOTTER;
volatile int newbpmstatus = 0, oldbpmstatus = 0, bpmalertcd = 0;
int bpmalertflg = 0;
int sentfb = 0;

volatile int rate[10];                    // array to hold last ten IBI values
volatile unsigned long sampleCounter = 0;          // used to determine pulse timing
volatile unsigned long lastBeatTime = 0;           // used to find IBI
volatile int P = 512;                     // used to find peak in pulse wave, seeded
volatile int T = 512;                     // used to find trough in pulse wave, seeded
volatile int thresh = 530;                // used to find instant moment of heart beat, seeded
volatile int amp = 0;                   // used to hold amplitude of pulse waveform, seeded
volatile boolean firstBeat = true;        // used to seed rate array so we startup with reasonable BPM
volatile boolean secondBeat = false;      // used to seed rate array so we startup with reasonable BPM



hw_timer_t * timer = NULL;
volatile SemaphoreHandle_t timerSemaphore;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

hw_timer_t * timer1 = NULL;
volatile SemaphoreHandle_t timerSemaphore1;
portMUX_TYPE timerMux1 = portMUX_INITIALIZER_UNLOCKED;

//MPU6050----------------------------------------------------------------------------------------------------------------------------------------------------------
const int MPU_addr = 0x68; // I2C address of the MPU-6050
int16_t AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;
float ax = 0, ay = 0, az = 0, gx = 0, gy = 0, gz = 0;

//int data[STORE_SIZE][5]; //array for saving past data
//byte currentIndex=0; //stores current data array index (0-255)
boolean fall = false; //stores if a fall has occurred
boolean trigger1 = false; //stores if first trigger (lower threshold) has occurred
boolean trigger2 = false; //stores if second trigger (upper threshold) has occurred
boolean trigger3 = false; //stores if third trigger (orientation change) has occurred

byte trigger1count = 0; //stores the counts past since trigger 1 was set true
byte trigger2count = 0; //stores the counts past since trigger 2 was set true
byte trigger3count = 0; //stores the counts past since trigger 3 was set true
int angleChange = 0;
int sendAM2fb = 0;
volatile int fbcheckoperation = 0;

//------------------------------------------------------------------------------------------------------------------------------------------------------------------
void IRAM_ATTR onTimer() {
  portENTER_CRITICAL_ISR(&timerMux);
  getPulse();
  portEXIT_CRITICAL_ISR(&timerMux);
  xSemaphoreGiveFromISR(timerSemaphore, NULL);
}

void IRAM_ATTR onTimer1() {
  portENTER_CRITICAL_ISR(&timerMux1);
  fbcheckoperation = 1;
  portEXIT_CRITICAL_ISR(&timerMux1);
  xSemaphoreGiveFromISR(timerSemaphore1, NULL);
}

void getPulse()
{
  // read the Pulse Sensor, bits of ESP32 ADC ch is 4 times larger
  sampleCounter += 2;                         // keep track of the time in mS with this variable
  int N = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise

  //  find the peak and trough of the pulse wave
  if (Signal < thresh && N > (IBI / 5) * 3) { // avoid dichrotic noise by waiting 3/5 of last IBI
    if (Signal < T) {                       // T is the trough
      T = Signal;                         // keep track of lowest point in pulse wave
    }
  }

  if (Signal > thresh && Signal > P) {        // thresh condition helps avoid noise
    P = Signal;                             // P is the peak
  }                                        // keep track of highest point in pulse wave

  //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
  // signal surges up in value every time there is a pulse
  if (N > 250) {                                  // avoid high frequency noise
    if ( (Signal > thresh) && (Pulse == false) && (N > (IBI / 5) * 3) ) {
      Pulse = true;                               // set the Pulse flag when we think there is a pulse
      IBI = sampleCounter - lastBeatTime;         // measure time between beats in mS
      lastBeatTime = sampleCounter;               // keep track of time for next pulse

      if (secondBeat) {                      // if this is the second beat, if secondBeat == TRUE
        secondBeat = false;                  // clear secondBeat flag
        for (int i = 0; i <= 9; i++) {       // seed the running total to get a realisitic BPM at startup
          rate[i] = IBI;
        }
      }

      if (firstBeat) {                       // if it's the first time we found a beat, if firstBeat == TRUE
        firstBeat = false;                   // clear firstBeat flag
        secondBeat = true;                   // set the second beat flag
        sei();                               // enable interrupts again
        return;                              // IBI value is unreliable so discard it
      }


      // keep a running total of the last 10 IBI values
      word runningTotal = 0;                  // clear the runningTotal variable

      for (int i = 0; i <= 8; i++) {          // shift data in the rate array
        rate[i] = rate[i + 1];                // and drop the oldest IBI value
        runningTotal += rate[i];              // add up the 9 oldest IBI values
      }

      rate[9] = IBI;                          // add the latest IBI to the rate array
      runningTotal += rate[9];                // add the latest IBI to runningTotal
      runningTotal /= 10;                     // average the last 10 IBI values
      BPM = 60000 / runningTotal;             // how many beats can fit into a minute? that's BPM!
      QS = true;                              // set Quantified Self flag
      // QS FLAG IS NOT CLEARED INSIDE THIS ISR
    }
  }

  if (Signal < thresh && Pulse == true) {  // when the values are going down, the beat is over
    Pulse = false;                         // reset the Pulse flag so we can do it again
    amp = P - T;                           // get amplitude of the pulse wave
    thresh = amp / 2 + T;                  // set thresh at 50% of the amplitude
    P = thresh;                            // reset these for next time
    T = thresh;
  }

  if (N > 2500) {                          // if 2.5 seconds go by without a beat
    thresh = 530;                          // set thresh default
    P = 512;                               // set P default
    T = 512;                               // set T default
    lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date
    firstBeat = true;                      // set these to avoid noise
    secondBeat = false;                    // when we get the heartbeat back
    QS = false;
    BPM = 0;
    IBI = 600;                  // 600ms per beat = 100 Beats Per Minute (BPM)
    Pulse = false;
    amp = 100;                  // beat amplitude 1/10 of input range.

  }
}

void checkoperation()
{
  if (Firebase.getFloat("operation") == 1)
  {
    Firebase.setFloat("bpm", BPM);
    // handle error
    if (Firebase.failed()) {
      Serial.print("setting /number failed:");
      Serial.println(Firebase.error());
      return;
    }
    Firebase.setFloat("operation", 0 );
  }
}

void interruptSetup() { // CHECK OUT THE Timer_Interrupt_Notes TAB FOR MORE ON INTERRUPTS
  timerSemaphore = xSemaphoreCreateBinary();
  timer = timerBegin(0, 80, true);    // Use 1st timer of 4 (counted from zero).Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more info).
  timerAttachInterrupt(timer, &onTimer, true);// Attach onTimer function to our timer.
  timerAlarmWrite(timer, 2000, true);// Set alarm to call onTimer function every second (value in microseconds). Repeat the alarm (third parameter)
  timerAlarmEnable(timer);// Start an alarm

  timerSemaphore1 = xSemaphoreCreateBinary();
  timer1 = timerBegin(0, 80, true);    // Use 1st timer of 4 (counted from zero).Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more info).
  timerAttachInterrupt(timer1, &onTimer1, true);// Attach onTimer function to our timer.
  timerAlarmWrite(timer1, 1000000, true);// Set alarm to call onTimer function every second (value in microseconds). Repeat the alarm (third parameter)
  timerAlarmEnable(timer1);// Start an alarm
}

void setup() {
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(115200);             // we agree to talk fast!
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  Serial.print("connecting");
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(".");
    delay(500);
  }
  Serial.println();
  Serial.print("connected: ");
  Serial.println(WiFi.localIP());

  Firebase.begin(FIREBASE_HOST, FIREBASE_AUTH);
  interruptSetup();                 // sets up to read Pulse Sensor signal every 2mS
  pinMode(onboardLED, OUTPUT);
  digitalWrite(onboardLED, HIGH);
}

//  Where the Magic Happens
void loop() {
  if (fbcheckoperation == 1)
  {
    checkoperation();
    fbcheckoperation=0;
  }

  Signal = analogRead(pulsePin) / 4;
  if (BPM != 0 && BPM >= 60 && BPM <= 100)
  {
    newbpmstatus = 1;
  }
  else
  {
    newbpmstatus = 0;
  }
  if (newbpmstatus == oldbpmstatus)
  {
    if (newbpmstatus == 0)
    {
      bpmalertcd++;
      Serial.print("bpmalertcd: ");
      Serial.println(bpmalertcd);
    }
    else
    {
      bpmalertcd = 0;
    }
  }
  else
  {
    bpmalertcd = 0;
  }
  Serial.print(BPM);
  Serial.print(",");
  Serial.print(IBI);
  Serial.print(",");
  Serial.println(Signal);


  if (QS == true) {    // A Heartbeat Was Found


    // BPM and IBI have been Determined
    // Quantified Self "QS" true when arduino finds a heartbeat
    QS = false;                      // reset the Quantified Self flag for next time
  }
  if (bpmalertcd >= 2000 )
  {
    if (Firebase.getFloat("apr") == 0)
    {
      Firebase.setFloat("apr", 1);
      bpmalertcd = 0;
    }
    else
    {
      bpmalertcd = 0;
    }
  }
  oldbpmstatus = newbpmstatus;
  delay(20);                             //  take a break
  mpu_read();
  //2050, 77, 1947 are values for calibration of accelerometer
  // values may be different for you
  ax = (AcX - 2050) / 16384.00;
  ay = (AcY - 77) / 16384.00;
  az = (AcZ - 1947) / 16384.00;

  //270, 351, 136 for gyroscope
  gx = (GyX + 270) / 131.07;
  gy = (GyY - 351) / 131.07;
  gz = (GyZ + 136) / 131.07;

  // calculating Amplitute vactor for 3 axis
  float Raw_AM = pow(pow(ax, 2) + pow(ay, 2) + pow(az, 2), 0.5);
  int AM = Raw_AM * 10;  // as values are within 0 to 1, I multiplied
  // it by for using if else conditions

  Serial.println(AM);
  //Serial.println(PM);
  //delay(500);

  if (trigger3 == true) {
    trigger3count++;
    //Serial.println(trigger3count);
    if (trigger3count >= 10) {
      angleChange = pow(pow(gx, 2) + pow(gy, 2) + pow(gz, 2), 0.5);
      //delay(10);
      Serial.println(angleChange);
      if ((angleChange >= 0) && (angleChange <= 10)) { //if orientation changes remains between 0-10 degrees
        fall = true; trigger3 = false; trigger3count = 0;
        Serial.println(angleChange);
      }
      else { //user regained normal orientation
        trigger3 = false; trigger3count = 0;
        Serial.println("TRIGGER 3 DEACTIVATED");
      }
    }
  }
  if (fall == true) { //in event of a fall detection
    Serial.println("FALL DETECTED");
    digitalWrite(onboardLED, LOW);
    delay(20);
    digitalWrite(onboardLED, HIGH);
    fall = false;
    // exit(1);
  }
  if (trigger2count >= 6) { //allow 0.5s for orientation change
    trigger2 = false; trigger2count = 0;
    Serial.println("TRIGGER 2 DECACTIVATED");
  }
  if (trigger1count >= 6) { //allow 0.5s for AM to break upper threshold
    trigger1 = false; trigger1count = 0;
    Serial.println("TRIGGER 1 DECACTIVATED");
  }
  if (trigger2 == true) {
    trigger2count++;
    //angleChange=acos(((double)x*(double)bx+(double)y*(double)by+(double)z*(double)bz)/(double)AM/(double)BM);
    angleChange = pow(pow(gx, 2) + pow(gy, 2) + pow(gz, 2), 0.5); Serial.println(angleChange);
    if (angleChange >= 30 && angleChange <= 400) { //if orientation changes by between 80-100 degrees
      trigger3 = true; trigger2 = false; trigger2count = 0;
      Serial.println(angleChange);
      Serial.println("TRIGGER 3 ACTIVATED");
    }
  }
  if (trigger1 == true) {
    trigger1count++;
    if (AM >= 12) { //if AM breaks upper threshold (3g)
      trigger2 = true;
      Serial.println("TRIGGER 2 ACTIVATED");
      trigger1 = false; trigger1count = 0;
    }
  }
  if (AM <= 2 && trigger2 == false) { //if AM breaks lower threshold (0.4g)
    trigger1 = true;
    Serial.println("TRIGGER 1 ACTIVATED");
  }
  //It appears that delay is needed in order not to clog the port
  sendAM2fb++;
  if (sendAM2fb >= 1000)
  {
    Firebase.setFloat("am", AM);
    sendAM2fb = 0;
  }
  //  delay(100);
  //
}

void mpu_read() {
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr, 14, true); // request a total of 14 registers
  AcX = Wire.read() << 8 | Wire.read(); // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)
  AcY = Wire.read() << 8 | Wire.read(); // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ = Wire.read() << 8 | Wire.read(); // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp = Wire.read() << 8 | Wire.read(); // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX = Wire.read() << 8 | Wire.read(); // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY = Wire.read() << 8 | Wire.read(); // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ = Wire.read() << 8 | Wire.read(); // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)

}

How to display only bpm value on Nucleo 64 board?

Hi,

I tried some examples from Pulsesensor Playground, from the Pulsesensor_Nucleo, how can I display only BPM values on serial monitor? I tried the Pulsesensor_BPM and Getting_BPM_to_monitor, both yielded no result.

OS: Windows 10
Software used: Arduino v18.8

MKR1000_BPM_ALTERNATIVE :Edit

Hello! I test with this sensor with MKR1000

I understood that BPM_ALTERNATIVE code can print BPM on serial monitor

with MKR1000 but I want to see only BPM..

I thought that I need to edit pulsesensorserial.cpp to print BPM(not with IBI etc)

so I edited like

`/*
Formatting of Serial output from PulseSensors.
See https://www.pulsesensor.com to get started.

Copyright World Famous Electronics LLC - see LICENSE
Contributors:
Joel Murphy, https://pulsesensor.com
Yury Gitman, https://pulsesensor.com
Bradford Needham, @bneedhamia, https://bluepapertech.com

Licensed under the MIT License, a copy of which
should have been included with this software.

This software is not intended for medical use.
*/
#include "PulseSensorSerialOutput.h"

PulseSensorSerialOutput::PulseSensorSerialOutput() {
pOutput = NULL;
OutputType = SERIAL_PLOTTER;
}

void PulseSensorSerialOutput::setSerial(Stream &output) {
pOutput = &output;
}

Stream *PulseSensorSerialOutput::getSerial() {
return pOutput;
}

void PulseSensorSerialOutput::setOutputType(byte outputType) {
OutputType = outputType;
}

void PulseSensorSerialOutput::outputSample(PulseSensor sensors[], int numSensors) {
if (!pOutput) {
return; // no serial output object has been set.
}

switch (OutputType) {
case SERIAL_PLOTTER:
if (numSensors == 1) {
pOutput->print(sensors[0].getBeatsPerMinute());
// pOutput->print(F(","));
// pOutput->print(sensors[0].getInterBeatIntervalMs());
pOutput->print(F(","));
pOutput->println(sensors[0].getLatestSample());
} else {
for (int i = 0; i < numSensors; ++i) {
if (i != 0) {
pOutput->print(F(","));
}
pOutput->print(sensors[i].getLatestSample());
// Could output BPM and IBI here.
}
pOutput->println();
}
break;

case PROCESSING_VISUALIZER:
  // Don't print bpm and ibi here; they're printed per-beat.
  if (numSensors == 1) {
    outputToSerial('S', sensors[0].getLatestSample());
  } else {
    // PulseSensor 0 = a; #1 = b; #2 = c, etc.
    for(int i = 0; i < numSensors; ++i){
      outputToSerial('a' + i, sensors[i].getLatestSample());
    }
  }
  break;

default:
  // unknown output type: no output
  break;

}
}

void PulseSensorSerialOutput::outputBeat(PulseSensor sensors[], int numSensors, int sensorIndex) {
if (!pOutput) {
return; // no serial output object has been set.
}

switch (OutputType) {
case SERIAL_PLOTTER:
/*
The plotter doesn't understand occasionally-printed data,
so we print nothing per-beat.
*/
break;

case PROCESSING_VISUALIZER:
  if (numSensors == 1) {
    outputToSerial('B', sensors[sensorIndex].getBeatsPerMinute());
   // outputToSerial('Q', sensors[sensorIndex].getInterBeatIntervalMs());
  } else {
    // PulseSensor 0 = A, M; #1 = B, N; etc.
    outputToSerial('A' + sensorIndex
      , sensors[sensorIndex].getBeatsPerMinute());
    //outputToSerial('M' + sensorIndex
      //, sensors[sensorIndex].getInterBeatIntervalMs());
  }
  break;

default:
  // unknown output type: no output
  break;

}
}

// // testing feedback
// void printThreshSetting() {
//
// }

void PulseSensorSerialOutput::outputToSerial(char symbol, int data) {
if (!pOutput) {
return; // no serial output object has been set.
}

pOutput->print(symbol);
pOutput->println(data);
}
`

but it still prints all in serial monitor..

How can I get only BPM value from it to store value in one variable& print in serial monitor?

Display BPM only one time!

Hi! I'm doing a project with a pulse sensor, I'm new to arduino too and i got some proplems. Is there anyway to just send 20 first BPM value to serial (to get the stable value) and display the 20th BPM to LCD (just display 1 time)? Or get the BPM just in 10 seconds, display the BPM that appear oftenly and then stop? All i need is just get 1 BPM value when i think it's stable . How can I do that?
Thanks for reading this! Sorry for my bad English.

PulseSensor 3.3V

Hi!
Great work with the PulseSensorPlayground library :)
However, I'm having some issues implementing the method described below to use the sensor with 3.3V rather than 5V.

Screenshot 2019-04-05 at 17 36 49

The page says that the PulseSensor_Amped_Arduino arduino code (where I found the interrupt tab) 'has been superseded' by this library: Link (https://www.eecs.yorku.ca/~jr/res/m/MD/PulseSensor.pdf)
However, I have been unable to find the code I need to change in the PulseSensorPlayground library.

Any guidance would be greatly appreciated.
Thanks!

MKR1000 compatibility issue

I think I found a compatibility issue between the PulseSensorPlayground library and the MKR1000. Different from the NANO, where the last version of PulseSensorPlayground (1.4.4) works perfectly with all provided examples, with MKR1000 I cannot compile examples whenever using PulseSensorPlayground versions above 1.2.3.
Please see the error below, when trying to compile "PullseSensor_BPM_Alternative" with 1.4.4:


C:\Users\marce\OneDrive\Documents\Arduino\libraries\PulseSensor_Playground\src\PulseSensorPlayground.cpp: In member function 'int PulseSensorPlayground::getPulseAmplitude(int)':

C:\Users\marce\OneDrive\Documents\Arduino\libraries\PulseSensor_Playground\src\PulseSensorPlayground.cpp:213:5: error: return-statement with no value, in function returning 'int' [-fpermissive]

 return; // out of range.

 ^

C:\Users\marce\OneDrive\Documents\Arduino\libraries\PulseSensor_Playground\src\PulseSensorPlayground.cpp: In member function 'long unsigned int PulseSensorPlayground::getLastBeatTime(int)':

C:\Users\marce\OneDrive\Documents\Arduino\libraries\PulseSensor_Playground\src\PulseSensorPlayground.cpp:220:5: error: return-statement with no value, in function returning 'long unsigned int' [-fpermissive]

 return; // out of range.

 ^

exit status 1
Error compiling for board Arduino/Genuino MKR1000.

This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

How to get Pulse Sensor working properly

I attached a pulse sensor to an Arduino Uno as suggested here. As code I used the GettingStartedProject as well as PulseSensor_BPM as well as this easy sketch:

void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}

void loop() {
// put your main code here, to run repeatedly:
Serial.println(analogRead(1));
}

Now to the problem: Somehow it seems to work, but not in the intended way. When I move i.e. the finger tip above the sensor, I get different values in the serial plotter. But when I put my finger on the sensor as intended, I get more or less the same value all the time. If the + is connected to 3.3V it ranges between 334 and 337, if it's connected to 5 V the values are between 507 and 511.

I thought maybe the sensor is defect, but another one behaves the same way. And what ist strange to me is that it gives me other values if you change the distance betweeen the sensor and a thing in front of it.

Any ideas what could be the problem?

Is there a way to simply get a numeric BPM

I'm looking for how to just pull the BPM number, not plot it on a graph but all the BPM sketches have a graphing output.

I'm assuming instead of calling pulseSensor.outputBeat() there's a way just to call for the numeric BPM?

What is the most accurate method for calculating BPM within a duration of 10s

So I want to calculate the BPM of many people within a duration of 10s, and I do not want to constantly adjust the threshold.

Would the best way be using the PulseSensor library and doing something as simple as:

while (millis() - startTime < 10000)
  {
    int BPM = pulseSensor.getBeatsPerMinute(); 
  }

Then the BPM of the person will be the value of the BPM variable after the while loop is completed?

Pulse sensor interfering with other sensor readings

Greetings,

I have encountered a rather strange issue while using two sensors and was hoping for some help. The two sensors of which I speak are as follows:

  1. a Galvanic skin response sensor (measuring skin conductivity)
    link: http://wiki.seeedstudio.com/Grove-GSR_Sensor/

  2. the Pulse sensor to measure heart rate
    https://pulsesensor.com/

So, the issue is as follows:

When i connect the sensors to analog slots (GSR on A0, and pulse sensor on A2 specifically), I experience readings that seem to suggest that the both data streams from the GSR and pulse sensor are interfering with one another (i.e. the pulse readings influence the GSR sensor's readings). Please see the images for clarification.

https://imgur.com/a/XO4amjk

In the images, the pulse readings is the orange curve, and the GSR reading the dark blue curve.

I suspect it is interference within the Arduino and because all of these screenshots were taken while I was not wearing the GSR sensor.

One observation I have made was that the interference only starts when the pulse rate (orange curve) increases it's amplitude (as shown in attachment 2). As we can see, during low amplitude readings, no interference is present (e.g. in attachment 3). Similarly, in attachment 4, we notice the only time the GSR reading spikes up (dark blue curve) is when a large amplitude pulse reading simultaneously occurs (orange curve).

Please find the code I am using below.

#define USE_ARDUINO_INTERRUPTS false
#include <PulseSensorPlayground.h>

const int GSR=A0;
const int PULSE_INPUT=A2;

const int OUTPUT_TYPE = SERIAL_PLOTTER;
const int THRESHOLD = 550;  
int sensorValue=0;
int gsr_average=0;

byte samplesUntilReport;
const byte SAMPLES_PER_SERIAL_SAMPLE = 10;

/* load pulseSensor library */
PulseSensorPlayground pulseSensor;

void setup() {
  Serial.begin(115200);
  
  /* ===== Setting up the pulse sensor ===== */
  pulseSensor.analogInput(PULSE_INPUT);
  pulseSensor.setSerial(Serial);
  pulseSensor.setOutputType(OUTPUT_TYPE);
  pulseSensor.setThreshold(THRESHOLD);
  // Skip the first SAMPLES_PER_SERIAL_SAMPLE in the loop().
  samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;
}

void loop() {

    /* ========== Collecting data from the GSR sensor ========== */
    long sum=0;
    //Average 10 measurements to reduce noise
    for(int i=0;i<10;i++) {          
      sensorValue=analogRead(GSR);
      sum += sensorValue;
      }
   gsr_average = sum/10;
 
  if (pulseSensor.sawNewSample()) {
    /*
       Every so often, send the latest Sample.
       We don't print every sample, because our baud rate
       won't support that much I/O.
    */
    if (--samplesUntilReport == (byte) 0) {
      samplesUntilReport = SAMPLES_PER_SERIAL_SAMPLE;

      /* outputs GSR readings along with pulse readings in the same line, separated by commas */
      pulseSensor.outputSample(gsr_average);
    }
  }
}

Any help would be greatly appreciated! I have been trying to figure this out for a while now..

EDIT: Fixed image URL

Pulse sensor w/Teensy board

Hi,

After running into some technical limitations I picked up a Teensy board to experiment with. I'm using the pulse-sensor peripheral and I've found some good programs that I'd like to run on my board. I've confirmed that all my pieces work together by setting up my circuit on my breadboard, and running the other tutorial ino files, but when I use this project on the Arduino programs that I'd like to run I run into an exception like:

Arduino: 1.8.8 (Mac OS X), Board: "Teensy 3.5, Serial, 120 MHz, Faster, US English"

Interrupt:28:5: error: expected constructor, destructor, or type conversion before '(' token
 ISR(TIMER2_COMPA_vect){                         // triggered when Timer2 counts to 124
     ^
/Users/dsiah/Documents/Arduino/pamp/PulseSensorAmped_Arduino_1.5.0/Interrupt.ino: In function 'void interruptSetup()':
Interrupt:18:3: error: 'TCCR2A' was not declared in this scope
   TCCR2A = 0x02;     // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
   ^
Interrupt:19:3: error: 'TCCR2B' was not declared in this scope
   TCCR2B = 0x06;     // DON'T FORCE COMPARE, 256 PRESCALER
   ^
Interrupt:20:3: error: 'OCR2A' was not declared in this scope
   OCR2A = 0X7C;      // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
   ^
Interrupt:21:3: error: 'TIMSK2' was not declared in this scope
   TIMSK2 = 0x02;     // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A
   ^
/Users/dsiah/Documents/Arduino/pamp/PulseSensorAmped_Arduino_1.5.0/Interrupt.ino: At global scope:
Interrupt:28:4: error: expected constructor, destructor, or type conversion before '(' token
 ISR(TIMER2_COMPA_vect){                         // triggered when Timer2 counts to 124
    ^
exit status 1
expected constructor, destructor, or type conversion before '(' token
/Users/dsiah/Documents/Arduino/pamp/PulseSensorAmped_Arduino_1.5.0/PulseSensorAmped_Arduino_1.5.0.ino

After some research i tried some things, including adding the correct imports:

#include <avr/io.h>
#include <avr/interrupt.h>

And when I tried to see if it wasn't picking up the avr header files i tried a bogus import and it sniped that, so I know the compiler is at least finding the header files, but this doesn't explain why the exception remains. I know this has something to do with interrupts on Teensy, but haven't had any stronger leads yet. Any help is greatly appreciated!

Two pulse sensor with servo morter doesn't work

Hi,

I'm following your Playground source code of "TwoPulseSensors_On_Onearduino" and "PulseSensor_Servo" and trying to create a project by combine the two example into "two pulse Sensor with a Servo" project.

However if I combine the both sample codes, the Arduino seems doesn't work, From my investigation, it appears if I remove the servo.h from header, the code would start working. below code is simply added Servo.h and created a variable in the sample code of "TwoPulseSensors_On_Onearduino", however the code won't work and Arduino would stop after a while. Do you have any idea ?

Env
Arduino IDE version 1.8.5.
Arduino Uno R3

// if I remove this Servo.h and remove the relevant sarvo variables, the code start working.
#include <Servo.h>

#define USE_ARDUINO_INTERRUPTS true
#include <PulseSensorPlayground.h>

const int OUTPUT_TYPE = SERIAL_PLOTTER;

const int PULSE_SENSOR_COUNT = 2;

const int PULSE_INPUT0 = A0;
const int PULSE_BLINK0 = 13;    // Pin 13 is the on-board LED
const int PULSE_FADE0 = 5;

const int PULSE_INPUT1 = A1;
const int PULSE_BLINK1 = 8;
const int PULSE_FADE1 = 11;

const int THRESHOLD = 550;   // Adjust this number to avoid noise when idle

PulseSensorPlayground pulseSensor(PULSE_SENSOR_COUNT);

Servo heart;
const int SERVO_PIN = 6;
int pos = 0;

void setup() {
  Serial.begin(250000);
  heart.attach(SERVO_PIN);
  heart.write(pos);

  // Configure the PulseSensor manager.  
  pulseSensor.analogInput(PULSE_INPUT0, 0);
  pulseSensor.blinkOnPulse(PULSE_BLINK0, 0);
  pulseSensor.fadeOnPulse(PULSE_FADE0, 0);

  pulseSensor.analogInput(PULSE_INPUT1, 1);
  pulseSensor.blinkOnPulse(PULSE_BLINK1, 1);
  pulseSensor.fadeOnPulse(PULSE_FADE1, 1);

  pulseSensor.setSerial(Serial);
  pulseSensor.setOutputType(OUTPUT_TYPE);
  pulseSensor.setThreshold(THRESHOLD);

  // Now that everything is ready, start reading the PulseSensor signal.
  if (!pulseSensor.begin()) {
    for(;;) {
     // Flash the led to show things didn't work.
      digitalWrite(PULSE_FADE0, LOW);
      digitalWrite(PULSE_FADE1, LOW);
      delay(50);
      digitalWrite(PULSE_FADE0, HIGH);
      digitalWrite(PULSE_FADE1, HIGH);
      delay(50);
    }
  }
}

void loop() {
  delay(20);

  // write the latest sample to Serial.
  pulseSensor.outputSample();

  for (int i = 0; i < PULSE_SENSOR_COUNT; ++i) {
    if (pulseSensor.sawStartOfBeat(i)) {
      pulseSensor.outputBeat(i);
    }
  }
}

thanks

BPM is 150+

I use BPM alternative source code on arduino 101(intel curie) board.
BPM is not stable...
image
What is problem??
I want stable value. Please help me.. :(

Hello, I have a problem, please help me.

Hello. I want to see the BPM on the OLED(SSD1306).
But I have problems, There are errer messages.
What can I do? please help me,

C:\Users\13Z940\AppData\Local\Temp\ccbjC5JN.ltrans1.ltrans.o: In function `begin':

C:\Users\13Z940\Documents\Arduino\libraries\PulseSensorPlayground-master\src/PulseSensorPlayground.cpp:56: undefined reference to `PulseSensorPlayground::UsingInterrupts'

C:\Users\13Z940\Documents\Arduino\libraries\PulseSensorPlayground-master\src/PulseSensorPlayground.cpp:57: undefined reference to `PulseSensorPlaygroundSetupInterrupt()'

collect2.exe: error: ld returned 1 exit status

exit status 1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.