Galvanic Skin Response Sensor

Galvanic skin response readings are simply the measurement of electrical resistance through the body. Two leads are attached to two fingertips. One lead sends current while the other measures the difference. This setup measures GSR every 50 milliseconds. Each reading is graphed, while peaks are highlighted and an average is calculated to smooth out the values. A baseline reading is taken for 10 seconds if the readings go flat (fingers removed from leads).

Arduino Code:

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

void loop(){
  int a=analogRead(0);
  if (Serial.available() > 0) {

    byte inbyte=Serial.read();
    if(inbyte=='a'){
      Serial.print(a,BYTE);

    }
  }
}

Processing Code:

import processing.serial.*;
Serial myPort;  

int hPosition = 1;     // the horizontal position on the graph
float currentReading;
float lastReading;
int count=0;
int zeroLinePos=0;

float gsrAverage,prevGsrAverage;
float baseLine=0;
long lastFlatLine=0;
color graphColor=color(255,255,255);
int baselineTimer=10000;
int gsrValue;
int gsrZeroCount=0;
float gsrRange=0;
int downhillCount=0;
int uphillCount=0;
boolean downhill;
boolean peaked=false;
float peak, valley;

void setup () {
  size(900, 450);
  // List all the available serial ports
  //println(Serial.list());

  myPort = new Serial(this, Serial.list()[0], 9600);
  currentReading=0;
  lastReading=0;
  gsrAverage=0;
  background(0);

  smooth();
}

void draw () {
  //best delay setting for gsr readings
  delay(50);
  //image(myMovie, 0, 0);

  if (gsrValue<15 &&gsrValue>-15){
    if( gsrZeroCount>10){
      currentReading=0;//flatline
      gsrAverage=0;
      baseLine=0;
      lastFlatLine=millis();
      gsrZeroCount=0;
      // println("reset");

    }
    gsrZeroCount++;
  }
  else{
    currentReading=gsrValue-baseLine;
    gsrZeroCount=0;
  }

  if(millis()-lastFlatLine>baselineTimer){
    baseLine=gsrAverage;
  }

  //graph colors
  if(gsrAverage>0 && gsrAverage<height/2.0*.25) graphColor=color(255,255,255);
  else if(gsrAverage>height/2.0*.25 && gsrAverage<height/2.0*.5) graphColor=color(255,250,100);
  else if(gsrAverage>height/2.0*.5 && gsrAverage<height/2.0*.75) graphColor=color(255,250,0);
  else if(gsrAverage>height/2.0*.75) graphColor=color(255,100,0);

  gsrRange=peak-valley;

  // at the edge of the screen, go back to the beginning:
  if (hPosition >= width) {
    hPosition = 0;

    //cover last drawing
    fill(0,200);
    noStroke();
    rect(0,0,width,height);
  }
  else {
    hPosition+=1;
  }

  gsrAverage=smooth(currentReading,.97,gsrAverage);

  //draw stuff

  //spike
  noStroke();
  if(gsrRange>200){
    fill(255);
    ellipse(10,10,20,20);
  }
  else{
    fill(0);
    ellipse(10,10,20,20);
  }

  //graph
  strokeWeight(.5);
  stroke(graphColor);
  line(hPosition-1, height/2.0-lastReading, hPosition, height/2.0-currentReading);
  stroke(255,0,100);
  line(hPosition-1,height/2.0-prevGsrAverage,hPosition,height/2.0-gsrAverage);

  //draw peaks
  int thres=7;

  noFill();
  stroke(255,0,0);
  strokeWeight(2);

  if (currentReading-thres>lastReading&& peaked==true){
    downhill=false;
    //println(downhillCount);
    uphillCount++;
    downhillCount=0;
    point(hPosition-1, height/2.0-lastReading);
    valley=lastReading;
    peaked=false;

  }
  if(currentReading+thres<lastReading && peaked==false){
    //println(uphillCount);
    downhill=true;
    uphillCount=0;
    downhillCount++;
    point(hPosition-1, height/2.0-lastReading);
    peak=lastReading;
    peaked=true;
  }

  prevGsrAverage=gsrAverage;
  lastReading=currentReading;
  //send 'a' for more bytes
  myPort.write('a');
}

void serialEvent (Serial myPort) {
  int inByte=myPort.read();
  //0-255
  gsrValue=inByte;
}

void keyPressed(){
  if (keyCode==DOWN)zeroLinePos+=3;
  if (keyCode==UP)zeroLinePos-=3;

  strokeWeight(1);
  stroke(255,0,0);
  line(0,zeroLinePos,2,zeroLinePos);
}

int smooth(float data, float filterVal, float smoothedVal){
  if (filterVal > 1){      // check to make sure param's are within range
    filterVal = .99;
  }
  else if (filterVal <= 0){
    filterVal = 0;
  }
  smoothedVal = (data * (1 - filterVal)) + (smoothedVal  *  filterVal);
  return (int)smoothedVal;
}



Tips: Arduino code is not supported by new version, so you have to alter the code.
      The resistor have to be around 300K, because human body's resistance is about 300K , if it is too low,
      the reading would be very low(almost zero), if it too high, the reading woud be 1023.
      The basic principle is that the analogRead is actually reading the voltage of the resistor, not the body, 
      if body resistance is much much bigger than the resistor, even if the body resistance changed , the voltage
      of the resistor will not change much(I am sure we have learned this in senior high school)
      

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s