Arduino Forum

Using Arduino => Programming Questions => Topic started by: saidbk on Jan 07, 2014, 06:55 pm

Title: KY039 Arduino Heart rate code
Post by: saidbk on Jan 07, 2014, 06:55 pm
Hi all,

I am a newly using arduino. I got an KY039 sensor to get heartbeat and rate.

So I have 2 questions
2- is it normal that  last value are around 1023?
1 - How to calculate Rate every 1min in this code?

this is the code ...thanks

Code: [Select]
// Project 12 - Pulse Monitor Test Script

int ledPin = 13;
int sensorPin = 0;
double alpha = 0.75;
int period = 20;
double change = 0.0;
void setup()                  
{
 pinMode(ledPin, OUTPUT);
 Serial.begin(115200);
}
void loop()                    
{
   static double oldValue = 0;
   static double oldChange = 0;
   int rawValue = analogRead(sensorPin);
   double value = alpha * oldValue + (1 - alpha) * rawValue;
   Serial.print(rawValue);
   Serial.print(",");
   Serial.println(value);
   oldValue = value;
   delay(period);
}








Title: Re: KY039 Arduino Heart rate code
Post by: UKHeliBob on Jan 07, 2014, 07:45 pm
Please remove the unnecessary blank lines from your code and post it again using code tags as requested in http://forum.arduino.cc/index.php?topic=97455.0

Is that really the output from that program ?   Why are there no commas in it ?

How is the sensor wired ?
Title: Re: KY039 Arduino Heart rate code
Post by: saidbk on Jan 08, 2014, 07:47 am
Hi,
I tried to delete spacing , sorry.
with commas is the same,  with using commas,I tried to get value, oldvalue and change still weird too. 
I add a pic of the sensor
Title: Re: KY039 Arduino Heart rate code
Post by: UKHeliBob on Jan 08, 2014, 08:18 am
The code is easier to read but you have put it in quote tags rather than code tags.

The picture of the sensor is no good at all.  Too small and it does not show how you have connected it to the Arduino.  If you are consistently reading rawValue as 1023 then my guess would be that the sensor is wired wrongly.  Please provide a diagram, hand drawn if necessary, of how the sensor is wired.  The sensor appears to have 3 pins.  What are they and which Arduino pins are they wired to ?
Title: Re: KY039 Arduino Heart rate code
Post by: saidbk on Jan 08, 2014, 08:35 am
Ok thanks, my post is much better now.

Sensor is well connected, do you know why I am getting data around 1023 plz?

(http://1.jpg)
Title: Re: KY039 Arduino Heart rate code
Post by: UKHeliBob on Jan 08, 2014, 09:32 am
Quote
Sensor is well connected, do you know why I am getting data around 1023 plz?
I will ask one more time then I am going to give up if you don't provide details. 

Exactly how is it connected ?  Which sensor pin to which Arduino pin ?  The larger picture tells us nothing.  For instance, have you got the sensor analogue pin connected to Arduino A0 or Arduino pin 0 ?

If you have got the wiring right then have you tried shielding the whole sensor to prevent ambient light affecting the reading ?  I assume that you are actually putting your finger between the LED and the sensor in the first place.
Title: Re: KY039 Arduino Heart rate code
Post by: saidbk on Jan 08, 2014, 07:34 pm
Hi,
signal pin of Sensor is connected to A0 analog Arduino UNO.
I think that you just answered my question...  and yah I was puting finger between two led emitter/reciever. I shall cover it from light, that is right?
Title: Re: KY039 Arduino Heart rate code
Post by: saidbk on Jan 08, 2014, 07:47 pm
a pic of my connection.

The zedgraph Im a getting on C# is weired too.

(http://WP_000115.jpg)
Title: Re: KY039 Arduino Heart rate code
Post by: UKHeliBob on Jan 08, 2014, 08:29 pm
The connections to the sensor look right in the picture but I cannot see a resistor for that other LED.  I know that you are not using it in this project, but it looks wrong to me just connected to two Arduino pins.

Yes, I meant that you should put the sensor in the dark and try reading it.
Title: Re: KY039 Arduino Heart rate code
Post by: saidbk on Jan 08, 2014, 09:07 pm
Hi,

even in dark it give same results... I will change sensor, maybe it is defected
Thanks
Title: Re: KY039 Arduino Heart rate code
Post by: limeychiney on Mar 01, 2014, 04:39 am
I also didn't understand how to make use of the data this sensor was returning. When I probed the signal from the pulse rate sensor with an oscilloscope, there was no discernible voltage change when my finger was on the sensor. i.e. it wasn't picking up any pulse and showing even a slight difference in values. The waveform was flat and zoomed in as far as the scope would allow.

The sensor was responding though. When I had my finger on the sensor with the IR LED right on top of my finger nail I was getting integer values in the 960's. When uncovered, I got readings in the low 900's.

My code is almost identical to that posted above (it's the sample code shown in the pdf for the sensor pack this comes in).

Code: [Select]
// Pulse Monitor Test Script from 37-1 manual
int  sensPin      = 19;     //Sample code specs pin 2, which is digital and does nothing that I can tell
                                       // in that the return values don't change, regardless of sensor being covered
                                       // So I assigned an analog pin
double alpha   = 0.75;
int period         = 20;
double change = 0.0;

void setup ()
{
  pinMode (sensPin, INPUT);
  Serial.begin (115200);
}

void loop ()
{
static double oldValue = 0;
int rawValue = analogRead (sensPin);
double value = alpha * oldValue + (1 - alpha) * rawValue;
Serial.print (rawValue);
Serial.print (",");
Serial.println (value);
oldValue = value;
delay (period);
}


Not sure how to proceed but if anyone has had success with this sensor, I'd love to hear about it. Thanks
Title: Re: KY039 Arduino Heart rate code
Post by: UKHeliBob on Mar 01, 2014, 07:41 am
Try the code on this page http://www.ebay.co.uk/itm/NEW-KY-039-Finger-Measuring-Heartbeat-Sensor-Module-for-Arduino-/331127966386

Note the advice on the page about shielding stray light from the sensor.
Title: Re: KY039 Arduino Heart rate code
Post by: KVinS on Apr 10, 2014, 07:52 pm
The same problem: The same connected; The same code
Always ~1022 in console (light / dark)
Tested two sensors

With finger drop to ~900
(http://s1.ipicture.ru/uploads/20140410/pGPmcJaR.jpg)

The sensor does not light up. So it should be?

Quote
1021,1021.54
1022,1021.65
1021,1021.49
1021,1021.37
1021,1021.28
1022,1021.46
1022,1021.59
1021,1021.44
1021,1021.33
1021,1021.25
1022,1021.44
1021,1021.33
1022,1021.50
1021,1021.37
1021,1021.28
1021,1021.21
1021,1021.16
1021,1021.12
1022,1021.34
1022,1021.50
1022,1021.63
1021,1021.47
1021,1021.35
1022,1021.51
1021,1021.39
1022,1021.54
1021,1021.40
1022,1021.55
1021,1021.42
1022,1021.56
1022,1021.67
1021,1021.50


Code: [Select]
int ledPin = 13;
int sensorPin = 0;
double alpha = 0.75;
int period = 20;
double change = 0.0;
void setup ()
{
  pinMode (ledPin, OUTPUT);
  Serial.begin (115200);
}
void loop ()
{
    static double oldValue = 0;
    static double oldChange = 0;
    int rawValue = analogRead (sensorPin);
    double value = alpha * oldValue + (1 - alpha) * rawValue;
   
    Serial.print (rawValue);
    Serial.print (",");
    Serial.println (value);
    oldValue = value;
    delay (period);
}

Title: Re: KY039 Arduino Heart rate code
Post by: cpu20 on Apr 23, 2014, 02:51 pm
Like you are holding the sensor in the picture it can not work. The light from the led is going over your finger. The concept is that it reflects from your finger tot the phototransistor. Or it goes trough your finger.
So you will have to point the led on your finger, for it to work.
Title: Re: KY039 Arduino Heart rate code
Post by: johnjameson on Jun 09, 2014, 10:10 pm
I'm after getting one of these sensors,should there be light coming from the Led when you apply power to the sensor?
Title: Re: KY039 Arduino Heart rate code
Post by: ik0jre on Aug 31, 2014, 08:01 pm
In the code I think there is error.

You can verify if trasmitter LED ( 5mm round ) lights with you smartphone camera (keep a trasmitter led near camera and if you must see a blue light). If didn't, try to modify code:

void setup ()
{
  pinMode (ledPin, OUTPUT);
  digitalWrite(ledPin,HIGH);  //new line to power on led
  Serial.begin (115200);
}

Retry to see led light.
With led on you must read min value.
Title: Re: KY039 Arduino Heart rate code
Post by: Christian_R on Oct 13, 2014, 10:23 pm
Did you solve the problem ?
Title: Re: KY039 Arduino Heart rate code
Post by: brianivie on Oct 30, 2014, 07:49 pm
The Keyes-039 or KY039 Heart rate monitor consists of two things, an Infrared LED, and an Infrared Phototransistor.  The IR LED should come on whenever the sensor has power and stay on (because it is infrared, you won't be able to see that it is on, but if you look through your cell phone camera as suggested previously you will).  The IR photo transistor causes the voltage to change on a "sensor" wire, and this should be connected to one of the Arduino's analog pins.

Here is a picture of the sensor:
(http://img.dxcdn.com/productimages/sku_227044_1.jpg)

And here is a schematic:
(http://s3.media.squarespace.com/production/1370812/16892027/_KBlvp5i4Mkk/S00xIs4OkGI/AAAAAAAABtA/7SD72PIntUc/s320/ArduinoHeartbeatSensor-Circuit-Diagram1.jpg)

There are 3 pins.  The top pin (with the backwards S by it) should go to one of the 6 analog pins of the Arduino (A0 to A5), The middle pin should be plugged into 5 volts, and the bottom pin (with the - next to it) should be plugged into ground.

Once the Arduino is powered the IR LED should come on and stay on (check with a cell phone camera).

Commented code for seeing the values is as follows:
Code: [Select]

// Pulse Monitor Test Script
int ledPin = 13; // This pin is connected on the Arduino board to an LED, if you want to blink this LED
                       // to indicate a pulse is being detected, defining it here is a good idea, however
                       // in the code that follows, this is never done, so this line could be deleted.
int sensorPin = 0; // This is the analog sensor pin the backwards S pin is connected to
                           // you can use any of the analog pins, but would need to change this to match
double alpha = 0.75; // This code uses a rather cool way of averaging the values, using 75% of the
                               // average of the previous values and 25% of the current value.
int period = 20; // This is how long the code delays in milliseconds between readings (20 mSec)
double change = 0.0; // My guess is that this was going to be used to detect the peaks, but the
                                // code never does... you can delete this line as well.

// This code runs on startup, it sets ledPin to output so it can blink the LED that is built into the
// Arduino (but then never does), and sets the serial port up for fast 115,200 baud communication
// of the values (make sure you change your serial monitor to match).
void setup ()
{
  pinMode (ledPin, OUTPUT); // not used, can remove
  Serial.begin (115200); // the baud rate of the serial data
}
void loop ()
{
    static double oldValue = 0; // used for averaging.
    static double oldChange = 0; // not currently used
    int rawValue = analogRead (sensorPin); // This reads in the value from the analog pin.
                                                              // this is a 10 bit number, and will be between 0 and 1023
                                                              // If this value doesn't change, you've connected up
                                                              // something wrong


    double value = alpha * oldValue + (1 - alpha) * rawValue; // Calculate an average using 75% of the
                                                                                         // previous value and 25% of the new
   
    Serial.print (rawValue); // Send out serially the value read in
    Serial.print (",");          // Send a comma
    Serial.println (value);   // Send out the average value and a new line
    oldValue = value;        // Save the average for next iteration
    delay (period);            // Wait 20 mSec
}


Title: Re: KY039 Arduino Heart rate code
Post by: WilFerraciolli on Oct 31, 2014, 11:20 pm
Hi guys, thank you for your effort for explaining it. I followed the commented code, I can understand it now however it is still giving me the same results.
Title: Re: KY039 Arduino Heart rate code
Post by: rggassner on Nov 05, 2014, 10:51 pm
Hello,

     I just got one of those, and i was able to (sort of) make a led blink with the same frequency of my heart.

     As you can see at the image below, in a heart beat there is more than one area of "no pressure variation". Consider this while you coding.

(http://www.ni.com/cms/images/devzone/epd/image8625341876827900359.png)

     Do not press your finger too tight, or the sensor wont catch the blood pressure change.

     Using the code below, the led will light when there is no pressure variation at the sensor.

Code: [Select]

int ledc = 10; 
int sensorPin = 0;
int period = 100;
int change, oldvalue, value;
void setup ()
{
  pinMode(ledc, OUTPUT);
  Serial.begin (9600);
}
void loop ()
{
  value = analogRead (sensorPin);
  change = abs(oldvalue - value);
  if(change >= 2 )
  {
    Serial.println (change);
    analogWrite(ledc, 0);
  }
  else
  {
    analogWrite(ledc,255);
  }
  oldvalue = value;
  delay (period);
}
Title: Re: KY039 Arduino Heart rate code
Post by: GNUton on Jan 14, 2015, 01:07 am
Hi there,
I have bought the very same chinese sensor. KY-039, but it has not been a good deal!

Have a look at https://www.youtube.com/watch?v=psTa5ZrqAyo or on other project on youtube..
and you can understand that you may wanna get something better than just a led, and IR receiver and two resistors. you may want to amplify and clean the signal here.

BTW here is my two-mins simple attempt to get something useful from this incomplete sensor.

Quote
int ledc = 13;  
int sensorPin = 0;
int period = 20;
int change, oldvalue, value;
int time = 0;

void setup ()
{
  pinMode(ledc, OUTPUT);
  Serial.begin (9600);
}
void loop ()
{
  value = analogRead (sensorPin);
  Serial.print ("  ");
  Serial.println(value);
  change = abs(oldvalue - value);
  if(change > 1 )
  {
    Serial.println (change);
    time +=1;
  }
  else
  {
     time -=1;
     if (time < 0)
       time = 0;
  }
  
  if (time > 0)
    analogWrite(ledc, 255);
  else
    analogWrite(ledc,0);
    
  oldvalue = value;
  delay (period);
}

Title: Re: KY039 Arduino Heart rate code
Post by: sglandry on Mar 13, 2015, 10:04 pm
Glad to see I'm not alone with this cheap finger pulse detector.

Any updates on this sensor? Has anyone been able to actually use it as a halfway decent pulse detector?
What about (god forbid) estimating current heart rate from this data?
Can you use micros() to figure out the time interval between pulses?  currenttime - oldtime = RRinterval? 60000(ms per minute)/RRinterval = bpm (for just that 1 pulse interval if it continued at that same pace for a minute)?

Are you guys just guessing what jump in sensor value (between current and last value) signifies a heart beat? If it's too sensitive, up the value, if it's too infrequent, lower the value? Keep changing it until you feel the light is blinking at the same rate as your heart beat?

How come you don't have to specify that the sensor is connected to an analog pin? Shouldn't it be:
"int sensorPin = A0;"
instead of just 
"int sensorPin = 0;"


Is there any suggestions for other cheap pulse sensors that might work better? I have seperate IR led & detector, but I don't see what advantage that would have over this current sunfounder sensor.

Part of the fun was only spending a very little on hardware and making it work, but it looks like you can get a decent one for 25 bucks from http://pulsesensor.com/ .
Title: Re: KY039 Arduino Heart rate code
Post by: sonyhome on Mar 31, 2015, 02:14 pm
OK, this is my first post!  8)

I just got a very similar board, and the discussion here allowed me to confirm how it can be connected since the pinout is not very clearly printed.

I managed to tweak generic ebay code after looking at the output to generate a somewhat responsive heart monitor code. Since there is no amplification, the resolution of the signal is very low, since the dynamic range is small while the finger is on the sensor (960~967), but it is enough to get a coarse heart rate signal (see included graph for about 2 sec of data).

The solution is to do a simple peak detection, done by finding the max, decaying it and resetting it when a new peak is found. The code blips the LED and also outputs to the serial console.

If you rest the sensor without pressing hard, and you don't move, you get a heartbeat display, with some beats missed or duped.

The bottom line is with proper filtering code this thing can work.

I have yet to find a use for it as a sensor to activate fun stuff, but I'm not sure I care to make this a real heart rate monitor. It would not be convenient anyways as it is as cumbersome as an oxymeter.

That said this is an infrared detector with a light source. There must be something I can do with that.

Note: I tried to take a photo of the rig to see the infrared beam, and I could not see it.

Code: [Select]

int ledPin=13;
int sensorPin=0;

float alpha=0.75;
int period=50;
float change=0.0;

void setup()
{
  // Built-in arduino board pin
  pinMode(ledPin,OUTPUT);

  Serial.begin(9600);
  Serial.print("Heartrate detection.\n");
  delay(100);
}

float max =0.0;

void loop()
{
  static float oldValue=1009;
  static float oldChange=0.2;

  // This is generic code provided with the board.
  int rawValue=analogRead(sensorPin);
  float value= alpha*oldValue +(1-alpha)* rawValue;
  change=value-oldValue;

  // Display data on the LED via a blip:
  // Empirically, if we detect a peak as being X% from
  // absolute max, we find the pulse even when amplitude
  // varies on the low side.
  
  // Reset max every time we find a new peak
  if (change >= max) {
    max= change;
    Serial.println("  |");
    digitalWrite(ledPin,1);
  } else {
    Serial.println("|");
    digitalWrite(ledPin,0);
  }
  // Slowly decay max for when sensor is moved around
  // but decay must be slower than time needed to hit
  // next heartbeat peak.
  max = max * 0.98;
  
  // Display debug data on the console
//  Serial.print(value);
//  Serial.print(", ");
//  Serial.print(change);
//  Serial.print(", ");
//  Serial.println(max);

  oldValue=value;
  oldChange=change;
  delay(period);
}
Title: Re: KY039 Arduino Heart rate code
Post by: jurs on Mar 31, 2015, 09:20 pm
I managed to tweak generic ebay code after looking at the output to generate a somewhat responsive heart monitor code. Since there is no amplification, the resolution of the signal is very low, since the dynamic range is small while the finger is on the sensor (960~967), but it is enough to get a coarse heart rate signal (see included graph for about 2 sec of data).
I think the signal becomes better when more light arrives at the detector.
Most likely the LED sends its beam a bit in the wrong direction.

Most likely you have to bend the LED a bit so that max. IR beam intensity is sent directly to the IR receiver.

I think if your signal is detected in the range of 400...600 it will be much better than at nearly end of range at 950+.
Title: Re: KY039 Arduino Heart rate code
Post by: luis_xxl on Apr 01, 2015, 08:35 pm
Simply leave the center pin (+) unpluged

you only need to conect 2 pins:

pin - to GND
pin S to A0

central pin (+) leave unconnected
Title: Re: KY039 Arduino Heart rate code
Post by: sonyhome on Apr 02, 2015, 08:03 am
Jurs is correct. My code works all the same but detection is much improved.

=> This sensor is actually becoming good enough to be used as a heart rate monitor! <=

The way the board is sold, the sensor ishorizontal (detector faces up), and the LED is bent 90 degrees, facing the sensor but emiting the light at right angle from the sensor.

By bending the LED to face down onto the sensor, the fully lit sensor now reads in the 20's instead or mid 40's.
When I put my finger the signal is now in the 700's. The dynamic range has not much improved but I suspect since there's more LED light there's more rejection from reflected lights and such.

So same code, new readout from the serial console: The blue signal is when the LED blips, the red is the RAW signal.

Overall the code could be simplified to just detect the light RAW and do the same max detectin on the RAW value instead of the math blurb done that generates a delta. No math, no floats, nothing...
Title: Re: KY039 Arduino Heart rate code
Post by: sonyhome on Apr 02, 2015, 08:07 am
Simply leave the center pin (+) unpluged

you only need to conect 2 pins:

pin - to GND
pin S to A0

central pin (+) leave unconnected

That does not make sense. The LED needs power. If I do that the reading will be 0.
Title: Re: KY039 Arduino Heart rate code
Post by: jurs on Apr 02, 2015, 11:23 am
By bending the LED to face down onto the sensor, the fully lit sensor now reads in the 20's instead or mid 40's.
When I put my finger the signal is now in the 700's.
I've made a photo of my sensor. The main beam of the LED should be directed to the sensor to provide max IR intensity. That way I can even get value readings below 500 when putting my finger between LED and sensor.

Overall the code could be simplified to just detect the light RAW and do the same max detectin on the RAW value instead of the math blurb done that generates a delta. No math, no floats, nothing...
It's interesting to see how many different codes can detect the heartrate. My solution would be much more complicated: Setting up a timer interrupt for sampling the signal to a FIFO buffer at a fixed interval, despite of what is going on at the same time (calculations, statistics, printing things on LCD). Then pulling the data from FIFO buffer and do all the calculations with sliding averages.(http://forum.arduino.cc/index.php?action=dlattach;topic=209140.0;attach=121017)

Title: Re: KY039 Arduino Heart rate code
Post by: sonyhome on Apr 02, 2015, 11:51 am
Jurs: Yes that's how I bent the LEDs to make it work well.


Here's a new version of the code that computes BPM.

The main routine heartbeatDetected() can be converted into a generic library for
that kind of sensor... With my board it works very well now, and the sleep can
be adjusted up to 150ms before the data becomes garbage.

If you want to tie the call to the routine to an interrupt handler there is no limitation.
It's not really needed though and what is needed is to know the latency between calls
(more or less) to adjust the decay of the detection levels.

Of course the main loop needs an exact time delta because it prints the BPM. For the
LED blinks however we don't care too much.

I tried 10ms ~150ms with a solid output.

Caveat: If you move the sensor, it may take a while to re-pick up the heart beat.
If that's an issue for some people I have plenty of ways to fix that I could come up
with, but I wanted to keep this all at a minimal memory footprint...


Code: [Select]

////////////////////////////////////////////////////////////////////////
/// Copyright (c)2015 Dan Truong
/// Permission is granted to use this software under the MIT
/// licence, with my name and copyright kept in source code
/// http://http://opensource.org/licenses/MIT
///
/// KY039 Arduino Heartrate Monitor V1.0 (April 02, 2015)
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
/// @param[in] IRSensorPin Analog pin on which IR detector is connected
/// @param[in] delay (msec) delay between calls to this method. It is
///                  best to call it at least 5 times per beat, aka
///                  no slower than 150msec for 70bpm. An ideal value
///                  is 60ms or faster to handle up to 200 BPM.
///
/// @brief
/// True if heartbeat is detected on the sensor.
/// This code is trivial and just does a peak detection, instead of
/// trying to detect the heart's pulse waveform.
/// Note: I am fudging sensor data with the delay to make the integer
/// math after that uses constants, somewhat independant of the sleep
/// delay used in the main loop. Otherwise if maxValue decays too slow
/// or too fast, it causes glitches and false beat detection.
////////////////////////////////////////////////////////////////////////
#define HBDEBUG(i) i
//#define HBDEBUG(i)

bool
heartbeatDetected(int IRSensorPin, int delay)
{
  static int maxValue = 0;
  static bool isPeak = false;
  int rawValue;
  bool result = false;
    
  rawValue = analogRead(IRSensorPin);
  // Separated because analogRead() may not return an int
  rawValue *= (1000/delay);
  HBDEBUG(Serial.print(isPeak); Serial.print("p, "));
  HBDEBUG(Serial.print(rawValue); Serial.print("r, "));
  HBDEBUG(Serial.print(maxValue); Serial.print("m, "));

  // If sensor shifts, then max is out of whack.
  // Just reset max to a new baseline.
  if (rawValue * 4L < maxValue) {
    maxValue = rawValue * 0.8;
    HBDEBUG(Serial.print("RESET, "));
  }
  
  // Detect new peak
  if (rawValue > maxValue - (1000/delay)) {
    // Only change peak if we find a higher one.
    if (rawValue > maxValue) {
      maxValue = rawValue;
    }
    // Only return true once per peak.
    if (isPeak == false) {
      result = true;
      Serial.print(result); Serial.print(",  *");
    }
    isPeak = true;
  } else if (rawValue < maxValue - (3000/delay)) {
    isPeak = false;
    // Decay max value to adjust to sensor shifting
    // Note that it may take a few seconds to re-detect
    // the signal when sensor is pushed on meatier part
    // of the finger. Another way would be to track how
    // long since last beat, and if over 1sec, reset
    // maxValue, or to use derivatives to remove DC bias.
    maxValue-=(1000/delay);
 }
  HBDEBUG(Serial.print("\n"));
  return result;
}


////////////////////////////////////////////////////////////////////////
// Arduino main code
////////////////////////////////////////////////////////////////////////
int ledPin=13;
int analogPin=0;

void setup()
{
  // Built-in arduino board pin for the display LED
  pinMode(ledPin,OUTPUT);
  
  // Init serial console
  Serial.begin(9600);
  Serial.println("Heartbeat detection sample code.");
}

const int delayMsec = 60; // 100msec per sample

// The main loop blips the LED and computes BPMs on serial port.
void loop()
{
  static int beatMsec = 0;
  int heartRateBPM = 0;
  
  if (heartbeatDetected(analogPin, delayMsec)) {
    heartRateBPM = 60000 / beatMsec;
    digitalWrite(ledPin,1);

    // Print msec/beat and instantaneous heart rate in BPM
    Serial.print(beatMsec);
    Serial.print(", ");
    Serial.println(heartRateBPM);
    
    beatMsec = 0;
  } else {
    digitalWrite(ledPin,0);
  }
  // Note: I assume the sleep delay is way longer than the
  // number of cycles used to run the code hence the error
  // is negligible for math.
  delay(delayMsec);
  beatMsec += delayMsec;
}
Title: Re: KY039 Arduino Heart rate code
Post by: sonyhome on Apr 02, 2015, 11:57 am
Darn I forgot to comment out the debug statements.
Remember you may have to wait like 30s to see your bpm.

Version that's non verbose on the console:

Code: [Select]

////////////////////////////////////////////////////////////////////////
/// Copyright (c)2015 Dan Truong
/// Permission is granted to use this software under the MIT
/// licence, with my name and copyright kept in source code
/// http://http://opensource.org/licenses/MIT
///
/// KY039 Arduino Heartrate Monitor V1.0 (April 02, 2015)
////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////
/// @param[in] IRSensorPin Analog pin on which IR detector is connected
/// @param[in] delay (msec) delay between calls to this method. It is
///                  best to call it at least 5 times per beat, aka
///                  no slower than 150msec for 70bpm. An ideal value
///                  is 60ms or faster to handle up to 200 BPM.
///
/// @brief
/// True if heartbeat is detected on the sensor.
/// This code is trivial and just does a peak detection, instead of
/// trying to detect the heart's pulse waveform.
/// Note: I am fudging sensor data with the delay to make the integer
/// math after that uses constants, somewhat independant of the sleep
/// delay used in the main loop. Otherwise if maxValue decays too slow
/// or too fast, it causes glitches and false beat detection.
////////////////////////////////////////////////////////////////////////
//#define HBDEBUG(i) i
#define HBDEBUG(i)

bool
heartbeatDetected(int IRSensorPin, int delay)
{
  static int maxValue = 0;
  static bool isPeak = false;
  int rawValue;
  bool result = false;
   
  rawValue = analogRead(IRSensorPin);
  // Separated because analogRead() may not return an int
  rawValue *= (1000/delay);
  HBDEBUG(Serial.print(isPeak); Serial.print("p, "));
  HBDEBUG(Serial.print(rawValue); Serial.print("r, "));
  HBDEBUG(Serial.print(maxValue); Serial.print("m, "));

  // If sensor shifts, then max is out of whack.
  // Just reset max to a new baseline.
  if (rawValue * 4L < maxValue) {
    maxValue = rawValue * 0.8;
    HBDEBUG(Serial.print("RESET, "));
  }
 
  // Detect new peak
  if (rawValue > maxValue - (1000/delay)) {
    // Only change peak if we find a higher one.
    if (rawValue > maxValue) {
      maxValue = rawValue;
    }
    // Only return true once per peak.
    if (isPeak == false) {
      result = true;
      HBDEBUG(Serial.print(result); Serial.print(",  *"));
    }
    isPeak = true;
  } else if (rawValue < maxValue - (3000/delay)) {
    isPeak = false;
    // Decay max value to adjust to sensor shifting
    // Note that it may take a few seconds to re-detect
    // the signal when sensor is pushed on meatier part
    // of the finger. Another way would be to track how
    // long since last beat, and if over 1sec, reset
    // maxValue, or to use derivatives to remove DC bias.
    maxValue-=(1000/delay);
 }
  HBDEBUG(Serial.print("\n"));
  return result;
}


////////////////////////////////////////////////////////////////////////
// Arduino main code
////////////////////////////////////////////////////////////////////////
int ledPin=13;
int analogPin=0;

void setup()
{
  // Built-in arduino board pin for the display LED
  pinMode(ledPin,OUTPUT);
 
  // Init serial console
  Serial.begin(9600);
  Serial.println("Heartbeat detection sample code.");
}

const int delayMsec = 60; // 100msec per sample

// The main loop blips the LED and computes BPMs on serial port.
void loop()
{
  static int beatMsec = 0;
  int heartRateBPM = 0;
 
  if (heartbeatDetected(analogPin, delayMsec)) {
    heartRateBPM = 60000 / beatMsec;
    digitalWrite(ledPin,1);

    // Print msec/beat and instantaneous heart rate in BPM
    Serial.print(beatMsec);
    Serial.print(", ");
    Serial.println(heartRateBPM);
   
    beatMsec = 0;
  } else {
    digitalWrite(ledPin,0);
  }
  // Note: I assume the sleep delay is way longer than the
  // number of cycles used to run the code hence the error
  // is negligible for math.
  delay(delayMsec);
  beatMsec += delayMsec;
}
Title: Re: KY039 Arduino Heart rate code
Post by: skylion on Apr 09, 2015, 03:53 pm
Guys...need help...i was not using ky039 module....i only use red led,ir transmitter and receiver...and i have connect to op amp to make it smooth...but when i was run i get the result is 700++...but i find the person who are done this project and used the same component but get different result...i wonder how can i get the same result as that person..


int ledPin = 13;
int sensorPin = 0;
double alpha = 0.75; //using 75% of the average of the previous values and 25% of the current value
int period = 10; // This is how long the code delays in milliseconds between readings (10 mSec)
double change = 0.0; //to be used to detect the peaks

void setup()
{
pinMode(ledPin, OUTPUT);
Serial.begin(115200);
}
void loop()
{
static double oldValue = 0; // used for averaging.
static double oldChange = 0;
int rawValue = analogRead(sensorPin); // This reads in the value from the analog pin
double value = alpha * oldValue + (1 - alpha) * rawValue; // Calculate an average using 75% of the previous value and 25% of the new
change = value - oldValue;
digitalWrite(ledPin, (change < 0.00 && oldChange > 0.00));

delay(1000);
Serial.println("Red IR");
Serial.print(rawValue);
Serial.print(" ");
Serial.print(value);
Serial.println(" ");
oldValue = value;
oldChange = change;
}
 
Title: Re: KY039 Arduino Heart rate code
Post by: jurs on Apr 09, 2015, 07:24 pm
wonder how can i get the same result as that person..
Why do you ask?

Because you don't understand anything about the code you posted?

Perhaps preplace:
Code: [Select]
delay(1000);
Serial.println("Red IR");

with
Code: [Select]
delay(period);

and watch if something different happens.

I don't know whether it may work, but to me it sounds much more reasonable to measure the input each 10 milliseconds instead of once per second only.
Title: Re: KY039 Arduino Heart rate code
Post by: sonyhome on Apr 11, 2015, 11:13 pm
skylion, try my code, and also look at the desvription on how the led is oriented through the finger. you seem to be getting data pulses. btw, 1000 is 1 sample per second, and you want like minimum 5 samples per pulse.
Title: Re: KY039 Arduino Heart rate code
Post by: skylion on Apr 24, 2015, 03:21 am
Thx sonyhome for your help..i think i already get the result for the oxygen saturation..now i want to ask about measure heartbeat and oxygen saturation in one program..i have 2 sepatare coding

This is for measuring heartbeat:

// Pins
const int ledPin = 13;
const int sensePin = 0;

// LED blink variables
int ledState = LOW;
long ledOnMillis = 0;
long ledOnInterval = 50;

// Hearbeat detect variables
int newHeartReading = 0;
int lastHeartReading = 0;
int Delta = 0;
int recentReadings[8] = {0,0,0,0,0,0,0,0};
int historySize = 8;
int recentTotal = 0;
int readingsIndex = 0;
boolean highChange = false;
int totalThreshold = 2;

// Heartbeat Timing
long lastHeartbeatTime = 0;
long debounceDelay = 150;
int currentHeartrate = 0;

void setup() {
// initialize the serial communication:
Serial.begin(115200);
// initialize the digital pin as an output:
pinMode(ledPin, OUTPUT);
}

void loop() {
// Turn off LED
digitalWrite(ledPin, LOW);

// Read analogue pin.
newHeartReading = analogRead(sensePin);
//Serial.println(newHeartReading);
//Calculate Delta
Delta = newHeartReading - lastHeartReading;
lastHeartReading = newHeartReading;

// Find new recent total
recentTotal = recentTotal - recentReadings[readingsIndex] + Delta;
// replace indexed recent value
recentReadings[readingsIndex] = Delta;
// increment index
readingsIndex = (readingsIndex + 1) % historySize;

//Debug
//Serial.println(recentTotal);

// Decide whether to start an LED Blink.
if (recentTotal >= totalThreshold) {
// Possible heartbeart, check time
if (millis() - lastHeartbeatTime >= debounceDelay) {
// Heartbeat
digitalWrite(ledPin, HIGH);
currentHeartrate = 60000 / (millis() - lastHeartbeatTime);
lastHeartbeatTime = millis();
// Print Results
//Serial.println("Beat");
if (currentHeartrate <= 200)
{ Serial.println(currentHeartrate); } } } delay(10); }


This one for measure oxygen level;

int ledPin = 13;
int sensorPin = 0;
double alpha = 0.75; //using 75% of the average of the previous values and 25% of the current value
int period = 5; // This is how long the code delays in milliseconds between readings (10 mSec)
double change = 0.0; //to be used to detect the peaks
int z;

void setup()
{
pinMode(ledPin, OUTPUT);
Serial.begin(115200);
}
void loop()
{
static double oldValue = 0; // used for averaging.
static double oldChange = 0;
int rawValue = analogRead(sensorPin)-700; // This reads in the value from the analog pin
double value = alpha * oldValue + (1 - alpha) * (rawValue);// Calculate an average using 75% of the previous value and 25% of the new
change = value - oldValue;
z = log(1/value)/(log(1/rawValue));
digitalWrite(ledPin, (change < 0.00 && oldChange > 0.00));


delay(2000);
Serial.println("IR Intensity led intensity");
Serial.print(rawValue);
Serial.print("            ");
Serial.print(value);
Serial.println("            ");
oldValue = value;
oldChange = change;
}
 
 and also the formula is unread..when i click the serial monitor the value z was 0..

anyone can help?
Title: Re: KY039 Arduino Heart rate code
Post by: sonyhome on Apr 30, 2015, 12:55 pm
z = log(1/value)/(log(1/rawValue));

replace with:

z = log(1.0/value)/(log(1.0/rawValue));

You may want to say what is your native language, maybe I or someone else speaks it.
Title: Re: KY039 Arduino Heart rate code
Post by: mlinaje on May 20, 2015, 10:02 pm
I have tried hard to work with this module both, powering from arduino and externally powering it. In both cases I do not get values that make sense for bpm (i.e., let's say 60-200bpm).
IR LED is working, since I am able to see it in the dark with a camera.

When using external power, intensity is higher (arduino pins are around 40mA aprox.) and the IR LED is brighter.

Any new idea not detailed in this forum?
Title: Re: KY039 Arduino Heart rate code
Post by: jurs on May 20, 2015, 10:42 pm
Any new idea not detailed in this forum?
Check the alignment of LED beam and sensor direction like shown in reply #27.

Then the analogRead values should be "in the middle" of the measuring range (i.e. 300...800) and not at the threshold of sensitivity.
Title: Re: KY039 Arduino Heart rate code
Post by: AlexMolnar on Jul 18, 2015, 02:35 pm
HELLO. This is my first post so sorry if I say something stupid.

I used the schematic and the code from this page : https://tkkrlab.nl/wiki/Arduino_KY-039_Detect_the_heartbeat_module

Can anyone tell me how to interpret the numbers so that I can get the heart beat/pulse?

I posted the numbers I measured in attachment.

Thank you.
Title: Re: KY039 Arduino Heart rate code
Post by: jurs on Jul 18, 2015, 03:15 pm
Can anyone tell me how to interpret the numbers so that I can get the heart beat/pulse?

I posted the numbers I measured in attachment.
For correct sensor adjustment see my reply #27 and the picture I posted.

Your data with many, many 0 measurements show that the LED in your hardware is not correctly adjusted to send its beam to the IR sensor.

As far as the code is concerned, you are doing measurement of the raw sensor data in a given moment:
Code: [Select]
   int rawValue = analogRead (sensorPin);

And then you are doing a low-pass filtering ("smooting", "averaging") of the values:
Code: [Select]
   double value = alpha * oldValue + (1 - alpha) * rawValue;

So "rawValue" is a momentary value measured at a single moment.
This number can change very quickly from one measure to the next.

And "value" is an filtered average value, created from several measured values.
This number can change slowly from one measure to the next, as it is an average created from several measurements.

So when printing both you will see this in your data:
- sometimes "rawValue" is higher than "value"
- sometime "rawValue" is lower than "value"

If you'd do that correctly (LED adjustment, low-pass filter value), you could see that the speed of this change will be in the rhythm of the heartbeat.
Title: Re: KY039 Arduino Heart rate code
Post by: sonyhome on Jul 19, 2015, 08:47 pm
I'd say try the piece of code I submitted instead of that calculated value that does not work too good.
Title: Re: KY039 Arduino Heart rate code
Post by: philpugh on Oct 05, 2015, 05:02 pm
I built one of these pulse rate sensors for a company whilst at university back in 1971.  Using similar components that were then available - but the solution didn't include any processors!!

Key things to think about.  The level of the signal you are interested in is 'swamped' by the level of "DC" voltage seen by the sensor.  This "DC" offset voltage will vary enormously between people and also for the same person in different conditions (e.g. hot or cold, well or ill).

You should shield the sensor from external light - especially mains driven - which adds a further signal conditioning problem - that's why the ones used in (eg) hospitals clip over the finger.  With care you should be able to get some readings but I suspect that the variations in output levels will make it difficult to detect accurately.
Title: Re: KY039 Arduino Heart rate code
Post by: icksjot on Oct 21, 2015, 01:35 pm
On my KY-039 the little yellow men put a red LED in wrong direction >:(
Any questions?
Title: Re: KY039 Arduino Heart rate code
Post by: harshdshah32 on Jun 02, 2016, 07:27 pm
HI all. I used the same code and get the output between 4080-4094. What should be the output of this sensor ?
Is there any equation so I can convert this output numbers in regular pulse number , eg. Like 60-100.

this is my code.
int ledPin = 13;
int sensorPin = A0;
int alpha = 0.75;   //try with double
int period = 1000;
//double change = 0.0;

//double minval = 0.0;
void setup ()
{
  pinMode(ledPin,OUTPUT);
  Serial.begin(9600);
}
void loop ()
{
    static int oldValue = 0;
 //   static double oldChange = 0;
 
    int rawValue = analogRead(A0);
    Serial.println(rawValue);
    digitalWrite(ledPin,HIGH);
    int value = alpha * oldValue + (1 - alpha) * rawValue;

    // Serial.println(rawValue);
    Serial.println("   and,  ");
    Serial.println (value);
   
    digitalWrite(ledPin, LOW);
    oldValue = value;
 
    delay (period);
}
Title: Re: KY039 Arduino Heart rate code
Post by: KamalLagh on Feb 27, 2019, 11:53 pm
For correct sensor adjustment see my reply #27 and the picture I posted.

Your data with many, many 0 measurements show that the LED in your hardware is not correctly adjusted to send its beam to the IR sensor.

As far as the code is concerned, you are doing measurement of the raw sensor data in a given moment:
Code: [Select]
   int rawValue = analogRead (sensorPin);

And then you are doing a low-pass filtering ("smooting", "averaging") of the values:
Code: [Select]
   double value = alpha * oldValue + (1 - alpha) * rawValue;

So "rawValue" is a momentary value measured at a single moment.
This number can change very quickly from one measure to the next.

And "value" is an filtered average value, created from several measured values.
This number can change slowly from one measure to the next, as it is an average created from several measurements.

So when printing both you will see this in your data:
- sometimes "rawValue" is higher than "value"
- sometime "rawValue" is lower than "value"

If you'd do that correctly (LED adjustment, low-pass filter value), you could see that the speed of this change will be in the rhythm of the heartbeat.

Hi,
But why the speed of this change will be in the rhythm of the heartbeat?