Archive for the ‘Processing’ Category

Arduino: Controlling the Robot Arm

arduino processing robot arm pt2

So the arm is wired into Arduino as per the previous post, Arduino: Modifying a Robot Arm and hopefully this has worked. In this next part I alter the Arduino sketch slightly and write the first Processing sketch to test control of the arm – video at the bottom.

To control the robot arm we’ll be sending a byte value over the serial port and then reading that in the Arduino code. Depending upon the value sent different motors will be activated.

For the processing sketch I’ve made a few buttons for each motor and also coded the use of the keyboard for another control method. Using either arbitrarily moves the arms motors.

This sketch is the basis for all the further work as well as testing the arm, from this I will move to inverse kinematics as well as programming repeat actions for the arm to perform. Ultimately leading to the arm responding to sensors and other stimuli – eventually! (I have a lot to write up).

For a basic example of working with controlling Arduino using Processing please read my tutorial “Using Processing to Send Values to Arduino” which explains about sending data over the serial port.

The Arduino Sketch
Nothing much has changed from the sketch in the previous post, the main difference is that now you can see we’re reading values from the serial port and acting accordingly. All the logic happens in the Processing code.

/* controls each motor in an Edge Robotic Arm using data sent from 
    a Processing Sketch
    luckylarry.co.uk
 
*/
// set the output pins
// 14-18 are actually analog pins 0-4
int baseMotorEnablePin = 2;
int baseMotorPin1 = 3;                             
int baseMotorPin2 = 4;                           
int shoulderMotorEnablePin = 14;
int shoulderMotorPin1 = 15;                             
int shoulderMotorPin2 = 16; 
int elbowMotorEnablePin = 8;
int elbowMotorPin1 = 9;                             
int elbowMotorPin2 = 10;                           
int wristMotorEnablePin = 5;
int wristMotorPin1 = 6;                             
int wristMotorPin2 = 7; 
int handMotorEnablePin = 11;
int handMotorPin1 = 17;                             
int handMotorPin2 = 18; 
// set a variable to store the byte sent from the serial port
int incomingByte;

void setup() {
  // set the SN754410 pins as outputs:
  pinMode(baseMotorPin1, OUTPUT);
  pinMode(baseMotorPin2, OUTPUT);
  pinMode(baseMotorEnablePin, OUTPUT);
  digitalWrite(baseMotorEnablePin, HIGH);
  pinMode(shoulderMotorPin1, OUTPUT);
  pinMode(shoulderMotorPin2, OUTPUT);
  pinMode(shoulderMotorEnablePin, OUTPUT);
  digitalWrite(shoulderMotorEnablePin, HIGH);
  pinMode(elbowMotorPin1, OUTPUT);
  pinMode(elbowMotorPin2, OUTPUT);
  pinMode(elbowMotorEnablePin, OUTPUT);
  digitalWrite(elbowMotorEnablePin, HIGH);
  pinMode(wristMotorPin1, OUTPUT);
  pinMode(wristMotorPin2, OUTPUT);
  pinMode(wristMotorEnablePin, OUTPUT);
  digitalWrite(wristMotorEnablePin, HIGH);
  pinMode(handMotorPin1, OUTPUT);
  pinMode(handMotorPin2, OUTPUT);
  pinMode(handMotorEnablePin, OUTPUT);
  digitalWrite(handMotorEnablePin, HIGH);
  // start sending data at 9600 baud rate
  Serial.begin(9600);
}

void loop() {
  // check that there's something in the serial buffer
  if (Serial.available() > 0) {
    // read the byte and store it in our variable 
    // the byte sent is actually an ascii value
    incomingByte = Serial.read();
    // note the upper casing of each letter!
    // each letter turns a motor different way.
    if (incomingByte == 'Q') {
    digitalWrite(baseMotorPin1, LOW);   
    digitalWrite(baseMotorPin2, HIGH);  
    } 
    if (incomingByte == 'W') {
    digitalWrite(baseMotorPin1, HIGH);   
    digitalWrite(baseMotorPin2, LOW);  
    }
    if (incomingByte == 'E') {
    digitalWrite(shoulderMotorPin1, LOW);   
    digitalWrite(shoulderMotorPin2, HIGH);  
    } 
    if (incomingByte == 'R') {
    digitalWrite(shoulderMotorPin1, HIGH);   
    digitalWrite(shoulderMotorPin2, LOW);  
    }
    if (incomingByte == 'A') {
    digitalWrite(elbowMotorPin1, LOW);   
    digitalWrite(elbowMotorPin2, HIGH);  
    } 
    if (incomingByte == 'S') {
    digitalWrite(elbowMotorPin1, HIGH);   
    digitalWrite(elbowMotorPin2, LOW);  
    }
    if (incomingByte == 'D') {
    digitalWrite(wristMotorPin1, LOW);   
    digitalWrite(wristMotorPin2, HIGH);  
    } 
    if (incomingByte == 'F') {
    digitalWrite(wristMotorPin1, HIGH);   
    digitalWrite(wristMotorPin2, LOW);  
    }
    if (incomingByte == 'Z') {
    digitalWrite(handMotorPin1, LOW);   
    digitalWrite(handMotorPin2, HIGH);  
    } 
    if (incomingByte == 'X') {
    digitalWrite(handMotorPin1, HIGH);   
    digitalWrite(handMotorPin2, LOW);  
    }
    // if a O is sent make sure the motors are turned off
    if (incomingByte == 'O') {
    digitalWrite(baseMotorPin1, LOW);   
    digitalWrite(baseMotorPin2, LOW);  
    digitalWrite(shoulderMotorPin1, LOW);   
    digitalWrite(shoulderMotorPin2, LOW); 
    digitalWrite(elbowMotorPin1, LOW);   
    digitalWrite(elbowMotorPin2, LOW);  
    digitalWrite(wristMotorPin1, LOW);   
    digitalWrite(wristMotorPin2, LOW); 
    digitalWrite(handMotorPin1, LOW);   
    digitalWrite(handMotorPin2, LOW); 
    }
  }
}

[ad#Google Ad in content]

The Processing Sketch
I’ve drawn some fancy arrows for my buttons in this sketch but otherwise the code is pretty simple – if I press Q or q on the keyboard or if I press an arrow button then send the ascii value of Q (note the uppercase) over the serial port for the Arduino to pick up and turn the motor on. There is nothing here really complicated just a fair few lines of code for the user interface.

/* 
   Processing sketch that send a ascii byte character to Arduino which
   then subsquentally controls a motor
   luckylarry.co.uk
 
*/

// load the serial library for Processing
import processing.serial.*; 
// instance of the serial class
Serial port;
// values to store X, Y for each button
int M1LX, M1RX, M2LX, M2RX, M3LX, M3RX, M4LX, M4RX, M5LX, M5RX;
int M1LY, M1RY, M2LY, M2RY, M3LY, M3RY, M4LY, M4RY, M5LY, M5RY;
// stores the width/height of the box
int boxSize = 64;
// 2 new instances of my arrow class
// also set an array of coordinates for each arrow
arrow myRightArrow;
int[]rightArrowxpoints={30,54,30,30,0,0,30}; 
int[]rightArrowypoints={0,27,54,40,40,15,15};
arrow myLeftArrow;
int[]leftArrowxpoints={0,24,24,54,54,24,24}; 
int[]leftArrowypoints={27,0,15,15,40,40,54};
// set the font
PFont myFont;

void setup()  {
  // screen size of the program
  size(145, 455);
  // set the coordinates of each button box
  // base motor M1LX = Motor 1 Left X  etc..
  M1LX = 5;
  M1LY = 25;
  M1RX = 75;
  M1RY = 25;  
  // shoulder motor
  M2LX = 5;
  M2LY = 115;
  M2RX = 75;
  M2RY = 115;
  // elbow motor
  M3LX = 5;
  M3LY = 205;
  M3RX = 75;
  M3RY = 205;
  // wrist motor
  M4LX = 5;
  M4LY = 295;
  M4RX = 75;
  M4RY = 295;
  // hand motor
  M5LX = 5;
  M5LY = 385;
  M5RX = 75;
  M5RY = 385;
  
  // List all the available serial ports in the output pane. 
  // You will need to choose the port that the Arduino board is 
  // connected to from this list. The first port in the list is 
  // port #0 and the third port in the list is port #2. 
  println(Serial.list()); 
  // set the font to use
  myFont = createFont("verdana", 12);
  textFont(myFont);
  // Open the port that the Arduino board is connected to (in this case #0) 
  // Make sure to open the port at the same speed Arduino is using (9600bps)
  port = new Serial(this, Serial.list()[1], 9600); 
  // create the base arrow
  myRightArrow = new arrow(rightArrowxpoints,rightArrowypoints,7);
  myLeftArrow = new arrow(leftArrowxpoints,leftArrowypoints,7);
}

void draw() 
{ 
  background(0);
  noStroke();
  fill(150);
  // draw each box/ button with a label above each    
  text("Base Motor (Q/W)", 5, 5, 200, 75); 
  text("Shoulder Motor (E/R)", 5, 95, 200, 75);
  text("Elbow Motor (A/S)", 5, 185, 200, 75);
  text("Wrist Motor (D/F)", 5, 275, 200, 75);     
  text("Hand Motor (Z/X)", 5, 365, 200, 75);

  // start looking to see whats pressed and send a value
  // over the serial port
  if(keyPressed) {
    if (key == 'q' || key == 'Q') {
      port.write('Q');
    }
    if (key == 'w' || key == 'W') {
      port.write('W');
    }
    if (key == 'e' || key == 'E') {
      port.write('E');
    }
    if (key == 'r' || key == 'R') {
      port.write('R');
    }
    if (key == 'a' || key == 'A') {
      port.write('A');
    }
    if (key == 's' || key == 'S') {
      port.write('S');
    }
    if (key == 'd' || key == 'D') {
      port.write('D');
    }
    if (key == 'f' || key == 'F') {
      port.write('F');
    }
    if (key == 'z' || key == 'Z') {
      port.write('Z');
    }
    if (key == 'x' || key == 'X') {
      port.write('X');
    }
  } 
  // if no key is pressed check to see if the mouse button is pressed
  else if (mousePressed == true) {
    // check to see if the mouse is inside each box/ button if so send the value
    if (mouseX > M1LX-boxSize && mouseX < M1LX+boxSize && 
      mouseY > M1LY-boxSize && mouseY < M1LY+boxSize) {
        port.write('Q'); 
    } 
    else if(mouseX > M1RX-boxSize && mouseX < M1RX+boxSize && 
      mouseY > M1RY-boxSize && mouseY < M1RY+boxSize) {
        port.write('W'); 
    } 
    else if(mouseX > M2LX-boxSize && mouseX < M2LX+boxSize && 
      mouseY > M2LY-boxSize && mouseY < M2LY+boxSize) {
        port.write('E'); 
    } 
    else if(mouseX > M2RX-boxSize && mouseX < M2RX+boxSize && 
      mouseY > M2RY-boxSize && mouseY < M2RY+boxSize) {
        port.write('R'); 
    } 
    else if(mouseX > M3LX-boxSize && mouseX < M3LX+boxSize && 
      mouseY > M3LY-boxSize && mouseY < M3LY+boxSize) {
        port.write('A');   
    } 
    else if(mouseX > M3RX-boxSize && mouseX < M3RX+boxSize && 
      mouseY > M3RY-boxSize && mouseY < M3RY+boxSize) {
        fill(200);
        port.write('S');     
    }
    else if (mouseX > M4LX-boxSize && mouseX < M4LX+boxSize && 
      mouseY > M4LY-boxSize && mouseY < M4LY+boxSize) {
        port.write('D');     
    } 
    else if(mouseX > M4RX-boxSize && mouseX < M4RX+boxSize && 
      mouseY > M4RY-boxSize && mouseY < M4RY+boxSize) {
        port.write('F');  
    } 
    else if (mouseX > M5LX-boxSize && mouseX < M5LX+boxSize && 
      mouseY > M5LY-boxSize && mouseY < M5LY+boxSize) {
        port.write('Z'); 
    }
    else if(mouseX > M5RX-boxSize && mouseX < M5RX+boxSize && 
      mouseY > M5RY-boxSize && mouseY < M5RY+boxSize) {
        port.write('X');    
    }
    else {
      // if the mouse is pressed but not with in a box make sure nothings moving
      port.write('O');   
    } 
  } else {
    // no key or mouse press then make sure nothings moving.
    port.write('O');   
  } 
  
  // draw the buttons
  myRightArrow.drawArrow(80,30);
  myRightArrow.drawArrow(80,120);
  myRightArrow.drawArrow(80,210);
  myRightArrow.drawArrow(80,300);
  myRightArrow.drawArrow(80,390);
  myLeftArrow.drawArrow(10,30);
  myLeftArrow.drawArrow(10,120);
  myLeftArrow.drawArrow(10,210);
  myLeftArrow.drawArrow(10,300);
  myLeftArrow.drawArrow(10,390);
}

class arrow extends java.awt.Polygon { 
  /* our class is basically an instance of java.awt.Polygons and this class expects and array of X points, Y points and the number of 
     points in our shape. The variable names also have to be direct references to what this class expects, so xpoints, ypoints and npoints are all
     set/defined in the java class.
  */
  public arrow(int[] xpoints,int[] ypoints, int npoints) {
    // super invokes the java.awt.Polygon class
    super(xpoints,ypoints,npoints);
    
  } 
    // supply offsets to draw the arrow, means I don't need to set points for each one
    void drawArrow(int xOffset, int yOffset){
    fill(150);
    rect(xOffset-5, yOffset-5, boxSize, boxSize);
    fill(255);
    beginShape();
    for(int i=0;i

[ad#Google Ad in content]

Does it work?
Hopefully the sketch is working and you can control the arm via your computer. If not then first check that all motors are wired in properly and your batteries are not flat. If you arrow moves the arm the wrong way then you can either switch the motor pins on the circuit or change the Arduino sketch to alter the motors direction.

Calibrating the arm
We need to set start positions for the arm and note the positions and counts in order to later calculate the positions for the next parts of this work. This is where we'll look to more benefits of Arduino and possibly PID (Proportional, Integral, Derivative) control, PWM or someother way to get accurate positions for the motor. The only catch is each motor is in a gearbox so using an encoder or other device to measure motor rotations is not an option. But for now we can control our arm from the computer at least - check out the video below.


Arduino: Modifying a Robot Arm: How to wire up the robot arm to Arduino.

Arduino + Processing – 3D Sensor Data Visualisation

Arduino 3D scan

So following on from my previous posts about visualising sensor data in Processing, I’m now looking at drawing 3D representations of the data recorded from the Sharp IR sensor – although can be any kind of range finder.

I started by rigging 2 servos, one to pan left to right, the other up to down. The latter is limited to only 60 degrees of movement. I’m going to represent each servo position in a grid to start with, so a grid 180 wide (x) by 60 tall (y). The distance measured from the sensor will form the z index position so how far/ close a point will appear.

The setup is pretty much the same, Arduino records and sends the sensor data to the serial port buffer along with the X and Y position of the servos. Processing then picks this up and populates an array. Now this time I’m using multi-dimensional arrays, that is one array that stores other arrays. I could make just one array of 10800 items (180 * 60) but its far more efficient to make an array of 180 items, each item being another array of 60 items to store the distance measured. So for every 1 degree I move left to right, I record the 60 positions of the up/ down servo and the reading taken.

To visualise this I started drawing squares using the QUAD_STRIP shape to produce a grid layout (image at the top of the post). Of course because I’m actually using polar co-ordinates (degrees) instead of cartesian (x, y) then what the sensor is reading can’t really be translated to a flat grid. Because when it measures something vertical the measurements will all be different and when translated to my flat grid, it would make anything vertical look slanted. Trouble is now we’re trying to view something in 3D space so it doesn’t look all that great – so I’ve added in some animation to rotate the object slightly, looks fine when you zoom in close enough to one section but otherwise it’s just a random shape.

There are 2 ways around this, firstly we can convert our co-ordinates to cartesian. Or we can alter the grid used to display our data, the shape needed is basically a 60 degree arc thats lathed 180 degrees – so it kind of looks like a tyre wall. The radius used to draw our 60 degree arc is calculated by the distance taken from the sensor.

Arduino 3D Sensor Data Parts

SRF05 Ultrasonic range finder or Sharp GP2Y0A02 IR sensor (basically any kind of distance sensor)
Arduino Deumilanove w/ ATMEGA328
Breadboard / Prototyping board
Jumper/ Connector wires
2x Servos (has to need no more than 5v supply)
C shaped Servo brackets (If anyone can make these cheap enough let me know!)

Arduino 3D Plotter Circuit

Using the below posts you should be able to figure out how to wire the sensor and how to use the servos. I use digital pins 9 and 10 for the servos and analog pin 1 for the sensor reading.

Arduino SRF-05 Tutorials
Arduino Servo Tutorials
How to use the Sharp IR range finder

Arduino Sketch

We use the servo libary and a couple of FOR loops to control 2 servos, for every degree panned we tilt the other servo through 60 degrees taking a series of sensor readings for each position and averaging them. We output these values with the X and Y position in degrees to the serial port buffer. At the end of each loop we reset the servo position. If the sensor reading is outside the range of operation of the servo we also handle this.

/*
luckylarry.co.uk
3D Scan Visualisation for Sharp GP2Y0A02 IR range finder
Sends sensor readings for every degree moved by the servo
values sent to serial port to be picked up by Processing
*/
#include             // include the standard servo library
Servo leftRightServo;         // set a variable to map the servo
Servo upDownServo;
int leftRightPos = 0;         // set a variable to store the servo position
int upDownPos = 0;
const int numReadings = 10;   // set a variable for the number of readings to take
int index = 0;                // the index of the current reading
float total = 0;              // the total of all readings must be a float to allow totaling of float values
int average = 0;              // the average
int IRpin = 1;                // analog pin for reading the IR sensor

/* setup the pins, servo and serial port */
void setup() {
  leftRightServo.attach(9);
  upDownServo.attach(10);
  // initialize the serial port:
  Serial.begin(9600);
} 

/* begin rotating the servo and getting sensor values */
void loop() {
 for(leftRightPos = 0; leftRightPos < 180; leftRightPos++)
  {
    leftRightServo.write(leftRightPos);             

  for(upDownPos = 60; upDownPos < 120; upDownPos++)
  {
    upDownServo.write(upDownPos);  

      for (index = 0; index<=numReadings;index++) {            // take x number of readings from the sensor and average them
        float volts = analogRead(IRpin)*0.0048828125;   // value from sensor * (5/1024) - if running 3.3.volts then change 5 to 3.3
        float distance = 65*pow(volts, -1.10);          // worked out from graph 65 = theretical distance / (1/Volts)S - luckylarry.co.uk
        total = total + distance;                              // update total
        delayMicroseconds(20);
      }
    average = (int) total/numReadings;                               // create average reading
        if (average < 20) {
         average = 20;
        }
        if (average > 150) {
         average = 150;
        }
        //average = 0 - average;
    if (index >= numReadings)  {                               // reset the counts when at the last item of the array
      index = 0;
      total = 0;
    }       

Serial.print("Y");
Serial.print(upDownPos-60);
Serial.print("X");
Serial.print(leftRightPos);
Serial.print("Z");
Serial.println(average);

  }
    upDownServo.write(60);
  }

    leftRightServo.write(0);              

}

[ad#Google Ad in content]

Processing Sketch

We now listen to the serial port and each time there is an event we take the values and populate an array based on the X and Y values sent from the Arduino code. We add this value on to the existing value and then for each complete mapping we work out the average value – so the longer it runs for the more normalised the results should appear.

Using some basic trigonometry we have a class that makes an arc. Our draw() method calls this arc and translates/ rotates it for each of the 180 degrees. The arc itself is calculated from using the distance reading from the sensor as its radius.

If using a grid instead of this shape then we just say at point X,Y set the Z value instead of worrying about radius’s etc…

/*
luckylarry.co.uk
3D Scan Visualisation for Sharp GP2Y0A02
Maps out an area of what the GP2Y0A02 sees into a 3D view
*/
import processing.serial.*;     // import serial library
Serial myPort;                  // declare a serial port
int x, y, z;                     // variable to store x and y co-ordinates for vertices
int value = 0;                  // value from sensor
int[][][] data = new int[181][61][1];  // create an array to store each new sensor value for each servo position
int count;
int average = 1;
PFont myFont;                   // setup fonts in Processing
int numberOfSegments = 179;
createArc Arc;                  // create an instance of the Arc class
float radius = 150;
float angle = 0;

void setup(){
  size(640, 360, P3D);
  Arc = new createArc();        // assign the Arc classes to an object
  myFont = createFont("verdana", 12);
  textFont(myFont);
  // setup the serial port and buffer
  myPort = new Serial(this, Serial.list()[1], 9600);
  myPort.bufferUntil('\n');

}

void draw(){
  background(255);
  float tempX = 0, tempY = 1, tempZ = 0;
  fill(200);
  lights();
  translate(width/2, 200, 110);
  angle = 180.0 / numberOfSegments;
  rotateY(count * PI/10800);
  for (int j = 0; j < numberOfSegments; j++){
      tempZ = cos(radians(angle))*radius;
      tempX = sin(radians(angle))*radius;
      pushMatrix();
      translate(tempX, tempY, tempZ); // move each instance we create of the arc object to a slightly new position and rotation
      rotateY(radians(angle));
      Arc.create(j);
      popMatrix();
      angle += 180.0/numberOfSegments;
  }

}
// creates an arc object using QUAD_STRIP
class createArc {
// pass values to create method to know which array to load 1 to 180...
  void create(int degree){
    pushMatrix();
    rotateY(radians(135));
    beginShape(QUAD_STRIP);
    for(int a=60; a < 120;a++) {
      float x1 = cos(radians(((90+a))))*(data[degree][a-60][0]/average);
      float y1 = sin(radians(((90+a))))*(data[degree][a-60][0]/average);
      float x2 = cos(radians(((90+a))))*(data[degree+1][a-60][0]/average);
      float y2 = sin(radians(((90+a))))*(data[degree+1][a-60][0]/average);
      vertex(x1,y1,100);
      vertex(x2,y2,105);
    }
    endShape();
    popMatrix();
  }
} 

/* get values from serial port */

void serialEvent (Serial myPort) {
  String xString = myPort.readStringUntil('\n');  // read the serial port until a new line
    if (xString != null) {  // if theres data in between the new lines
    	xString = trim(xString); // get rid of any whitespace just in case
    	String getY = xString.substring(1, xString.indexOf("X")); // get the value of the servo position
        String getX = xString.substring(xString.indexOf("X")+1, xString.indexOf("Z")); // get the value of the sensor reading
        String getZ = xString.substring(xString.indexOf("Z")+1, xString.length()); // get the value of the sensor reading
    	x = Integer.parseInt(getX); // set the values to variables
    	y = Integer.parseInt(getY);
        z = Integer.parseInt(getZ);
        data[x][y][0] += z;
        //println(z); // for debugging
        count++;
        if (count > 10800) {
          count = 0;
          average++;
        }
  }
}

[ad#Google Ad in content]

So here’s a quick screen grab of the 3D object that represents what the sensor sees, looks pretty confusing but if you zoom in and take a small section of it then it’s a bit better. Other than that its just a random shape!

3D-scan02

Arduino + Processing – Make a Radar Screen – Part 3: Visualising the Data from Sharp Infrared Range Finder

Arduino Sharp IR radar

So I had some luck with getting the Sharp Infrared range finder working and I’ve now plugged this on to my servo rig to see if I get better results on my radar styled display.

Check out how to use the Sharp IR range finder here

Few things to bare in mind, whilst the code is pretty much the same there are a few subtle differences. Firstly for better readings the Arduino code has a longer delay – but since we’re not allowing for a sonar ping there’s not much noticeable difference.

Next we’re expecting integer values in the processing code so when sending values to over the serial port we cast them from float to integer.

Because the IR sensor has a different range I’ve altered the display to measure only up to 150cm. And becasue of this range limitation, if there is any value recorded outside of this range then we need to handle it to avoid seeing spikes and the same for any value under 20cm we need to also handle this.

To make the display more readable I keep the same size screen and area (radius of 300) and then multiply the sensor values by 2 to magnify them a bit more.

Other than it, it’s basically the same code as before and when we look at the image comparison now between what the sensor records and what is physically there we see a far better match, in some cases it’s a little to accurate.

Sharp-IR-radar

Arduino sketch

/*
luckylarry.co.uk
Radar Screen Visualisation for Sharp GP2Y0A02 IR range finder
Sends sensor readings for every degree moved by the servo
values sent to serial port to be picked up by Processing
*/
#include             // include the standard servo library
Servo leftRightServo;         // set a variable to map the servo
int leftRightPos = 0;         // set a variable to store the servo position
const int numReadings = 10;   // set a variable for the number of readings to take
int index = 0;                // the index of the current reading
float total = 0;              // the total of all readings must be a float to allow totaling of float values
int average = 0;              // the average
int IRpin = 1;                // analog pin for reading the IR sensor
 
/* setup the pins, servo and serial port */
void setup() { 
  leftRightServo.attach(9);
  // initialize the serial port:
  Serial.begin(9600);
} 
 
/* begin rotating the servo and getting sensor values */
void loop() { 
  for(leftRightPos = 0; leftRightPos < 180; leftRightPos++) {  // going left to right.                                
    leftRightServo.write(leftRightPos);             
      for (index = 0; index<=numReadings;index++) {            // take x number of readings from the sensor and average them
        float volts = analogRead(IRpin)*0.0048828125;          // value from sensor * (5/1024) - if running 3.3.volts then change 5 to 3.3
        float distance = 65*pow(volts, -1.10);                 // worked out from graph 65 = theretical distance / (1/Volts)S - luckylarry.co.uk
        total = total + distance;                              // update total
        delay(20);
      }
    average = (int) total/numReadings;                         // create average reading CAST TO INT!! remove the decimal places
 
    if (index >= numReadings)  {                               // reset the counts when at the last item of the array    
      index = 0;           
      total = 0;     
    }
    Serial.print("X");                                         // print leading X to mark the following value as degrees
    Serial.print(leftRightPos);                                // current servo position
    Serial.print("V");                                         // preceeding character to separate values
    Serial.println(average);                                   // average of sensor readings
  }
  /* 
  start going right to left after we got to 180 degrees 
  same code as above
  */
  for(leftRightPos = 180; leftRightPos > 0; leftRightPos--) {  // going right to left                                
    leftRightServo.write(leftRightPos);             
    for (index = 0; index<=numReadings;index++) {
      float volts = analogRead(IRpin)*0.0048828125;            // value from sensor * (5/1024) - if running 3.3.volts then change 5 to 3.3
      float distance = 65*pow(volts, -1.10);                   // worked out from graph 65 = theretical distance / (1/Volts)S - luckylarry.co.uk
      total = total + distance;
      delay(20);
    }
    average = (int) total/numReadings;  
    if (index >= numReadings)  {           
      index = 0;           
      total = 0;     
    }
    Serial.print("X");
    Serial.print(leftRightPos);
    Serial.print("V");
    Serial.println(average);
   }  
}

[ad#Google Ad in content]

Processing sketch

/*
luckylarry.co.uk
Radar Screen Visualisation for Sharp GP2Y0A02
Maps out an area of what the GP2Y0A02 sees from a top down view.
Takes and displays 2 readings, one left to right and one right to left.
Displays an average of the 2 readings
Displays motion alert if there is a large difference between the 2 values.
*/
import processing.serial.*;     // import serial library
Serial myPort;                  // declare a serial port
float x, y;                     // variable to store x and y co-ordinates for vertices   
int radius = 350;               // set the radius of objects
int w = 300;                    // set an arbitary width value
int degree = 0;                 // servo position in degrees
int value = 0;                  // value from sensor
int motion = 0;                 // value to store which way the servo is panning
int[] newValue = new int[181];  // create an array to store each new sensor value for each servo position
int[] oldValue = new int[181];  // create an array to store the previous values.
PFont myFont;                   // setup fonts in Processing
int radarDist = 0;              // set value to configure Radar distance labels
int firstRun = 0;               // value to ignore triggering motion on the first 2 servo sweeps

/* create background and serial buffer */
void setup(){
  // setup the background size, colour and font.
  size(750, 450);
  background (0); // 0 = black
  myFont = createFont("verdana", 12);
  textFont(myFont);
  // setup the serial port and buffer
  myPort = new Serial(this, Serial.list()[1], 9600);
  myPort.bufferUntil('\n');
}

/* draw the screen */
void draw(){
  fill(0);                              // set the following shapes to be black
  noStroke();                           // set the following shapes to have no outline
  ellipse(radius, radius, 750, 750);    // draw a circle with a width/ height = 750 with its center position (x and y) set by the radius
  rectMode(CENTER);                     // set the following rectangle to be drawn around its center
  rect(350,402,800,100);                // draw rectangle (x, y, width, height)
  if (degree >= 179) {                  // if at the far right then set motion = 1/ true we're about to go right to left
    motion = 1;                         // this changes the animation to run right to left
  }
  if (degree <= 1) {                    // if servo at 0 degrees then we're about to go left to right
    motion = 0;                         // this sets the animation to run left to right
  }
  /* setup the radar sweep */
  /* 
  We use trigonmetry to create points around a circle.
  So the radius plus the cosine of the servo position converted to radians
  Since radians 0 start at 90 degrees we add 180 to make it start from the left
  Adding +1 (i) each time through the loops to move 1 degree matching the one degree of servo movement
  cos is for the x left to right value and sin calculates the y value
  since its a circle we plot our lines and vertices around the start point for everything will always be the center.
  */
  strokeWeight(7);                      // set the thickness of the lines
  if (motion == 0) {                    // if going left to right
    for (int i = 0; i <= 20; i++) {     // draw 20 lines with fading colour each 1 degree further round than the last
      stroke(0, (10*i), 0);             // set the stroke colour (Red, Green, Blue) base it on the the value of i
      line(radius, radius, radius + cos(radians(degree+(180+i)))*w, radius + sin(radians(degree+(180+i)))*w); // line(start x, start y, end x, end y)
    }
  } else {                              // if going right to left
    for (int i = 20; i >= 0; i--) {     // draw 20 lines with fading colour
      stroke(0,200-(10*i), 0);          // using standard RGB values, each between 0 and 255
      line(radius, radius, radius + cos(radians(degree+(180+i)))*w, radius + sin(radians(degree+(180+i)))*w);
    }
  }
  /* Setup the shapes made from the sensor values */
  noStroke();                           // no outline
  /* first sweep */
  fill(0,50,0);                         // set the fill colour of the shape (Red, Green, Blue)
  beginShape();                         // start drawing shape
    for (int i = 0; i < 180; i++) {     // for each degree in the array
      x = radius + cos(radians((180+i)))*((oldValue[i]*2)); // create x coordinate
      y = radius + sin(radians((180+i)))*((oldValue[i]*2)); // create y coordinate
      vertex(x, y);                     // plot vertices
    }
  endShape();                           // end shape
  /* second sweep */
  fill(0,110,0);
  beginShape();
    for (int i = 0; i < 180; i++) {
      x = radius + cos(radians((180+i)))*(newValue[i]*2);
      y = radius + sin(radians((180+i)))*(newValue[i]*2);
      vertex(x, y);
    }
  endShape();
  /* average */
  fill(0,170,0);
  beginShape();
    for (int i = 0; i < 180; i++) {
      x = radius + cos(radians((180+i)))*(((newValue[i]+oldValue[i])/2)*2); // create average
      y = radius + sin(radians((180+i)))*(((newValue[i]+oldValue[i])/2)*2);
      vertex(x, y);
    }
  endShape();
  /* if after first 2 sweeps, highlight motion with red circle*/
  if (firstRun >= 360) {
    stroke(150,0,0);
    strokeWeight(1);
    noFill();
      for (int i = 0; i < 180; i++) {
        if (oldValue[i] - newValue[i] > 35 || newValue[i] - oldValue[i] > 35) {
          x = radius + cos(radians((180+i)))*(newValue[i]*2);
          y = radius + sin(radians((180+i)))*(newValue[i]*2);
          ellipse(x, y, 10, 10); 
        }
      }
  }
  /* set the radar distance rings and out put their values, 50, 100, 150 etc.. */
  for (int i = 0; i <=6; i++){
    noFill();
    strokeWeight(1);
    stroke(0, 255-(30*i), 0);
    ellipse(radius, radius, (100*i), (100*i)); 
    fill(0, 100, 0);
    noStroke();
    text(Integer.toString(radarDist+25), 380, (305-(radarDist*2)), 50, 50); // change this to measure up to 150cm
    radarDist+=25;
  }
  radarDist = 0;
  /* draw the grid lines on the radar every 30 degrees and write their values 180, 210, 240 etc.. */
  for (int i = 0; i <= 6; i++) {
    strokeWeight(1);
    stroke(0, 55, 0);
    line(radius, radius, radius + cos(radians(180+(30*i)))*w, radius + sin(radians(180+(30*i)))*w);
    fill(0, 55, 0);
    noStroke();
    if (180+(30*i) >= 300) {
      text(Integer.toString(180+(30*i)), (radius+10) + cos(radians(180+(30*i)))*(w+10), (radius+10) + sin(radians(180+(30*i)))*(w+10), 25,50);
    } else {
      text(Integer.toString(180+(30*i)), radius + cos(radians(180+(30*i)))*w, radius + sin(radians(180+(30*i)))*w, 60,40);
    }
  }
  /* Write information text and values. */
  noStroke();
  fill(0);
  rect(350,402,800,100);
  fill(0, 100, 0);
  text("Degrees: "+Integer.toString(degree), 100, 380, 100, 50);         // use Integet.toString to convert numeric to string as text() only outputs strings
  text("Distance: "+Integer.toString(value), 100, 400, 100, 50);         // text(string, x, y, width, height)
  text("Radar screen code at luckylarry.co.uk", 540, 380, 250, 50);
  fill(0);
  rect(70,60,150,100);
  fill(0, 100, 0); 
  text("Screen Key:", 100, 50, 150, 50);
  fill(0,50,0);
  rect(30,53,10,10);
  text("First sweep", 115, 70, 150, 50);
  fill(0,110,0);
  rect(30,73,10,10);
  text("Second sweep", 115, 90, 150, 50);
  fill(0,170,0);
  rect(30,93,10,10);
  text("Average", 115, 110, 150, 50);
  noFill();
  stroke(150,0,0);
  strokeWeight(1);
  ellipse(29, 113, 10, 10); 
  fill(150,0,0);
  text("Motion", 115, 130, 150, 50);
}

/* get values from serial port */
void serialEvent (Serial myPort) {
  String xString = myPort.readStringUntil('\n');  // read the serial port until a new line
    if (xString != null) {  // if theres data in between the new lines
    	xString = trim(xString); // get rid of any whitespace just in case
    	String getX = xString.substring(1, xString.indexOf("V")); // get the value of the servo position
    	String getV = xString.substring(xString.indexOf("V")+1, xString.length()); // get the value of the sensor reading
    	degree = Integer.parseInt(getX); // set the values to variables
    	value = Integer.parseInt(getV);
        /*
        If our values are outside either end of the sensors range then convert them to the max/min for a better display without the spikes
        */
        if (value > 150) {
          value = 150; 
        }
        if (value < 20) {
          value = 20;
        }
    	oldValue[degree] = newValue[degree]; // store the values in the arrays.
    	newValue[degree] = value;  
        /* sets a counter to allow for the first 2 sweeps of the servo */
    	firstRun++;
    	if (firstRun > 360) {
    	  firstRun = 360; // keep the value at 360 
    	}
  }
}

[ad#Google Ad in content]
Part 1: Setting up the Circuit and Outputting Values
Part 2: Visualising the Data

Arduino + Processing: Make a Radar Screen to Visualise Sensor Data from SRF-05 – Part 2: Visualising the Data

Arduino SRF 05 radar

This is where all the work is done to read an interpret the values from the servo and the sensor. If the readings are to erratic then you won’t have nice shapes. Also if you don’t allow enough time to the signals to be sent back then you’ll get false distance readings. So this code is only as good as your Arduino code and sensor setup.

Took me a few evenings to work this out to get it how I wanted, the hardest bit is the trigonometry involved which isn’t that difficult, everything else is done by loops and a few IF statements. I use the FOR loops alot because the all the elements can be displayed programmatically without having to write each rectangle, cirle and line to the screen with their own statement.

If you’re not familiar with Processing then head over to Processing.org. Processing is a tool/ IDE that lets you program and code graphics and animation, it’s free to use and pretty powerful – best part is it works hand in hand with Arduino in the same C/C++ style of code, letting us take data from Arduino and whatever’s plugged into it and then visualise it on screen, e.g. like a radar screen.

First we have to setup our variables, background and load in the serial port libraries to ensure we can read the data sent by the Arduino. We also have to include a function from the serial library called serialEvent() which listens for data being sent and allows us to read the data easily. We do some easy string work, splitting the serial port lines to get the servo position and sensor value.

Also we can setup the radar screen, drawing the text, measurements and display grid. With processing whats nearest the top of the draw() function is displayed first with everything subsequentally drawn on top of this. So our lines and text will be at the bottom of the function so it will always be visible. To draw the lines and measurements we use a FOR loop. The draw() function draws one frame, so we basically re-draw the frame 180 times – we use a couple of arrays to store the previous values to make it look continuous.

Now that we have those we can then begin to display the values on our screen. We use a FOR loop to loop through each item in our array, newValue and oldValue. These are setup to hold 181 items – 1 item per servo position with 1 extra just in case, we loop through these to constantly display the previous readings – if we were to use the servo position itself to iterate through the array then no previous data would be displayed since the servo position is always changing.

Thoughout we need to calculate the X and Y co-ordinates of each servo position and sensor distance reading. To get these values we use trigonometry using sine and cosine and converting the servo position to a radian using the sensor reading as the distance from the center from which to draw the point. To learn more about this and to save me writing it up check out this tutorial at Processing.org.

The Sketch
Below is the code used to create the radar screen, it has comments to help explain. Everything used is an in built function of the Processing language and you can find the reference for the functions that I use in the reference section on the Processing.org website. So methods such as fill(), stroke(), rect(), line() etc…

/*
luckylarry.co.uk
Radar Screen Visualisation for SRF-05
Maps out an area of what the SRF-05 sees from a top down view.
Takes and displays 2 readings, one left to right and one right to left.
Displays an average of the 2 readings
Displays motion alert if there is a large difference between the 2 values.
*/
import processing.serial.*;     // import serial library
Serial myPort;                  // declare a serial port
float x, y;                       // variable to store x and y co-ordinates for vertices
int radius = 350;               // set the radius of objects
int w = 300;                    // set an arbitary width value
int degree = 0;                 // servo position in degrees
int value = 0;                  // value from sensor
int motion = 0;                 // value to store which way the servo is panning
int[] newValue = new int[181];  // create an array to store each new sensor value for each servo position
int[] oldValue = new int[181];  // create an array to store the previous values.
PFont myFont;                   // setup fonts in Processing
int radarDist = 0;              // set value to configure Radar distance labels
int firstRun = 0;               // value to ignore triggering motion on the first 2 servo sweeps

/* create background and serial buffer */
void setup(){
  // setup the background size, colour and font.
  size(750, 450);
  background (0); // 0 = black
  myFont = createFont("verdana", 12);
  textFont(myFont);
  // setup the serial port and buffer
  myPort = new Serial(this, Serial.list()[1], 9600);
  myPort.bufferUntil('n');
}

/* draw the screen */
void draw(){
  fill(0);                              // set the following shapes to be black
  noStroke();                           // set the following shapes to have no outline
  ellipse(radius, radius, 750, 750);    // draw a circle with a width/ height = 750 with its center position (x and y) set by the radius
  rectMode(CENTER);                     // set the following rectangle to be drawn around its center
  rect(350,402,800,100);                // draw rectangle (x, y, width, height)
  if (degree >= 179) {                  // if at the far right then set motion = 1/ true we're about to go right to left
    motion = 1;                         // this changes the animation to run right to left
  }
  if (degree <= 1) {                    // if servo at 0 degrees then we're about to go left to right
    motion = 0;                         // this sets the animation to run left to right
  }
  /* setup the radar sweep */
  /*
  We use trigonmetry to create points around a circle.
  So the radius plus the cosine of the servo position converted to radians
  Since radians 0 start at 90 degrees we add 180 to make it start from the left
  Adding +1 (i) each time through the loops to move 1 degree matching the one degree of servo movement
  cos is for the x left to right value and sin calculates the y value
  since its a circle we plot our lines and vertices around the start point for everything will always be the center.
  */
  strokeWeight(7);                      // set the thickness of the lines
  if (motion == 0) {                    // if going left to right
    for (int i = 0; i <= 20; i++) {     // draw 20 lines with fading colour each 1 degree further round than the last
      stroke(0, (10*i), 0);             // set the stroke colour (Red, Green, Blue) base it on the the value of i
      line(radius, radius, radius + cos(radians(degree+(180+i)))*w, radius + sin(radians(degree+(180+i)))*w); // line(start x, start y, end x, end y)
    }
  } else {                              // if going right to left
    for (int i = 20; i >= 0; i--) {     // draw 20 lines with fading colour
      stroke(0,200-(10*i), 0);          // using standard RGB values, each between 0 and 255
      line(radius, radius, radius + cos(radians(degree+(180+i)))*w, radius + sin(radians(degree+(180+i)))*w);
    }
  }
  /* Setup the shapes made from the sensor values */
  noStroke();                           // no outline
  /* first sweep */
  fill(0,50,0);                         // set the fill colour of the shape (Red, Green, Blue)
  beginShape();                         // start drawing shape
    for (int i = 0; i < 180; i++) {     // for each degree in the array
      x = radius + cos(radians((180+i)))*((oldValue[i])); // create x coordinate
      y = radius + sin(radians((180+i)))*((oldValue[i])); // create y coordinate
      vertex(x, y);                     // plot vertices
    }
  endShape();                           // end shape
  /* second sweep */
  fill(0,110,0);
  beginShape();
    for (int i = 0; i < 180; i++) {
      x = radius + cos(radians((180+i)))*(newValue[i]);
      y = radius + sin(radians((180+i)))*(newValue[i]);
      vertex(x, y);
    }
  endShape();
  /* average */
  fill(0,170,0);
  beginShape();
    for (int i = 0; i < 180; i++) {
      x = radius + cos(radians((180+i)))*((newValue[i]+oldValue[i])/2); // create average
      y = radius + sin(radians((180+i)))*((newValue[i]+oldValue[i])/2);
      vertex(x, y);
    }
  endShape();
  /* if after first 2 sweeps, highlight motion with red circle*/
  if (firstRun >= 360) {
    stroke(150,0,0);
    strokeWeight(1);
    noFill();
      for (int i = 0; i < 180; i++) {
        if (oldValue[i] - newValue[i] > 35 || newValue[i] - oldValue[i] > 35) {
          x = radius + cos(radians((180+i)))*(newValue[i]);
          y = radius + sin(radians((180+i)))*(newValue[i]);
          ellipse(x, y, 10, 10);
        }
      }
  }
  /* set the radar distance rings and out put their values, 50, 100, 150 etc.. */
  for (int i = 0; i <=6; i++){
    noFill();
    strokeWeight(1);
    stroke(0, 255-(30*i), 0);
    ellipse(radius, radius, (100*i), (100*i));
    fill(0, 100, 0);
    noStroke();
    text(Integer.toString(radarDist+50), 380, (305-radarDist), 50, 50);
    radarDist+=50;
  }
  radarDist = 0;
  /* draw the grid lines on the radar every 30 degrees and write their values 180, 210, 240 etc.. */
  for (int i = 0; i <= 6; i++) {
    strokeWeight(1);
    stroke(0, 55, 0);
    line(radius, radius, radius + cos(radians(180+(30*i)))*w, radius + sin(radians(180+(30*i)))*w);
    fill(0, 55, 0);
    noStroke();
    if (180+(30*i) >= 300) {
      text(Integer.toString(180+(30*i)), (radius+10) + cos(radians(180+(30*i)))*(w+10), (radius+10) + sin(radians(180+(30*i)))*(w+10), 25,50);
    } else {
      text(Integer.toString(180+(30*i)), radius + cos(radians(180+(30*i)))*w, radius + sin(radians(180+(30*i)))*w, 60,40);
    }
  }
  /* Write information text and values. */
  noStroke();
  fill(0);
  rect(350,402,800,100);
  fill(0, 100, 0);
  text("Degrees: "+Integer.toString(degree), 100, 380, 100, 50);         // use Integet.toString to convert numeric to string as text() only outputs strings
  text("Distance: "+Integer.toString(value), 100, 400, 100, 50);         // text(string, x, y, width, height)
  text("Radar screen code at luckylarry.co.uk", 540, 380, 250, 50);
  fill(0);
  rect(70,60,150,100);
  fill(0, 100, 0);
  text("Screen Key:", 100, 50, 150, 50);
  fill(0,50,0);
  rect(30,53,10,10);
  text("First sweep", 115, 70, 150, 50);
  fill(0,110,0);
  rect(30,73,10,10);
  text("Second sweep", 115, 90, 150, 50);
  fill(0,170,0);
  rect(30,93,10,10);
  text("Average", 115, 110, 150, 50);
  noFill();
  stroke(150,0,0);
  strokeWeight(1);
  ellipse(29, 113, 10, 10);
  fill(150,0,0);
  text("Motion", 115, 130, 150, 50);
}

/* get values from serial port */
void serialEvent (Serial myPort) {
  String xString = myPort.readStringUntil('n');  // read the serial port until a new line
    if (xString != null) {  // if theres data in between the new lines
        xString = trim(xString); // get rid of any whitespace just in case
        String getX = xString.substring(1, xString.indexOf("V")); // get the value of the servo position
        String getV = xString.substring(xString.indexOf("V")+1, xString.length()); // get the value of the sensor reading
        degree = Integer.parseInt(getX); // set the values to variables
        value = Integer.parseInt(getV);
        oldValue[degree] = newValue[degree]; // store the values in the arrays.
        newValue[degree] = value;
        /* sets a counter to allow for the first 2 sweeps of the servo */
        firstRun++;
        if (firstRun > 360) {
          firstRun = 360; // keep the value at 360
        }
  }
}

[ad#Google Ad in content]

The end result
Here’s a video below of it all working! There is an issue to bare in mind with the SRF-05 and thats that it works best as a static range finder, it emits a conical wave which will bounce back off of anything small or large and has a wide detection field of vision so it may pick up something that’s not directly in front of it. As you can see by the below image the detection range is so wide that it doesn’t truly see all the gaps as its detected something else in its field of vision.

sonar-topdown

If there are less objects it works fine… time to look at other sensors I think – anyway here’s the video below just showing it working on my screen.

Part 1: Setting up the Circuit and Outputting Values
Part 3: Visualising the Data from Sharp Infrared Range Finder

Arduino + Processing – Make a Radar Screen to Visualise Sensor Data from SRF-05 – Part 1: Setting up the Circuit and Outputting Values

arduino servo SRF05

First things first, we need to build our circuit. This is the easy bit! We’ll be using the Arduino to control a servo that will rotate our sensor around 180 degrees. The Arduino will then send the value from the distance sensor along with the current angle of the servo to the serial port.

Before proceeding please take a moment to check out some of my other work with the SRF-05 and servos if you’re unfamiliar with either.
Arduino SRF-05 Tutorials
Arduino Servo Tutorials

I’m building this with the SRF-05 ultrasonic range finder/ distance sensor, but because this has a fairly wide field of detection it’s not very precise – I think I’ll end up trying a different range finder maybe an IR one as the SRF-05 works best as a static sensor/ detector, anyway…

Arduino Radar Parts list

SRF05 Ultrasonic range finder
Arduino Deumilanove w/ ATMEGA328
Breadboard / Prototyping board
Jumper/ Connector wires
1x Servo (has to need no more than 5v supply)
You’ll also need some way to mount the sensor to the servo.

Arduino Radar Servo Circuit

Straight forward, we have the Arduino providing power to the breadboard and we have the servo and the SRF-05 sharing this power. Then we have the servo output pin going to Arduino digital pin 9 and the SRF-05 pins going to digital pin 2 and 3. You’ll notice that in my pictures I have 2 servos – I’m just using the bottom one of the pair to rotate the sensor round. On your servo you’ll need to figure out a way to mount the sensor on to the servo wheel – I used a lot of blu-tac! You’ll also see I’ve mounted my sensor vertically so that the when the servo moves there’ll be less interference with recieving values – placing the sensor horisontally seemed to give differences of up to and sometimes over 5cm between the first and second readings.

My servos do tend to move a bit so I’ve used more blu-tak/ modelling clay to hold them down and in place – if the servos move other than the way they’re meant to then it means dodgy readings.

SRF05 pin layout
arduino-servo-SRF05
Simple rig to rotate sensor 180 degrees

Arduino SRF05 Radar Sketch

The hardest bit – rotate the servo from left to right, then right to left and for every degree of movement take a series of readings and send them to the serial port. We’ll want to produce an average reading value for consistancy. Unfortunately with this ultrasound sensor we have to be quite slow to make sure we’re getting accurate values and we have to allow time for the signal to come back each time and register in order to produce the average value.

We do the rotation using a for loop to count to 180 and for each iteration we move the servo by +1 or -1 depending on which way we’re going – if you’ve hacked your servos then you can do a full 360 loop. During this loop we do another FOR loop to count to 10/ numReadings and for each iteration we add the distance measured to the total and after 10 readings we get our average by dividing the total by the number of readings. Then reset the total and the counter to start again for the next servo position. Finally before finishing the  the FOR loop for the servo we output the servo position and average reading to the serial port each with a preceeding character for us to later use to identify the values when reading the serial port in Processing. The last line is using println which will start a new line for the next set of values – each reading has its own line in the serial buffer makign it much easier to get our values back out.

/*
luckylarry.co.uk
Radar Screen Visualisation for SRF-05
Sends sensor readings for every degree moved by the servo
values sent to serial port to be picked up by Processing
*/
#include             // include the standard servo library
Servo leftRightServo;         // set a variable to map the servo
int leftRightPos = 0;         // set a variable to store the servo position
const int numReadings = 10;   // set a variable for the number of readings to take
int index = 0;                // the index of the current reading
int total = 0;                // the total of all readings
int average = 0;              // the average
int echoPin = 2;              // the SRF05's echo pin
int initPin = 3;              // the SRF05's init pin
unsigned long pulseTime = 0;  // variable for reading the pulse
unsigned long distance = 0;   // variable for storing distance

/* setup the pins, servo and serial port */
void setup() {
  leftRightServo.attach(9);
  // make the init pin an output:
  pinMode(initPin, OUTPUT);
  // make the echo pin an input:
  pinMode(echoPin, INPUT);
  // initialize the serial port:
  Serial.begin(9600);
} 

/* begin rotating the servo and getting sensor values */
void loop() {
  for(leftRightPos = 0; leftRightPos < 180; leftRightPos++) {  // going left to right.
    leftRightServo.write(leftRightPos);
      for (index = 0; index<=numReadings;index++) {            // take x number of readings from the sensor and average them
        digitalWrite(initPin, LOW);
        delayMicroseconds(50);
        digitalWrite(initPin, HIGH);                           // send signal
        delayMicroseconds(50);                                 // wait 50 microseconds for it to return
        digitalWrite(initPin, LOW);                            // close signal
        pulseTime = pulseIn(echoPin, HIGH);                    // calculate time for signal to return
        distance = pulseTime/58;                               // convert to centimetres
        total = total + distance;                              // update total
        delay(10);
      }
    average = total/numReadings;                               // create average reading

    if (index >= numReadings)  {                               // reset the counts when at the last item of the array
      index = 0;
      total = 0;
    }
    Serial.print("X");                                         // print leading X to mark the following value as degrees
    Serial.print(leftRightPos);                                // current servo position
    Serial.print("V");                                         // preceeding character to separate values
    Serial.println(average);                                   // average of sensor readings
  }
  /*
  start going right to left after we got to 180 degrees
  same code as above
  */
  for(leftRightPos = 180; leftRightPos > 0; leftRightPos--) {  // going right to left
    leftRightServo.write(leftRightPos);
    for (index = 0; index<=numReadings;index++) {
      digitalWrite(initPin, LOW);
      delayMicroseconds(50);
      digitalWrite(initPin, HIGH);
      delayMicroseconds(50);
      digitalWrite(initPin, LOW);
      pulseTime = pulseIn(echoPin, HIGH);
      distance = pulseTime/58;
      total = total + distance;
      delay(10);
    }
    average = total/numReadings;
    if (index >= numReadings)  {
      index = 0;
      total = 0;
    }
    Serial.print("X");
    Serial.print(leftRightPos);
    Serial.print("V");
    Serial.println(average);
   }
}

[ad#Google Ad in content]

Part 2: Visualising the Data
Part 3: Visualising the Data from Sharp Infrared Range Finder

Arduino – Basic Theremin meets Processing!

Arduino piano theremin

My last theremin involved a small speaker. Now I’ve replaced the speaker with my PC, using processing to pick up the values from the SRF05 ultrasound sonar distance sensor and play different notes accordingly – which gives multiple possibilities and far better sounds.

So to start with check out my previous theremin, the circuit is the same except for removing the speaker and the Arduino code now prints values to the serial port instead of outputing directly to a speaker. The only thing that I’m doing here that is really new is using the minim libary for Processing, built by this chap (thankyou). What this allows us is to assign a sound file to a variable in Processing and then gives us functions to start/stop the sound.

In my processing code you’ll see that I’ve got 12 sounds, one for each chromatic note and at the moment they’re from a piano. To get sounds and samples to use you can sign up to freesound.org. Mine I got here from ‘pinkyfinger’ and once you’ve decided which sounds you want to use then the rest is fairly easy – the more samples and octaves the better. I’ve used the piano set here just so I can hear the different notes and I’ve only 12 notes (chromatic scale) but eventually Iwould like to expand this to say 48 notes.

When you get your sounds I’ve found it’s easiest to use .wavs but minim will allow you to use WAV, AIFF, AU, SND, and MP3 files. Also I store my sounds in the root of the folder where I’m saving my processing sketch.

Ok, lets start with the Arduino parts, circuit and sketch.

Arduino Theremin Parts

SRF05 Ultrasonic range finder
Arduino Deumilanove w/ ATMEGA328
Breadboard / Prototyping board (you can actually do this without a breadboard)
Jumper/ Connector wires

The Theremin Arduino Circuit

Basically the same as before just without the speaker on it. For more info on the SRF05 checkout my past stuff here. In this instance Processing is going to do all the work, so the circuit just needs to pass values from the SRF05 to Arduino, which in turn passes values to my PC via the USB cable.

piano-theremin

The Arduino Theremin Sketch

Very cut down version, it takes the value as before and converts it to a distance and then just prints it to a new line in on the serial port.

// written at: luckylarry.co.uk
// very easy Theremin combined with processing
// sketch prints out distance to the serial port
// processing picks up value and plays notes accordingly
// no annoying speaker drone! :)

// setup pins and variables for SRF05 sonar device
int echoPin = 2;                                // SRF05 echo pin (digital 2)
int initPin = 3;                                // SRF05 trigger pin (digital 3)
unsigned long pulseTime = 0;                    // stores the pulse in Micro Seconds
unsigned long distance = 0;                     // variable for storing the distance (cm) we'll use distance as a switch for the speaker

//setup
void setup() {

  pinMode(initPin, OUTPUT);                     // set init pin 3 as output
  pinMode(echoPin, INPUT);                      // set echo pin 2 as input
  Serial.begin(9600);                           // start the serial port

} 

// execute
void loop() {
  digitalWrite(initPin, HIGH);                  // send 10 microsecond pulse
  delayMicroseconds(10);                        // wait 10 microseconds before turning off
  digitalWrite(initPin, LOW);                   // stop sending the pulse
  pulseTime = pulseIn(echoPin, HIGH);           // Look for a return pulse, it should be high as the pulse goes low-high-low
  distance = pulseTime/58;                      // convert the pulse into distance (cm)

  // make the sound.
  // check the distance, if over 50cm make no sound - send no signal
  if (distance > 50) {
    Serial.println(distance);                   // print the distance value to the serial port
    delay(50);                                  // delay for 50 milliseconds before starting again...
  }
}

[ad#Google Ad in content]
Next up we have processing, which will look for values on the serial port, so first upload the Arduino code to your board and test it works. Next start up Processing to finish off the code. If like me you’re fairly new to processing there’s lots of info to be had at: http://www.arduino.cc/playground/Interfacing/Processing

The Processing Theremin Sketch

With your code now running on the Arduino board we now need processing to pick up these values. Previously I had something of an issue getting these values and reading them. But in hindsight I was being a bit dim when I realised I could just look in the serial port for when a new line (n) was printed which would tell me that a new value was about to be sent. Of course thats providing your Arduino sketch is using Serial.println() (print line) instead of Serial.print() which just chucks every value into one long string – and if you look at my previous attempts with processing you can laugh at how I started splitting this huge string up etc… Oh hindsight is a wonderful thing, anyway, I digress, below is the processing sketch:

// written at: luckylarry.co.uk
// very easy Theremin combined with processing
// sketch prints out distance to the serial port
// processing picks up value and plays notes accordingly
// no annoying speaker drone! :) replace the sounds and delays with
// your own...

import processing.serial.*;                // import serial library so we can read the serial port
import ddf.minim.*;                        // import minim library

// define the serial port
Serial myPort;          

// define minim variables:
// here we say that variable A is an audiosample etc...
Minim minim;
AudioSample GSharp;
AudioSample A;
AudioSample Bb;
AudioSample B;
AudioSample C;
AudioSample CSharp;
AudioSample D;
AudioSample Eb;
AudioSample E;
AudioSample F;
AudioSample FSharp;
AudioSample G;

// setup
void setup () {

  // set up the variables, loading in the sound files from your project folder
  // which should be the same place as where you save this sketch
  // details on using minim and audioSample are here: http://code.compartmental.net/tools/minim/manual-audiosample/
  minim = new Minim(this);
  GSharp = minim.loadSample("GSharp.wav", 2048);
  A = minim.loadSample("A.wav", 2048);
  Bb = minim.loadSample("Bb.wav", 2048);
  B = minim.loadSample("B.wav", 2048);
  C = minim.loadSample("C.wav", 2048);
  CSharp = minim.loadSample("CSharp.wav", 2048);
  D = minim.loadSample("D.wav", 2048);
  Eb = minim.loadSample("Eb.wav", 2048);
  E = minim.loadSample("E.wav", 2048);
  F = minim.loadSample("F.wav", 2048);
  FSharp = minim.loadSample("FSharp.wav", 2048);
  G = minim.loadSample("G.wav", 2048);

  // List serial ports, saves us trying to figure out which COM we're using.
  println(Serial.list());
  // Open the active port - providing you've only got one sending serial data (which you should)
  myPort = new Serial(this, Serial.list()[1], 9600);
  // don’t read the serial buffer until we see a new line - this is genius and simple compared with my last efforts
  myPort.bufferUntil('n');
}

void draw() {
  // we need to declare the draw function even though we're not using it!!
}

void serialEvent (Serial myPort) {
  // get the string from the serial buffer - gets all chars until the next line break...
  String bufferString = myPort.readStringUntil('n');

  if (bufferString != null) {
    // get rid of any whitespace - sometimes the serial buffer can have blanks etc.. in the string
    bufferString = trim(bufferString);
    // convert the value to an int - we're only sending numbers over the serial port so parsing it to an int shouldn't ever be an issue.
    float inByte = float(bufferString);
    int pulse = int(bufferString);         // declare a variable to hold our value.
    println(pulse);                        // for debug print the value so we can check it.

    // remember that our pulse is in CM so if its less than 5cm then do this etc... else do this... else do this.. for as many sound samples
    if ( pulse < 5 ) {
      GSharp.trigger();
      delay(25);
    }
    else if ( pulse < 8 ) {
      A.trigger();
      delay(25);
    }
    else if ( pulse < 11 ) {
      Bb.trigger();
      delay(25);
    }
    else if ( pulse < 14 ) {
      B.trigger();
      delay(25);
    }
    else if ( pulse < 17 ) {
      C.trigger();
      delay(25);
    }
    else if ( pulse < 20 ) {
      CSharp.trigger();
      delay(25);
    }
    else if ( pulse < 23 )  {
      D.trigger();
      delay(25);
    }
    else if ( pulse < 26 ) {
      Eb.trigger();
      delay(25);
    }
    else if ( pulse < 29 ) {
      E.trigger();
      delay(25);
    }
    else if ( pulse < 32 ) {
      F.trigger();
      delay(25);
    }
    else if ( pulse < 35 ) {
      FSharp.trigger();
      delay(25);
    }
    else if ( pulse < 38 ) {
      G.trigger();
      delay(25);
    }
    else if ( pulse > 50 ) {
      // if the distance is greater than 50cm then play nothing
    }

  } // end if there's a value in the serial bufferstring

}   // end void serialevent()

[ad#Google Ad in content]

Arduino & Processing – Getting values from SRF05 ultrasound sensor & serial port

arduino processing

I’ve started to delve into Processing and passing values between Processing and Arduino. If you’re wondering what Processing is, basically its an open source programming language for vizualising data that can interface with Arduino either by reading values/ pins or by setting them. Just remember that they are 2 very different things and require 2 different sketches!

This is very cool if you want to display information from Arduino in a graphical way, or if you want to have a physical input device for your computer, for instance a Flash application that takes inputs from switches and potentiometers.

So anyway, it’s really very easy to get this installed and working, just do the following steps here: http://www.arduino.cc/playground/Interfacing/Processing

Now, I’ve had a bit of an issue getting values from my SRF05 from Arduino to Processing. In Arduino it works fine and the serial port shows the values correctly but in Processing I couldn’t get the values. Some people suggest using Firmata but the trouble with this is that it has very few of the functions that I need for example delayMicroseconds() is not available when using Firmata.

Also I saw alot of people trying to get this working using different mode settings for the SRF05 but to be honest I like my code so I want to use that – I use separate echo and trigger pins rather than a singular pin. I reckon this may also help you out should you be having problems getting other values.

Another issue I ran across was converting serial port output to an integer, it just didn’t like this at all so I found a quick solution into fixing this. Although this introduces another error which we have to catch but now I think I have a set of code that works pretty well for what I need.

So first of all take a look at my Arduino SRF05 tutorial.

Arduino SRF05 Sketch

Now you’ve got the circuit and parts use the following sketch on the Arduino board:

const int numReadings = 10;
int readings[numReadings];      // the readings from the analog input
int index = 0;                  // the index of the current reading
int total = 0;                  // the running total
int average = 0;                // the average
int echoPin = 2;             // the SRF05's echo pin
int initPin = 3;             // the SRF05's init pin
unsigned long pulseTime = 0;  // variable for reading the pulse
unsigned long distance = 0;  // variable for storing the distance

void setup() {

  // make the init pin an output:
  pinMode(initPin, OUTPUT);
  // make the echo pin an input:
  pinMode(echoPin, INPUT);
  // initialize the serial port:
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
     readings[thisReading] = 0;
  }
  // set the serial port to begin logging values which Processing will later read.
  Serial.begin(9600);
}

void loop() {
  // send the sensor a 10microsecond pulse:
  digitalWrite(initPin, HIGH);
  delayMicroseconds(50);
  digitalWrite(initPin, LOW);

  // wait for the pulse to return. The pulse
  // goes from low to HIGH to low, so we specify
  // that we want a HIGH-going pulse below:

  // converts the microsecond time to distance in CM
  pulseTime = pulseIn(echoPin, HIGH);
  distance = pulseTime/58;

  // subtract the last reading:
  total= total - readings[index];
  // read from the sensor:
  readings[index] = distance;
  // add the reading to the total:
  total= total + readings[index];
  // advance to the next position in the array:
  index = index + 1;                    

  // if we're at the end of the array...
  if (index >= numReadings)  {
    // ...wrap around to the beginning:
    index = 0;
  }
  // calculate the average:
  average = total / numReadings;  

  // print out an A character to set the start of the value and help us
  // cast this value to a string and integer later on in Processing.
  Serial.print('A');

  // now write out our value from the sensor.
  Serial.print(average);
  // delay must be the same as the delay in the processing code
  delay(100);
}

[ad#Google Ad in content]

It’s not too different from the previous tutorial, just gets rid of the LED and the main thing to note is the serial port output at the bottom. We add an A to mark the beginning of the value in the serial output and we use this later on to help cast ou value as a string and then integer, for some reason trying to pass the serial value as an integer or trying to parse it as such fails.

SRF05 Processing Sketch

Now for the Processing code we just need this bit and that’s it – we’re just looking in the log file here to see the values being read correctly. Basically we do a few checks to make sure we have no null values, that the output we’re reading is of expected length and has the correct identifying symbol at the front, you don’t have to use ‘A’, this can actually be anything you want.

// import the serial libary for Processing
import processing.serial.*; 

// define a new port object
Serial port;

// setup the port, this referes to the port object above
// COM8 is my USB port that I use, your's maybe anythign like COM1, etc..
// 9600 is the baud rating (how much data is transferred over a set time)
// it is important to make sure your Arduino is outputting to the same baud rating!!

void setup(){
     port = new Serial(this, "COM8", 9600);
}

// begin our output for Processing
void draw(){

  // delay 100 milliseconds - this must be the same delay used in the Arduino sketch.
  delay(100);

  // create a string to store the value from reading the serial port
  String serialBuffer = port.readString();

  // check if the value is not null, that the value is greater that 2 and no more than 4 characters
  if (serialBuffer != null && serialBuffer.length() >= 2 && serialBuffer.length() <= 4) {

    // check that the first character in the string is A
    // we add A to our output to cast the serial value to a string type.
    // Its also handy as the A is doubled up as a marker for a new value in the serial log
    if (serialBuffer.indexOf("A") == 0) {
      // if this is true then remove A
      serialBuffer =  serialBuffer.substring(1,serialBuffer.length());
    }
    // double check to make sure there are no more A's in our string - otherwise we can't convert to a number
    if (serialBuffer.indexOf("A") == -1) {
      // convert the string to an integer
      int i = Integer.parseInt(serialBuffer);
      // print our integer
      println(i);
    }
  }

}

[ad#Google Ad in content]

Make sure...

Make sure that your serial port is set to the same baud rating in both the Arduino and Processing sketch.

Make sure that the delay used in both executable methods matches.

Make sure that the correct port is being read.