Description
Create a physically interactive system of your choice that relies on a multimedia computer for some sort of processing or data analysis. The Final should use BOTH Processing AND Arduino. Your focus should be on careful and timely sensing of the relevant actions of the person or people that you’re designing this for, and on clear, prompt, and effective responses. Any interactive system is going to involve systems of listening, thinking, and speaking from both parties. Whether it involves one cycle or many, the exchange should be engaging. You may work alone or in pairs.
Description of the game
So, I used a pulse sensor to make a heartbeat monitor which can be used for different purposes. Maybe in the health care industry or sports industry.
I used two LEDs that turn on and off according to the pulse rate. I added a scaling component in the code to adjust the size of the rate. I also checked the timings between heartbeat by subtracting the last-current. I also made the heart pump by increasing the stroke weight. You can also use “S” or “s” to save the heartbeat in the folder where the code. it saved and later you can compare the heartbeat.
I did the user testing as well after that. The test person came back from a run, thus his heart was beating faster.
He gave some feedback. Thank you.
Certain challenges:-
- It took me some time to figure out how the sensor worked because I have never worked with a pulse sensor before.
- it was hard to display the pulse wave first, then I found some resources to make me understand the concept.
- it was hard to add further things to the project to make it more useful.
The code is following:-
Arduino
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 TBH = 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 = false; // Set to 'false' by Default. Re-set to 'true' to see Arduino Serial Monitor ASCII Visual Pulse
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
if (QS == true){ // A Heartbeat Was Found
// BPM and TBH have been Determined
// Quantified Self "QS" true when arduino finds a heartbeat
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
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 serialOutput(){ // Decide How To Output Serial.
if (serialVisual == true){
arduinoSerialMonitorVisual('-', Signal); // goes to function that makes Serial Monitor Visualizer
sendDataToSerial('S', Signal); // goes to sendDataToSerial function
// Decides How To OutPut BPM and TBH Data
void serialOutputWhenBeatHappens(){
if (serialVisual == true){ // Code to Make the Serial Monitor Visualizer Work
Serial.print("*** Heart-Beat Happened *** "); //ASCII Art Madness
sendDataToSerial('B',BPM); // send heart rate with a 'B' prefix
sendDataToSerial('Q',TBH); // send time between beats with a 'Q' prefix
// Sends Data to Pulse Sensor Processing App, Native Mac App, or Third-party Serial Readers.
void sendDataToSerial(char symbol, int data ){
// Code to Make the Serial Monitor Visualizer Work
void arduinoSerialMonitorVisual(char symbol, int data ){
const int sensorMin = 0; // sensor minimum, discovered through experiment
const int sensorMax = 1024; // sensor maximum, discovered through experiment
int sensorReading = data;
// map the sensor range to a range of 12 options:
int range = map(sensorReading, sensorMin, sensorMax, 0, 11);
// do something different depending on the
Serial.println(""); /////ASCII Art Madness
Serial.println("------");
Serial.println("---------");
Serial.println("------------");
Serial.println("--------------|-");
Serial.println("--------------|---");
Serial.println("--------------|-------");
Serial.println("--------------|----------");
Serial.println("--------------|----------------");
Serial.println("--------------|-------------------");
Serial.println("--------------|-----------------------");
volatile int rate[10]; // array to hold last ten TBH values
volatile unsigned long sampleCounter = 0; // used to determine pulse timing
volatile unsigned long lastBeatTime = 0; // used to find TBH
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 = 525; // 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
// Initializes Timer2 to throw an interrupt every 2mS.
TCCR2A = 0x02; // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
TCCR2B = 0x06; // DON'T FORCE COMPARE, 256 PRESCALER
OCR2A = 0X7C; // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
TIMSK2 = 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(TIMER2_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 > (TBH/5)*3){ // avoid dichrotic noise by waiting 3/5 of last TBH
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 > (TBH/5)*3) ){
Pulse = true; // set the Pulse flag when we think there is a pulse
digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
TBH = 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
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; // TBH value is unreliable so discard it
// keep a running total of the last 10 TBH 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 TBH value
runningTotal += rate[i]; // add up the 9 oldest TBH values
rate[9] = TBH; // add the latest TBH to the rate array
runningTotal += rate[9]; // add the latest TBH to runningTotal
runningTotal /= 10; // average the last 10 TBH 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
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!
// 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 TBH = 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 = false; // 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 TBH have been Determined
// Quantified Self "QS" true when arduino finds a heartbeat
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
}
void serialOutput(){ // Decide How To Output Serial.
if (serialVisual == true){
arduinoSerialMonitorVisual('-', Signal); // goes to function that makes Serial Monitor Visualizer
} else{
sendDataToSerial('S', Signal); // goes to sendDataToSerial function
}
}
// Decides How To OutPut BPM and TBH Data
void serialOutputWhenBeatHappens(){
if (serialVisual == true){ // Code to Make the Serial Monitor Visualizer Work
Serial.print("*** Heart-Beat Happened *** "); //ASCII Art Madness
Serial.print("BPM: ");
Serial.print(BPM);
Serial.print(" ");
} else{
sendDataToSerial('B',BPM); // send heart rate with a 'B' prefix
sendDataToSerial('Q',TBH); // send time between beats with a 'Q' prefix
}
}
// Sends Data to Pulse Sensor Processing App, Native Mac App, or Third-party Serial Readers.
void sendDataToSerial(char symbol, int data ){
Serial.print(symbol);
Serial.println(data);
}
// Code to Make the Serial Monitor Visualizer Work
void arduinoSerialMonitorVisual(char symbol, int data ){
const int sensorMin = 0; // sensor minimum, discovered through experiment
const int sensorMax = 1024; // sensor maximum, discovered through experiment
int sensorReading = data;
// map the sensor range to a range of 12 options:
int range = map(sensorReading, sensorMin, sensorMax, 0, 11);
// do something different depending on the
// range value:
switch (range) {
case 0:
Serial.println(""); /////ASCII Art Madness
break;
case 1:
Serial.println("---");
break;
case 2:
Serial.println("------");
break;
case 3:
Serial.println("---------");
break;
case 4:
Serial.println("------------");
break;
case 5:
Serial.println("--------------|-");
break;
case 6:
Serial.println("--------------|---");
break;
case 7:
Serial.println("--------------|-------");
break;
case 8:
Serial.println("--------------|----------");
break;
case 9:
Serial.println("--------------|----------------");
break;
case 10:
Serial.println("--------------|-------------------");
break;
case 11:
Serial.println("--------------|-----------------------");
break;
}
}
volatile int rate[10]; // array to hold last ten TBH values
volatile unsigned long sampleCounter = 0; // used to determine pulse timing
volatile unsigned long lastBeatTime = 0; // used to find TBH
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 = 525; // 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.
TCCR2A = 0x02; // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
TCCR2B = 0x06; // DON'T FORCE COMPARE, 256 PRESCALER
OCR2A = 0X7C; // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
TIMSK2 = 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(TIMER2_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 > (TBH/5)*3){ // avoid dichrotic noise by waiting 3/5 of last TBH
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 > (TBH/5)*3) ){
Pulse = true; // set the Pulse flag when we think there is a pulse
digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
TBH = 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] = TBH;
}
}
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; // TBH value is unreliable so discard it
}
// keep a running total of the last 10 TBH 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 TBH value
runningTotal += rate[i]; // add up the 9 oldest TBH values
}
rate[9] = TBH; // add the latest TBH to the rate array
runningTotal += rate[9]; // add the latest TBH to runningTotal
runningTotal /= 10; // average the last 10 TBH 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
// 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 TBH = 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 = false; // 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 TBH have been Determined
// Quantified Self "QS" true when arduino finds a heartbeat
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
}
void serialOutput(){ // Decide How To Output Serial.
if (serialVisual == true){
arduinoSerialMonitorVisual('-', Signal); // goes to function that makes Serial Monitor Visualizer
} else{
sendDataToSerial('S', Signal); // goes to sendDataToSerial function
}
}
// Decides How To OutPut BPM and TBH Data
void serialOutputWhenBeatHappens(){
if (serialVisual == true){ // Code to Make the Serial Monitor Visualizer Work
Serial.print("*** Heart-Beat Happened *** "); //ASCII Art Madness
Serial.print("BPM: ");
Serial.print(BPM);
Serial.print(" ");
} else{
sendDataToSerial('B',BPM); // send heart rate with a 'B' prefix
sendDataToSerial('Q',TBH); // send time between beats with a 'Q' prefix
}
}
// Sends Data to Pulse Sensor Processing App, Native Mac App, or Third-party Serial Readers.
void sendDataToSerial(char symbol, int data ){
Serial.print(symbol);
Serial.println(data);
}
// Code to Make the Serial Monitor Visualizer Work
void arduinoSerialMonitorVisual(char symbol, int data ){
const int sensorMin = 0; // sensor minimum, discovered through experiment
const int sensorMax = 1024; // sensor maximum, discovered through experiment
int sensorReading = data;
// map the sensor range to a range of 12 options:
int range = map(sensorReading, sensorMin, sensorMax, 0, 11);
// do something different depending on the
// range value:
switch (range) {
case 0:
Serial.println(""); /////ASCII Art Madness
break;
case 1:
Serial.println("---");
break;
case 2:
Serial.println("------");
break;
case 3:
Serial.println("---------");
break;
case 4:
Serial.println("------------");
break;
case 5:
Serial.println("--------------|-");
break;
case 6:
Serial.println("--------------|---");
break;
case 7:
Serial.println("--------------|-------");
break;
case 8:
Serial.println("--------------|----------");
break;
case 9:
Serial.println("--------------|----------------");
break;
case 10:
Serial.println("--------------|-------------------");
break;
case 11:
Serial.println("--------------|-----------------------");
break;
}
}
volatile int rate[10]; // array to hold last ten TBH values
volatile unsigned long sampleCounter = 0; // used to determine pulse timing
volatile unsigned long lastBeatTime = 0; // used to find TBH
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 = 525; // 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.
TCCR2A = 0x02; // DISABLE PWM ON DIGITAL PINS 3 AND 11, AND GO INTO CTC MODE
TCCR2B = 0x06; // DON'T FORCE COMPARE, 256 PRESCALER
OCR2A = 0X7C; // SET THE TOP OF THE COUNT TO 124 FOR 500Hz SAMPLE RATE
TIMSK2 = 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(TIMER2_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 > (TBH/5)*3){ // avoid dichrotic noise by waiting 3/5 of last TBH
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 > (TBH/5)*3) ){
Pulse = true; // set the Pulse flag when we think there is a pulse
digitalWrite(blinkPin,HIGH); // turn on pin 13 LED
TBH = 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] = TBH;
}
}
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; // TBH value is unreliable so discard it
}
// keep a running total of the last 10 TBH 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 TBH value
runningTotal += rate[i]; // add up the 9 oldest TBH values
}
rate[9] = TBH; // add the latest TBH to the rate array
runningTotal += rate[9]; // add the latest TBH to runningTotal
runningTotal /= 10; // average the last 10 TBH 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
Processing:-
import processing.sound.*;
import processing.serial.*;
int Sensor; // holds pusle sensor data from the arduino
int TBH; // HOLDS TIME BETWEN HEARTBEATS FROM ARDUINO
int BPM; // HOLDS HEART RATE VALUE FROM ARDUINO
int[] RawY; // HOLDS HEARTBEAT WAVEFORM DATA BEFORE SCALING
int[] ScaledY; // USED TO POSITION SCALED HEARTBEAT WAVEFORM
int[] rate; // USED TO POSITION BPM DATA WAVEFORM
float zoom; // USED WHEN SCALING PULSE WAVEFORM TO PULSE WINDOW
float offset; // USED WHEN SCALING PULSE WAVEFORM TO PULSE WINDOW
color eggshell = color(171,219,227);
int heart = 0; // This variable times the heart image 'pulse' on screen
// THESE VARIABLES DETERMINE THE SIZE OF THE DATA WINDOWS
int PulseWindowWidth = 490;
int PulseWindowHeight = 512;
int BPMWindowWidth = 180;
int BPMWindowHeight = 340;
boolean beat = false; // set when a heart beat is detected, then cleared when the BPM graph is advanced
// SERIAL PORT STUFF TO HELP YOU FIND THE CORRECT SERIAL PORT
String[] serialPorts = new String[Serial.list().length];
boolean serialPortFound = false;
Radio[] button = new Radio[Serial.list().length];
size(700, 600); // Stage size
file = new SoundFile(this, "heart.mp3");
font = loadFont("Arial-BoldMT-24.vlw");
// Scrollbar constructor inputs: x,y,width,height,minVal,maxVal
scaleBar = new Scrollbar (400, 575, 180, 12, 0.5, 1.0); // set parameters for the scale bar
RawY = new int[PulseWindowWidth]; // initialize raw pulse waveform array
ScaledY = new int[PulseWindowWidth]; // initialize scaled pulse waveform array
rate = new int [BPMWindowWidth]; // initialize BPM waveform array
zoom = 0.75; // initialize scale of heartbeat window
// set the visualizer lines to 0
for (int i=0; i<rate.length; i++){
rate[i] = 555; // Place BPM graph line at bottom of BPM Window
for (int i=0; i<RawY.length; i++){
RawY[i] = height/2; // initialize the pulse window data line to V/2
// DRAW OUT THE PULSE WINDOW AND BPM WINDOW RECTANGLES
text("Select Your Serial Port",245,30);
// ONLY RUN THE VISUALIZER AFTER THE PORT IS CONNECTED
// PRINT THE DATA AND VARIABLE VALUES
fill(eggshell); // get ready to print text
text("Check your Heart Beat and Pulse",245,30); // tell them what you are
text("TBH " + TBH + "mS",600,585); // print the time between heartbeats in mS
text(BPM + "BPM",600,200); // print the Beats Per Minute
text("Scale the Pulse Rate " + nf(zoom,1,2), 150, 585); // show the current scale of Pulse Window
// DO THE SCROLLBAR THINGS
scaleBar.update (mouseX, mouseY);
} else { // SCAN BUTTONS TO FIND THE SERIAL PORT
for(int i=0; i<button.length; i++){
button[i].overRadio(mouseX,mouseY);
button[i].displayRadio();
// DRAW OUT THE PULSE WINDOW AND BPM WINDOW RECTANGLES
fill(eggshell); // color for the window background
rect(255,height/2,PulseWindowWidth,PulseWindowHeight);
rect(600,385,BPMWindowWidth,BPMWindowHeight);
void drawPulseWaveform(){
// DRAW THE PULSE WAVEFORM
// prepare pulse data points
RawY[RawY.length-1] = (1023 - Sensor) - 212; // place the new raw datapoint at the end of the array
zoom = scaleBar.getPos(); // get current waveform scale value
offset = map(zoom,0.5,1,150,0); // calculate the offset needed at this scale
for (int i = 0; i < RawY.length-1; i++) { // move the pulse waveform by
RawY[i] = RawY[i+1]; // shifting all raw datapoints one pixel left
float dummy = RawY[i] * zoom + offset; // adjust the raw data to the selected scale
ScaledY[i] = constrain(int(dummy),44,556); // transfer the raw data array to the scaled array
stroke(250,0,0); // red is a good color for the pulse waveform
beginShape(); // using beginShape() renders fast
for (int x = 1; x < ScaledY.length-1; x++) {
vertex(x+10, ScaledY[x]); //draw a line connecting the data points
// DRAW THE BPM WAVE FORM
// first, shift the BPM waveform over to fit then next data point only when a beat is found
if (beat == true){ // move the heart rate line over one pixel every time the heart beats
beat = false; // clear beat flag (beat flag waset in serialEvent tab)
for (int i=0; i<rate.length-1; i++){
rate[i] = rate[i+1]; // shift the bpm Y coordinates over one pixel to the left
// then limit and scale the BPM value
BPM = min(BPM,200); // limit the highest BPM value to 200
float dummy = map(BPM,0,200,555,215); // map it to the heart rate window Y
rate[rate.length-1] = int(dummy); // set the rightmost pixel to the new data point value
// GRAPH THE HEART RATE WAVEFORM
stroke(250,0,0); // color of heart rate graph
strokeWeight(2); // thicker line is easier to read
for (int i=0; i < rate.length-1; i++){ // variable 'i' will take the place of pixel x position
vertex(i+510, rate[i]); // display history of heart rate datapoints
// DRAW THE HEART AND MAYBE MAKE IT BEAT
// the 'heart' variable is set in serialEvent when arduino sees a beat happen
heart--; // heart is used to time how long the heart graphic swells when your heart beats
heart = max(heart,0); // don't let the heart variable go into negative numbers
if (heart > 0){ // if a beat happened recently,
strokeWeight(8); // make the heart big
smooth(); // draw the heart with two bezier curves
bezier(width-100,50, width-20,-20, width,140, width-100,150);
bezier(width-100,50, width-190,-20, width-200,140, width-100,150);
strokeWeight(1); // reset the strokeWeight for next time
void listAvailablePorts(){
serialPorts = Serial.list();
// set a counter to list the ports backwards
for(int i=serialPorts.length-1; i>=0; i--){
button[i] = new Radio(35, 95+(yPos*20),12,color(180),color(80),color(255),i,button);
text(serialPorts[i],50, 100+(yPos*20));
import processing.sound.*;
SoundFile file;
import processing.serial.*;
PFont font;
PFont portsFont;
Scrollbar scaleBar;
Serial port;
int Sensor; // holds pusle sensor data from the arduino
int TBH; // HOLDS TIME BETWEN HEARTBEATS FROM ARDUINO
int BPM; // HOLDS HEART RATE VALUE FROM ARDUINO
int[] RawY; // HOLDS HEARTBEAT WAVEFORM DATA BEFORE SCALING
int[] ScaledY; // USED TO POSITION SCALED HEARTBEAT WAVEFORM
int[] rate; // USED TO POSITION BPM DATA WAVEFORM
float zoom; // USED WHEN SCALING PULSE WAVEFORM TO PULSE WINDOW
float offset; // USED WHEN SCALING PULSE WAVEFORM TO PULSE WINDOW
color eggshell = color(171,219,227);
int heart = 0; // This variable times the heart image 'pulse' on screen
// THESE VARIABLES DETERMINE THE SIZE OF THE DATA WINDOWS
int PulseWindowWidth = 490;
int PulseWindowHeight = 512;
int BPMWindowWidth = 180;
int BPMWindowHeight = 340;
boolean beat = false; // set when a heart beat is detected, then cleared when the BPM graph is advanced
// SERIAL PORT STUFF TO HELP YOU FIND THE CORRECT SERIAL PORT
String serialPort;
String[] serialPorts = new String[Serial.list().length];
boolean serialPortFound = false;
Radio[] button = new Radio[Serial.list().length];
void setup() {
size(700, 600); // Stage size
file = new SoundFile(this, "heart.mp3");
frameRate(100);
font = loadFont("Arial-BoldMT-24.vlw");
textFont(font);
textAlign(CENTER);
rectMode(CENTER);
ellipseMode(CENTER);
// Scrollbar constructor inputs: x,y,width,height,minVal,maxVal
scaleBar = new Scrollbar (400, 575, 180, 12, 0.5, 1.0); // set parameters for the scale bar
RawY = new int[PulseWindowWidth]; // initialize raw pulse waveform array
ScaledY = new int[PulseWindowWidth]; // initialize scaled pulse waveform array
rate = new int [BPMWindowWidth]; // initialize BPM waveform array
zoom = 0.75; // initialize scale of heartbeat window
// set the visualizer lines to 0
for (int i=0; i<rate.length; i++){
rate[i] = 555; // Place BPM graph line at bottom of BPM Window
}
for (int i=0; i<RawY.length; i++){
RawY[i] = height/2; // initialize the pulse window data line to V/2
}
background(0);
noStroke();
// DRAW OUT THE PULSE WINDOW AND BPM WINDOW RECTANGLES
drawDataWindows();
drawHeart();
// GO FIND THE ARDUINO
fill(eggshell);
text("Select Your Serial Port",245,30);
listAvailablePorts();
}
void draw() {
if(serialPortFound){
// ONLY RUN THE VISUALIZER AFTER THE PORT IS CONNECTED
background(0);
noStroke();
drawDataWindows();
drawPulseWaveform();
drawBPMwaveform();
drawHeart();
// PRINT THE DATA AND VARIABLE VALUES
fill(eggshell); // get ready to print text
text("Check your Heart Beat and Pulse",245,30); // tell them what you are
text("TBH " + TBH + "mS",600,585); // print the time between heartbeats in mS
text(BPM + "BPM",600,200); // print the Beats Per Minute
text("Scale the Pulse Rate " + nf(zoom,1,2), 150, 585); // show the current scale of Pulse Window
// DO THE SCROLLBAR THINGS
scaleBar.update (mouseX, mouseY);
scaleBar.display();
} else { // SCAN BUTTONS TO FIND THE SERIAL PORT
for(int i=0; i<button.length; i++){
button[i].overRadio(mouseX,mouseY);
button[i].displayRadio();
}
}
} //end of draw loop
void drawDataWindows(){
// DRAW OUT THE PULSE WINDOW AND BPM WINDOW RECTANGLES
fill(eggshell); // color for the window background
rect(255,height/2,PulseWindowWidth,PulseWindowHeight);
rect(600,385,BPMWindowWidth,BPMWindowHeight);
}
void drawPulseWaveform(){
// DRAW THE PULSE WAVEFORM
// prepare pulse data points
RawY[RawY.length-1] = (1023 - Sensor) - 212; // place the new raw datapoint at the end of the array
zoom = scaleBar.getPos(); // get current waveform scale value
offset = map(zoom,0.5,1,150,0); // calculate the offset needed at this scale
for (int i = 0; i < RawY.length-1; i++) { // move the pulse waveform by
RawY[i] = RawY[i+1]; // shifting all raw datapoints one pixel left
float dummy = RawY[i] * zoom + offset; // adjust the raw data to the selected scale
ScaledY[i] = constrain(int(dummy),44,556); // transfer the raw data array to the scaled array
}
stroke(250,0,0); // red is a good color for the pulse waveform
noFill();
beginShape(); // using beginShape() renders fast
for (int x = 1; x < ScaledY.length-1; x++) {
vertex(x+10, ScaledY[x]); //draw a line connecting the data points
}
endShape();
}
void drawBPMwaveform(){
// DRAW THE BPM WAVE FORM
// first, shift the BPM waveform over to fit then next data point only when a beat is found
if (beat == true){ // move the heart rate line over one pixel every time the heart beats
file.play();
beat = false; // clear beat flag (beat flag waset in serialEvent tab)
for (int i=0; i<rate.length-1; i++){
rate[i] = rate[i+1]; // shift the bpm Y coordinates over one pixel to the left
}
// then limit and scale the BPM value
BPM = min(BPM,200); // limit the highest BPM value to 200
float dummy = map(BPM,0,200,555,215); // map it to the heart rate window Y
rate[rate.length-1] = int(dummy); // set the rightmost pixel to the new data point value
}
// GRAPH THE HEART RATE WAVEFORM
stroke(250,0,0); // color of heart rate graph
strokeWeight(2); // thicker line is easier to read
noFill();
beginShape();
for (int i=0; i < rate.length-1; i++){ // variable 'i' will take the place of pixel x position
vertex(i+510, rate[i]); // display history of heart rate datapoints
}
endShape();
}
void drawHeart(){
// DRAW THE HEART AND MAYBE MAKE IT BEAT
fill(250,0,0);
stroke(250,0,0);
// the 'heart' variable is set in serialEvent when arduino sees a beat happen
heart--; // heart is used to time how long the heart graphic swells when your heart beats
heart = max(heart,0); // don't let the heart variable go into negative numbers
if (heart > 0){ // if a beat happened recently,
strokeWeight(8); // make the heart big
}
smooth(); // draw the heart with two bezier curves
bezier(width-100,50, width-20,-20, width,140, width-100,150);
bezier(width-100,50, width-190,-20, width-200,140, width-100,150);
strokeWeight(1); // reset the strokeWeight for next time
}
void listAvailablePorts(){
serialPorts = Serial.list();
fill(0);
textFont(font,16);
textAlign(LEFT);
// set a counter to list the ports backwards
int yPos = 0;
for(int i=serialPorts.length-1; i>=0; i--){
button[i] = new Radio(35, 95+(yPos*20),12,color(180),color(80),color(255),i,button);
text(serialPorts[i],50, 100+(yPos*20));
yPos++;
}
textFont(font);
textAlign(CENTER);
}
import processing.sound.*;
SoundFile file;
import processing.serial.*;
PFont font;
PFont portsFont;
Scrollbar scaleBar;
Serial port;
int Sensor; // holds pusle sensor data from the arduino
int TBH; // HOLDS TIME BETWEN HEARTBEATS FROM ARDUINO
int BPM; // HOLDS HEART RATE VALUE FROM ARDUINO
int[] RawY; // HOLDS HEARTBEAT WAVEFORM DATA BEFORE SCALING
int[] ScaledY; // USED TO POSITION SCALED HEARTBEAT WAVEFORM
int[] rate; // USED TO POSITION BPM DATA WAVEFORM
float zoom; // USED WHEN SCALING PULSE WAVEFORM TO PULSE WINDOW
float offset; // USED WHEN SCALING PULSE WAVEFORM TO PULSE WINDOW
color eggshell = color(171,219,227);
int heart = 0; // This variable times the heart image 'pulse' on screen
// THESE VARIABLES DETERMINE THE SIZE OF THE DATA WINDOWS
int PulseWindowWidth = 490;
int PulseWindowHeight = 512;
int BPMWindowWidth = 180;
int BPMWindowHeight = 340;
boolean beat = false; // set when a heart beat is detected, then cleared when the BPM graph is advanced
// SERIAL PORT STUFF TO HELP YOU FIND THE CORRECT SERIAL PORT
String serialPort;
String[] serialPorts = new String[Serial.list().length];
boolean serialPortFound = false;
Radio[] button = new Radio[Serial.list().length];
void setup() {
size(700, 600); // Stage size
file = new SoundFile(this, "heart.mp3");
frameRate(100);
font = loadFont("Arial-BoldMT-24.vlw");
textFont(font);
textAlign(CENTER);
rectMode(CENTER);
ellipseMode(CENTER);
// Scrollbar constructor inputs: x,y,width,height,minVal,maxVal
scaleBar = new Scrollbar (400, 575, 180, 12, 0.5, 1.0); // set parameters for the scale bar
RawY = new int[PulseWindowWidth]; // initialize raw pulse waveform array
ScaledY = new int[PulseWindowWidth]; // initialize scaled pulse waveform array
rate = new int [BPMWindowWidth]; // initialize BPM waveform array
zoom = 0.75; // initialize scale of heartbeat window
// set the visualizer lines to 0
for (int i=0; i<rate.length; i++){
rate[i] = 555; // Place BPM graph line at bottom of BPM Window
}
for (int i=0; i<RawY.length; i++){
RawY[i] = height/2; // initialize the pulse window data line to V/2
}
background(0);
noStroke();
// DRAW OUT THE PULSE WINDOW AND BPM WINDOW RECTANGLES
drawDataWindows();
drawHeart();
// GO FIND THE ARDUINO
fill(eggshell);
text("Select Your Serial Port",245,30);
listAvailablePorts();
}
void draw() {
if(serialPortFound){
// ONLY RUN THE VISUALIZER AFTER THE PORT IS CONNECTED
background(0);
noStroke();
drawDataWindows();
drawPulseWaveform();
drawBPMwaveform();
drawHeart();
// PRINT THE DATA AND VARIABLE VALUES
fill(eggshell); // get ready to print text
text("Check your Heart Beat and Pulse",245,30); // tell them what you are
text("TBH " + TBH + "mS",600,585); // print the time between heartbeats in mS
text(BPM + "BPM",600,200); // print the Beats Per Minute
text("Scale the Pulse Rate " + nf(zoom,1,2), 150, 585); // show the current scale of Pulse Window
// DO THE SCROLLBAR THINGS
scaleBar.update (mouseX, mouseY);
scaleBar.display();
} else { // SCAN BUTTONS TO FIND THE SERIAL PORT
for(int i=0; i<button.length; i++){
button[i].overRadio(mouseX,mouseY);
button[i].displayRadio();
}
}
} //end of draw loop
void drawDataWindows(){
// DRAW OUT THE PULSE WINDOW AND BPM WINDOW RECTANGLES
fill(eggshell); // color for the window background
rect(255,height/2,PulseWindowWidth,PulseWindowHeight);
rect(600,385,BPMWindowWidth,BPMWindowHeight);
}
void drawPulseWaveform(){
// DRAW THE PULSE WAVEFORM
// prepare pulse data points
RawY[RawY.length-1] = (1023 - Sensor) - 212; // place the new raw datapoint at the end of the array
zoom = scaleBar.getPos(); // get current waveform scale value
offset = map(zoom,0.5,1,150,0); // calculate the offset needed at this scale
for (int i = 0; i < RawY.length-1; i++) { // move the pulse waveform by
RawY[i] = RawY[i+1]; // shifting all raw datapoints one pixel left
float dummy = RawY[i] * zoom + offset; // adjust the raw data to the selected scale
ScaledY[i] = constrain(int(dummy),44,556); // transfer the raw data array to the scaled array
}
stroke(250,0,0); // red is a good color for the pulse waveform
noFill();
beginShape(); // using beginShape() renders fast
for (int x = 1; x < ScaledY.length-1; x++) {
vertex(x+10, ScaledY[x]); //draw a line connecting the data points
}
endShape();
}
void drawBPMwaveform(){
// DRAW THE BPM WAVE FORM
// first, shift the BPM waveform over to fit then next data point only when a beat is found
if (beat == true){ // move the heart rate line over one pixel every time the heart beats
file.play();
beat = false; // clear beat flag (beat flag waset in serialEvent tab)
for (int i=0; i<rate.length-1; i++){
rate[i] = rate[i+1]; // shift the bpm Y coordinates over one pixel to the left
}
// then limit and scale the BPM value
BPM = min(BPM,200); // limit the highest BPM value to 200
float dummy = map(BPM,0,200,555,215); // map it to the heart rate window Y
rate[rate.length-1] = int(dummy); // set the rightmost pixel to the new data point value
}
// GRAPH THE HEART RATE WAVEFORM
stroke(250,0,0); // color of heart rate graph
strokeWeight(2); // thicker line is easier to read
noFill();
beginShape();
for (int i=0; i < rate.length-1; i++){ // variable 'i' will take the place of pixel x position
vertex(i+510, rate[i]); // display history of heart rate datapoints
}
endShape();
}
void drawHeart(){
// DRAW THE HEART AND MAYBE MAKE IT BEAT
fill(250,0,0);
stroke(250,0,0);
// the 'heart' variable is set in serialEvent when arduino sees a beat happen
heart--; // heart is used to time how long the heart graphic swells when your heart beats
heart = max(heart,0); // don't let the heart variable go into negative numbers
if (heart > 0){ // if a beat happened recently,
strokeWeight(8); // make the heart big
}
smooth(); // draw the heart with two bezier curves
bezier(width-100,50, width-20,-20, width,140, width-100,150);
bezier(width-100,50, width-190,-20, width-200,140, width-100,150);
strokeWeight(1); // reset the strokeWeight for next time
}
void listAvailablePorts(){
serialPorts = Serial.list();
fill(0);
textFont(font,16);
textAlign(LEFT);
// set a counter to list the ports backwards
int yPos = 0;
for(int i=serialPorts.length-1; i>=0; i--){
button[i] = new Radio(35, 95+(yPos*20),12,color(180),color(80),color(255),i,button);
text(serialPorts[i],50, 100+(yPos*20));
yPos++;
}
textFont(font);
textAlign(CENTER);
}
scaleBar.press(mouseX, mouseY);
for(int i=0; i<button.length; i++){
if(button[i].pressRadio(mouseX,mouseY)){
port = new Serial(this, Serial.list()[i], 115200); // make sure Arduino is talking serial at this baud rate
port.clear(); // flush buffer
port.bufferUntil('\n'); // set buffer full flag on receipt of carriage return
println("Couldn't open port " + Serial.list()[i]);
case 's': // pressing 's' or 'S' will take a jpg of the processing window
saveFrame("heartLight-####.jpg"); // take a shot of that!
void mousePressed(){
scaleBar.press(mouseX, mouseY);
if(!serialPortFound){
for(int i=0; i<button.length; i++){
if(button[i].pressRadio(mouseX,mouseY)){
try{
port = new Serial(this, Serial.list()[i], 115200); // make sure Arduino is talking serial at this baud rate
delay(1000);
println(port.read());
port.clear(); // flush buffer
port.bufferUntil('\n'); // set buffer full flag on receipt of carriage return
serialPortFound = true;
}
catch(Exception e){
println("Couldn't open port " + Serial.list()[i]);
}
}
}
}
}
void mouseReleased(){
scaleBar.release();
}
void keyPressed(){
switch(key){
case 's': // pressing 's' or 'S' will take a jpg of the processing window
case 'S':
saveFrame("heartLight-####.jpg"); // take a shot of that!
break;
default:
break;
}
}
void mousePressed(){
scaleBar.press(mouseX, mouseY);
if(!serialPortFound){
for(int i=0; i<button.length; i++){
if(button[i].pressRadio(mouseX,mouseY)){
try{
port = new Serial(this, Serial.list()[i], 115200); // make sure Arduino is talking serial at this baud rate
delay(1000);
println(port.read());
port.clear(); // flush buffer
port.bufferUntil('\n'); // set buffer full flag on receipt of carriage return
serialPortFound = true;
}
catch(Exception e){
println("Couldn't open port " + Serial.list()[i]);
}
}
}
}
}
void mouseReleased(){
scaleBar.release();
}
void keyPressed(){
switch(key){
case 's': // pressing 's' or 'S' will take a jpg of the processing window
case 'S':
saveFrame("heartLight-####.jpg"); // take a shot of that!
break;
default:
break;
}
}
color baseColor, overColor, pressedColor;
Radio(int xp, int yp, int s, color b, color o, color p, int m, Radio[] r) {
boolean pressRadio(float mx, float my){
if (dist(_x, _y, mx, my) < size/2){
for(int i=0; i<radios.length; i++){
if(i != me){ radios[i].pressed = false; }
boolean overRadio(float mx, float my){
if (dist(_x, _y, mx, my) < size/2){
for(int i=0; i<radios.length; i++){
if(i != me){ radios[i].over = false; }
ellipse(_x,_y,size,size);
ellipse(_x,_y,dotSize,dotSize);
ellipse(_x,_y,dotSize,dotSize);
class Radio {
int _x,_y;
int size, dotSize;
color baseColor, overColor, pressedColor;
boolean over, pressed;
int me;
Radio[] radios;
Radio(int xp, int yp, int s, color b, color o, color p, int m, Radio[] r) {
_x = xp;
_y = yp;
size = s;
dotSize = size - size/3;
baseColor = b;
overColor = o;
pressedColor = p;
radios = r;
me = m;
}
boolean pressRadio(float mx, float my){
if (dist(_x, _y, mx, my) < size/2){
pressed = true;
for(int i=0; i<radios.length; i++){
if(i != me){ radios[i].pressed = false; }
}
return true;
} else {
return false;
}
}
boolean overRadio(float mx, float my){
if (dist(_x, _y, mx, my) < size/2){
over = true;
for(int i=0; i<radios.length; i++){
if(i != me){ radios[i].over = false; }
}
return true;
} else {
return false;
}
}
void displayRadio(){
noStroke();
fill(baseColor);
ellipse(_x,_y,size,size);
if(over){
fill(overColor);
ellipse(_x,_y,dotSize,dotSize);
}
if(pressed){
fill(pressedColor);
ellipse(_x,_y,dotSize,dotSize);
}
}
}
class Radio {
int _x,_y;
int size, dotSize;
color baseColor, overColor, pressedColor;
boolean over, pressed;
int me;
Radio[] radios;
Radio(int xp, int yp, int s, color b, color o, color p, int m, Radio[] r) {
_x = xp;
_y = yp;
size = s;
dotSize = size - size/3;
baseColor = b;
overColor = o;
pressedColor = p;
radios = r;
me = m;
}
boolean pressRadio(float mx, float my){
if (dist(_x, _y, mx, my) < size/2){
pressed = true;
for(int i=0; i<radios.length; i++){
if(i != me){ radios[i].pressed = false; }
}
return true;
} else {
return false;
}
}
boolean overRadio(float mx, float my){
if (dist(_x, _y, mx, my) < size/2){
over = true;
for(int i=0; i<radios.length; i++){
if(i != me){ radios[i].over = false; }
}
return true;
} else {
return false;
}
}
void displayRadio(){
noStroke();
fill(baseColor);
ellipse(_x,_y,size,size);
if(over){
fill(overColor);
ellipse(_x,_y,dotSize,dotSize);
}
if(pressed){
fill(pressedColor);
ellipse(_x,_y,dotSize,dotSize);
}
}
}
from the book "Processing" by Reas and Fry
int x,y; // the x and y coordinates
float sw, sh; // width and height of scrollbar
float pos; // position of thumb
float posMin, posMax; // max and min values of thumb
boolean rollover; // true when the mouse is over
boolean locked; // true when it's the active scrollbar
float minVal, maxVal; // min and max values for the thumb
Scrollbar (int xp, int yp, int w, int h, float miv, float mav){ // values passed from the constructor
posMax = x + sw/2; // - sh;
// updates the 'over' boolean and position of thumb
void update(int mx, int my) {
if (over(mx, my) == true){
rollover = true; // when the mouse is over the scrollbar, rollover is true
pos = constrain (mx, posMin, posMax);
// locks the thumb so the mouse can move off and still update
void press(int mx, int my){
locked = true; // when rollover is true, pressing the mouse button will lock the scrollbar on
// resets the scrollbar to neutral
// returns true if the cursor is over the scrollbar
boolean over(int mx, int my){
if ((mx > x-sw/2) && (mx < x+sw/2) && (my > y-sh/2) && (my < y+sh/2)){
// draws the scrollbar on the screen
rect(x, y, sw, sh); // create the scrollbar
if ((rollover == true) || (locked == true)){
strokeWeight(8); // make the scale dot bigger if you're on it
ellipse(pos, y, sh, sh); // create the scaling dot
strokeWeight(1); // reset strokeWeight
// returns the current value of the thumb
float scalar = sw / sw; // (sw - sh/2);
float ratio = (pos-(x-sw/2)) * scalar;
float p = minVal + (ratio/sw * (maxVal - minVal));
/*
from the book "Processing" by Reas and Fry
*/
class Scrollbar{
int x,y; // the x and y coordinates
float sw, sh; // width and height of scrollbar
float pos; // position of thumb
float posMin, posMax; // max and min values of thumb
boolean rollover; // true when the mouse is over
boolean locked; // true when it's the active scrollbar
float minVal, maxVal; // min and max values for the thumb
Scrollbar (int xp, int yp, int w, int h, float miv, float mav){ // values passed from the constructor
x = xp;
y = yp;
sw = w;
sh = h;
minVal = miv;
maxVal = mav;
pos = x - sh/2;
posMin = x-sw/2;
posMax = x + sw/2; // - sh;
}
// updates the 'over' boolean and position of thumb
void update(int mx, int my) {
if (over(mx, my) == true){
rollover = true; // when the mouse is over the scrollbar, rollover is true
} else {
rollover = false;
}
if (locked == true){
pos = constrain (mx, posMin, posMax);
}
}
// locks the thumb so the mouse can move off and still update
void press(int mx, int my){
if (rollover == true){
locked = true; // when rollover is true, pressing the mouse button will lock the scrollbar on
}else{
locked = false;
}
}
// resets the scrollbar to neutral
void release(){
locked = false;
}
// returns true if the cursor is over the scrollbar
boolean over(int mx, int my){
if ((mx > x-sw/2) && (mx < x+sw/2) && (my > y-sh/2) && (my < y+sh/2)){
return true;
}else{
return false;
}
}
// draws the scrollbar on the screen
void display (){
noStroke();
fill(255);
rect(x, y, sw, sh); // create the scrollbar
fill (250,0,0);
if ((rollover == true) || (locked == true)){
stroke(250,0,0);
strokeWeight(8); // make the scale dot bigger if you're on it
}
ellipse(pos, y, sh, sh); // create the scaling dot
strokeWeight(1); // reset strokeWeight
}
// returns the current value of the thumb
float getPos() {
float scalar = sw / sw; // (sw - sh/2);
float ratio = (pos-(x-sw/2)) * scalar;
float p = minVal + (ratio/sw * (maxVal - minVal));
return p;
}
}
/*
from the book "Processing" by Reas and Fry
*/
class Scrollbar{
int x,y; // the x and y coordinates
float sw, sh; // width and height of scrollbar
float pos; // position of thumb
float posMin, posMax; // max and min values of thumb
boolean rollover; // true when the mouse is over
boolean locked; // true when it's the active scrollbar
float minVal, maxVal; // min and max values for the thumb
Scrollbar (int xp, int yp, int w, int h, float miv, float mav){ // values passed from the constructor
x = xp;
y = yp;
sw = w;
sh = h;
minVal = miv;
maxVal = mav;
pos = x - sh/2;
posMin = x-sw/2;
posMax = x + sw/2; // - sh;
}
// updates the 'over' boolean and position of thumb
void update(int mx, int my) {
if (over(mx, my) == true){
rollover = true; // when the mouse is over the scrollbar, rollover is true
} else {
rollover = false;
}
if (locked == true){
pos = constrain (mx, posMin, posMax);
}
}
// locks the thumb so the mouse can move off and still update
void press(int mx, int my){
if (rollover == true){
locked = true; // when rollover is true, pressing the mouse button will lock the scrollbar on
}else{
locked = false;
}
}
// resets the scrollbar to neutral
void release(){
locked = false;
}
// returns true if the cursor is over the scrollbar
boolean over(int mx, int my){
if ((mx > x-sw/2) && (mx < x+sw/2) && (my > y-sh/2) && (my < y+sh/2)){
return true;
}else{
return false;
}
}
// draws the scrollbar on the screen
void display (){
noStroke();
fill(255);
rect(x, y, sw, sh); // create the scrollbar
fill (250,0,0);
if ((rollover == true) || (locked == true)){
stroke(250,0,0);
strokeWeight(8); // make the scale dot bigger if you're on it
}
ellipse(pos, y, sh, sh); // create the scaling dot
strokeWeight(1); // reset strokeWeight
}
// returns the current value of the thumb
float getPos() {
float scalar = sw / sw; // (sw - sh/2);
float ratio = (pos-(x-sw/2)) * scalar;
float p = minVal + (ratio/sw * (maxVal - minVal));
return p;
}
}
void serialEvent(Serial port){
String inData = port.readStringUntil('\n');
inData = trim(inData); // cut off white space (carriage return)
if (inData.charAt(0) == 'S'){ // leading 'S' for sensor data
inData = inData.substring(1); // cut off the leading 'S'
Sensor = int(inData); // convert the string to usable int
if (inData.charAt(0) == 'B'){ // leading 'B' for BPM data
inData = inData.substring(1); // cut off the leading 'B'
BPM = int(inData); // convert the string to usable int
beat = true; // set beat flag to advance heart rate graph
heart = 20; // begin heart image 'swell' timer
if (inData.charAt(0) == 'Q'){ // leading 'Q' means IBI data
inData = inData.substring(1); // cut off the leading 'Q'
TBH = int(inData); // convert the string to usable int
// println(e.toString());
void serialEvent(Serial port){
try{
String inData = port.readStringUntil('\n');
inData = trim(inData); // cut off white space (carriage return)
if (inData.charAt(0) == 'S'){ // leading 'S' for sensor data
inData = inData.substring(1); // cut off the leading 'S'
Sensor = int(inData); // convert the string to usable int
}
if (inData.charAt(0) == 'B'){ // leading 'B' for BPM data
inData = inData.substring(1); // cut off the leading 'B'
BPM = int(inData); // convert the string to usable int
beat = true; // set beat flag to advance heart rate graph
heart = 20; // begin heart image 'swell' timer
}
if (inData.charAt(0) == 'Q'){ // leading 'Q' means IBI data
inData = inData.substring(1); // cut off the leading 'Q'
TBH = int(inData); // convert the string to usable int
}
} catch(Exception e) {
// println(e.toString());
}
}
void serialEvent(Serial port){
try{
String inData = port.readStringUntil('\n');
inData = trim(inData); // cut off white space (carriage return)
if (inData.charAt(0) == 'S'){ // leading 'S' for sensor data
inData = inData.substring(1); // cut off the leading 'S'
Sensor = int(inData); // convert the string to usable int
}
if (inData.charAt(0) == 'B'){ // leading 'B' for BPM data
inData = inData.substring(1); // cut off the leading 'B'
BPM = int(inData); // convert the string to usable int
beat = true; // set beat flag to advance heart rate graph
heart = 20; // begin heart image 'swell' timer
}
if (inData.charAt(0) == 'Q'){ // leading 'Q' means IBI data
inData = inData.substring(1); // cut off the leading 'Q'
TBH = int(inData); // convert the string to usable int
}
} catch(Exception e) {
// println(e.toString());
}
}