Using Processing 2.0

I wanted to use the computer language ‘Processing’ to read data from a serial port and record the data. Here are my collected notes on doing this.

Processing is an open-source programming language which has been designed to teach computer programming fundamentals through a visual environment. It is the basis of the language used for the Arduino development envrionment.

It is designed to be easy to use, but also powerful and have lots of features useful for students, artists and designers. It is also multi-platform and can easily create executable stand-alone code. The programs can easily be shared with others.

I had used it briefly for a hack-session with Active Ingredient, building a lamp which varies its brightness in response to changes in atmospheric CO2 levels.

Design idea

Lots of the power monitoring equipment I have been building recently has been streaming data out via a serial connection. I am implementing a universal protocol for the data streams, hence I can produce plug and play devices which work with all the equipment I produce.

I wanted to take this stream of data (generated approximately every second) and display it in an interesting format and also record the data to a spreadsheet file.

I also wanted the program to be multi-platform and easy to alter, adjust and hack for other people to use.

Data format

The data is sent in 12 byte strings with a ‘a’ at the start of each piece of data. Each device has a unique reference. The format from the Pedalog is as follows:

  • aXXV+++—–
  • aXXI++++—-
  • aXXP++++—-

At 115200 baud.

Where XX is the unique reference (this must be in capitals and can be from AA to ZZ). The data is within the ++++ part of the output and the 12 bytes are filled with ‘-‘ as padding to make up 12 bytes. Voltage (volts) and Current (amps) both have one decimal place, whereas Power is in Watts

For example:

aFFV123—–

This device reference ‘FF’ and the voltage is 12.3V

aABI1234—–

This is device reference ‘AB’ and the current is 123.4A

aCCP1234—-

This is device reference ‘CC’ and the power is 1234W

 We need to grab the data arriving at the serial port and parse it (strip out all the bits we dont need) and display those values.

Reading the Serial Port

 There is an example code in the processing examples. This works to read data from a serial port (found by listing all the serial ports). It then displays any data which arrives at the serial port.

// Serial read data
//
// By Matt Little
// 24/7/13
//
// This code reads in data streamed to the serial port at 115200 baud.
// The data is parsed to get the Voltage, Current and Power.
// The data is then displayed upon the screen
// Original example by Tom Igoe
// Modified:
// 24/7/13  Matt Little  Changed baud rate
import processing.serial.*;
Serial myPort;  // The serial port
void setup() {
  // List all the available serial ports
  println(Serial.list());
  // Open the port you are using at the rate you want:
  myPort = new Serial(this, Serial.list()[0], 115200);
}
void draw() {
  while (myPort.available() > 0) {
    int inByte = myPort.read();
    println(inByte);
  }
}

This works well, but the data stream is the ‘int’ value, whereas we want to the ‘int’s converted into ‘char’ type. This was done using the (char)int conversion.

I also added code to check that the data started with an ‘a’ and hence put each 12 byte data stream into a seperate buffer.

// Serial read data
//
// By Matt Little
// 24/7/13
//
// This code reads in data streamed to the serial port at 115200 baud.
// The data is parsed to get the Voltage, Current and Power.
// The data is then displayed upon the screen
// Original example by Tom Igoe
// Modified:
// 24/7/13  Matt Little  Changed baud rate
// 24/7/13  Matt Little  Added int to char conversion
import processing.serial.*;
// ****** Serial Data Read***********
// Variables for the serial data read
Serial myPort;  // The serial port
int inByte;         // incoming serial char
String str_buffer = "";  // This is the holder for the string which we will display
void setup() {
  // List all the available serial ports
  println(Serial.list());
  // Open the port you are using at the rate you want:
  myPort = new Serial(this, Serial.list()[0], 115200);
}
void draw() {
  
  if (myPort.available() > 0) {
    inByte = myPort.read(); // Read whatever is happening on the serial port    
    if(inByte=='a')    // If we see an 'a' then read in the next 11 chars into a buffer.
    {   
      str_buffer+=(char)inByte;
      for(int i = 0; i<12;i++)  // Read in the next 11 chars - this is the data
      {
        inByte = myPort.read(); 
        str_buffer+=(char)inByte;
      }
      println(str_buffer);  // TEST - print the str_buffer data (if it has arrived)
      str_buffer="";  // Reset the buffer to be filled again
    }
  }
}

The next thing to do was to strip out the voltage, current and power as data values. This next code reads the incomming serial port values, checks that they have come from the correct device ID, checks that they are the correct ‘aXXXXXXXXXXX’ format. It then displays them on the screen as strings. These are then converted into integers and then back into strings to be displayed again.

// Serial read data
//
// By Matt Little
// 24/7/13
//
// This code reads in data streamed to the serial port at 115200 baud.
// The data is parsed to get the Voltage, Current and Power.
// The data is then displayed upon the screen
// Original example by Tom Igoe
// Modified:
// 24/7/13  Matt Little  Changed baud rate
// 24/7/13  Matt Little  Added int to char conversion
// 24/7/13  Matt Little  Added conversion string -> int -> string
import processing.serial.*;
// ****** Serial Data Read***********
// Variables for the serial data read
Serial myPort;  // The serial port
int inByte;         // incoming serial char
String str_buffer = "";  // This is the holder for the string which we will display
boolean errorFlag = false;  // This is a flag which is set if there is an error  
String deviceID = "";  // This holds the read-in substring
String deviceIDcheck = "AA";  // This holds the device ID we are looking for
String currentStr = "0";  // These hold the string values
String voltageStr = "0";
String powerStr = "0";
int currentInt = 0;
int voltageInt = 0;
int powerInt = 0;
void setup() {
  
  size(640, 360);  // Size of the display area
  background(0);   // Set background colour
  // Create the font
  textFont(createFont("Georgia", 36));
  noStroke();  
  // List all the available serial ports
  println(Serial.list());
  
  if(Serial.list().length >= 1)
  {
    // Open the port you are using at the rate you want:
    myPort = new Serial(this, Serial.list()[0], 115200);
  }
  else{
    println("Error - no serial connected");
    errorFlag=true;
  }
}
void draw() {
  if(errorFlag==false)
  {
    // First want to try and get any data which may appear on the serial port
    getData();
    // Now we want to display the data:
    // First blank the display
    background(0);   // Blank the display
    text("Current: "+currentStr, 50, 50); 
    text("Voltage: "+voltageStr, 50, 100); 
    text("Power: "+powerStr, 50, 150); 
    
    // Here we convert the string into an int
    // Need to be careful this is only done with int values, no empty arrays or it will crash
    currentInt = Integer.parseInt(currentStr);
    voltageInt = Integer.parseInt(voltageStr);
    powerInt = Integer.parseInt(powerStr);
    
    // Display the int values on the screen (put them back into strings
    text("CurrentInt: "+String.valueOf(currentInt), 50, 200); 
    text("VoltageInt: "+String.valueOf(voltageInt), 50, 250); 
    text("PowerInt: "+String.valueOf(powerInt), 50, 300); 
  }
  else if(errorFlag==true)
  {  
    text("ERROR - No Serial Connection", 50, 50);
  }
}
// This subroutine checks for and gets any data on the serial port.
// We also send the data to the 'sortData' routine to strip out the useful data
void getData()
{
  if (myPort.available() > 0) {
    inByte = myPort.read(); // Read whatever is happening on the serial port    
    if(inByte=='a')    // If we see an 'a' then read in the next 11 chars into a buffer.
    {   
      str_buffer+=(char)inByte;
      for(int i = 0; i<12;i++)  // Read in the next 11 chars - this is the data
      {
        inByte = myPort.read(); 
        str_buffer+=(char)inByte;
      }
      println(str_buffer);  // TEST - print the str_buffer data (if it has arrived) 
      sortData();    // Sort the data - check if the strings match   
      str_buffer="";  // Reset the buffer to be filled again   
    }  
  }   
}
// **********************SORT DATA SUBROUTINE*****************************************
// This sub-routine takes the read-in data string (12 char, starting with a) and does what is required with it
// The str-buffer is global so we do not need to send it to the routine
void sortData()
{ 
  deviceID = str_buffer.substring(1,3);
  // We first want to check if the device ID matches.
  // If it does not then we disregard the command (as it was not meant for monitoring)     
  if(deviceID.equals(deviceIDcheck) == true)
  {
    // If yes then we can do further checks on ths data
    // This is where we do all of the checks on the incomming serial command:
    println("Matches Device ID");  // TEST - got into this routine
    
    // Now we strip out the interesting data points.
    // If the next parts is V/I/P then we can get the correct strings of data
    if(str_buffer.substring(3,4).equals("I")==true)
    {
      println("CURRENT");
      currentStr = str_buffer.substring(4,8);
 
    }
    else if(str_buffer.substring(3,4).equals("V")==true)
    {
      println("VOLTAGE");
      voltageStr = str_buffer.substring(4,7);
    }
    else if(str_buffer.substring(3,4).equals("P")==true)
    {     
      println("POWER");
      powerStr = str_buffer.substring(4,8);
    }    
    
    
    
  }
  else
  {
    text("Device ID does not match", 50, 200);
    println("Device ID does not match");  // We do not have matching device IDs)
  }
}

I need to add some more checks to ensure that strings which are not integers are never converted (as this crashes the program).

Here is a screen shot of the program running:

Graphing the data

The next thing to do was to plot the data on a graph. This is where Processing comes into its own – there are loads of examples of interesting ways to display information visually.

The first example displays a circle which gets larger for a higher generated power. This looked OK, but was not as good as I thought, mainly due to the ‘jerky’ motion caused by the data being streamed at 1 second samples.

The code to do this was simple, I just drew an ellipse, after displaying the data, with a diameter proportional to the powerInt:

    ellipse(400,400, powerInt*10, powerInt*10);

There is lots more work that could be done here, but I’ve got something working and so will develop that. This blog post is a reminder of the steps I made to get going with drawing data.

Saving the data to a file

The last thing to do was to save the data stream to a file, preferably some kind of data file, like comma sperated variables (.csv).

This turns out to be pretty straight forward. The main command is saveStrings :

  saveStrings("e:/lines.txt", lines);

There is an example of saving data to a file within the Processign examples. This does pretty much exactly what I need – append data to a file.

So I’m now in the position or reading and parsing data from the serial port, displaying that data visually and saving the data to a text file. Now to work on the full code design.

Leave a Reply

Your email address will not be published. Required fields are marked *