Go Down

Topic: Trying to read serial data being printed by an Arduino using Processing (Read 2554 times) previous topic - next topic

Onceler

Hi there,

I'm trying to read a pulse rate (BPM) from a pulse sensor on my Arduino Uno r3.  The pulse sensor came with premade some code, that already sends data to Processing via Serial communication.  This data was then used in another premade program that creates a nice Java window to display the heartbeat signal and some other stuff. I don't want to use the premade Processing code, so I'm writing a new one.  I am, however, modifying the premade Arduino code, because most of that is useful.  There is also an "Interrupt" Arduino sketch to go along with the one I've posted below, but I haven't messed with that because it deals with the sensor output.  I can post that if need be.

What I want to do is to capture the BPM data from the pulse sensor and save it to a .csv file to look at later.  I am trying to modify the premade pulse sensor code to let me do this.  

Arduino code:

Code: [Select]
/*
>> Pulse Sensor Amped 1.1 <<
This code is for Pulse Sensor Amped by Joel Murphy and Yury Gitman
   www.pulsesensor.com
   >>> Pulse Sensor purple wire goes to Analog Pin 0 <<<
Pulse Sensor sample aquisition and processing happens in the background via Timer 2 interrupt. 2mS sample rate.
PWM on pins 3 and 11 will not work when using this code, because we are using Timer 2!
The following variables are automatically updated:
Signal :    int that holds the analog signal data straight from the sensor. updated every 2mS.
IBI  :      int that holds the time interval between beats. 2mS resolution.
BPM  :      int that holds the heart rate value, derived every beat, from averaging previous 10 IBI values.
QS  :       boolean that is made true whenever Pulse is found and BPM is updated. User must reset.
Pulse :     boolean that is true when a heartbeat is sensed then false in time with pin13 LED going out.

This code is designed with output serial data to Processing sketch "PulseSensorAmped_Processing-xx"
The Processing sketch is a simple data visualizer.
All the work to find the heartbeat and determine the heartrate happens in the code below.
Pin 13 LED will blink with heartbeat.
If you want to use pin 13 for something else, adjust the interrupt handler
It will also fade an LED on pin fadePin with every beat. Put an LED and series resistor from fadePin to GND.
Check here for detailed code walkthrough:
http://pulsesensor.myshopify.com/pages/pulse-sensor-amped-arduino-v1dot1

Code Version 02 by Joel Murphy & Yury Gitman  Fall 2012
This update changes the HRV variable name to IBI, which stands for Inter-Beat Interval, for clarity.
Switched the interrupt to Timer2.  500Hz sample rate, 2mS resolution IBI value.
Fade LED pin moved to pin 5 (use of Timer2 disables PWM on pins 3 & 11).
Tidied up inefficiencies since the last version.
*/


//  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


// these variables are volatile because they are used during the interrupt service routine!
volatile int BPM;                   // used to hold the pulse rate
volatile int Signal;                // holds the incoming raw data
volatile int IBI = 600;             // holds the time between beats, the Inter-Beat Interval
volatile boolean Pulse = false;     // true when pulse wave is high, false when it's low
volatile boolean QS = false;        // becomes true when Arduoino finds a beat.


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
  // UN-COMMENT THE NEXT LINE IF YOU ARE POWERING The Pulse Sensor AT LOW VOLTAGE,
  // AND APPLY THAT VOLTAGE TO THE A-REF PIN
  //analogReference(EXTERNAL);  
}



void loop(){
//  sendDataToProcessing('S', Signal);     // send Processing the raw Pulse Sensor data
//  if (QS == true){                       // Quantified Self flag is true when arduino finds a heartbeat
//        fadeRate = 255;                  // Set 'fadeRate' Variable to 255 to fade LED with pulse
//        sendDataToProcessing('B',BPM);   // send heart rate with a 'B' prefix
//        sendDataToProcessing('Q',IBI);   // send time between beats with a 'Q' prefix
//        QS = false;                      // reset the Quantified Self flag for next time    
//     }
//  
//  ledFadeToBeat();
 
 // Serial.print(BPM, DEC);        // Trying to print to Serial
 // Serial.print(",");                 // Maybe delimiting it will help?
  Serial.println(BPM);          //  Trying again to print to Serial
 
 delay(100);                             //  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 sendDataToProcessing(char symbol, int data ){
   Serial.print(symbol);                // symbol prefix tells Processing what type of data is coming
   Serial.println(data);                // the data to send culminating in a carriage return
 }


The code I have grafted in is under the "void loop()", the two "Serial.print" and the "Serial.println" lines. With the "Serial.println" line active, and the two "Serial.print" lines commented (those two lines were experimental), I am able to get integers running on the serial monitor.  I've commented out the other code in the loop because it adds some other characters(like "S") and things that are needed for the premade Processing program.  

I'm trying to capture this serial output using this Processing code:

Code: [Select]
import processing.serial.*;
PrintWriter output;

Serial port;

void setup() {
 // Create a new file in the sketch directory
 output = createWriter("positions.txt");


// GO FIND THE ARDUINO
 println(Serial.list());    // print a list of available serial ports
 // choose the number between the [] that is connected to the Arduino
 port = new Serial(this, Serial.list()[1], 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
}

void loop() {
 print(BPM);
}

void keyPressed() {
 output.flush();  // Writes the remaining data to the file
 output.close();  // Finishes the file
 exit();  // Stops the program
}


Running this code throws an error: "Cannot find anything named 'BPM' ".  I should mention that I've cannibalized the "// GO FIND THE ARDUINO" section of the setup section from the premade Processing code, which I've attached.

I've been trying to learn how to use Arduino and Processing by poring over the examples (e.g. createWriter(), PrintWriter, print(), read(), etc...) in the Processing documentation, but I'm having trouble understanding what's going on here.  

I know that good data (constantly updating integers) is coming out of the Arduino, because I can see it when I check the Serial Monitor.  I'm expecting that the Serial Monitor represents the data coming directly into the serial port, and that Processing can read what I can see on the monitor.  This is where my understanding breaks down.  As far as I know, I'm trying to point Processing at the serial port, and get it to store the data it finds there, but it looks like Processing can't tell what it's looking at.  

Any help would be appreciated!  Please let me know if I need to provide any more information.  




PaulS

Code: [Select]
  port.clear();            // flush buffer
How much data can there be in the buffer, nanoseconds after you opened the port? The Arduino isn't even done resetting yet.

The Processing compiler is right. There is nothing named BPM anywhere in that sketch. There is nothing even that reads the serial port.

Getting serial data into Processing doesn't magically happen. Was there a serialEvent() function in the original code?

What you have done in Processing is equivalent to Serial.begin() on the Arduino. What you don't have is the equivalent of Serial.available() and Serial.read() (or Serial.readUntil()).

Onceler

There was a serialEvent sketch with the original Processing code. 

Here it is:

Code: [Select]
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'
     IBI = int(inData);                   // convert the string to usable int
   }
}


I wonder if there is any way to use the "BPM" readings from this code, although I'd still like to try and get my own working. 

Is this where they're reading in the data from the serial port, and then passing it to the main program (the one I attached)? 

PaulS

Quote
Is this where they're reading in the data from the serial port, and then passing it to the main program (the one I attached)? 

Yes, it is. The comments there are pretty clear. All the data in one packet is read in. The end of packet marker is the \n (part of what println() adds to the data it sends).

The leading S is stripped off. You aren't sending one, so delete that block of code.

There isn't a B, either, but the block of code is necessary - just not the if statement and the braces. Actually, only the assignment to BPM is needed.

There is no trailing Q, so that block of code goes away, too.

BPM still needs to be declared as a global variable (an int).

Onceler

Alright, so following your suggestions I've modified my two sets of code.  The problem I'm having now is that Processing is not receiving the data.  My code creates a nice text file in the sketch directory, but the text file is empty.  I think it's a problem with how I'm printing my BPM, but I can't be sure whether I've set up Processing correctly in order to receive data. Any help would be appreciated!

New Processing code: 

Code: [Select]

import processing.serial.*;
Serial port;
PrintWriter output;

int BPM;         // HOLDS HEART RATE VALUE FROM ARDUINO


void setup() {
  // Create a new file in the sketch directory
  output = createWriter("BPM.txt");
 
 
  // GO FIND THE ARDUINO
  println(Serial.list());    // print a list of available serial ports
  // choose the number between the [] that is connected to the Arduino
  port = new Serial(this, Serial.list()[1], 115200);  // make sure Arduino is talking serial at this baud rate
  port.bufferUntil('\n');  // set buffer full flag on receipt of carriage return
}


void serialEvent(Serial port){
   String inData = port.readStringUntil('\n');
   inData = trim(inData);                 // cut off white space (carriage return)
   
     BPM = int(inData);                   // convert the string to usable int
//     port.write(1);                     // Try to write to serial port to test if Processing can communicate with correct serial port
   }


void draw() {      // Could use void loop() here instead?
  output.println(BPM);  // Write the BPM to the file
 
}

void keyPressed() {
  output.flush();  // Writes the remaining data to the file
  output.close();  // Finishes the file
  exit();  // Stops the program
}]



The only part of the old Arduino code that I modified was this part (the void loop()): 

Code: [Select]
void loop(){
//  sendDataToProcessing('S', Signal);     // send Processing the raw Pulse Sensor data
//  if (QS == true){                       // Quantified Self flag is true when arduino finds a heartbeat
//        fadeRate = 255;                  // Set 'fadeRate' Variable to 255 to fade LED with pulse
//        sendDataToProcessing('B',BPM);   // send heart rate with a 'B' prefix
//        sendDataToProcessing('Q',IBI);   // send time between beats with a 'Q' prefix
//        QS = false;                      // reset the Quantified Self flag for next time   
//     }
// 
//  ledFadeToBeat();

//sendDataToProcessing('B', BPM);     // send Processing the raw Pulse Sensor data

Serial.println(BPM);  //  Trying again to print to Serial
 
  delay(100);                             //  take a break
}


PaulS

Do you KNOW that your Arduino is connected to the 2nd item in the list of serial ports?

You can add print() and println() statements to the Processing sketch, to see whether serialEvent is ever called.

Onceler

In the Arduino IDE, under Tools > Serial Port, "COM3" is selected.  In Processing, when I run my code, the following is produced in the output window at the bottom of the Processing IDE:

Code: [Select]
Stable Library
=========================================
Native lib Version = RXTX-2.1-7
Java lib Version   = RXTX-2.1-7
[0] "COM1"
[1] "COM3"





I think I have the right port entry, but feel free to correct me if I'm wrong. 


If I add

Code: [Select]
println(9999);
inside the "void serialEvent(Serial port)" section, I DO get a bunch of "9999"s printed, at about the same rate as the serial monitor is producing my "BPM" integers. 

PaulS

Quote
inside the "void serialEvent(Serial port)" section, I DO get a bunch of "9999"s printed, at about the same rate as the serial monitor is producing my "BPM" integers.

Why aren't you printing something useful, like inData?

Onceler

Ok, with this:

Code: [Select]
println(inData);

I get the same output as I would normally get in the Arduino's serial monitor. 

PaulS

Quote
I get the same output as I would normally get in the Arduino's serial monitor.

Excellent. So, where did you put that print() statement? Before of after the call to trim()?

What do you get when you print BPM?

Onceler

Ok, so here is my new code, with the print line in it:


Code: [Select]

import processing.serial.*;
Serial port;
PrintWriter output;

int BPM;         // HOLDS HEART RATE VALUE FROM ARDUINO


void setup() {
  // Create a new file in the sketch directory
  output = createWriter("BPM.txt");
 
 
  // GO FIND THE ARDUINO
  println(Serial.list());    // print a list of available serial ports
  // choose the number between the [] that is connected to the Arduino
  port = new Serial(this, Serial.list()[1], 115200);  // make sure Arduino is talking serial at this baud rate
  port.bufferUntil('\n');  // set buffer full flag on receipt of carriage return
}


void serialEvent(Serial port){
   String inData = port.readStringUntil('\n');
   inData = trim(inData);                 // cut off white space (carriage return)
   
     BPM = int(inData);                   // convert the string to usable int
    println(inData);
   }


void draw() {      // Could use void loop() here instead?
  output.println(BPM);  // Write the BPM to the file
 
}

void keyPressed() {
  output.flush();  // Writes the remaining data to the file
  output.close();  // Finishes the file
  exit();  // Stops the program
}


It's printing my BPM ints after the trim, and they are appearing as integers with returns in between,

e.g. (this is a copy-paste from the black output terminal)

83
83
84
84
84
84
84
85
85
85
85
85
85
85
85
85
85
85
85

PaulS

Quote
It's printing my BPM ints after the trim

No, it isn't. It's printing the trimmed string, not the int that was created from the string. Hoping that BPM was constructed correctly from the string is one thing. KNOWING that BPM was constructed correctly from the string is another.

Print BPM in serialEvent, instead of inData.

Then, if that works, print BPM in draw, instead of serialEvent.

If that works, then the problem is how you are writing to the file.

(Why you want to do that every pass through draw, instead of every time there is new data, is a mystery.)

Onceler

The most recent iteration of my code DID work, I just hadn't checked the output file in a few runs.  To clear things up for anyone having similar problems, I've posted my final Processing code below.  Thanks so much for your help, PaulS!

Code: [Select]

import processing.serial.*;
Serial port;
PrintWriter output;

int BPM;         // HOLDS HEART RATE VALUE FROM ARDUINO


void setup() {
  // Create a new file in the sketch directory
  output = createWriter("BPM.txt");
 
 
  // GO FIND THE ARDUINO
  println(Serial.list());    // print a list of available serial ports
  // choose the number between the [] that is connected to the Arduino
  port = new Serial(this, Serial.list()[1], 115200);  // make sure Arduino is talking serial at this baud rate
  port.bufferUntil('\n');  // set buffer full flag on receipt of carriage return
}


void serialEvent(Serial port){
   String inData = port.readStringUntil('\n');
   inData = trim(inData);                 // cut off white space (carriage return)
   
     BPM = int(inData);                   // convert the string to usable int
//    println(BPM);
   }


void draw() {      // Could use void loop() here instead?
  output.println(BPM);  // Write the BPM to the file
 
}

void keyPressed() {
  output.flush();  // Writes the remaining data to the file
  output.close();  // Finishes the file
  exit();  // Stops the program
}

Go Up