~ interfacing ~
This week on HTMAA, Hannah learns how to create a GUI interface for the acceleration data coming from her final project board.
My goal is for the GUI to plot the XYZ coordinates of acceleration in a persistent way over time in 3D. Furthermore, I’d like to have this point cloud rotate continuously (even better if I could rotate with my mouse) so that I may observe the clusters that correspond to different locations.
A brief google search provided me with a tutorial for something pretty similar to what I am looking for.
After downloading Processing I loaded up a script (a la the tutorial linked above) to print an assortment of random dots. It looks really cool!
Interestingly, the Processing language and application are incredibly similar to the Arduino ones.
I started by sending data to serial on my accelerometer board. I used special delimiters so that I could check that the data I receive makes sense:
put_string(&serial_port,serial_pin_out,str_x);
put_string(&serial_port,serial_pin_out,",");
put_string(&serial_port,serial_pin_out,str_y);
put_string(&serial_port,serial_pin_out,",");
put_string(&serial_port,serial_pin_out,str_z);
put_string(&serial_port,serial_pin_out,";");
With the above code I expect the data received to look like:
x,y,z;
x,y,z;
...
The Processing documentation explains how to read serial data as ascii. Implementing this code was straight forward and worked immediately!
Here is some of the output from the Processing console:
141,225,84;
152,233,91;
145,226,81;
1
48,231,89;
1
44,226,82;
1
55,239,95;
14
2,227,85;
146,2
34,93;
146,23
0,81;
150,23
You can see that, although the spacing and formatting are quite strange, there are always three numbers between every semicolon. Then I realized that the buffer likely didn’t just have one “line” of acceleration data. I checked this by printing “buffer” after println(inBuffer) so that I could count how many packets of data were being sent each time.
After some playing around with this, it turned out it wasn’t too easy to do the above. Basically, the strings returned were not consistently what I expected, which made extracting the x, y, and z values challenging.
I eventually found a different approach to the above. This method uses the “bufferUntil” function, which will add bytes (characters) to the buffer until a selected termination character is reached (in my case, the new line character). Then, “serialEvent” is triggered which then reads the string on the buffer and extracts the x, y, z integer values. Finally this is passed into the draw function for graphics.
import processing.serial.*;
Serial myPort;
String myString;
String[] acceleration;
int x,y,z;
void setup(){
// Open the port you are using at the rate you want:
myPort = new Serial(this,"/dev/cu.usbserial-FT9P30PT", 9600);
myPort.bufferUntil(10); //new line
}
void draw(){
println(x, " ", y, " ", z, " ");
}
void serialEvent(Serial p) {
myString = p.readString();
if (myString != null){
if (myString.length() >= 3){
acceleration = split(myString, ' ');
x = Integer.parseInt(trim(acceleration[0]));
y = Integer.parseInt(trim(acceleration[1]));
z = Integer.parseInt(trim(acceleration[2]));
}
}
}
import processing.serial.*;
Serial myPort;
String myString;
String[] acceleration;
int x,y,z;
void setup(){
size(600, 500, P3D);
background(0);
noFill();
stroke(255);
strokeWeight(3);
// Open the port you are using at the rate you want:
myPort = new Serial(this,"/dev/cu.usbserial-FT9P30PT", 9600);
myPort.bufferUntil(10); //new line
}
void draw(){
// println(x, " ", y, " ", z, " ");
background(0);
translate(width/2, height/2);
rotateY(frameCount / 200.0);
box(500);
point(x, y, z);
}
void serialEvent(Serial p) {
myString = p.readString();
if (myString != null){
if (myString.length() >= 3){
acceleration = split(myString, ' ');
x = Integer.parseInt(trim(acceleration[0]));
y = Integer.parseInt(trim(acceleration[1]));
z = Integer.parseInt(trim(acceleration[2]));
}
}
}
And now, to implement location tracking over time. I implemented a 300 long buffer so that the last 300 acceleration points are plotted.
import processing.serial.*;
Serial myPort;
String myString;
String[] acceleration;
int x,y,z;
int BUFFER_SIZE = 300;
int buffer_loc = 0;
int[] x_buffer = new int[BUFFER_SIZE];
int[] y_buffer = new int[BUFFER_SIZE];
int[] z_buffer = new int[BUFFER_SIZE];
void setup(){
size(600, 500, P3D);
background(0);
noFill();
stroke(255);
strokeWeight(3);
// Open the port you are using at the rate you want:
myPort = new Serial(this,"/dev/cu.usbserial-FT9P30PT", 9600);
myPort.bufferUntil(10); //new line
}
void draw(){
println(x, " ", y, " ", z, " ");
background(0);
translate(width/2, height/2);
rotateY(frameCount / 300.0);
box(500);
for(int i = 0; i<BUFFER_SIZE; i++) {
point(x_buffer[i], y_buffer[i], z_buffer[i]);
}
}
void serialEvent(Serial p) {
myString = p.readString();
if (myString != null){
if (myString.length() >= 3){
acceleration = split(myString, ' ');
x = Integer.parseInt(trim(acceleration[0]));
y = Integer.parseInt(trim(acceleration[1]));
z = Integer.parseInt(trim(acceleration[2]));
buffer_loc = (buffer_loc < BUFFER_SIZE -1) ? buffer_loc+1 : 0;
x_buffer[buffer_loc] = x;
y_buffer[buffer_loc] = y;
z_buffer[buffer_loc] = z;
}
}
}