4/13/2008

still alive? heartbeat (IR)sensor report

Principles: Sense heart rate by using a pair of infrared emitter and reciever, next to each other on top the measuring site on top of the finger. The light bounces from the emitter to the detector across the site. with each heart beat the heart contracts and there is a surge of arterial blood, which momentarily increases arterial blood volume across the measuring site. This results in more light absorption during the surge. if light signals received at the photodetector are looked at 'as a waveform', there should be peaks with each heartbeat and troughs between heartbeats.
(http://www.oximetry.org/pulseox/principles.htm)



Sensors: Infrared Emitters and Detectors
SKU#: SEN-00241
Price: $1.95

Description: Side-looking Infrared Emitters and IR Detectors. These simple devices operate at 940nm and work well for generic IR systems including remote control and touch-less object sensing. Using a simple ADC on any microcontroller will allow variable readings to be collected from the detector. The emitter is driven up to 50mA with a current limiting resistor as with any LED device. The detect is a NPN transistor that is biased by incoming IR light.

datasheet:
  • IR Emitter (Clear)
  • IR Detector (Tinted pink)

  • how it works:


    R1

    270 ohm resistor

    R2

    10k resistor

    LED1

    Infrared LED

    Q1

    Infrared-sensitive photoresistor


    Circuit: (simple one without amplifier)

    Dubug process: The signal is sometimes weak, sometimes strong. It may be because of my finger position, my IR sensors which are very fragile or my circuit, or just simply because the signal is weak.

    pot is used to set the threshold. So I could detect the heartbeat.


    Code:

    arduino:

    /* I AM ALIVE heart beat led
    * by meng li based on the code by Jeff Gray - 2008
    * ----------------
    * Triggers a one time event when value goes over threshold,
    * and a different trigger once the value goes back below the threshold
    */

    int an1,an2 = 0;
    int redLedPin =13;
    boolean triggered = false;

    void setup(){
    Serial.begin(9600);
    pinMode(redLedPin, OUTPUT); // set the red LED pin to be an output
    // Serial.println("Starting");
    }
    void loop(){
    // read analog value in
    int an2 = analogRead(0);
    Serial.print("Y");
    Serial.println(an2,DEC);
    //threshold
    int an1= analogRead(5);
    Serial.print("X");
    Serial.println(an1,DEC);


    if(an1 > an2 && !triggered){
    triggered = true;
    digitalWrite(redLedPin, HIGH); // turn off the red LED
    }
    if(an1 <= an2 && triggered){
    triggered = false;
    digitalWrite(redLedPin, LOW); // turn off the red LED
    }
    }

    processing:

    import processing.serial.*;

    String buff = "";
    int val = 0;
    int NEWLINE = 10;
    int xPos,yPos,zPos = 0;
    int displaySize = 2;
    int an1, an2, an3;
    //an1 pot; an2 ir;

    Serial port;

    void setup(){
    background(80);
    size(800,600);
    smooth();

    port = new Serial(this, Serial.list()[1], 9600);
    }

    void draw(){
    // new background over old
    fill(80,5);
    noStroke();
    rect(0,0,width,height);

    // wipe out a small area in front of the new data
    fill(80);
    rect(xPos+displaySize,0,50,height);

    // check for serial, and process
    while (port.available() > 0) {
    serialEvent(port.read());
    }

    }


    void serialEvent(int serial) {
    print("A"); //header variable, so we know which sensor value is which
    println(an1); //send as a ascii encoded number - we'll turn it back into a number at the other end
    //Serial.print(10, BYTE); //terminating character

    print("B"); //header variable, so we know which sensor value is which
    println(an2); //send as a ascii encoded number - we'll turn it back into a number at the other end
    //Serial.print(10, BYTE); //terminating character


    if(serial != '\n') {
    buff += char(serial);
    }
    else {
    int curX = buff.indexOf("X");
    int curY = buff.indexOf("Y");


    if(curX >=0){
    String val = buff.substring(curX+1);
    an1 = Integer.parseInt(val.trim());

    xPos++;
    if(xPos > width) xPos = 0;

    sensorTic1(xPos,an1);
    }
    if(curY >=0){
    String val = buff.substring(curY+1);
    an2 = Integer.parseInt(val.trim());

    yPos++;
    if(yPos > width) yPos = 0;

    sensorTic2(yPos,an2);
    }

    // Clear the value of "buff"
    buff = "";
    }
    }

    void sensorTic1(int x, int y){
    stroke(0,0,255);
    fill(0,0,255);
    ellipse(x,y,displaySize,displaySize);
    }

    void sensorTic2(int x, int y){
    stroke(255,0,0);
    fill(255,0,0);
    ellipse(x,y,displaySize,displaySize);
    }




    Since the signals to different people are different. Some seems have very weak heartbeat or even no signal according to my way of sensing. So I decided to use amplifier to filter and amplify signals.




    (thanks to justin downs and yanyan cao at itp)

    http://johnhenryshammer.com/TEChREF/opAmps/IRHEARTSCHMATIC.html




    Code:

    arduino:
    // from justin)

    #define mask 255 // kill top bits

    int potPin = 0; // select the input pin for the pot

    int ledPin = 13; // select the pin for the LED

    int val = 16706; // variable to store the value coming from the sensor

    int val2 =0;

    int a =0;

    int b =0;

    int beats[]= {0,0,0,0,0};// to track last five reads for a pattern

    boolean beated = false;

    //function dec

    boolean getBioData();


    void setup() {
    pinMode(ledPin, OUTPUT); // declare the ledPin as an OUTPUT
    Serial.begin(9600);
    }

    void loop() {
    char check=' ';
    val = analogRead(potPin); // read the value from the sensor
    if (Serial.read() =='a'){ // check buffer for an 'a'
    val2 = val;
    b= val & mask;
    a =((val2>>8) & mask); //just in case mask
    delay(20);
    // Serial.print("b"); // debug
    // Serial.print(b);
    Serial.print(a,BYTE);
    Serial.print(b,BYTE);
    if (getBioData()){ // call bio function
    Serial.print('b',BYTE);
    }
    else Serial.print('n',BYTE);
    }
    }
    boolean getBioData(){
    int beatVal = analogRead(potPin); // read the value from the sensor
    beats[4] = beatVal; // put in back of array
    int beatDif = beats[5 - 1] - beats[0];
    for (int i = 0; i < 5;i++){
    beats[i] = beats[i+1]; // push zero out front
    }
    // check for beat
    if ( beatDif > 10 && (beated != true)){
    beated = true;
    return true;
    }
    else if( beatDif < 2 ){
    beated = false;
    return false;
    }
    else return false;
    }


    processing:

    //CODE USED TO GET DATA AND GRAPH IT FROM THE

    // HEART MONITOR ARDUINO CODE

    // in Java




    import processing.serial.*;


    Serial port; // Create object from Serial class

    int val; // Data received from the serial port

    int WIDTH=800; // set width

    int number=0;

    int num[] = new int[3];

    int points[]= new int[WIDTH]; // points to be drawn from incoming data

    char beat=' ';

    int beats=0;

    int dropNum[] = new int[4]; // array used to compare data not needed

    void setup()
    {
    println(Serial.list());
    size(WIDTH, 700);
    frameRate(30);
    // Open the port that the board is connected to and use the same speed (9600 bps)
    port = new Serial(this,Serial.list()[1], 9600);
    }

    void draw()
    {
    background(0);// to erase
    port.write('a');
    if (2 < port.available()) { // wait for three bytes
    for (int i=0;i<3;i++){
    num[i] = port.read(); // read them into an array
    }
    //println( num[0]);
    //println( num[1]);
    number = (num[0] << 8)+num[1]; // num range add two incoming bytes together after shifting
    beat = (char) num[2]; // look to see if there is a 'b' to signal a beat
    println(beats);
    }
    stroke(0,255,100); // color stroke
    if (beat == 'b'){// sent from arduino
    beats++;
    }
    // draw heart beat data
    strokeWeight(1);
    points[(WIDTH/2)] = number; // strat drawing half way accross screen give current reading to array
    //goes through all points and draws a line between consecutive ones
    for (int i=1 ;i points[i]= points[i+1];
    line(i,height-points[i-1]-40,i,height-points[i]-40);
    }
    }




    Documentation:
    without amplifier:


    with amplifier:

    3 comments:

    André said...

    Dear Mr. meng li, why does your project especify exactly this kind of component "EMITTER SEN-00241"? My group in college are doing exactly the same project that you did and we are having some troubles with our Infrared Emitter and Detector (but none of them are these ones especified in your project)..

    Thanks

    André

    Lex said...

    There is a mistake in the last few lines of your posted code :)

    for (int i=1 ;i <missing
    points[i]= points[i+1];
    line(i,height-points[i-1]-40,i,height-points[i]-40);
    }
    }

    Alfonso said...

    hi buddy i have a question about the circuit. i already done it but i cant find the IR sensor at anywhere here in mexico but my doubt is Can i replace the IR sensor with anything else? and how can i put it in the same circuit? thx for the help