Drw wave with serial data from Ardino, analyse with Max/msp

Dec 6, 2010 at 7:12pm

Drw wave with serial data from Ardino, analyse with Max/msp

I aim to measure heart rates through the arduino using an infra red led and a IR phototransistor to detect the pulse in my finger. This creates a data list in the serial window. From there i need to transform the data into a visually identifiable wave form using processing, send the wave to Max/ Msp which can analyse the waves for peaks and troughs, and then control the speed of a captured sound file of waves crashing against the beach using the frequency of the heart beat. There is 10 days to do this. I am sort of hoping that its not quite as difficult as it sounds. I have discovered pachube. Any help or advice would be gold dust, thanks everyone.

#53718
Dec 6, 2010 at 10:42pm

There’s some example code and a patch here, relating to graphing analog input to Processing and Max:

http://arduino.cc/en/Tutorial/Graph

If you’re happy with this, then look at [peak] and [trough] and related objects

Brendan

#193213
Dec 7, 2010 at 4:57am

#193214
Dec 7, 2010 at 5:07am

thanks very much Brendan, Ill check that out now.

Heres a few posts I have found to help me with the processing/ arduino side of things.

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1233536778
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1286747908

i’ve also been looking at jitter tutorial 28 which looks at tracking msp sound waves amplitudes. Hopefully i’m going down the right track with this

#193215
Dec 7, 2010 at 6:06am

nice project, it is more or less exactly what I did, although I used synthesis to create the waves instead of a .wav and using vbap to spatialize the sound.
I’m not sure why you want to include processing and not take the whole thing into max though.
just ask if you need more help

#193216
Dec 7, 2010 at 6:02pm

Hi llumen, most definitely could do with any help I can get.
This is the project sketch I am starting with for the arduino which records the heartbeat as serial data in the serial monitor;

int ledPin = 13;
int sensorPin = 0;

double alpha = 0.75;
int period = 20;
double change = 0.0;

void setup()
{
pinMode(ledPin, OUTPUT);
}

void loop()
{
static double oldValue = 0;
static double oldChange = 0;
int rawValue =
analogRead(sensorPin);
// smooths wave form using alpha value for level of smoothing
double value = alpha * oldValue
+ (1 – alpha) * rawValue;

digitalWrite(ledPin, (change < 0.0 && oldChange > 0.0));

oldValue = value;
oldChange = change;
delay(period);
}

[attachment=148320,1502]

Attachments:
  1. resized.jpg
#193217
Dec 7, 2010 at 6:03pm

ill check out the details you have posted now and hopefully come up with something, thanks

#193218
Dec 7, 2010 at 7:17pm

what I suggest is that you take a look at the icubeX website (http://infusionsystems.com/catalog/), they have heartbeat sensors that fit their system (but they fit arduino’s too). In any case are they normal adc sensors with a 0-1024 scale.

They have maxpatches http://infusionsystems.com/catalog/product_info.php/products_id/197 (look at software) that readout the full signal and turn it into BPM etc (very handy)

also, why don’t you use firmata on the arduino http://www.arduino.cc/playground/Interfacing/Firmata and maxuino http://www.maxuino.org/

all of this will make sure you can work on the fun stuff instead of the tedious stuff

#193219
Dec 7, 2010 at 10:41pm

Hi. the heart rate monitor is a little out of my budget. Its good to struggle though as its an educational project. I have previously installed the maxuino library but im really sweating it trying to see the bigger picture of how to bring things together. My heart rate monitor does scale between 0- 1024 though. My previous patch above was the wrong one, here is the one im using to collect serial data.

int ledPin = 13;
int sensorPin = 0;

double alpha = 0.75;
int period = 20;
double change = 0.0;

void setup()
{
pinMode(ledPin, OUTPUT);
Serial.begin(115200);
}

void loop()
{
static double oldValue = 0;
static double oldChange = 0;
int rawValue =
analogRead(sensorPin);
double value = alpha * oldValue
+ (1 – alpha) * rawValue;

Serial.print(rawValue);
Serial.print(“,”);
Serial.println(value);

oldValue = value;
delay(period);
}

Brendans link above has a viable option although I have not got it working with my sketch yet.

max

{
“boxes” : [ {
"box" : {
"maxclass" : "comment",
"text" : "GraphnnThis patch takes a string, containing ASCII formatted number from 0 to 1023, with a carriage return and linefeed at the end. It converts the string to an integer and graphs it.nncreated 2006nby David A. Mellisnmodified 14 Apr 2009nby Scott Fitzgerald and Tom Igoe",
"linecount" : 10,
"patching_rect" : [ 479.0, 6.0, 344.0, 144.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-32″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “newobj”,
“text” : “select 0 1″,
“patching_rect” : [ 327.0, 80.0, 62.0, 20.0 ],
“numoutlets” : 3,
“fontsize” : 12.0,
“outlettype” : [ "bang", "bang", "" ],
“id” : “obj-30″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “comment”,
“text” : “click here to close the serial port”,
“patching_rect” : [ 412.0, 231.0, 206.0, 20.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-26″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “comment”,
“text” : “click here to open the serial port”,
“patching_rect” : [ 412.0, 205.0, 206.0, 20.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-27″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “message”,
“text” : “close”,
“patching_rect” : [ 327.0, 231.0, 39.0, 18.0 ],
“numoutlets” : 1,
“fontsize” : 12.0,
“outlettype” : [ "" ],
“id” : “obj-21″,
“fontname” : “Arial”,
“numinlets” : 2
}

}
, {
“box” : {
“maxclass” : “message”,
“text” : “port a”,
“patching_rect” : [ 349.0, 205.0, 41.0, 18.0 ],
“numoutlets” : 1,
“fontsize” : 12.0,
“outlettype” : [ "" ],
“id” : “obj-19″,
“fontname” : “Arial”,
“numinlets” : 2
}

}
, {
“box” : {
“maxclass” : “multislider”,
“candicane7″ : [ 0.878431, 0.243137, 0.145098, 1.0 ],
“patching_rect” : [ 302.0, 450.0, 246.0, 167.0 ],
“contdata” : 1,
“numoutlets” : 2,
“peakcolor” : [ 0.498039, 0.498039, 0.498039, 1.0 ],
“slidercolor” : [ 0.066667, 0.058824, 0.776471, 1.0 ],
“candicane8″ : [ 0.027451, 0.447059, 0.501961, 1.0 ],
“outlettype” : [ "", "" ],
“setminmax” : [ 0.0, 1023.0 ],
“settype” : 0,
“candicane6″ : [ 0.733333, 0.035294, 0.788235, 1.0 ],
“setstyle” : 3,
“bgcolor” : [ 0.231373, 0.713726, 1.0, 1.0 ],
“id” : “obj-1″,
“candicane4″ : [ 0.439216, 0.619608, 0.070588, 1.0 ],
“candicane5″ : [ 0.584314, 0.827451, 0.431373, 1.0 ],
“candicane2″ : [ 0.145098, 0.203922, 0.356863, 1.0 ],
“candicane3″ : [ 0.290196, 0.411765, 0.713726, 1.0 ],
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “comment”,
“text” : “Click here to get a list of serial ports”,
“patching_rect” : [ 412.0, 179.0, 207.0, 20.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-2″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “comment”,
“text” : “Here’s the number from Arduino’s analog input”,
“linecount” : 2,
“patching_rect” : [ 153.0, 409.0, 138.0, 34.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-3″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “comment”,
“text” : “Convert ASCII to symbol”,
“patching_rect” : [ 379.0, 378.0, 147.0, 20.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-4″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “comment”,
“text” : “Convert integer to ASCII”,
“patching_rect” : [ 379.0, 355.0, 147.0, 20.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-5″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “number”,
“patching_rect” : [ 302.0, 414.0, 37.0, 20.0 ],
“numoutlets” : 2,
“fontsize” : 12.0,
“outlettype” : [ "int", "bang" ],
“bgcolor” : [ 0.866667, 0.866667, 0.866667, 1.0 ],
“id” : “obj-6″,
“triscale” : 0.9,
“fontname” : “Arial”,
“htextcolor” : [ 0.870588, 0.870588, 0.870588, 1.0 ],
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “newobj”,
“text” : “fromsymbol”,
“patching_rect” : [ 302.0, 378.0, 74.0, 20.0 ],
“numoutlets” : 1,
“fontsize” : 12.0,
“outlettype” : [ "" ],
“id” : “obj-7″,
“fontname” : “Arial”,
“color” : [ 1.0, 0.890196, 0.090196, 1.0 ],
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “newobj”,
“text” : “itoa”,
“patching_rect” : [ 302.0, 355.0, 46.0, 20.0 ],
“numoutlets” : 1,
“fontsize” : 12.0,
“outlettype” : [ "int" ],
“id” : “obj-8″,
“fontname” : “Arial”,
“color” : [ 1.0, 0.890196, 0.090196, 1.0 ],
“numinlets” : 3
}

}
, {
“box” : {
“maxclass” : “newobj”,
“text” : “zl group 4″,
“patching_rect” : [ 302.0, 332.0, 64.0, 20.0 ],
“numoutlets” : 2,
“fontsize” : 12.0,
“outlettype” : [ "", "" ],
“id” : “obj-9″,
“fontname” : “Arial”,
“numinlets” : 2
}

}
, {
“box” : {
“maxclass” : “newobj”,
“text” : “select 10 13″,
“patching_rect” : [ 244.0, 281.0, 77.0, 20.0 ],
“numoutlets” : 3,
“fontsize” : 12.0,
“outlettype” : [ "bang", "bang", "" ],
“id” : “obj-10″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “toggle”,
“patching_rect” : [ 244.0, 43.0, 15.0, 15.0 ],
“numoutlets” : 1,
“outlettype” : [ "int" ],
“id” : “obj-11″,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “newobj”,
“text” : “qmetro 10″,
“patching_rect” : [ 244.0, 80.0, 65.0, 20.0 ],
“numoutlets” : 1,
“fontsize” : 12.0,
“outlettype” : [ "bang" ],
“id” : “obj-12″,
“fontname” : “Arial”,
“numinlets” : 2
}

}
, {
“box” : {
“maxclass” : “message”,
“text” : “print”,
“patching_rect” : [ 369.0, 179.0, 36.0, 18.0 ],
“numoutlets” : 1,
“fontsize” : 12.0,
“outlettype” : [ "" ],
“id” : “obj-13″,
“fontname” : “Arial”,
“numinlets” : 2
}

}
, {
“box” : {
“maxclass” : “newobj”,
“text” : “serial a 9600″,
“patching_rect” : [ 244.0, 255.0, 84.0, 20.0 ],
“numoutlets” : 2,
“fontsize” : 12.0,
“outlettype” : [ "int", "" ],
“id” : “obj-14″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “comment”,
“text” : “Read serial input buffer every 10 milliseconds”,
“linecount” : 2,
“patching_rect” : [ 53.0, 72.0, 185.0, 34.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-15″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “comment”,
“text” : “If you get newline (ASCII 10), send the list. If you get return (ASCII 13) do nothing. Any other value, add to the list”,
“linecount” : 3,
“patching_rect” : [ 332.0, 269.0, 320.0, 48.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-16″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
, {
“box” : {
“maxclass” : “comment”,
“text” : “Click to open/close serial port and start/stop patch”,
“linecount” : 2,
“patching_rect” : [ 271.0, 32.0, 199.0, 34.0 ],
“numoutlets” : 0,
“fontsize” : 12.0,
“id” : “obj-17″,
“fontname” : “Arial”,
“numinlets” : 1
}

}
],
“lines” : [ {
"patchline" : {
"source" : [ "obj-6", 0 ],
“destination” : [ "obj-1", 0 ],
“hidden” : 0,
“midpoints” : [ ]
}

}
, {
“patchline” : {
“source” : [ "obj-7", 0 ],
“destination” : [ "obj-6", 0 ],
“hidden” : 0,
“midpoints” : [ ]
}

}
, {
“patchline” : {
“source” : [ "obj-8", 0 ],
“destination” : [ "obj-7", 0 ],
“hidden” : 0,
“midpoints” : [ ]
}

}
, {
“patchline” : {
“source” : [ "obj-9", 0 ],
“destination” : [ "obj-8", 0 ],
“hidden” : 0,
“midpoints” : [ ]
}

}
, {
“patchline” : {
“source” : [ "obj-10", 0 ],
“destination” : [ "obj-9", 0 ],
“hidden” : 0,
“midpoints” : [ 253.5, 308.0, 311.5, 308.0 ]
}

}
, {
“patchline” : {
“source” : [ "obj-10", 2 ],
“destination” : [ "obj-9", 0 ],
“hidden” : 0,
“midpoints” : [ 311.5, 320.0, 311.5, 320.0 ]
}

}
, {
“patchline” : {
“source” : [ "obj-14", 0 ],
“destination” : [ "obj-10", 0 ],
“hidden” : 0,
“midpoints” : [ ]
}

}
, {
“patchline” : {
“source” : [ "obj-12", 0 ],
“destination” : [ "obj-14", 0 ],
“hidden” : 0,
“midpoints” : [ ]
}

}
, {
“patchline” : {
“source” : [ "obj-11", 0 ],
“destination” : [ "obj-12", 0 ],
“hidden” : 0,
“midpoints” : [ ]
}

}
, {
“patchline” : {
“source” : [ "obj-13", 0 ],
“destination” : [ "obj-14", 0 ],
“hidden” : 0,
“midpoints” : [ 378.5, 200.5, 253.5, 200.5 ]
}

}
, {
“patchline” : {
“source” : [ "obj-19", 0 ],
“destination” : [ "obj-14", 0 ],
“hidden” : 0,
“midpoints” : [ 358.5, 228.5, 253.5, 228.5 ]
}

}
, {
“patchline” : {
“source” : [ "obj-21", 0 ],
“destination” : [ "obj-14", 0 ],
“hidden” : 0,
“midpoints” : [ 336.5, 251.5, 253.5, 251.5 ]
}

}
, {
“patchline” : {
“source” : [ "obj-30", 0 ],
“destination” : [ "obj-21", 0 ],
“hidden” : 0,
“midpoints” : [ ]
}

}
, {
“patchline” : {
“source” : [ "obj-30", 1 ],
“destination” : [ "obj-19", 0 ],
“hidden” : 0,
“midpoints” : [ ]
}

}
, {
“patchline” : {
“source” : [ "obj-11", 0 ],
“destination” : [ "obj-30", 0 ],
“hidden” : 0,
“midpoints” : [ 253.0, 71.0, 336.5, 71.0 ]
}

}
]
}

arduino

void setup() {
// initialize the serial communication:
Serial.begin(9600);
}

void loop() {
// send the value of analog input 0:
Serial.println(analogRead(A0));
// wait a bit for the analog-to-digital converter
// to stabilize after the last reading:
delay(10);
}

#193220
Dec 12, 2010 at 5:51am

This paart of the project is now up and running. Thanks brendan for that link. The serial data from the arduino can now be indeed be translated into a graph using the the patch found at http://arduino.cc/en/Tutorial/Graph. I am now looking to analyse the graph for peaks and use this to drive the speed of a sound file (containing the sound of waves hitting the beach) within the Max/ Msp patch. My project will be completed and handed into university by the 17th and I will publish my entire project on the forum. Its only a creative beginners project but hopefully someone may find something of interest. In the mean time, anyone who can help us with the task in hand please add a post. Thanks to everyone on the forum, your all stars

#193221
Dec 12, 2010 at 2:07pm

“I am now looking to analyse the graph for peaks and use this to drive the speed of a sound file (containing the sound of waves hitting the beach) within the Max/ Msp patch”

Is this the remaining task you need help with? How do you wish to apply the data peaks, as a discrete trigger or continuous control value?

Here is a quick mock-up of how to evaluate peaks, and extract control data for playback speed; there are better (more aesthetic) ways to do this, this is a demo of the kind of thing you can easily do in Max:

– Pasted Max Patch, click to expand. –

Brendan

#193222
Dec 12, 2010 at 3:04pm

ps

there is a valuable object called [past] which, imo, may work more intuitively than [peak] or [maximum] in this context

– Pasted Max Patch, click to expand. –

Brendan

#193223
Dec 12, 2010 at 10:28pm

Hey Brendan, in response to your post,”discrete trigger or continuous control value”; i'm not entirely sure. I'm thinking it would be a discrete trigger as I am using a prerecorded audio file. Ive taking some screen shots to show you what i have been up to. My first problem has been the graph patches interpretation of the wave. The serial data enters the patch as two values; the raw value and the value (check arduino sketch, 5th post). This is separated by a delimiter(,). Pic 1 shows how a used a 2 axis graph to display the heart beat using a spread sheet.
This led me to look at max basics tutorials, Data 2. I was trying to incorporate the part of the patch showing in pic2 so that the patch could read the .wav file and display it to the full potential in the graph by using the Peak and Trough objects to Analyse the beats range of values, adapting the graph to only show the minimum and maximum values ignoring those out of range. This would let me see what was going on better.
Pic 3 shows how i have added your patch which is working with the audio file, I'm so happy. I guess I just need to adjust the button argument values which are triggered to control the rate. Is that what the patch is doing? I really need to fix my graph readings. This is a massive help. I think ones I fix my incoming serial data for the graph and make a few tweaks to the values I will be up and running with this. Having thought this through discrete values would be fine.
thanks Brendan for all your help

[attachment=148896,1531] [attachment=148896,1532]

Attachments:
  1. 2.png
#193224
Dec 12, 2010 at 10:40pm

this is the 3rd pic as i could only load 2 pictures at a time.
Also the serial data prints as in the txt file,

[attachment=148897,1533]

Attachments:
  1. heartb.txt
#193225
Dec 12, 2010 at 10:56pm

#193226
Dec 12, 2010 at 11:20pm

The first patch is for pic 2 left hand side and the 2nd is for pic 3.

Attachments:
  1. graph2.maxpat
#193227
Dec 13, 2010 at 12:24am

sorry about this, patch one seems to be crashing my computer as i pasted some patches together without thinking and Im getting some sort of conflict disabling my keyboard and stalling Max. Don’t open it, thanks

#193228
Dec 13, 2010 at 1:36am

this is the max window

[attachment=148910,1538]

Attachments:
  1. list.png
#193229
Dec 13, 2010 at 2:17am

Im looking at 3 things at the moment. 1.Is the multislider capable of displaying this data
2. are the two values in each line in the serial data x, Y coordinates
3. How can I change the patch to recognise two values in the same line separated by the delimiter (,), and how can I graph them

#193230
Dec 13, 2010 at 2:53am

I modified the arduino sketch by deleting two of the lines;

int sensorPin = 0;

double alpha = 0.9;
int period = 20;
double change = 0.0;

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

void loop()
{
static double oldValue = 0;
static double oldChange = 0;
int rawValue =
analogRead(sensorPin);
// smoothing operation
double value = alpha * oldValue
+ (1 – alpha) * rawValue;
// the following two lines were removed
//Serial.print(rawValue);
//Serial.print(“,”);
//The last line was kept but now prints out
//the rawValue,
Serial.println(rawValue);

oldValue = value;
delay(period);
}

This makes the input compatible with the MAx/Msp patch which expects one value per line. Ive figured there was no need for the other printed values. I keep the raw value and it seems to be working to some degree of success although further calibration of the alpha value is needed. Hope I dont get into trouble for posting to much here, lol, its turning into a blogg

#193231
Dec 15, 2010 at 1:07am

Hi, the problem im facing is that the out put from the multislider is measuring the peak amplitude of the waves while I need to measure the frequency. Does anyone know how I could approach this dilemma? Im sure there has to be something in MSP, some sort of counter

#193232
Jan 14, 2011 at 12:53am

Hi all

Interesting thread. I know the initial call was a few months ago now, but this is a recurring area on this forum, so I thought I’d share my own recent work, using Pulse Oximenters with Arduino FIO, Xbee etc.

You can download the collective and a sample data file via my blog

http://georgekhut.com/2011/01/heart-and-breath-sensing-w-max-msp/

It uses Pulse and Breath data measured by GP-4u PPG and GP-Resp (purchased from Dr. Philip Brotman, Allied Products/Biofeedback Instrument Corp, and manufactured by J&J Engineering).

The sensors are connected to two Arduino FIO’s, and this data is transmitted to my Mac using XBee based Zigbee wireless connection. The Max patch includes the Arduino code for both the Breath sensor and Pulse sensor (they are different!).

I use the “dot.schmitt” schmitt trigger object by Joseph Malloch, Stephen Sinclair, and Marlon Schumacher, to determine beats and inter beat intervals, then extract various parameters from there…

I’m still looking for help to implement Frequency Domain (LOMB) analysis of the heart RATE variations… any suggestions?

Hope its useful to other exploring this area. Always happy to discuss issues, opportunities etc.

#193233

You must be logged in to reply to this topic.