HRM heart rate monitor

Hi all!

I know you have seen this topic a thousand times, but I read through all of them, and no seems to have my problem.
To introduce:
In this semester I have a Python programming course. (The language itself is pretty easy to understand, but I prefer C+.) As a final assignment, one should make a game in python. It seemed cool to make a game that gets harder when your heart rate goes up. So far the background.

For the sensor I used these LDR: link, in combination with several 10K resistors.
For transmitter I used a 2mW red laser.

I used a clothes peg to make a clamp with on the one side the laser and the other side the LDR. I wired the laser to 5V and GND, and the LDR in series with a 10K resistor, with a lead from the LDR’s out to the Analog0 (attachment). I use an Arduino Mega 2560 board.

Now my problem:
The heart rate varies enormously. From 10 to >300. Sometimes I get steady rates, but they do not seem to correlate with my actual heart rate. I tried adding more 10K resistors, but that doesn’t help. Neither does lowering the voltage of the laser to 3.3V or further (3.3V + 82OHM resistor).
I tried to measure it in another way (red or white LED and LDR alongside each other), but it doesn’t make any difference.
In the code I tried changing the thresholds and the recent value-list, which seem to help a little bit, but not enough…

Do you guys have any tips for me? I cannot seem to identify the problem:/

Thank you so much for your help!

// 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[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int historySize = 32;
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(9600);
  // 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
      currentHeartrate = 60000 / (millis() - lastHeartbeatTime);
      lastHeartbeatTime = millis();
      // Print Results
      if (currentHeartrate <= 250) 
      { 
        digitalWrite(ledPin, HIGH);
        Serial.println(currentHeartrate); 
      } 
    }
  } 
delay(10);
}

circuit.png

First off an LDR is not very fast in it's response so try a photo transistor.

I tried to measure it in another way (red or white LED and LDR alongside each other)

You should be using IR LEDs not visible ones.

Finally you have to be still while taking the measurements any movement will give false readings.

Where do you measure?

When you measure e.g. the transparency of an finger, the width of the blood vessels varies with temperature, stress, shock, adrenaline, caffeine and more. Muscle activity in the arm will bypass blood and restrict near-by blood vessels, while changed oxygen concentration affects blood color. One such sensor uses different colours to also measure oxygen concentration.

Even if your sensor works fine in steady state, with no physical or psychical activity, this does not mean that it also works with changed or changing states. It would be interesting to record the measured values and according situations, so that you can find out the impact of the player's entire physical or psychical state on the signal.

First let me thank you all for your quick responses!

@Grumpy Mike: using a simple script having only analogRead, the resistance varies continuously (a little though, but is varies). I think the problem might be somewhere else. However, I am gonna order some IR leds and photo transistors, because you are probably right;) Can’t I use a laser? I thought it might be preferable because of the single wavelength, or doesn’t it matter here?

@DrDiettrich: I have tried multiple places: fingertips (mostly my pinkies) and the flap between the index finger and thumb, they all yield about the same results: alternating high and low beat frequencies, for example 80 and the next reading (about a second later) gives 180 and then 40.
I haven’t really thought about all the other factors affecting the fingers transparency. I assumed it varied on the short term only by the blood flow.

Would it work better if I placed the transmitter and receiver on the same side of the finger?
Might it be worth to amplify the voltage difference over the photoresistor or transistor? A higher difference might yield better results, doesn’t it?

using a simple script having only analogRead, the resistance varies continuously (a little though, but is varies).

You would the same script even if you use the right components.

Can't I use a laser?

You could use an IR laser, not a visible light one.

I thought it might be preferable because of the single wavelength, or doesn't it matter here?

It doesn't matter.

Would it work better if I placed the transmitter and receiver on the same side of the finger?

Yes, I thought that is what you were doing anyway. The bone reflects the light and so it travels twice through the blood flow thus giving you twice the signal.

Might it be worth to amplify the voltage difference over the photoresistor or transistor?

Yes it would.

Sorry for my late reply (apparently the flu isn't over yet).

Thanks for your elaborate explanation. I'm gonna order some IR transistors and LEDs tonight, so I will be able to continue soon.