Pulse Sensor Amped without Processing

Hi,
can I use the Pulse Sensor on a Arduino Leoardo without Processing?

Thank you

What Pulse Sensor would that be ?

Do you have some Idea for my Problem ?

Sandmannn:
Do you have some Idea for my Problem ?

When I look at the Arduino code example for that sensor at http://pulsesensor.com/pages/pulse-sensor-amped-arduino-v1dot1 I see that the sensor is read by “analogRead()” within a timer interrupt:

ISR(TIMER2_COMPA_vect){ 
  Signal = analogRead(pulsePin);

Every Arduino board is able to deal with timer interrupts and the analogRead() function.

I even see that there are additional hints how the programming example needs to be changed to work with 32U4 Arduinos like the ‘Leonardo’ board:

The only other thing you will need is the correct ISR vector in the next step.
ATmega32u4 devices use ISR(TIMER1_COMPA_vect)

As far as I see, the open-source vizualizing tool/language ‘Processing’ is only needed for visualizing data on a PC.

As the example software comes with full source, you can off course change the source code, so that your results are not visualized with Processing, but perhaps only sent to the Arduino serial monitor or to a text LCD display.

Programming is up to you, I’d say, except you’d like to use the example program exactly how it is provided as an programming example.

Sorry but I'm quite a beginner,

so what i must change in der example software to see the heart rate in the serial monitor.

Thank you

Sandmannn:
so what i must change in der example software to see the heart rate in the serial monitor.

Both changes needed to make the sketch work with 32U4 controllers like the LEONARDO are clearly notified on the page I linked in my last reply.

Did you do those two changes regarding the use of a timer interrupt in the source code?

If you want no further processing of data with the "Processing" environment, just delete sending the "Signal" within the loop and just send BPM and IBI when they are detected:

Untested changes:

void loop(){
//  sendDataToProcessing('S', Signal); 
  if (QS == true){                                     
//    sendDataToProcessing('B',BPM); 
//    sendDataToProcessing('Q',IBI);
    Serial.print(BPM);
    Serial.print('\t');
    Serial.println(IBI);
    fadeVal = 255;    
    QS = false;                        
   }
   ledFadeToBeat();
   delay(20);                          
}

The sketch will only show data, if a pulse could be detected.
No pulse detected = No data sent

And also watch out for the baud rate set in the sketch: The baud rate in the sketch MUST match the baud rate in the serial monitor. Wrong baudrate = You see nothing.

Maximum baudrate for the serial monitor is 115200.

If you have problems with getting it all to work, just start with a simple sketch showing some raw data from the pulse sensor. Here is a test sketch showing raw data from an analogue input for 30 seconds:

#define PULSEPIN A0  // Pulse Sensor purple wire connected to analog pin A0

void setup() {
  Serial.begin(115200);
  Serial.println();
  Serial.println("Start reading data");
}

unsigned long lastADCsample;
unsigned long numSamples;
void loop() 
{
  long now=micros();
  if (now> 30000000L) // 30000000L µs = 30 seconds
  { // stop program after 30 seconds
    Serial.print("Time: ");Serial.println(now/1000000.0,6);
    Serial.print("Samples: ");Serial.println(numSamples);
    Serial.println("Finished - END");
    while(1);
  }
  else if (now-lastADCsample>=1000)
  {
    lastADCsample+=1000;
    Serial.println(analogRead(PULSEPIN)>>2); // reduce ADC resolution to 8 bit
    numSamples++;
  }
}

If you still have trouble, give it a try, and post some seconds of data so that I can have a look what data you have.

thank you for your quick response,

now i have two problems:

fadeVal = 255;

is not declared in this scope (picture in the attach)

  1. after i uploaded the sample sketch on the arduino, the arduino is a unknown device for my pc and so can’t upload a new sketch. :fearful:

Thank you

Sandmannn:
thank you for your quick response,

now i have two problems:

I think the number of problems you have is much higher than two.

First problem: The Arduino UNO is the board for beginner 'Newbies'. All of the example sketches are made for the UNO. You purchase a different board, the LEONARDO, and many examples are NOT made for the LEONARDO as it is a bit different. So many example codes may need changes, to be adapted to the Leonardo board. Including the example for your heartbeat sensor.

Second problem: You are unable to program the changes needed. Why that? The changes needed for the Leonardo are on the page. I sent you the link!

Third problem: You never answer any queries. In my last posting I asked:

Did you do those two changes regarding the use of a timer interrupt in the source code?

You did not answer that, but instead I read:

fadeVal = 255; is not declared in this scope
and
after i uploaded the sample sketch on the arduino, the arduino is a unknown device

How can you upload a sketch that even does NOT COMPILE?
This is NOT POSSIBLE!
You can only upload a sketch if is has been compiled free of errors.
So if 'fadeval' is not declared, you must have done something with the original code, that 'fadeval' is not declared any longer. And if you afterwards could compile the sketch, you must have done some corrections or disimprovements to the worse, that the sketch could be compiled.

Fourth problem: You are sending images of screens instead of sending error messages in full text. Do not send images of error messages, but copy the text error message into the clipboard of your PC and insert the message into your forums posting!

Fifth problem: After all your mistakes you made like "uploading wrong code to the wrong board" it looks like you have locked yourself out from the Leonardo, so that you are unable to upload any sketch to the device.

So you would have to do this to get control back over your Leonardo board:

  • Load a 100% working sketch into to IDE like the "Blink" or "BareMinimum" sketch
  • Compile and upload the sketch using 'upload using manual reset'

After you have managed yourself being locked out from the Leonardo, the "auto-reset upload" will not work any longer and you need the "manual reset upload".

Do you know how to do that?

OK,

third problem: 1.I have changed the timer interrupt in the source code for the leonardo.

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 = 512;                // used to find instant moment of heart beat, seeded
volatile int amp = 100;                   // 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


void interruptSetup(){     
  // Initializes Timer2 to throw an interrupt every 2mS.
  TCCR0A = 0x02;     // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
  TCCR0B = 0x04;     // DON'T FORCE COMPARE, 256 PRESCALER 
  OCR0A = 0X7C;      // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
  TIMSK0 = 0x02;     // ENABLE INTERRUPT ON MATCH BETWEEN TIMER2 AND OCR2A
  sei();                // MAKE SURE GLOBAL INTERRUPTS ARE ENABLED      
} 


// THIS IS THE TIMER 2 INTERRUPT SERVICE ROUTINE. 
// Timer 2 makes sure that we take a reading every 2 miliseconds
ISR(TIMER1_COMPA_vect){                         // triggered when Timer2 counts to 124
  cli();                                      // disable interrupts while we do this
  Signal = analogRead(pulsePin);              // read the Pulse Sensor 
  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
      digitalWrite(blinkPin,HIGH);                // turn on pin 13 LED
      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
    digitalWrite(blinkPin,LOW);            // turn off pin 13 LED
    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 = 512;                          // 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
  }

  sei();                                   // enable interrupts when youre done!
}// end isr
  1. I upload the source code without
void loop(){
//  sendDataToProcessing('S', Signal); 
  if (QS == true){                                     
//    sendDataToProcessing('B',BPM); 
//    sendDataToProcessing('Q',IBI);
    Serial.print(BPM);
    Serial.print('\t');
    Serial.println(IBI);
    fadeVal = 255;    
    QS = false;                        
   }
   ledFadeToBeat();
   delay(20);                          
}

that change, so the sketch can compile.

fourth problem:

This report would have more information with
“Show verbose output during compilation”
enabled in File > Preferences.
Arduino: 1.0.6 (Windows NT (unknown)), Board: “Arduino Leonardo”
PulseSensorAmped_Arduino_1dot2.ino: In function ‘void loop()’:
PulseSensorAmped_Arduino_1dot2:67: error: ‘fadeVal’ was not declared in this scope

fitht problem: now my arduino leonardo works again.

Sandmannn:
PulseSensorAmped_Arduino_1dot2:67: error: 'fadeVal' was not declared in this scope

Then comment out the line by setting comment slashes in front of it:

//    fadeVal = 255;

If the variable is unknown at compile time, most likely it's never used for anything.

Sandmannn:
fitht problem: now my arduino leonardo works again.

Congratulations!

BTW: If you had decided for an UNO instead a LEONARDO, the lock-out problem would never occur: Only the 32U4 based boards like LEONARDO and MICRO can be programmed to lock-out the user. Boards based on Atmega328 like UNO can always be programmed, even if you compiled the silliest code and uploaded to the board. At most you would have to disconnect all connected hardware from the board before you can upload to an UNO board, if upload fails. With LEONARDO it's different and you may need "manual" upload to unlock the lock-out.

Great,

but now the Serial Monitor show me that numers.

Sandmannn:
but now the Serial Monitor show me that numers.

That's what you print from the loop:

    Serial.print(BPM);
    Serial.print('\t');
    Serial.println(IBI);

BPM stands for "Beats Per Minute". This is the first number in each row.

As the 'BPM' number is wavering up and down, your signal is most likely of poor quality. Perhaps sensor badly conneted. Or a bad sensor. Or a bad software calculating BPM badly.

And if you don't know what IBI is, I don't know either.
Perhaps: RTFM

P.S.: Didn't I already tell you NOT to post screenshot images of text messages in this forum?
Instead: Mark and copy the text you want to post into the clipboard, then insert text into a forums posting from the clipboard.

If you don't know about clipbpard functions of your PC, as a starting point please read Wikipedia Clipboard (computing)

So actually i must get my heartbeat with  Serial.print(BPM); ?

Sandmannn:
So actually i must get my heartbeat with

  Serial.print(BPM);

?

That's correct.

But I don't know how that value is calculated.

Maybe it's a "raw BPM" value that's calculated just from the time difference between the last two beats detected: In that case the value is hopping very much up and down, as the time between two heartbeats is fluctuating very much.

Or it's a BMP value that is already filtered by a low-pass filter, so that you might get and "average" calculated on the time difference averaged for more than on beat.

So if the BPM shown is just calculated from the time difference of two beats, that's some kind of "raw data" and you need to do the low-pass filtering by yourself.

And if the BPM shown is already low-pass filtered, it's the actual BPM rate.

As you have the full source code and also comments to the source ==> Go an find out what you have!

If you have "raw data" maybe it needs further processing (low-pass filtering) to get a more stable value.

guys exactly referring to the above code if we need to set-up a couter to count pulses , where exactly do we kick in to set up the counter ?
i needed help in this perticular aspect

Hi, I have a similar problem with the same Pulse sensor Amped. I want to show the BMP on a display (oled 128x64). I read through the comments and I understood that i need to change the source code so it will show it on my display. But I where exactly I need to do a change. Can someone help me pls?
This is the code which i am using

/*  Pulse Sensor Amped 1.4    by Joel Murphy and Yury Gitman   http://www.pulsesensor.com

----------------------  Notes ----------------------  ---------------------- 
This code:
1) Blinks an LED to User's Live Heartbeat   PIN 13
2) Fades an LED to User's Live HeartBeat
3) Determines BPM
4) Prints All of the Above to Serial

Read Me:
https://github.com/WorldFamousElectronics/PulseSensor_Amped_Arduino/blob/master/README.md   
 ----------------------       ----------------------  ----------------------
*/

//  Variables
int pulsePin = 0;                 // Pulse Sensor purple wire connected to analog pin 0
int blinkPin = 13;                // pin to blink led at each beat
int fadePin = 5;                  // pin to do fancy classy fading blink at each beat
int fadeRate = 0;                 // used to fade LED on with PWM on fadePin

// 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.

// Regards Serial OutPut  -- Set This Up to your needs
static boolean serialVisual = true;   // Set to 'false' by Default.  Re-set to 'true' to see Arduino Serial Monitor ASCII Visual Pulse 


void setup(){
  pinMode(blinkPin,OUTPUT);         // pin that will blink to your heartbeat!
  pinMode(fadePin,OUTPUT);          // pin that will fade to your heartbeat!
  Serial.begin(115200);             // we agree to talk fast!
  interruptSetup();                 // sets up to read Pulse Sensor signal every 2mS 
   // IF YOU ARE POWERING The Pulse Sensor AT VOLTAGE LESS THAN THE BOARD VOLTAGE, 
   // UN-COMMENT THE NEXT LINE AND APPLY THAT VOLTAGE TO THE A-REF PIN
//   analogReference(EXTERNAL);   
}


//  Where the Magic Happens
void loop(){
  
    serialOutput() ;       
    
  if (QS == true){     // A Heartbeat Was Found
                       // BPM and IBI have been Determined
                       // Quantified Self "QS" true when arduino finds a heartbeat
        digitalWrite(blinkPin,HIGH);     // Blink LED, we got a beat. 
        fadeRate = 255;         // Makes the LED Fade Effect Happen
                                // Set 'fadeRate' Variable to 255 to fade LED with pulse
        serialOutputWhenBeatHappens();   // A Beat Happened, Output that to serial.     
        QS = false;                      // reset the Quantified Self flag for next time    
  }
     
  ledFadeToBeat();                      // Makes the LED Fade Effect Happen 
  delay(20);                             //  take a break
}





void ledFadeToBeat(){
    fadeRate -= 15;                         //  set LED fade value
    fadeRate = constrain(fadeRate,0,255);   //  keep LED fade value from going into negative numbers!
    analogWrite(fadePin,fadeRate);          //  fade LED
  }/code]

Can anyone help plss

But I where exactly I need to do a change.

Where do you get/have the value you want to display on the LCD? Why can't you simply add the code to write to the LCD there?

I changed the code now, and add the display code to it.
These are the values to show it on the display, but its not working…

display.clearDisplay();

  • display.setCursor(0,0);*
  • display.print("Heart Rate: ");*
  • display.println(BPM);*
/*  Pulse Sensor Amped 1.4    by Joel Murphy and Yury Gitman   http://www.pulsesensor.com

----------------------  Notes ----------------------  ---------------------- 
This code:
1) Blinks an LED to User's Live Heartbeat   PIN 13
2) Fades an LED to User's Live HeartBeat
3) Determines BPM
4) Prints All of the Above to Serial

Read Me:
https://github.com/WorldFamousElectronics/PulseSensor_Amped_Arduino/blob/master/README.md   
 ----------------------       ----------------------  ----------------------
*/
//display
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

//  Variables
int pulsePin = 0;                 // Pulse Sensor purple wire connected to analog pin 0
int blinkPin = 13;                // pin to blink led at each beat
int fadePin = 5;                  // pin to do fancy classy fading blink at each beat
int fadeRate = 0;                 // used to fade LED on with PWM on fadePin

// 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.

// display
#define OLED_MOSI   9
#define OLED_CLK   10
#define OLED_DC    11
#define OLED_CS    12
#define OLED_RESET 13

Adafruit_SSD1306 display(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);


// Regards Serial OutPut  -- Set This Up to your needs
static boolean serialVisual = true;   // Set to 'false' by Default.  Re-set to 'true' to see Arduino Serial Monitor ASCII Visual Pulse 


void setup(){
  //pinMode(blinkPin,OUTPUT);         // pin that will blink to your heartbeat!
  //pinMode(fadePin,OUTPUT);          // pin that will fade to your heartbeat!
  display.begin(SSD1306_SWITCHCAPVCC); //display
  Serial.begin(115200);             // we agree to talk fast!
  interruptSetup();                 // sets up to read Pulse Sensor signal every 2mS 
   // IF YOU ARE POWERING The Pulse Sensor AT VOLTAGE LESS THAN THE BOARD VOLTAGE, 
   // UN-COMMENT THE NEXT LINE AND APPLY THAT VOLTAGE TO THE A-REF PIN
//   analogReference(EXTERNAL);   
}


//  Where the Magic Happens
void loop(){
  sendDataToProcessing('S', Signal);     // send Processing the raw Pulse Sensor data
    //serialOutput() ;       
    
  if (QS == true){     // A Heartbeat Was Found
    fadeRate = 255;         // Makes the LED Fade Effect Happen
    sendDataToProcessing('B',BPM);   // send heart rate with a 'B' prefix
    sendDataToProcessing('Q',IBI);   // send time between beats with a 'Q' prefix
                   
        //digitalWrite(blinkPin,HIGH);     // Blink LED, we got a beat. 
        
                                // Set 'fadeRate' Variable to 255 to fade LED with pulse
        //serialOutputWhenBeatHappens();   // A Beat Happened, Output that to serial.     
        QS = false;                      // reset the Quantified Self flag for next time 
        display.clearDisplay(); 
        display.setCursor(0,0);
        display.print("Heart Rate: ");
        display.println(BPM);  
  }
     
  ledFadeToBeat();                      // Makes the LED Fade Effect Happen 
  delay(20);                             //  take a break
}





void ledFadeToBeat(){
    fadeRate -= 15;                         //  set LED fade value
    fadeRate = constrain(fadeRate,0,255);   //  keep LED fade value from going into negative numbers!
    analogWrite(fadePin,fadeRate);          //  fade LED
  }
void sendDataToProcessing(char symbol, int data ){
   Serial.print(symbol);                // symbol prefix tells Processing what type of data is coming
   Serial.println(data);                // the data to send culminating in a carriage return
}