miércoles, 27 de julio de 2011

Arduino + JoystickShield + Processing = Shuriken



This project is pretty cool. It consists of using one Arduino with a Joystick Shield for sending data to the computer, and then reading that data from Processing to create a (sort of) Shuriken and move it with the joystick. This project is divided in two parts: arduino code and processing code.
Arduino Code
Hardware stuff needed: just one arduino with a joystick shield.
Joystick Shield consists of 4 big buttons and one pushable Joystick (another button), for this project we'll only be using the joystick. The joystick consists of two potentiometers, so we need to read them as normal potentiometers using the analogRead() function. Remember these values differ from 0 to 1023. With the joystick, the values we'll usually get from it when we are not touching it are near 500 (standard position). This means that when we read something really close to 500, we do not want our shuriken to move and it will keep its position on screen.
Communicating via a serial port with Arduino is pretty easy, we'll set BaudRate(9600) for this project. Through this serial port we'll be sending string packages, each package will include the two analog measurements from the joystick (x and y position). Processing sketch will later take care to unpack packages. But we'll only send this packages when we receive serial commands from the processing sketch (we'll be synchronous with the computer), this is a must do, in order to not overload computer's buffer and avoid lag in our sketch. Here the Arduino Sketch:
void setup(){
  Serial.begin(9600);
}

void loop(){
  //send package only when requested
  if(Serial.available() > 0){
    //data will be divided by a coma
    Serial.print(analogRead(0));
    Serial.print(",");
    Serial.println(analogRead(1));
    //little delay
    delay(2);
    //clean arduino buffer
    Serial.flush();
  }
}
Processing Code
Here's the tough part of the project. The shuriken is made by drawing and rotating several triangles, this figur, in order to be displayed around the screen, needs to be translated, we will use translate() function to do so, this function asks for two values, x coordinate and y coordinate, so we'll use the joystick coordinates, this way we'll see our shuriken moving.
In our setup function, we must set size screen (I set it with openGL render, you can also use P3D), after doing so we load a font for text drawing. Now we have to create our serialport object, at BaudRate of 9600bps. Our drawing function has already been explained, during this function we will be continuously asking the arduino for data, and we will be continuously mapping it, this mapping will consist of checking if our joystick coordinates are left,right, up or down of screen's center. This means, that if we move left our joystick it will make the shuriken horizontal counter to increase making it move left, opposite will happen for righ movement, same applies for vertical movement. It will be center aligned when coordinate values are near 500 (joystick standard position). Some extra-features are commented on the code, check them out:
//Arduino+JoystickShield+Processing=Shuriken
//Made by Henry Serrano 28/7/2011
//You can use/modify code in any way you like,
//support OpenSource community

import processing.opengl.*;
import processing.serial.*;

PFont a;
int k=0,j=0,e=50, xPos = 0, yPos = 0, positionx = 0, positiony = 0;
boolean flanders=true;
boolean flanders2=true;
int joystick[] = {0,0};
int joystick2[] = {0,0};
Serial myPort;

void setup(){
  //use if computer can't handle opengl
  //size(800, 500, P3D);
  size(800, 500, OPENGL);
  a = loadFont("ARDARLING-48.vlw");
  textFont(a,32);
  serialportconnect();
  smooth();
  noStroke();
}

void draw(){
  background(0);
  fill(255);
  text("Arduino+JoystickShield+Processing=Shuriken", width/8,25);
  //in case you want to use mouse coordinates:
  //translate(mouseX,mouseY);
  serialread();
  joystickmap();
  translate(positionx, positiony);
  //uncomment next lines for cool rotation
  //rotateX(frameCount*PI/60);
  //rotateY(frameCount*PI/60);
  rotate(frameCount*PI/60);
  text("H",-11,10);
  //here's the magic for the shuriken
  //we create one triangle then we rotate it
  //making lots of triangle and rotating forms a shuriken
  for (int i=0; i<20; i++){
    fill(i+200,j+146,k+89,e);
    triangle(20,20,100,100,40,100);
    rotate(TWO_PI/20);
 }
 //we make shuriken pieces to change color and opacity
 altercolors();
}

void altercolors(){
  if(flanders == true){
   k++;
   j++;
   if(k == 50){
     flanders=false;
   }
  }else{
   k--;
   j--;
   if(k==0){
     flanders = true;
   }
 }
 if(flanders2==true){
   e++;
   if(e==240){
     flanders2=false;
   }
 }else{
   e--;
   if(e==50){
     flanders2=true;
   }
 }
}
void joystickmap(){
  //here we process joystick data
  if(joystick[1]>508){
    joystick2[1]=10;
    positionx+=joystick2[1];
  }
  if(joystick[1]<498){
    joystick2[1]=-10;
    positionx+=joystick2[1];
  }
  if(joystick[0]>508){
    joystick2[0]=10;
    positiony+=joystick2[0];
  }
  if(joystick[0]<498){
    joystick2[0]=-10;
    positiony+=joystick2[0];
  }
  if(joystick[1]>=498 && joystick[1] <=508){
    joystick2[1]=0;
    positionx+=joystick2[1];
  }
  if(joystick[0]>=498 && joystick[0] <=508){
    joystick2[0]=0;
    positiony+=joystick2[0];
  }
  if(positionx>800){
    positionx=800;
  }
  if(positionx<0){
    positionx=0;
  }
  if(positiony>500){
    positiony=500;
  }
  if(positiony<0){
    positiony=0;
  }
}
void serialread(){
  //tell arduino to send data
  myPort.write("ok");
  String inString = myPort.readStringUntil('\n');
 
  if (inString != null) {
    //trim off any whitespace
    inString = trim(inString);
    //split data into joystick array
    joystick = int(split(inString, ','));
    print(joystick[0]);
    print(",");
    println(joystick[1]);
  }
  joystick2[0] = joystick[0];
  joystick2[1] = joystick[1];
}

void serialportconnect(){
  int excep=0;
  //print available serial ports access numbers
  println(Serial.list());
  //Serial.list()[n], n is the number assigned to arduino's port
  //check processing's console for port's number
  myPort = new Serial(this, Serial.list()[2], 9600);
}
Now you only need to upload code to your Arduino, and run the sketch.
I'll add both sketches here for download, for easier reading and testing. I'll also add one image of one cool expansion you could do with the code. I made one mini-game, which consists of killing flanders with the Shuriken and getting points racing against time.