by Jamie Allen Feb 1st, 2007

This is Processing code (Arduino code commented in at the bottom) for graphing data. This code includes a 'true' data trail indicating a visual history of the last 50 samples.

This code might be a good starting point for Sensors and Time assignments, among other things.



/*
psychadelic dataviewer with hysteresis 
for two values based on Tom Igoe's & Melvin Ochsmann's work
(with some help from James Tu!)
by Jamie Allen 2007

This program takes raw bytes from the serial port that are seperated by headers
"A", "B", etc. at 9600 baud and graphs them. 

Note that the data protocol in this case is not very efficient.  We're taking in
a byte for each character in the incoming number (i.e.: worst case, we're actually
reading in "A,X,X,X,X,_,B,X,X,X,X,_" or TWELVE BYTES, 12 x 8 = 96 bits.  The 
'information content of this data is actually 2 x 10 bits = 20 bits (the ADC results 
themselves, at 10 bits each).  We're therefore adding an overhead of 76 bits in our 
protocol!  There are better ways to approach this, but this method is good because 
it allows us to 'see' the incoming data in an inteligible way in the Arduino serial
monitor or other terminal programs. 

Arduino code for sending this data in the first place from the board is 
commented in below the Processing code

*/

import processing.serial.*;

Serial myPort;  // The serial port
PFont myFont;     // The display font: 

// initial variables:
int val = 0;
int NEWLINE = 10;
int i = 1;                   // counter
int j;                       // counter
int valueA, valueB;          // the converted data from serial port
boolean buf;
String bufA="", bufB="";     // buffers in which to store ascii data as it comes in
float valNormA, valNormB;    // normalized values of A and B - so we can write 
                             // them to the screen based on the size of the screen itself
int indexA=0;  //used to create a running array of the imcoming samples
int indexB=0;
float[] valuesA = new float[50];  //these arrays hold the last 50 incoming samples
float[] valuesB = new float[50];  //increasing the number of stored variables in these array
                                  //will make the 'trails' longer

int wrote = 0;                    //this is used if we want to print the numeric value to the screen
int offset = 0;                   //
int offsettext = 25;
int lf = 10;


void setup () {
  size(500, 500);        // window size
  frameRate(60);         // drawing framerate

 // load a font - it doesn't need to be this one
 // but it needs to be in your 'data' folder
  myFont = loadFont("Courier-Bold-12.vlw");  
  textFont(myFont, 16); 
  textAlign(CENTER);
  textMode(SCREEN);
  fill(#E9FF5B, 200);

  // set inital background:
  background(#000000);

  strokeCap(ROUND);
  strokeWeight(3);
  smooth();
  ellipseMode(CENTER);

  // List all the available serial ports
  println(Serial.list());
  // I know that the third port in the serial list on my mac
  // is always my  Keyspan adaptor, so I open Serial.list()[2].
  // Open whatever port is the one you're using.
  myPort = new Serial(this, Serial.list()[2], 9600);
  //myPort.bufferUntil(lf);
}

void draw()
{
  j++;

  while (myPort.available() > 0) {
    serialEvent(myPort.read());
  }

  background(#000000);
  valNormB = valueB/1023.0;

  for (int k=0; k<valuesA.length; k=k+1)
  {
  stroke(#555FFF, k*3);
  fill(#55F555, k*1);
  ellipse(i+2*k, height - valuesA[k]*height,10,10);
  //println(valuesA[k]);

  stroke(#FF55FF,k*3);
  fill(#222222,k*1);
  ellipse(i+2*k, height - valuesB[k]*height, 20,20);
  //println(valuesB[k]);
  }


  // at the edge of the screen, go back to the beginning:
  if (i > width) {
    i = 0;
    background(#000000);
  } 
  else {
    i++;
  }

  //piece of code to print the numeric value to the screen

  /*
  //only display the value once every 50 readings
  //just to keep things clean 
  if (wrote > 50)
  {
    fill(#FFFFFF);
    text(valNormA, i, height - valuesA[k]*height);
    text(valNormB, i, height - valuesB[k]*height);
    wrote = 0;
  }
  wrote++;
  */
}

//Serial parsing stuff to seperate out the 
//sensor variable data
void serialEvent(int serial){

  // if we've got a new piece of data, with header
  if(serial!=lf) {      
      if (serial=='A') buf = true;  //detect header
      if (serial=='B') buf = false;  //detect header

      // gather the remaining pieces of 
      if (buf){ if (serial!='A') bufA += char(serial);
                }else{
                if (serial!='B') bufB+= char(serial);
                }
      } else {
                if (buf){  valueA = int(bufA); bufA="";
                } else {   valueB = int(bufB); bufB="";
                }
      }      

    //println(valueA);      
    //print(valueB);
    //println(valueA);
    //println("*");
    //print(valuesA.length);

    if (valuesA.length == 50)
    {
      //if the array is full, we have to chop off the last value, and replace it with 
      //the most recent value
      valuesA = subset(valuesA, 1);  //removing the first item from the array
      valuesA = append(valuesA,0.0);
      //print(valuesA);
      //print(valuesA.length);
      indexA=valuesA.length-1;  //hack to keep the array adding to the end, instead of starting again at the beginning
    }

    // collect values in an array for display of 'trails
    valuesA[indexA]=(valueA/1023.0);
    indexA = (indexA+1)%valuesA.length;

    //println(valuesA);      
    //println("-");

    //same thing for the second piece of data "B"
    if (valuesB.length == 50)
    {
      valuesB = subset(valuesB, 1);  //removing the first item from the array
      valuesB = append(valuesB,1.0);
      //print(valuesB);
      //print(valuesB.length);
     indexB =valuesB.length-1;   
    }
    valuesB[indexB]=(valueB/1023.0);
    indexB = (indexB+1)%valuesB.length;
}


/*
Arduino code to send data to this Processing program:
*/

/*
//  Sending two pieces of data, deliminated by a header - "A", "B", at the beginning -
//  and a line break at the end.

// based on stuff from Melvin Ochsmann and Tom Igoe. 
// reworked a bit for Sensor Workshop class by Jamie Allen, 2007

int sensorPin1 = 4;    // select the input pin for sensor
int sensorPin2 = 5;    // select the input pin for other sensor
int ledPin = 13;   // select the pin for the LED
int val1 = 0;       // variable to store the value coming from the sensor
int val2 = 0;       // variable to store the value coming from the sensor

void setup() {
  pinMode(ledPin, OUTPUT);  // declare the ledPin as an OUTPUT

  Serial.begin(9600);	// opens serial port, sets data rate to 9600 bps
}

void loop() {

  digitalWrite(ledPin, HIGH);    // sets the LED on

  val1 = analogRead(sensorPin1);    // read the value from the sensor
  val2 = analogRead(sensorPin2);    // read the value from the sensor

  Serial.print("A");  //header variable, so we know which sensor value is which
  Serial.print(val1, DEC);  //send as a ascii encoded number - we'll turn it back into a number at the other end
  Serial.print(10, BYTE);  //terminating character

  Serial.print("B");  //header variable, so we know which sensor value is which
  Serial.print(val2, DEC);  //send as a ascii encoded number - we'll turn it back into a number at the other end
  Serial.print(10, BYTE);  //terminating character

  delay(10);
}

*/