Plotting acceleration
Tuesday, October 16th, 2007This project was a proof-of-concept to get accelerometer data into Processing where it can be used for more interesting things. This basic project was simply to see how it could be done. When the program is running, the window show a plot of the X, Y, and Z data traces that are being read from the serial port. I also added a little red “worm” which makes it into a kind of game almost.
And here’s the code:
/* A program to read and plot the X,Y,Z values that are output by the
SparkFun WiTilt 2.5 3-degree bluetooth accelerometer.
For a little fun, you can also turn on the “Worm” to practice your
drawing skills! With thanks to Jean-Baptiste Labrune for some of the serial-in code.Brock Craft, 2007 | http://www.brock.craft.org
Produced at the London Knowledge Lab
*/
import processing.opengl.*;
import processing.serial.*;
// the serial port:
Serial port;
// variable to hold keystoke values:
int thisByte = -1;
// incoming serial data:
int whichKey = -1;
// general purpose counter to help with drawing lines
float counter=0.0;
// start mark
boolean debut = false;
boolean menuWiTilt = true;
int prevX=0; // values to store the previous location so that we can draw a line
int prevY=0;
int prevZ=0;
float wormX=0; // if we want to draw the worm, we need to save his coordinates
float wormY=0;
PFont fontA; // font for printing:
int X, Y, Z = 0; // 3 Coordinates of the 3 axis accelero
int[] serialInArray = new int[28]; // Where we’ll put what we receive
int serialCount = 0; // A count of how many bytes we receive
boolean firstContact = false; // Whether we’ve heard from the microcontroller
void setup() {
size(800, 800, P3D); // window size:
background(120);
fontA = loadFont(”ArialNarrow-48.vlw”); // load and prep fonts to print to window.
textFont(fontA, 24); // use Tools –>Create Font… to make your own font.
println(Serial.list()); // list all the available serial ports:
// as usual with serial thingys you should find how your card is named by your computer…
String device = “/dev/cu.SparkFun-BT-COM0-1″; //In the list printed above you should find something with SparkFun blablabli inside, this is it !
port = new Serial(this, device, 57600); // 57000 is the baud rate, actually it works also fines at other rates like 9600
println(”Voici le device attaché : “+device);
delay(300); // If the WiTilt has been reset, we need to trigger data send mode, first we wait 300 ms
char tosendz = 061; // Tell the WiTilt to send the dataz by sending a 1 (061 in ascii) to the menu
port.write(tosendz+”\r”);
println(”+++++++++++++++++ Init WiTilt normal”); // everything is ok
}
void draw() {
// Debugging mode that lets you see the value entered in the console
// text(”Received: ” + char(thisByte), 10, 130);
// text(”Sent: ” + char(whichKey), 10, 100);
readPort();
plot(); // draw a trace of the X, Y, and Z axes
addText();
updateWorm(); // un-comment these to draw the worm.
drawWorm();
prevX=X; // since we draw a line from each value to the next, we have to store the current value
prevY=Y; // that we will be using for the line segment origination point in the next draw cycle
prevZ=Z;
}
void keyPressed() {
// This is for debugging, lets you talk to the WiTilt
// send the keystroke out:
char tosend = char(key);
port.write(tosend+”\r”);
println(”sent “+tosend);
whichKey = key;
}
void processByte(char inByte) {
//
// Well, it is a bit of a balagan to explain what i do here but it kinda works ![]()
// Basically, the WiTilt ASCII mode sends series of 28 decimals that represents the data :
//
// 88 61 45 48 46 51 56 49 32 89 61 32 49 46 48 52 50 32 90 61 45 48 46 56 48 52 10 13
// X = - 0 . 3 8 1 SP Y = SP 1 . 0 4 2 SP Z = - 0 . 8 0 4 \n \r
//
// SP : space
// \n : Line feed
// \r : Carriage return
//
// Every serie is separated by a \r char meaning 13 in decimal. We localize it , then do an array of the 28
// next values and then parse 3 substring with my X, Y, and Z values.
//
// There are occasional synchronization issues with the serial data stream that can cause an
// exception because of trying to read the array out of bounds. Some error-checking code
// would be a good thing to add here.
// localize the Carriage return byte to know where we are in the data stream
if (inByte == 13){
debut = true;
}
if (debut) {
// Add the latest byte from the serial port to array:
serialInArray[serialCount] = inByte;
serialCount++;
if (serialCount == 24 ) {
serialCount = 0;
String serialInString = new String(char(serialInArray));
// Since we know that the WiTilt spits out an ‘=’ sign before each value,
// we use that to determine where the next data value is coming from
// to parse serialInString into three different substrings
String parse[] = split(serialInString, ‘=’);
String strX = new String(parse[1].substring(0,2));
if (int(strX)!=0){ // to avoid an Exception, only parse the string if we have a value > 0
X = int(10*Integer.parseInt(strX));
}
String strY = new String(parse[2].substring(0,2));
if (int(strY)!=0){
Y = int(10*Integer.parseInt(strY));
}
String strZ = new String(parse[3].substring(0,2));
if (int(strZ)!=0){
Z = int(5*Integer.parseInt(strZ));
}
debut = false;
}
}
}
void plot(){
fill(220,220,220,70);
stroke(0);
line(counter-1,(prevX/2)+100,counter,(X/2)+100);
line(counter-1,prevY/2+300,counter,300+Y/2);
line(counter-1,prevZ/2+500,counter,500+Z/2);
noStroke();
ellipse(counter,100+X/2,5,5);
ellipse(counter,300+Y/2,5,5);
ellipse(counter,500+Z/2,5,5);
fill(120);
rect(counter+1,60,10,height); // erase the olde traces
counter=counter+1;
if (counter>width){
counter=0;
}
}
void addText(){
fill(120,120,120);
rect(0,0,width,60); // erase the old text by drawing a rect matchng the background
rect(20,300,60,22); // could have used the background() method, with some more code…
rect(20,500,60,22);
rect(20,660,60,22);
fill(255);
text(”WiTilt 2.5 - X, Y, Z plot. Sample time 220Hz max.”,20,40);
text(”X: “+X,20,320);
text(”Y: “+Y,20,520);
text(”Z: “+Z,20,680);
}
void readPort(){
while (port.available() > 0) {
thisByte = port.read();
if (thisByte == 84){
if (menuWiTilt){
delay(300);
//Tell the WiTilt to send the dataz by sending a 1 (061 in ascii) to the menu
char tosendz = 061;
port.write(tosendz+”\r”);
println(”+++++++++++++++++ Init WiTilt abnormal”); // happens when the delay above is not enough or when we loose the bluetooth signal…
menuWiTilt = false;
}
}
// println(X+” “+Y+” “+Z); // DEBUG
processByte(char(thisByte)); // Process the input buffer (see below)
}
}
void updateWorm(){
if(X>490){
wormX=(wormX+(X/200));
}
if(X<470){
wormX=(wormX-(X/200));
}
if(Y>470){
wormY=(wormY+(Y/200));
}
if(Y<450){
wormY=(wormY-(Y/200));
}
if(wormX>width){ // keep it on the screen
wormX=0;
}
if(wormY>height){
wormY=0;
}
if(wormX<0){ // keep it on the screen
wormX=width;
}
if(wormY<0){
wormY=height;
}
if(Z<100){ // we can flick the WiTilt sensor in the Z dimension
wormX=width/2; // to re-home the worm at the screen center.
wormY=height/2;
}
}
void drawWorm(){
fill(188,15,15,50);
ellipse(wormX,wormY,10,10);
}