Go Down

Topic: Recording Realtime Graph for reviewing (Read 9246 times) previous topic - next topic

Johan12

I am currently using an Arduino and Processing Interface in order to view readings of 5 sensors via Realtime Graph in processing. I just wondered if it is possible to record my readings somehow to review later and possibly pause the graph at certain time intervals. Does Anyone have any good Ideas how this could be done?

PaulS

Quote
I just wondered if it is possible to record my readings somehow to review later

Well, Processing runs on a PC, right? There is a file allocation table on your PC, right? This means that you can create files, right? Of course you can. The Processing application is a file. So, look into creating and writing to files using Processing.

Quote
possibly pause the graph at certain time intervals

Pause as in stop collecting and graphing the data? Or, pause as in continue collecting the data, but stop updating the screen for a period of time? Both are possible.
The art of getting good answers lies in asking good questions.

Johan12

ok, With Pause I mean, Pause as in stop collecting and graphing the data. Let me put it this way, I can at the moment see the graph live of all the sensors which is great.

So I would like to collect data for a minute or two, stop collecting data then have a playback option to review the data, except this time be able to pause the graph at certain intervals of time in order to document sensor readings at specific times.  :-/

PaulS

Pausing is easy.

Data is being collected in each pass through the draw function. Add a boolean flag, initialized to false. Draw a "Wait, wait, hold on a minute..." "button". Detect mouse clicks in that "button". If a mouse click occurs in that area, toggle the boolean (flag = !flag).

If the boolean (flag) is true, collect, record, and draw the next batch of data. If not, don't.

The playback option is really a separate program. You can define that in any way you like.
The art of getting good answers lies in asking good questions.

Johan12

Thanks, that makes some sense and seems simple, although it seems that the playback option would be the main control I need for what I want to create.

With "another program" do you mean one of the programs like a video program loaded in processing/libraries? Any suggestions on which program would be suitable to use for the playback feature and how I will be able to combine it with my existing program in order to 'playback' my Realtime graph?

This is the first time I am using processing or Arduino.

Thanks for all the help so far and having patience with the newbe  ::)

PaulS

You have copied or written a Processing application to collect, record, and graph data.

The "another program" I was referring to is the new program you will write to replay that recorded data, in whatever was seems appropriate to you. There is nothing existing that will replay your data the way that you want.
The art of getting good answers lies in asking good questions.

Johan12

#6
Aug 19, 2010, 02:28 pm Last Edit: Aug 19, 2010, 02:37 pm by Johan12 Reason: 1
Thank you. I understand. At the moment I am using this code below in order to visualise the realtime graph. Any Ideas for a code for the playback option? All I need really is a recording of the values of the individual sensors at certain times. If I am not able to program a playback code to actually see a visual graph, cant I somehow just review the values of the sensors numerically at certain times?

Code: [Select]
/*
 Serial Graphing Sketch
 by Tom Igoe
 Language: Processing

 This sketch takes ASCII values from the serial port
 at 9600 bps and graphs them.
 The values should be comma-delimited, with a newline
 at the end of every set of values.
 The expected range of the values is between 0 and 1023.

 Created 20 April 2005
 Updated 27 June 2008
*/

import processing.serial.*;

int maxNumberOfSensors = 6;       // Arduino has 6 analog inputs, so I chose 6
boolean fontInitialized = false;  // whether the font's been initialized
Serial myPort;                    // The serial port

float[] previousValue = new float[maxNumberOfSensors];  // array of previous values
int xpos = 0;                     // x position of the graph
PFont myFont;                     // font for writing text to the window

void setup () {
 // set up the window to whatever size you want:
 size(800, 600);        
 // List all the available serial ports:
 println(Serial.list());
 // I know that the first port in the serial list on my mac
 // is always my  Arduino or Wiring module, so I open Serial.list()[0].
 // Open whatever port is the one you're using.
 String portName = Serial.list()[0];
 myPort = new Serial(this, portName, 9600);
 myPort.clear();
 // don't generate a serialEvent() until you get a newline (\n) byte:
 myPort.bufferUntil('\n');
 // create a font with the fourth font available to the system:
 myFont = createFont(PFont.list()[3], 14);
 textFont(myFont);
 fontInitialized = true;
 // set inital background:
 background(0);
 // turn on antialiasing:
 smooth();
}

void draw () {
 // nothing happens in the draw loop,
 // but it's needed to keep the program running
}

void serialEvent (Serial myPort) {
 // get the ASCII string:
 String inString = myPort.readStringUntil('\n');

 // if it's not empty:
 if (inString != null) {
   // trim off any whitespace:
   inString = trim(inString);

   // convert to an array of ints:
   int incomingValues[] = int(split(inString, ","));

   // print out the values
   //  print("length: " + incomingValues.length + " values.\t");
   if (incomingValues.length <= maxNumberOfSensors && incomingValues.length > 0) {
     for (int i = 0; i < incomingValues.length; i++) {

       // map the incoming values (0 to  1023) to an appropriate
       // graphing range (0 to window height/number of values):
       float ypos = map(incomingValues[i], 0, 1023, 0, height/incomingValues.length);

       // figure out the y position for this particular graph:
       float graphBottom = i * height/incomingValues.length;
       ypos = ypos + graphBottom;

       // make a black block to erase the previous text:
       noStroke();
       fill(0);
       rect(10, graphBottom+1, 110, 20);

       // print the sensor numbers to the screen:
       fill(255);
       int textPos = int(graphBottom) + 14;
       // sometimes serialEvent() can happen before setup() is done.
       // so you need to make sure the font is initialized before
       // you text():
       if (fontInitialized) {
         text("Sensor " + i + ":" + incomingValues[i], 10, textPos);
       }
       // draw a line at the bottom of each graph:
       stroke(127);
       line(0, graphBottom, width, graphBottom);
       // change colors to draw the graph line:
       stroke(64*i, 32*i, 255);
       line(xpos, previousValue[i], xpos+1, ypos);
       // save the current value to be the next time's previous value:
       previousValue[i] = ypos;
     }
   }
   // if you've drawn to the edge of the window, start at the beginning again:
   if (xpos >= width) {
     xpos = 0;
     background(0);
   }
   else {
     xpos++;
   }
 }
}

PaulS

The serialEvent method is called every time there is serial data to read. In that method, add code to write the time and the values to a file (that is opened in setup()).

If the file is a .csv file (comma separated values), and the fields (time and sensor values) are separated by some separator (there's a hint in the name), the file can be opened in Excel. Then, you can just scroll down and see the values. If you are fancy with Excel (I am not), you can even make it graph values for you. Or find the minimum and maximum.
The art of getting good answers lies in asking good questions.

Johan12

That sounds like a wonderfull idea and I understand the concept but for the last two days I have been struggeling with understanding the code. I got some examples from the libraries on saving Strings, frames, bytes, Streams etc. It seems that I should add the code right at the end of my existing processing code, with some of them the program runs but makes the graph in the sketch very slow. It just seems like I have no clue what's going on. Could It be possible to give me an example of what the code should look like and where to add it? Please :'(

andrew0

#9
Aug 22, 2010, 07:41 pm Last Edit: Aug 22, 2010, 07:44 pm by Andrew Reason: 1
For starters try putting

Code: [Select]
PrintWriter output;

at the start of your Processing code (after "Serial myPort;" would be a good place.

Then put

Code: [Select]
output = createWriter("positions.txt");

in setup() at the end of the function, and put

Code: [Select]
output.println(ypos);

in the serialEvent() function, just after these two lines

Code: [Select]
// save the current value to be the next time's previous value:
previousValue[i] = ypos;


This should get you a file called "positions.txt" containing your graph's y values. You can then alter it to do what you want.

I'm basing this on the example at the processing.org website - http://processing.org/learning/topics/savefile2.html - did you look at these examples?

Andrew

Johan12

Thanks, At the moment I am getting an error ( Cannot find anything named "ypos"). Any ideas?
Code: [Select]

import processing.serial.*;

int maxNumberOfSensors = 3;       // Arduino has 6 analog inputs, so I chose 6
boolean fontInitialized = false;  // whether the font's been initialized
Serial myPort;   // The serial port
PrintWriter output;

float[] previousValue = new float[maxNumberOfSensors];  // array of previous values
int xpos = 0;                     // x position of the graph
PFont myFont;                     // font for writing text to the window

void setup () {
 // set up the window to whatever size you want:
 size(800, 600);        
 // List all the available serial ports:
 println(Serial.list());
 // I know that the first port in the serial list on my mac
 // is always my  Arduino or Wiring module, so I open Serial.list()[0].
 // Open whatever port is the one you're using.
 String portName = Serial.list()[4];
 myPort = new Serial(this, portName, 9600);
 myPort.clear();
 // don't generate a serialEvent() until you get a newline (\n) byte:
 myPort.bufferUntil('\n');
 // create a font with the fourth font available to the system:
 myFont = createFont(PFont.list()[3], 14);
 textFont(myFont);
 fontInitialized = true;
 // set inital background:
 background(0);
 // turn on antialiasing:
 smooth();
 output.printIn(ypos);
}

void draw () {
 // nothing happens in the draw loop,
 // but it's needed to keep the program running
}

void serialEvent (Serial myPort) {
 // get the ASCII string:
 String inString = myPort.readStringUntil('\n');

 // if it's not empty:
 if (inString != null) {
   // trim off any whitespace:
   inString = trim(inString);

   // convert to an array of ints:
   int incomingValues[] = int(split(inString, ","));

   // print out the values
   //  print("length: " + incomingValues.length + " values.\t");
   if (incomingValues.length <= maxNumberOfSensors && incomingValues.length > 0) {
     for (int i = 0; i < incomingValues.length; i++) {

       // map the incoming values (0 to  1023) to an appropriate
       // graphing range (0 to window height/number of values):
       float ypos = map(incomingValues[i], 0, 1023, 0, height/incomingValues.length);

       // figure out the y position for this particular graph:
       float graphBottom = i * height/incomingValues.length;
       ypos = ypos + graphBottom;

       // make a black block to erase the previous text:
       noStroke();
       fill(0);
       rect(10, graphBottom+1, 110, 20);

       // print the sensor numbers to the screen:
       fill(255);
       int textPos = int(graphBottom) + 14;
       // sometimes serialEvent() can happen before setup() is done.
       // so you need to make sure the font is initialized before
       // you text():
       if (fontInitialized) {
         text("Sensor " + i + ":" + incomingValues[i], 10, textPos);
       }
       // draw a line at the bottom of each graph:
       stroke(127);
       line(0, graphBottom, width, graphBottom);
       // change colors to draw the graph line:
       stroke(64*i, 32*i, 255);
       line(xpos, previousValue[i], xpos+1, ypos);
       // save the current value to be the next time's previous value:
       previousValue[i] = ypos;
     }
   }
   // if you've drawn to the edge of the window, start at the beginning again:
   if (xpos >= width) {
     xpos = 0;
     background(0);
   }
   else {
     xpos++;
     // save the current value to be the next time's previous value:
previousValue[i] = ypos;
   }
 }
}

andrew0

#11
Aug 22, 2010, 08:36 pm Last Edit: Aug 22, 2010, 08:40 pm by Andrew Reason: 1
Yes, you've put the output.println(ypos) in the wrong place. Like I said, it goes in the serialEvent() function towards the end, just after previousValue=ypos;

Andrew

Johan12

Oops, ok its working fine now and I have changed it to a csv file like PaulS said so that it is simpler to convert into a graph.

Thanks a million you guys!!! :)

Go Up