Using Processing to Send Values to Arduino

Using Processing to Send Values to Arduino

In this write-up, I’ll show how to create a value in Processing and then send this value to the Arduino. In the example I’m setting values of LEDs making them brighter or dimmed but this example can be extended to control other items – which I plan to do later!

Basically I’m going to set a value between 0 and 255 and then send this value to Arduino which will then use the analogWrite() function to alter the brightness of the LED using PWM (Pulse Width Modulation). I’ve already done a bit of work with LEDs and PWM here.

For the communication between Processing and Arduino I’ll be using the serial port – in other work previously I’ve sent information from Arduino to Processing so this is how to do it the other way around. There are a couple of things to note though. Firstly when using Arduino to read a string from the serial port we have to look at it at a byte level, in my example it’s just easier to ignore using strings and send 1 character at a time and then store it in an array. Secondly when debugging your code you can’t read the serial values in Arduinos serial monitor as you’ll already be using the port in Processing so sometimes this can be trial and error although you can at least preview the values your sending in Processing.

Of course you can also extend this code to write values from Arduino back to Processing. There are already plenty of examples online of how to do serial port communication between Arduino and Processing and vice versa and setting an LED to on or off but I’ve done a few extra things to show some basic work with interaction and user interfaces to set the LEDs.

We’re going to set 3 LED’s – Red, Green and Blue and rather than just on or off we’ll be setting the PWM/ levels of brightness. Also the sketches deal with setting an RGB LED (RGBL) with the combined values.

I’ve written 2 visualisations to achive the above.

The first is a set of sliders like a mixing desk – when sliding a slider it will set the value of the LED it’s assigned to and the combined value will set the RGB LED. The second is a triangle shape that you can move around to create the colours, so where ever you drag each point of the triangle it will set the brightness of the LED accordingly.

The Arduino circuit and sketch is very simple and remains the same no matter which visualisation is used. So starting with the circuit…

Shopping List
Arduino Deumilanova w/ ATMEGA328
Breadboard/ Prototyping board
Jumper/ Connector wires
3x LED (Red, Green, Blue)
1x RGB LED
6x 270 Ohm resistors

The Circuit
Very simple: 3 LEDs each with a common ground back to the Arduino board, the positive pins (the longer pin) has a 270 Ohm resistor between it and a connection to a digital pin. The RGB LED has 4 pins – 1 is for the power supply – some RGB LEDs instead may connect to GND so check before doing so. The other 3 pins each connect to a digital pin on the Arduino board.

LEDs

The Sketch
The Arduino code is very simple as well – we set the the digital pins all as outputs, we setup the serial port we wish to use and then we read the values from the serial port and store them in an array, each item in the array corresponds to a value for an LED. There is a small catch however – it seems my RGB LED sees the value 255 as off and 0 as on so I have had to write some code to take this into account.

/* Sets LED values based on values sent on the serial port from Processing application.
   luckylarry.co.uk
 
*/
 
// create an array of LED pins - need to be the PWM digital pins
int ledPin[] = {9,10,11}; 
// an array to store the pins for the RGB LED
int RGBLpins[] = {3,5,6};
// array to store the 3 values from the serial port
int incomingByte[3]; 
 
void setup() {
  // initialize serial communication - make sure its the same as expected in the processing code
  Serial.begin(9600);
  // loop through and set the pins as outputs
  for (int i=0; i<3; i++) {
    pinMode(ledPin[i], OUTPUT);
    pinMode(RGBLpins[i], OUTPUT);
  }
}
 
/*  3 pins are stored in an array, 3 values from the serial buffer
are stored in an array, by looping through both we can light up the LEDs
using the values sent from the Processing sketch. NOTE: the values sent over
the serial port didn't seem to be in order, rather than RGB I got GBR so it
looks like it misses the first byte - so its just trial and error matching
the correct pin to the correct value.
*/
 
void loop() {
  // check to make sure there's 3 bytes of data waiting
  if (Serial.available() >= 3) {
    // read the oldest byte in the serial buffer:
    for (int i=0; i<3; i++) {
      // read each byte
      incomingByte[i] = Serial.read();
      // pass the value to each pin
      // analogWrite is used to write a value between 0 and 255 to the PWM pin.
      // lightup the separate LED's
      analogWrite(ledPin[i], incomingByte[i]);
      // seems that my RGB LED sees the values differently - it sees 255 as nothing and 0 as full colour!
      int val = 255 - int(incomingByte[i]);
      analogWrite(RGBLpins[i], val);
    }
  }
 
}

The Processing Sketches
Whilst both sketches visually look different they use pretty much the same methods. The main thing is that for each point, shape or item we wish to click and drag we rely on detecting where the mouse is, if its been clicked and if we’re dragging the mouse. We can use Processings inbuilt functions mousePressed() and mouseDragged() but we still need to write conditional statements depending on where the mouse is.

To do this we can get the X and Y co-ordinates of the mouse using mouseX and mouseY and to compare these values we need to store the X and Y co-ordinates of any shape as variables – the easiest way is to use the PVector variable type which in its simplest use is an array that stores an X and Y value. Now we can mathematically compare the values and limit the movement of our shapes only moving when the mouse is in the correct area.

In the second sketch, the RGB triangle, I also wanted to test to make sure that the triangles points/vertices we’re dragging remain inside a triangular area, to do this there is no Processing code as such its much easier to extend a class and use Javas polygon class (java.awt.Polygon) which will do all the work for us. In order to set the values we have to work out the distance we are from the original points, for which we can use the dist() method which allows us to draw a radius from a point and check to see how far our second point is from the original – we can also use this to create a circular detection area.

When getting the X, Y values from the mouse position we need to make sure these are converted to integers, for which we first use the round() method to convert our float to 1 decimal place and then use the int() method to cast the value as an integer. We also need integer values as it makes it much easier to send ints over the serial port as the libraries allow for these values.

The rest of the processing code is fairly straight forward we use text(), rect(), ellipse(), line(), fill() and stroke() functions to create our visualisation.

The only other thing to note is that in draw() method we always write the values to the serial port.

Visualisation One: RGB Sliders/ Mixing Desk
We have 3 sliders which each can set a value between 0 and 255, the Processing sketch writes each value separately to the serial port and displays the current mixed colour along with each slider value. You can download the sketch You can download the sketch here and try out the application below here and try out the application below. If you download the code please quickly do a find and replace to change //myPort to myPort – it’s done just so you can see the app running in this webpage.

/*
    Code by Lucky Larry: www.luckylarry.co.uk
 
    RGB visualisation to control LED's by dragging sliders to define colour
    Copyright (C) 2009 Pete Dainty aka 'Lucky Larry'
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
    Also makes use of gradient drawing code found at: http://processing.org/learning/basics/lineargradient.html
 
*/
 
// import the serial library to allow us to send data via the serial ports (USB in this case)
import processing.serial.*;
// create a new instance of the serial classes and assign it to 'myPort'
Serial myPort; 
// create set of variables to store vector infomation (X nd Y co-oordinates)
PVector redSlider,greenSlider,blueSlider,whichSlider,lockSliders;
// create an arry to store the vectors of each slider
PVector sliders[];
// boolean value (true or false) to store if lock sliders button has been clicked
boolean locked;
// values needed for gradient code
int Y_AXIS = 1;
int X_AXIS = 2; 
// setup our font
PFont myFont;
 
void setup() {
  // screen size
  size(300,315);
  // setup my font type and size 
  myFont = createFont("verdana", 10);
  textFont(myFont);
  // specifiy the co-ordinates for each slider, the lock sliders button
  redSlider = new PVector(50,150);
  greenSlider = new PVector(110,150);
  blueSlider = new PVector(170,150);
  lockSliders = new PVector(12,27);
  // setup an array to store the values of each slider
  sliders = new PVector[] {redSlider,greenSlider,blueSlider};
  // smooth shapes
  smooth();
    /* define which port to use mine is COM10 and is 2nd in the array list.
       you can print out to the screen which ports are accessible by using this code line below
       set the baud rate to the same as in your Arduino code so mine is 9600
    */
    // println(Serial.list()); 
    myPort = new Serial(this, Serial.list()[1], 9600);
} // end setup
 
void draw() {
  // set background colour to grey in case the setGradient code fails
  background(50);
  // set outlines of shapes to be black
  stroke(0);
  /* creates a rectangle shape based up on X and Y co-ords,
     width and height, 2 RGB values to the colours to mix and which
     axis to apply the gradient.
  */
  color b1 = color(130, 130, 130);
  color b2 = color(70, 70, 70);
  setGradient(0, 0, width, height, b1, b2, Y_AXIS);
  // set the backgrounds of our slider columns
  color sliderGrad1 = color(120, 120, 120);
  color sliderGrad2 = color(50, 50, 50);
  setGradient(25, 20, 50, 275, sliderGrad1, sliderGrad2, Y_AXIS);
  setGradient(85, 20, 50, 275, sliderGrad1, sliderGrad2, Y_AXIS);
  setGradient(145, 20, 50, 275, sliderGrad1, sliderGrad2, Y_AXIS);
  noFill();
  rectMode(CENTER);
  // draw the outlines of each column and a guide line in the center
  rect(50,160,50,275);
  rect(110,160,50,275);
  rect(170,160,50,275);
  line(50,30,50,285);
  line(110,30,110,285);
  line(170,30,170,285);
  // loop through 25 times to produce 25 measurement lines and measurements
  for (int i=0; i<=25; i++) {
    stroke(30);
    // first column
    line(46,30+(i*10),54,30+(i*10));
    // second column
    line(106,30+(i*10),114,30+(i*10));
    // third column
    line(166,30+(i*10),174,30+(i*10));
    // right hand gauge and measurement numbers
    fill(40);
    stroke(40);
    line(196,30+(i*10),201,30+(i*10));
    text(Integer.toString(i*10),216,35+(i*10),25,25);
  }
  // draw the sliders - one for each item in the sliders array
  for (int i=0; i<sliders.length; i++) {
    fill(50);
    stroke(0);
    rect(sliders[i].x,sliders[i].y,40,10); 
  }
  // display text at top of columns.
  text("RED",50,20,50,25);
  text("GREEN",110,20,50,25);
  text("BLUE",170,20,50,25);
  text("COLOUR",260,20,50,25);
  // rotate the lock sliders text using pushMatrix and opMatrix to isolate the transformation
  // so that it doesn't affect everything else
  pushMatrix();
    translate(-33,155);
    rotate(radians(270));
    text("Lock Sliders",100,50,100,25);
  popMatrix();
  // draw the rectangle button for locking sliders
  fill(255);
  rect(lockSliders.x,lockSliders.y,10,10);
  fill(0);
  // if locked is true then change the button to show its active.
  if(locked) {
    text("X",19,30,20,20);
  }
  // create 3 circles for each colour which will change depending on the slider
  fill(int(redSlider.y),0,0);
  ellipse(70,15,10,10);
  fill(0,int(greenSlider.y),0);
  ellipse(130,15,10,10);
  fill(0,0,int(blueSlider.y));
  ellipse(190,15,10,10);
  // create a colour square to show the current mixed colour
  fill(int(redSlider.y),int(greenSlider.y),int(blueSlider.y));
  rect(260,32,50,20);
  // display text at bottom of each column to show slider value (0-255)
  fill(40);
  text(Integer.toString(int(round(redSlider.y))-31),65,310,50,25);
  text(Integer.toString(int(round(greenSlider.y))-31),125,310,50,25);
  text(Integer.toString(int(round(blueSlider.y))-31),185,310,50,25);
  /* we need to send this fill value to the Arduino to light up the LED's accordingly
     we do this by writing a value to the serial port
     You can write values to the serial port using bytes, integers and chars.
     I'm going to send the 3 values separately and store them in an array on the Arduino
  */
  myPort.write(int(round(redSlider.y))-31);
  myPort.write(int(round(greenSlider.y))-31);
  myPort.write(int(round(blueSlider.y))-31);
}
 
/* when the mouse is pressed check if its within the slider area (40x20)
   If the mouse is in/on a slider then set the Y value of PVector whichSlider to this value
   So we know when dragging the mouse which slider to move.
*/
void mousePressed() {
    // always set to null unless the mouse is inside the  handle area
    whichSlider = null; 
    for (int i=0; i<sliders.length; i++) {  
        if (sliders[i].x-20 < mouseX &&
            sliders[i].x+20 > mouseX &&
            sliders[i].y-10 < mouseY &&
            sliders[i].y+10 > mouseY) { 
              whichSlider = sliders[i]; 
            } 
    }
    // check to see if the mouse is clicked inside the lock sliders button
    if (lockSliders.x-5 < mouseX &&
        lockSliders.x+5 > mouseX &&
        lockSliders.y-5 < mouseY &&
        lockSliders.y+5 > mouseY) { 
          // if so then check the current state and set our boolean to the opposite value
          if(locked) {
          locked = false; 
          } else {
          locked = true;
          }
       } 
}
 
/* If the mouse is pressed and the value of whichSlider is not null - it will be null if the mouse is outside the slider area.
   Then look to see if the mouseY is in range, so we dont want it to exceed a scale of 255
   Then look to see if the sliders are locked, if they are then set all sliders to the mouse Y
*/
void mouseDragged() {
    if (whichSlider != null) 
    { 
        if(mouseY > 30 && mouseY < 287 ) {
          // set the Y value of the slider
          if(!locked) {
            whichSlider.y = mouseY; 
          } else {
            for(int i=0; i<3; i++) {
              sliders[i].y = mouseY;
            }
          }
        }
    }   
}
 
/* following gradient code taken from:
   http://processing.org/learning/basics/lineargradient.html
*/
 
void setGradient(int x, int y, float w, float h, color c1, color c2, int axis ){
  // calculate differences between color components 
  float deltaR = red(c2)-red(c1);
  float deltaG = green(c2)-green(c1);
  float deltaB = blue(c2)-blue(c1);
 
  // choose axis
  if(axis == Y_AXIS){
    /*nested for loops set pixels
     in a basic table structure */
    // column
    for (int i=x; i<=(x+w); i++){
      // row
      for (int j = y; j<=(y+h); j++){
        color c = color(
        (red(c1)+(j-y)*(deltaR/h)),
        (green(c1)+(j-y)*(deltaG/h)),
        (blue(c1)+(j-y)*(deltaB/h)) 
          );
        set(i, j, c);
      }
    }  
  }  
  else if(axis == X_AXIS){
    // column 
    for (int i=y; i<=(y+h); i++){
      // row
      for (int j = x; j<=(x+w); j++){
        color c = color(
        (red(c1)+(j-x)*(deltaR/h)),
        (green(c1)+(j-x)*(deltaG/h)),
        (blue(c1)+(j-x)*(deltaB/h)) 
          );
        set(j, i, c);
      }
    }  
  }
}



Visualisation Two: RGB Triangle
A bit more complex we have triangle this time to control the mixing of colours/ setting of values – it works the same way pretty much as the first one. The only real difference is how the mouse is detected and movement is limited to a triangle. You can download the sketch here and try out the application below. Like the previous sketch the downloadable version has the serial port code commented out so it will work in this webpage. Do a find and replace to change //myPort to myPort and that should sort it out.

param name=”mayscript” value=”true” />

/*
    Code by Lucky Larry: www.luckylarry.co.uk
 
    RGB visualisation to control LED's by dragging shapes to define colour
    Copyright (C) 2009 Pete Dainty aka 'Lucky Larry'
 
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
 
// import the serial library to allow us to send data via the serial ports (USB in this case)
import processing.serial.*;
// create a new instance of the serial classes and assign it to 'myPort'
Serial myPort; 
// create set of variables to store vector infomation (X nd Y co-oordinates)
PVector areaPointA,areaPointB,areaPointC,pointA,pointB,pointC,pointDrag; 
// create an arry to store the vectors of each point of our shape in this case a triangle
PVector[] rgbTriangle; 
/* the next 3 lines uses a custom class at the bottom of this code.
   the class extends java.awt.polygon which means I can use this to create a triangle to test if the
   mouse is in side the shape. */
// new instance of our class
DragArea area;
// these lines specify the X value and Y value for each point of our triangle {xpoint1, xpoint2, xpoint3} etc..
int[]xpoints={152,23,284}; 
int[]ypoints={23,248,248};
// set 3 variables to store the colour values.
int R, G, B;
// setup our font
PFont myFont;
/* setup our background and variables */
void setup () { 
    // screen size
    size(305,271);     
    // setup my font type and size 
    myFont = createFont("verdana", 12);
    textFont(myFont);
    // define our new instance of the custom class. (X points, Y points, Number of points in the shape) more info below by the class
    area = new DragArea(xpoints,ypoints,3);
    // define the area vectors - we use these to see how far our point is from its original source, needed to calculate the value between 0 and 255
    areaPointA = new PVector(152,25); 
    areaPointB = new PVector(25,246); 
    areaPointC = new PVector(280,246); 
    // specifiy the starting co-ordinates for the triangle that we can move
    pointA = new PVector(152,40); 
    pointB = new PVector(40,230); 
    pointC = new PVector(265,230); 
    // set the array with the new points.
    rgbTriangle = new PVector[]{pointA,pointB,pointC}; 
    // center our shapes
    ellipseMode(CENTER);
    rectMode(CENTER); 
    // set smoothing for our shapes edges
    smooth(); 
    /* define which port to use mine is COM10 and is 2nd in the array list.
       you can print out to the screen which ports are accessible by using this code line below
       set the baud rate to the same as in your Arduino code so mine is 9600
    */
    // println(Serial.list()); 
    myPort = new Serial(this, Serial.list()[1], 9600);
} // end setup
 
/* begin our animation/ interaction */
void draw () { 
    // set background to black
    background(50);
    // set the colours and positions of the large colour circles to indentify where red is 100% etc...
    // fill(R, G, B);
    fill(255,0,0);
    // ellipse(X co-ordinate, Y co-ordinate,width, height)
    ellipse(areaPointA.x, areaPointA.y, 15,15);
    fill(0,255,0);
    ellipse(areaPointB.x, areaPointB.y, 15,15);
    fill(0,0,255);
    ellipse(areaPointC.x, areaPointC.y, 15,15); 
    // create our background triangle to show the area in which we can move.
    fill(100);
    beginShape(TRIANGLES); 
      vertex(areaPointA.x,areaPointA.y); 
      vertex(areaPointB.x,areaPointB.y); 
      vertex(areaPointC.x,areaPointC.y); 
    endShape(); 
    /* set the fill of our coloured triangle we work out the values by
       getting the current points co-ordinates and working out the distance
       from the original point. These distances are actually calculated on a 
       circular area so it draws an elliptical area from the origin point from 
       the 2 adjacent sides of the triangle. First set the values to our variables  
       R, G, B and round them so that they'll be integers and parse them using the int() method
    */
    R = int(round(255-dist(areaPointA.x,areaPointA.y,pointA.x,pointA.y)));
    G = int(round(255-dist(areaPointB.x,areaPointB.y,pointB.x,pointB.y)));
    B = int(round(255-dist(areaPointC.x,areaPointC.y,pointC.x,pointC.y)));
    fill(R,G,B);
    /* we need to send this fill value to the Arduino to light up the LED's accordingly
       we do this by writing a value to the serial port.
       You can write values to the serial port using bytes, integers and chars.
       I'm going to send the 3 values separately and store them in an array on the Arduino
    */
    myPort.write(R);
    myPort.write(G);
    myPort.write(B); 
    // create our RGB triangle from the draggable points
    beginShape(TRIANGLES); 
      vertex(pointA.x,pointA.y); 
      vertex(pointB.x,pointB.y); 
      vertex(pointC.x,pointC.y); 
    endShape(); 
    // create the drag handles for each point in the draggable shape.
    for (int i=0; i<rgbTriangle.length; i++) {
      // switch on the for loop iterator to change the fill colour depending on the point
      switch(i) {
        case 0: 
          fill(255,0,0);
        break;
        case 1: 
          fill(0,255,0);
        break;
        case 2: 
          fill(0,0,255);
        break;
      }
      // draw our handle at the point of each triangle
      ellipse(rgbTriangle[i].x,rgbTriangle[i].y,5,5);
    }  
    // create our text to show the value of the colour inside the triangle
    fill(150);
    text("Red: "+Integer.toString(R)+
    "\nGreen: "+Integer.toString(G)+
    "\nBlue: "+Integer.toString(B), 
    120, 50, 200, 75); 
 
} 
 
/* when the mouse is pressed check if its within the drag handle give or take 5 pixels either way
   If the mouse is in/on a handle then set the X and Y value of PVector pointDrag to these values
   So we know when dragging the mouse which point to set.
*/
void mousePressed () { 
    // always set to null unless the mouse is inside the  handle area
    pointDrag = null; 
    for (int i=0; i<rgbTriangle.length; i++) {  
        if (rgbTriangle[i].x-5 < mouseX &&
            rgbTriangle[i].x+5 > mouseX &&
            rgbTriangle[i].y-5 < mouseY &&
            rgbTriangle[i].y+5 > mouseY) { 
              pointDrag = rgbTriangle[i]; 
            } 
    }
} 
 
/* If the mouse is pressed and the value of pointDrag is not null - it will be null if the mouse is outside the handle area.
   We then do another check to see if our mouse pointer is inside our polygon area. In Processing we can use the .contains() method
   that we get from the custom class at the bottom to check if an XY value is inside the polygons area.
*/
void mouseDragged() { 
    if ( pointDrag != null ) 
    { 
      if(area.contains(mouseX,mouseY) ) {
        // set the XY values of the point we're dragging to the values of the mouse
        pointDrag.x = mouseX; 
        pointDrag.y = mouseY; 
      }
    } 
} 
 
/* This doesnt look like much code but what we're doing is extending a class with another class.
   By extending our class with java.awt.Polygon we then inherit that classes methods to use as our own.
   Since Processing is based upon Java there are many classes that we can import to extend Processing.
   The functions of java.awt.Polygon can be found here: http://java.sun.com/j2se/1.4.2/docs/api/java/awt/Polygon.html
   This makes it much easier to do collision detection with shapes - Processing can handle rectangles and circles fine
   but for triangles this saves alot of effort.
*/
class DragArea extends java.awt.Polygon { 
  /* our DragArea 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 DragArea(int[] xpoints,int[] ypoints, int npoints) {
    // super invokes the java.awt.Polygon class
    super(xpoints,ypoints,npoints);
  } 
}

This content is published under the Attribution-Noncommercial-Share Alike 3.0 Unported license.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • Digg
  • del.icio.us
  • StumbleUpon
  • Reddit
  • TwitThis
  • Facebook
  • Google Bookmarks
  • MySpace
  • Technorati
  1. Arduino: Controlling the Robot Arm
  2. 3 LED Crossfade with PWM and Arduino
  3. Arduino + Processing: Getting values from SRF05 ultrasound sensor & serial port
  4. Arduino: Basic Theremin meets Processing!
  5. Arduino + Processing: Make a Radar Screen to Visualise Sensor Data from SRF-05 – Part 2: Visualising the Data
  6. Arduino + Processing: Make a Radar Screen – Part 3: Visualising the Data from Sharp Infrared Range Finder
  7. Arduino + Processing: 3D Sensor Data Visualisation
  8. Arduino + Processing: Make a Radar Screen to Visualise Sensor Data from SRF-05 – Part 1: Setting up the Circuit and Outputting Values
  9. Arduino: A Basic Theremin
  10. Arduino: IR remote/ intervalometer for Nikon D80 DSLR (that means timelapse photography yarrr!)