Archive

Processing

The Picoboard and Processing

The sparkfun Picoboard is a great little device that lets you add some physical input to Scratch. It allows you to measure 4 resistance values, has a button, detect sound and light, and also has a slider. All of these send 10-bit analogue data back to the computer via a USB port. In Scratch the inputs are available on the “Sensing” tab, see below.

ScratchInput

But, I wondered, could you use the board with Processing? It turns out you can if you know how to talk to the board. Fortunately, the wonderful people at Scratch have published this information here.

To get information from the Picoboard you have to set up a serial port and send a request for data. This is done by sending a value 1 (not the digit). The board responds by sending 18 bytes as a series of high/low pairs from which the sensor data can be reconstructed. If you’re interested in the details, please see the tech info on the above Scratch link.

The Processing code I produced to communicate with the board is given below. When experimenting, I found that operation is more reliable if you ensure you read complete 18-byte packets of data at a time, otherwise some confusion arose if values were changing quickly and/or data was being requested at too high a rate.

import processing.serial.*;

Serial port;  // Create object from Serial class

int b1,b2;                            // byte pairs from the data packet
int  i;                               // general loop counter
int[]  ChanValues={0,0,0,0,0,0,0,0};  // the 8 channel values 
int[] ValBuffer=new int[18];          // the 18 byte data packet from the Picoboard
int  Channel;                         // used to identify the channel the data corresponds to
int  Val;                             // the value of the channel

void setup() {
  size(1035, 245);

  // SERIAL SET UP EXTRACT FROM:
  // Example 11-07 from "Getting Started with Processing" 
  // by Reas & Fry. O'Reilly / Make 2010
  //
  // see Ex_11_07 in Chapter 11 of Books->Getting Started in the Examples menu (File->Examples)
  //
  // IMPORTANT NOTE:
  // The first serial port retrieved by Serial.list()
  // should be your Arduino. If not, uncomment the next
  // line by deleting the // before it. Run the sketch
  // again to see a list of serial ports. Then, change
  // the 0 in between [ and ] to the number of the port
  // that your Arduino is connected to.
  //  println(Serial.list());

  String arduinoPort = Serial.list()[0];
  port = new Serial(this, arduinoPort, 38400);  // Picoboard works at 38.4k

  // set up a frame rate
  frameRate(50);  

  // send a request to the board to supply values
  port.write(1);

}

void draw()
{

  // reading from the picoboard requires a bit of care to get a full packet

  // read when at least 18 bytes of data are available
  if(port.available()>=18)
  {
    // take the first 18 bytes
    // these are 2-byte hi/lo pairs for 8 input channels + firmware version (channel 15)
    for (i=0;i<18;i++)
    {
      ValBuffer[i]=port.read();
    }

    // find the 10-bit values for channels 0-7
    // channel    Sensor
    //    0        D
    //    1        C
    //    2        B
    //    3        Button
    //    4        A
    //    5        Light
    //    6        Sound
    //    7        Slider

    for (i=0;i<18;i+=2)
    {
      b1=ValBuffer[i];
      b2=ValBuffer[i+1];
      Channel=(b1&120)>>3;
      Val=((b1&7)<<7)+(b2&127);    //channel value is bits 0-2 of hi byte and bits 0-6 of lo byte

      if (Channel<8)  ChanValues[Channel]=Val; // only store value if channel is in range  0-7
    }

    // sometimes there's extra data if things change fast and the FPS value is high
    // better performance is obtained if you ignore these partials and get a full set,
    // so read anything left in the buffer to flush it.
    while(port.available()>0)
    {
      b1=port.read();
    }
    // buffer now empty - ask for more data
    port.write(1);
  }

 // show values in monitor
  println(ChanValues[0]+", "+ChanValues[1]+", "+ChanValues[2]+", "+ChanValues[3]+", "+ChanValues[4]+", "+ChanValues[5]+", "+ChanValues[6]+", "+ChanValues[7]);

// plot bars to represent values 
  background(0);
  fill(255,0,0);     rect(5,5,ChanValues[0],25);        //  D
  fill(235,30,0);    rect(5,35,ChanValues[1],25);       //  C
  fill(215,60,0);    rect(5,65,ChanValues[2],25);       //  B
  fill(195,90,0);    rect(5,95,ChanValues[3],25);       //  Button
  fill(175,120,0);    rect(5,125,ChanValues[4],25);      //  A
  fill(1555,150,0);  rect(5,155,ChanValues[5],25);      //  Light
  fill(135,180,0);   rect(5,185,ChanValues[6],25);      //  Sound
  fill(115,210,0);   rect(5,215,ChanValues[7],25);      // Slider

}
If you highlight and copy/paste to a text editor you should be able to see all the comments. The code produces 8 bars that represent the output levels for the 8 sensors (described as channels in the tech document).
 ProcessingOut1
Enjoy!