Difference between revisions of "Processing"

From Mech
Jump to navigationJump to search
Line 37: Line 37:
setup() is the first function to run. In it you define the size of the window that Processing opens, how fast it updates, and initialize any variables or other functions. setup() runs only once.
setup() is the first function to run. In it you define the size of the window that Processing opens, how fast it updates, and initialize any variables or other functions. setup() runs only once.


draw() runs after setup(). draw() will be called a certain number of times a second, as defined in frameRate() in setup(). This means that draw() functions as an infinite loop. Typically you use draw() to update your graphics. You can also use draw() to check the status of variables , the mouse position, and other objects.
draw() runs after setup(). draw() will be called a certain number of times a second, as defined in frameRate() in setup(). This means that draw() functions as an infinite loop. Typically you use draw() to update your graphics. You can also use draw() to check the status of variables, the mouse position, and other objects.


<br clear=all>
<br clear=all>

Revision as of 20:49, 24 February 2010

Overview

Processing is an open source programming language and IDE based on Java. It is free, works on PC/Mac/Linux, and is easy to learn. Processing lets the programmer quickly make visual objects and interactive programs. It is also easy to use Processing to communicate with a serial port, so programs can interact with microcontrollers. This wiki page will describe how to get Processing, create a simple program, open a serial port, and use an external library to create a GUI (graphical user interface). At the end you will find a template for a Processing program that is ready to communicate over serial and interface with GUI objects.

Download

Processing can be found here. Download, unzip and install Processing. This will create two important folders. The first is the folder you have unzipped. It contains the actual Processing program. The second folder is something like Documents/Processing, depending on your platform. This folder is where you store your projects and add libraries.

Resources

Download Processing

Processing Basics

Processing Language Reference

Serial Library

Internal and External Libraries

GUI Library

Processing comes with a large number of great example projects. Go to File->Examples to see example code specific to making 3D objects, Basics, Libraries and Topics. The Processing website also contains example code and links to other projects that may contain examples.

A Simple Program

Processing IDE

Processing is designed to allow people who are unfamiliar with programming to quickly get up and running making visually compelling programs.

A Processing file is called a sketch. The IDE is shown at the right. A sketch is saved as a .pde in its own folder with the same name and opens in a tabbed format.


A simple Processing sketch

A simple Processing sketch is shown at the right. The IDE has several icons at the top which allow you to run your code, stop running code, save and open code, and export your project. At the bottom of the IDE is a debugging window that you can write to with the print() and println() functions. Processing is object oriented, which basically means that all functions are data structures, and all of your code will run in functions.

All Processing code has at least two major functions, setup() and draw().

setup() is the first function to run. In it you define the size of the window that Processing opens, how fast it updates, and initialize any variables or other functions. setup() runs only once.

draw() runs after setup(). draw() will be called a certain number of times a second, as defined in frameRate() in setup(). This means that draw() functions as an infinite loop. Typically you use draw() to update your graphics. You can also use draw() to check the status of variables, the mouse position, and other objects.


The sketch above contains the following code:

/*
Nick Marchuk
02/23/2010
The basic form of a Processing sketch
*/

// global variables
int x, y;

// setup() function
// this function is the first part of the code to run
// use it to setup propertie of the program and initialize variables
void setup() {
  size(400,400); // size(x,y) of the window in pixels
  frameRate(30); // call the draw() function at 30 frames per second to update the window
  background(30,30,220); // set the background color of the window in (red, green, blue), see Tools->Color Selector
  x = y = 0;
  println("Program Started!"); // print some text to the debug window
}

// draw() function
// this function acts as your infinite loop, running as often as defined in frameRate in setup()
void draw() {
  x = mouseX;
  y = mouseY;
  println("cursor at: " + x + ", " + y);
}

Note the sections used:

  • An area of comments stating who made the code and when, and the purpose of the code
  • Global variables. Remember that variables declared in a function, like in setup() or draw(), are local and their values will not be remembered between multiple calls of the function, so global variables will be needed, but try not to use too many, their use is not good programming style. They will eat up your memory and can get confusing. It is much better to pass variables between functions instead of using globals if at all possible.
  • void setup(). This function runs first and only once. We use it to:
    • set the size of the window in pixels
    • set the frameRate, how many times draw() will be called per second
    • set the background color of the window, in rgb
    • initialize the global variables x and y
    • write some text to the debug window to let us know the program is running
  • void draw(). In this case when draw() is called we put the value of the mouse position into the variables x and y and print them to the debug window.

Running this sketch will produce a blue window and a stream of text in the debug window. Hit the escape key or the stop button to end the program.

Another Simple Program

Lets edit the simple program and add some objects. Lets declare a function that will take the position of the mouse and change the color and radius of a circle and inversely change the background color of the window. Lets also move the circle back and forth across the screen.

/*
Nick Marchuk
02/23/2010
Another basic sketch, demonstrating how easy it is to program in Processing
*/

// global variables
//int x, y; // lets make the local to draw() instead of global

// setup() function
void setup() {
  size(400,400); // size(x,y) of the window in pixels, stored automatically in the parameters width and height
  frameRate(30); // call the draw() function at 30 frames per second to update the window
  background(128); // set the background color of the window, one number instead of 3 means the color will go from black->white as 0->255
  println("Program Started!"); // print some text to the debug window
}

// draw() function
void draw() {
  // get the mouse position
  int x = mouseX;
  int y = mouseY;
  println("cursor at: " + x + ", " + y);
  
  // call some functions to get the circle size, color and position
  int circle_rad = get_circle_rad(x,y);
  int circle_color = get_circle_color(x,y);
  int background_color = 255 - circle_color; // invert the color for the background
  background(background_color); // apply the color to the background
  int circle_x = get_circle_pos();
  
  // draw the circle
  fill(circle_color); // objects have no color, instead they are drawn with the color currently in fill, so all objects after this fill() will be drawn with this color
  ellipse(circle_x,height/2,circle_rad,circle_rad);
}

// send this function the position of the mouse and return what the radius should be
int get_circle_rad(int x, int y) {
  int rad = int(0.25*((2*x-y/2)^2)); // some arbitrary fn, must output an int but ^ works on floats
  return rad;
}

// send this function the position of the mouse and return the color the circle should be
int get_circle_color(int x, int y) {
  int c_color = int(map(x+y,0,width+height,0,255)); // some arbitrary fn, new number as float = map(current number,min current number, max current number, min new number, max new number)
  return c_color;
}

// return the x position of the circle
int get_circle_pos() {
  float m = millis(); // how many milliseconds have passed since the program started
  int c_x = int(width*abs(sin(2*PI*1/4000*m))); // make the cirle move back and forth
  return c_x;
}

The result looks like:

Another simple program in Processing


Serial Port Communication with Processing

To get Processing to interact with a microcontroller, we will open a serial port and read and write to it. What you read and write will depend on what you plan to do. This section will describe how to see the available comm ports, initialize one, write to it and read what comes in.

To use serial communication you need to include the serial library in your sketch. This library comes with Processing, all you need to do is add it to your sketch by selecting Sketch->Import Library...->Serial I/O. This will add the line

import processing.serial.*;

to the top of your code. You could manually type this in as well.

The serial library contains the data type Serial, which allows you to set the baud, flow control, and writing. A serial Event is created when Processing receives data, allowing you to read.

The following code will initialize a serial comm port, write and read.

// open a serial port
// expects a stream of input strings, in the form of "# #\n"
// so send it a number followed by a space followed by a number and a newline from your microcontroller

// include the serial library
import processing.serial.*;

// make some Serial objects 
int numPorts = 0; // how many serial ports you want to use in this sketch - 1 (minus one because it is the index of the array)
int numPortInList = 0; // the port you want to use, not the comm number but which one in the list made in the initSerial() function
int numPortUsing = 0; // which port you refer to, if you opened more than one
Serial myPorts[] = new Serial[numPorts]; // an array of serial objects

// initializations
void setup() {
  size(300,300);
  frameRate(30);
  println("Program started");
  initSerial(); // call a user written function to initialize the serial port, if there are none then exit the program
}

// infinite loop
void draw() {
  // your program here 
  
  // if the mouse is pressed, write the x and y position of the mouse out of the port
  // if you loop the serial tx to its rx as a test, this code will read the x y position and print it to the debug window
  if (mousePressed == true) {
    myPorts[numPortUsing].write(mouseX + " " + mouseY + "/n");
  }
}

// initialize the serial port
void initSerial() {
  println(Serial.list()); // List all the available serial ports in the debug window

  // see how many ports there are, if there aren't any then exit
  if (Serial.list().length > 0) {

    String portList = Serial.list()[numPortInList]; // grab the name of the port you want to use
    myPorts[numPortUsing] = new Serial(this, portList, 19200); // initialize the serial port with a baud rate of 19200

    // read bytes into a buffer until you get a linefeed (ASCII 10):
    myPorts[numPortUsing].bufferUntil('\n');
  }
  else { // uh oh, no ports, exit the program
    println("No serial ports found!");
    exit();
  }
}

// serial event. This event is triggered when bytes appear in the serial port buffer
// check which port generated the event, just in case there are more than 1 ports talking
// this code expects to see a string with a number, a space, a number and a newline
// it extracts the two number from the string and prints them to the debug window
void serialEvent(Serial thisPort) { 
  // variable to hold the number of the port
  int portNumber = -1;

  // iterate over the list of ports opened, and match the one that generated this event
  for (int p = 0; p < myPorts.length; p++) {
    if (thisPort == myPorts[p]) {
      portNumber = p;
    }
  }

  // read the serial buffer as a string until a newline appears
  String myString = thisPort.readStringUntil('\n');

  // if you got any bytes other than the newline
  if (myString != null) {

    myString = trim(myString); // ditch the newline

    // split the string at the spaces, save as integers, can't do floats
    int dataFromSerial[] = int(split(myString, ' '));

    // check to make sure its the right port and there are the correct number of integers in the packet
    if ((dataFromSerial.length == 2)&&(portNumber==numPortUsing)) {
      // print what it got in the debug window
      print(dataFromSerial[0]);
      print(" ");
      println(dataFromSerial[1]);
    }
  }
} // end serialEvent

A Graphical User Interface (GUI) with Processing

A GUI contains elements like check boxes, radio buttons, regular buttons, labels and text entry. While it is possible to write your own custom objects to perform the function objects found in a GUI (see the Examples->Topics->GUI->Button example), it would be even better to use a library that contains all of these elements. Processing does not come with a library of GUI objects, but there are several external libraries created by labs and individuals around the world with GUI objects. Check the external libraries available here (scroll down).

We will use the Graphic Interface library controlP5. Download the associated .zip file and unzip in a folder called libraries in the folder that contains your project folder. (Your file structure should look like:

  • My Documents
    • Processing
      • MyProject
        • MyProject.pde
      • libraries
        • controlP5

All external libraries should be put in this libraries folder)


A Template for a GUI using Serial Communication in Processing

This section will describe a template for Processing projects that use a GUI interface and serial communication. It is often a challenge to move code between pcs when the serial port is hard coded for one pc because the name and number of comm ports differs on every pc, particularly when the pc has bluetooth. This template attempts to solve this problem by listing all of the available comm ports and allowing the user to select the port they wish to use when the program loads. It contains all of the framework necessary to setup the serial communication and use common GUI objects.