First Semester
Second Semester
Physical Computing final
17 December 2009

Our product for the final in Physical Computing is a pair of wireless, tangible cubes you can use to control audio or visualizations. The official documentation is on cubes.runemadsen.com, and during the next months videos and more content will be uploaded.
This is a video taken from the ITP Winter Show 2009 with a demonstration of the cubes in action.
Dim lights Embed Embed this video on your site
Final Project update 1
21 November 2009
For my final project in the Physical Computing class, I'm working with Nikolas Psaroudakis to create 2 interactive cubes. The user will be able to control a Processing sketch (with audio) by turning each cube, and hopefully also control volume by rotating the cubes.
After setting up the XBee's (see last post) we worked on hooking up the accelerometer to our cube prototype, to be able to measure which side is up. It's working now:
Dim lights Embed Embed this video on your site
The Arduino code for doing this is pretty straight forward:
/* Properties
______________________________________________________________________*/
int xVal = 0;
int yVal = 0;
int zVal = 0;
int difference = 50;
int formerSide = 0;
int curSide = 0;
int counter = 0;
int changeTrigger = 2000;
boolean sideShowed = false;
/* Setup
______________________________________________________________________*/
void setup()
{
Serial.begin(9600);
}
/* Loop
______________________________________________________________________*/
void loop()
{
xVal = analogRead(0);
yVal = analogRead(2);
zVal = analogRead(1);
if(xVal < yVal - difference && xVal < zVal - difference) curSide = 1;
if(zVal > xVal + difference && zVal > yVal + difference) curSide = 2;
if(zVal < xVal - difference && zVal < yVal - difference) curSide = 3;
if(yVal < xVal - difference && yVal < zVal - difference) curSide = 4;
if(yVal > xVal + difference && yVal > zVal + difference) curSide = 6;
if(xVal > yVal + difference && xVal > zVal + difference) curSide = 6;
if(formerSide == curSide)
{
counter++;
//Serial.print("Counter: ");
//Serial.println(counter);
}
else
{
//Serial.println("Resetting counter");
counter = 0;
sideShowed = false;
formerSide = curSide;
}
if(counter > changeTrigger)
{
if(!sideShowed)
{
sideShowed = true;
Serial.println(curSide);
}
}
}
Right now the data is sent to Processing via USB, but next step is to connect the XBees and have them communicate wireless.
And the Processing code:
import processing.serial.*;
Serial myPort;
color[] colors = {
#00fa00,
#ff2700,
#0930ff,
#ff40ff,
#00fcff,
#fffb00
};
int curSide = 0;
PFont font;
void setup()
{
size(1000, 500);
setupSerial();
font = loadFont("Helvetica-70.vlw");
textFont(font);
}
/* Setup serial
_______________________________________________ */
void setupSerial()
{
println(Serial.list());
myPort = new Serial(this, Serial.list()[1], 9600);
myPort.bufferUntil('\n');
}
void draw()
{
background(0);
fill(colors[curSide]);
rect(30, 30, width - 60, height - 60);
fill(0);
text("Side up: " + (curSide + 1), width / 2 - 120, height / 2);
}
/* Serial Event
________________________________________________ */
void serialEvent(Serial myPort)
{
String message = myPort.readStringUntil('\n');
if(message != null)
{
message = trim(message);
curSide = Integer.parseInt(message) - 1;
}
}
Working with multiple XBees
18 November 2009
Introduction
For our final project in Physical Computing, we are building 2 interactive cubes. The idea is to let the user control a processing sketch (with audio) by turning the cubes. Depending on which side faces up, the user is able to switch instruments, turn them on/off and play with other parameters.
The cubes need to be wireless, so we bought 3 XBee Series 1 radios. These can transmit serial data wireless, and are a perfect fit when working with the Arduino. We connected them like this:

XBee 1, Connected to the computer

XBee 2 and XBee 3 are identical and will be put inside the cubes

XBee 2 and XBee 3 next to each other
When all hardware was connected, we suddenly felt completely lost: How do we make them speak to each other? Who's speaking to who? What are AT codes? What AT codes do we need to use?
AT Codes
An XBee radio needs to be configured, so it knows the following 4 things:
- What is my address? (ATMY)
- What is the lowest address I'm sending too? (ATDL)
- What is the highest address I'm sending too? (ATDH)
- To which group do I belong? (ATID)
This of it as a person wanting to send an email: He needs an email address to send from and an email address to send to. You're able to specify a group, so you don't receive data from XBee's that aren't yours. Here at ITP, there's many people with XBees, and by specifying a group, you don't run into trouble when multiple systems are running at once.
So.... what AT codes do we need?
Because we have 3 XBees, we have to time when each device sends serial codes. As an example, if both XBee 2 and Xbee 3 are sending data to Xbee 1 at the same time, the serial codes would be mixed up and would be impossible to read. So we decided to let XBee 1 control this process:
- XBee 1 tells XBee 2 to speak
- Xbee 2 sends values to XBee 1
- Xbee 1 tells Xbee 3 to speak
- Xbee 3 sends values to XBee 1
We used the following AT codes on the 3 XBees:
XBee 1 ATMY: 1 ATDL: FFFF ATDH: 0 ATID: 1992
XBee 2 ATMY: 2 ATDL: FFFF ATDH: 0 ATID: 1992
XBee 3 ATMY: 3 ATDL: FFFF ATDH: 0 ATID: 1992
As you may see, all of the XBees are sending data to all addresses in the group (from FFFF to 0). When XBee 1 starts the communication, the first thing written in the serial message will be the number of the Xbee we want to respond, and if XBee 2 or XBee 3 receives a message not intended for them, they will ignore it.
We used the program Cornflake to program the AT codes to the XBees. If you have several XBees, you can just plug them into the XBee USB adapter and program them one after the other. This is how I programmed XBee 1:
- Plug XBee 1 into the USB adapter
- Open Cornflake and select the usb port
- Press "+++" and hit the "send" button. This will set the XBee to command mode, where it accepts these AT commands. It will exit command mode after 10 seconds, so you may have to do this before all of the following commands.
- The XBee should respond with "ok".
- To set its own address, type "ATMY1,WR", press the "\r" button and press "send". The response should be "ok" "ok". "WR" means, that the address will be written to the flash memory and not disappear when you unplug the power.
- To set its lowest destination address, type "ATDLFFFF,WR", press the "\r" button and press "send". The response should be "ok" "ok".
- There's no need to set the highest destination address, because the default is 0.
- To set its group id, type "ATID1992,WR", press the "\r" button and press "send". The response should be "ok" "ok".
Let's start coding!
Now the hardware is set up, we need to start coding. On the computer we'll handle the XBee 1 serial communication with Processing. XBee 2 and Xbee 3 will be using the Arduinos to send back serial codes to Xbee 1.
This is the processing code:
/* Import
________________________________________________ */
import processing.serial.*;
/* Properties
________________________________________________ */
Serial myPort;
int xbeeNumber = 1;
int curXbee = 2;
char identifier = '*';
int xbeeValue2 = 0;
int xbeeValue3 = 0;
long lastRequest;
int requestReSend = 5000;
/* Setup
________________________________________________ */
void setup()
{
size(1023, 600);
setupSerial();
lastRequest = millis();
sendRequest();
}
/* Setup
_______________________________________________ */
void setupSerial()
{
println(Serial.list());
myPort = new Serial(this, Serial.list()[1], 9600);
myPort.bufferUntil('\n');
}
/* Draw
________________________________________________ */
void draw()
{
drawTest();
checkLastRequest();
}
void drawTest()
{
background(255);
stroke(0);
strokeWeight(10);
point(xbeeValue2, 200);
point(xbeeValue3, 400);
}
/* Serial Event
________________________________________________ */
void serialEvent(Serial myPort)
{
String message = myPort.readStringUntil('\n');
if(message != null)
{
message = trim(message);
checkMessage(message);
}
}
/* Check message
________________________________________________ */
void checkMessage(String message)
{
char c1 = message.charAt(0);
int c2 = Integer.parseInt(message.substring(1, 2));
if(c1 == identifier && c2 == xbeeNumber)
{
println("Value received: " + message.substring(2));
int value = Integer.parseInt(message.substring(2));
//if(curXbee == 2) xbeeValue2 = value;
//else if(curXbee == 3) xbeeValue3 = value;
curXbee = (curXbee == 2) ? 3 : 2;
sendRequest();
}
}
/* Send normal request
________________________________________________ */
void sendRequest()
{
myPort.write(identifier);
myPort.write(curXbee);
lastRequest = millis();
println("Message sent to Arduino number: " + curXbee);
}
void checkLastRequest()
{
if(millis() - lastRequest > requestReSend)
{
println("No response, resending to XBee " + curXbee);
sendRequest();
}
}
The Processing code will basically start everything by sending out a message to XBee 2. If it responds, it will try to talk to XBee 3 - and repeat this process over and over. If one of the XBees don't respond, the message will be resend after 5 seconds.
The Arduino code then need to handle 1 thing: Send back data when it receives a message inteded to it. If the message is not intended to it, it will ignore it.
/* Properties
___________________________________________________ */
int xbeeNumber = 3;
int computerNumber = 1;
char identifier = '*';
int readValue;
/* Setup
___________________________________________________ */
void setup()
{
Serial.begin(9600);
pinMode(2, OUTPUT);
}
/* Loop
___________________________________________________ */
void loop()
{
checkMessage();
delay(10);
}
/* Check message
___________________________________________________ */
void checkMessage()
{
if(Serial.available() > 0)
{
int firstByte = Serial.read();
if(firstByte == identifier)
{
int secondByte = Serial.read();
if(secondByte == xbeeNumber)
{
digitalWrite(2, HIGH);
Serial.print(identifier); // identifier
Serial.print(computerNumber, DEC); // xbeeNumber
Serial.print("This is from Arduino number: ");
Serial.println(xbeeNumber, DEC);
}
}
}
}
When this works, the test message is replaced by actual sensor values. Notice, that XBee 1 doesn't check whether or not XBee 2 and XBee 3 is powered before sending. It just sends out messages and retries if noone responds.
Etch a Sketch Media Controller
04 November 2009
For the Physical Computing midterm, Cindy Wong, Benji Canning Pereira, and myself decided to focus on a whimsical, fun project. Using Arduino and Processing, Etch Yo Sketch is a digital twist on the nostalgic kid's toy, Etch-a-Sketch. Rather then focusing solely on software, we wanted to mimic the tactile feel and imaginative play in an old-school format – so we constructed "Etch Yo Sketch" within an arcade-machine setup. Underneath the arcade machine is a Mac Book Pro reading the serial communication between our sensors and an Arduino which is displayed on screen.
Play Interaction
Twirl the 360-degree Potentiometers to draw lines along the screen canvas. Twist the regular potentiometers to select your choice of color for the lines. Hit the reset button to restart from scratch. Hit the upload button to see your work saved and presented on our Etch Yo Sketch gallery.
Physical Setup + Troubleshooting
We knew right off that we wanted to mimic a physical interface similar to the Etch A Sketch. At first, we thought to make a wood box. However, after testing a cardboard box as an initial prototype, we discovered that the Mac Book Pro was a perfect fit for this design. We nestled insulating foam to provide cushion and prevent shifting. We outlined the box to conform to an arcade machine, sculpted it out, and made room for the computer screen. Felt is used for exterior decoration and controller display.
With five Potentiometers, two buttons, we found wiring the breadboard to be nightmarish. Certain wires wouldn't stay plugged to the breadboard and would come undone easily. Plus, it was visually confusing with wires for Analog In, Ground, Power mixing around.
Solution: To ensure security and organization to the breadboard, we soldered the wires to a row of headers so they would stick. One row was dedicated to inputs (buttons, potentiometers), two other rows were dedicated to Power Source (ground, power). Don't forget to snick off the headers not being used so you don't get confused.
Software Setup + Troubleshooting
The hardware of the Etch Yo Sketch was designed to mimic the actual Etch A Sketch. Therefore, we needed our Processing software to interpret readings from the 360-degree pots we used for the drawing knobs. Regular potentiometers go in value from 0 to 1023 bytes and crank to about 300 degrees. How do we take into account a Potentiometer that can whirl around 360 degrees? Twirled continuously, the 360-degree pots repeated the values 0-1023 bytes over and over.
How could Processing interpret those values? How would it affect our Processing sketch? Left alone, on the Processing Sketch, a plotted line would appear glitchy, repeating and skitting across the screen as certain values were repeating.
Solution: We wanted the lines to move steadily in the same direction without glitches. In Processing, you would save the last value of the 360-degree potentiometer sensor, read the new value from the pot sensor, and subtract the new value from the previous value (Old value - New value = Difference in values). By taking the difference in values, you can use that measurement to move the line in a continuously smooth fashion. What happens if you go from a value of 1023 back to 0? In Processing, an IF statement would be triggered: if the difference in values (from the old pot reading - new pot reading), was greater then 500, that difference would be subtracted from 1023 (1023-difference in value readings).
Another dilemma: When drawing with potentiometers, keep this in mind. Sometimes, the numbers generated will flicker if you check them in Serial Monitor or in Processing. To eliminate the glitchy numbers, in Processing, we only used the differences if the value was greater then 1 or lower than -1
Arduino Setup
/*************** VARIABLES **************/
int leftRightPot = 0;
int upDownPot = 1;
int rPot = 2;
int gPot = 3;
int bPot = 4;
int resetButton = 2;
int uploadButton = 3;
int theValue = 0;
/*************** SETUP **************/
void setup()
{
Serial.begin (9600); // set up the communication between Arduino + PC
pinMode(resetButton, INPUT); // define button for INPUT
pinMode(uploadButton, INPUT); // define button for INPUT
}
/*************** CODE IN ACTION **************/
void loop()
{
theValue = analogRead(leftRightPot); // puts the values within the variable
Serial.print(theValue, DEC); // print the values in DEC format (#s)
Serial.print(","); // adds a comma to separate series of number readings
theValue = analogRead(upDownPot); // puts the values within the variable
Serial.print(theValue, DEC); // print the values in DEC format (#s)
Serial.print(","); // adds a comma to separate series of number readings
theValue = analogRead(rPot); // puts the values within the variable
Serial.print(theValue, DEC); // print the values in DEC format (#s)
Serial.print(","); // adds a comma to separate series of number readings
theValue = analogRead(rPot); // puts the values within the variable
Serial.print(theValue, DEC); // print the values in DEC format (#s)
Serial.print(","); // adds a comma to separate series of number readings
theValue = analogRead(gPot); // puts the values within the variable
Serial.print(theValue, DEC); // print the values in DEC format (#s)
Serial.print(","); // adds a comma to separate series of number readings
theValue = analogRead(bPot); // puts the values within the variable
Serial.print(theValue, DEC); // print the values in DEC format (#s)
Serial.print(","); // adds a comma to separate series of number readings
theValue = digitalRead(resetButton); // DIGITAL button: puts the values within the variable
Serial.print(theValue, DEC); // print the values in DEC format (#s)
Serial.print(","); // adds a comma to separate series of number readings
theValue = digitalRead(uploadButton); // DIGITAL BUTTON: puts the values within the variable
Serial.println(theValue, DEC); // print line: last line of code should end the code so it can restart a new set of values.
}
Recommendations
- TEST ALL YOUR WIRES/SETUP initially before you get fully invested in your idea. That helps you head off bad wiring issues that may crop up later i you don't carefully think of how to organize your breadboard setup.
- Experiment with new sensors before diving into a project – that'll let you know right away whether an idea is executable. We almost went without the 360-degree pots because of the values they generated -- which Rune was able to troubleshoot.
- Test first with a rough prototype before cutting precious supplies. Make a paper pattern or prototype if possible. We found we were able to see ideas quickly and execute them by testing with cardboard rather then using the woodshop supplies.
- Fabric Glue + Duct Tape = No fuss mockups. Felt covered alot of our pComp sins.
Stupid Pet Trick
02 October 2009
Dim lights Embed Embed this video on your site
For this weeks assignment (The "Show what you've learned until now" Stupid Pet Trick), I wanted to use the Tone library in Arduino to create an arpeggiator. An arpeggiator is an instrument that plays tones from a chord in a pattern-like way.
I wanted to be able to control the folowing parameters:
- Chord tone
- Major or a Minor
- Pattern speed
- Number of steps in pattern
I went to the container store to buy a plastic box (1.50$), to Radioshack to buy knobs and push buttons (11$) and I disassembled my cheap iPod dock to use one of the speakers. I started by putting the box upside down on the table, mounting the Arduino and my breadboard in the lid. In the bottom of the box I drilled holes for all the components, and soon all hardware was ready for programming. It was my first time ever mounting so many components, and I learned:
Keep track of your wires. If you have to be able to open and close your box, use electric tape to stick the wires to the bottom and the lid, leaving some extra wire in between so it bends when you open the lid, instead of ripping your wires from your breadboard.

Sometimes it's necessary to solder your wires on headers. This is really helpful if your wires keep jumping out of the breadboard

Also, I did the biggest rookie mistake: when buying switches, I accidently bought 8 switches that are open per default, and 8 switches that are closed as default... and I found out when everything was installed. That explains why the code has the DOWN_VALUES array constant, so I can keep track of whether or not the switches are down.
On the software side, I used the Tone library to generate the tones. I used the milis() command to check whether or not to play the next step in the pattern, and I simply used a counter to see whether or not to change to a new chord at the end of the pattern. The source code can be downloaded here. For a long time I was having trouble checking the time with milis() command, because after 30 seconds the tones would simply stop or go to a low frequency. Tom Igoe showed me, that when using the milis() command, you have to store the return in a long variable instead of an int variable, because the int will run out of memory.
This is how the final product looks:

