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.
Arduino Sharp IR Sensor Servo 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); } }
Processing Radar Style Data Visualisation 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 } } }
Part 1: Setting up the Circuit and Outputting Values
Part 2: Visualising the Data
This content is published under the Attribution-Noncommercial-Share Alike 3.0 Unported license.
- Arduino + Processing – Make a Radar Screen to Visualise Sensor Data from SRF-05 – Part 2: Visualising the Data
- Arduino + Processing – 3D Sensor Data Visualisation
- Arduino + Processing – Make a Radar Screen to Visualise Sensor Data from SRF-05 – Part 1: Setting up the Circuit and Outputting Values
- Arduino – Using a Sharp IR Sensor for Distance Calculation
- Arduino – Controlling the Robot Arm
- Arduino – Basic Theremin meets Processing!
- Arduino & Processing – Getting values from SRF05 ultrasound sensor & serial port
- Arduino – (Very) Basic motion tracking with 2 PIR sensors
- Using Processing to Send Values using the Serial Port to Arduino
- Controlling a Servo with Arduino










Hey larry,
really nice post! I gave it a go with IR and it works brilliantly! Im trying this again but with a stepper motor for 360° rotation but I’m having problems with sending the steps over to serial.print. Do you have any idea how I could solve this?
Cheers
Well you got another option: hack a servo for continous rotation – never done it myself but might be useful.
Anyway, not done too much with stepper motors, so apologies if I’m wrong.
Have a look at: http://arduino.cc/en/Reference/Stepper?from=Tutorial.Stepper
So first create a stepper motor object – are you using a bipolar stepper? If so I can help you out with the H-bridge/ motor controller chip
If you’ve got all that done and can control the stepper then we just need to calculate the steps per revolution the motor will have – might already be in your tech specs.
If you’ve got that then you should be able to use the Arduino stepper motor libraries and then send number of steps over the serial port?
Hi,
Came across your stuff online and loved it.
I am an artist only beginning to use arduino
You can see examples of my work here-
http://rhyshimsworth.com/work%207.htm
As you can see, I have been making some basic drawing and painting
machines and so far I have been using some very basic software that turns
a PC into a CNC machine, communicating to a driver box and powering
stepper motors.
I am now keen to make the pieces more interactive and am trying to make a
painting machine that will paint according to the movements of the viewer,
using a web cam to monitor the viewer and an arduino micro controller to
move the stepper motors in real time.
I have spoken to a friend of mine who has some experience of arduino who
was able to find some processing code that would turn movements on a web
cam into a drawing on the computer screen-
http://pastie.org/795453
It needs a plugin to be added to processing, from the JMyron site
http://webcamxtra.sourceforge.net/download.shtml
We were thinking that we should be able to tweak this to drive some
stepper motors, at least i hope my friend will be able to. Trouble is he
has little experience of stepper motors. The motors I have are like the
ones here-
http://www.xylotex.com/StepperMotor.htm
I have got the motors kind of working through the arduino, all though they move very slow. I am desperately trying to find some way of translating the processing code for JMyron into x and y coordinates to move the the stepper motors. I have an art exhibition opening next week and have 3 pieces that all rely on this working. I have bitten off more than I can chew so any help you can offer would be amazing!
Any advice you have would be greatly appreciated.
Thanks for your time.
Rhys
Hey Rhys,
Tall order! Umm… well I this wold be my logic:
Get image from jMyron
Map/scale the camera image to your Processing screen/document area
Translate the position of the jMyron item to a set of shapes/quads/lines and then produce co-ordinates from these – not sure how many points of reference you want but for example a hand you could split to several items.
Then you pass the x, y and z of each object made from the jMyron to Arduino via the serial port.
That probably makes it sound easier than it is. How precise do the movements need to be? and what do you want to detect – I guess you want to map the movement of a hand to alter the positions of the acid sprayer?
What I would do instead is have a look at this:
http://www.maximumpc.com/article/features/maximum_pc_builds_a_multitouch_surface_computer
And build a kind of touch screen that will detect a users hand/ fingerprints from infrared (can convert the webcam easy enough)
Not quite as fluid as monitoring a users hand but probably easier to achieve (Or not).
Sorry not much use here – not done anything like this yet.