Previously posted on blog.labrat.info on May 5, 2011

I’ve been looking around the internet for an easy way to make an “analog gauge” in Processing to help me get a better handle on an IMU I got from Sparkfun. Looking at numbers go by on the serial terminals was making me more motion sick than anything else.

Step one was to try to make an arrow. Luckily the internet came to the rescue and I found this in one of the Processing forums. The function is :

void arrow(int x1, int y1, int x2, int y2) {
  line(x1, y1, x2, y2);
  pushMatrix();
  translate(x2, y2);
  float a = atan2(x1-x2, y2-y1);
  rotate(a);
  line(0, 0, -10, -10);
  line(0, 0, 10, -10);
  popMatrix();
} 

With that knowledge I needed to find a way to take the angle I’m getting back form the IMU and tell Processing to draw me the gauge. Somewhere in the back of my mind I remembered there was something that I could give an angle and a radius and I could get X and Y position of the tip of that Radius. Another quick internet search and I found Polar Coordinates and then found there as already a tutorial on that on the Processing website. Quick re-factor of that code and I got this:

void guage(float r, float angle) {
  // Conver from Degree -> Rad
  angle = -angle*(PI/180) ;
    // Convert Polar -> Cartesian
  float x = r * cos(angle);
  float y = r * sin(angle);

  arrow(0,0, (int)x, (int)y) ;
}

And now to make it look like a guage just add a circle around it!

ellipse(0, 0, height/2, height/2) ;
guage(height/2, angleX) ;

So now that I can draw a cool guage-looking thing on the screen I made my Arduino print out to serial a tab-separated list of X and Y values that are read by the Processing sketch and the gauges now tell me the angle of the IMU!

import processing.serial.*; 

Serial arduino;

float angleX = 0 ;
float angleY = 0 ;

float minX=0 ; 
float maxX=0 ;
float minY=0 ;
float maxY=0 ;

void setup() {
  size(800,600) ;
  
  arduino = new Serial(this, Serial.list()[0], 9600);
  arduino.bufferUntil('\n');
  
}

void draw() {
  background(255);
  
  translate(width/4, height/2);
  
  stroke(0,0,0) ;
  ellipse(0, 0, height/2, height/2) ;
  strokeWeight(2);
  stroke(255,0,0) ;
  guage(height/4, angleX) ;
  
  translate(width/2, 0);
  stroke(0,0,0) ;
  ellipse(0, 0, height/2, height/2) ;
  stroke(0,255,0) ;
  guage(height/4, angleY) ;
  
  if (minX > angleX) minX = angleX ;
  if (minY > angleY) minY = angleY ;
  if (maxX < angleX) maxX = angleX ;
  if (maxY < angleY) maxY = angleY ;
  
  println(minX + "\t" + maxX + "\t" + minY + "\t" + maxY) ;
  
}

void serialEvent (Serial arduino)
{
 //get the ASCII strings:
 angleX = float(trim(arduino.readStringUntil('\t'))) ;
 angleY = float(trim(arduino.readStringUntil('\t'))) ;
 
}

void guage(float r, float angle) {
  // Conver from Degree -> Rad
  angle = -angle*(PI/180) ;
    // Convert Polar -> Cartesian
  float x = r * cos(angle);
  float y = r * sin(angle);

  arrow(0,0, (int)x, (int)y) ;
}

void arrow(int x1, int y1, int x2, int y2) {
  line(x1, y1, x2, y2);
  pushMatrix();
  translate(x2, y2);
  float a = atan2(x1-x2, y2-y1);
  rotate(a);
  line(0, 0, -10, -10);
  line(0, 0, 10, -10);
  popMatrix();
}