What is it?
A prototype for an interactive sculpture – puzzle. Intended for a group of 3 people to solve. This puzzle is fairly simple. If each person stands on one of the colored platform areas, they will complete the opening chord of Richard Strauss’ “Thus Spake Zarathustra.” Pulling on the rope triggers the fully orchestrated cliffhanger ending of the opening salvo to play from the computer.
How does it work?
The “sculpture” consists of 3 platforms, each one slightly taller than the next.
Each platform is rigged with a pressure sensor providing analog input to the Arduino. (I had to “fake” the 3rd platform. Apparently, if you have resistors in parallel, the total resistance goes up just like it’s supposed to. This made it very difficult to find a robust threshold for the 3rd sensor because by the time the first 2 sensors had been activated, the 3rd one was already way up, close to the max of 1023.
Each pressure sensor triggers a speaker. In order to get the Arduino to play multiple tones at the same time, I used this nice person’s code.
Finally, there is a button that sends data via the serial port to Processing, which in turn sets off an AppleScript to play the rest of the music from iTunes. (I originally tried using a flex sensor so I could model how pulling the rope might work, but I had trouble getting a reliable reading out of the flex sensor.
Just to see how much stuff I could load onto the Arduino, I also added a fan to the whole setup, which is controlled by a PWM output pin. It’s intended to spin faster and faster as the chord builds, but I think it will take a bunch more work to figure out how to do that in a way that can be perceived by the human eye.
Arduino Code
/* Code adapted from Jeremy Blum */ /* Timer reload value, globally available */ unsigned int tcnt2; /* Toggle HIGH or LOW digital write */ int toggle1 = 0; int toggle2 = 0; int toggle3 = 0; /* Keep track of when each note needs to be buttoned */ int count1 = 0; int count2 = 0; int count3 = 0; /* Frequency Output Pins */ #define c 4 #define g 5 #define C 6 //#define E 5 //#define Eflat 5 //const int ledPin = 6; const int fanPin = 9; // fan connected to digital pin 9 /* Analog input: Pressure Sensors */ const int pressurePin1 = 0; const int pressurePin2 = 1; const int pressurePin3 = 2; /* Digital Input: iTunes button*/ const int buttonPin = 8; /* Values of Pressure Sensors*/ int pressureValue1 = 0; int pressureValue2 = 0; int pressureValue3 = 0; /* Permanent value for sensor 3 (Hack) */ int permValue3 = 0; int totalPressure = 0; int fanPressure = 0; int buttonState = 0; //Setup Function will run once at initialization void setup() { /* First disable the timer overflow interrupt*/ TIMSK2 &= ~(1<8us. * (desired period) / 8us = 8. * MAX(uint8) - 8 = 248; */ /* Save value globally for later reload in ISR */ tcnt2 = 250; /* Finally load end enable the timer */ TCNT2 = tcnt2; TIMSK2 |= (1< 800, play first note if (pressureValue1 > 800 && count1 == 40) { digitalWrite(c, toggle1 == 0 ? HIGH : LOW); toggle1 = ~toggle1; count1 = 0; } //Count 2: Every 27 counts, if pressure of 2nd sensor is > 1010, play second note if (pressureValue2 > 1010 && count2 == 27) { digitalWrite(g, toggle2 == 0 ? HIGH : LOW); toggle2 = ~toggle2; count2 = 0; } //Count 3: Every 20 counts, if permanent value of 3rd sensor is 1, play 3rd note if (permValue3 == 1 && count3 == 20) { digitalWrite(C, toggle3 == 0 ? HIGH : LOW); toggle3 = ~toggle3; count3 = 0; } } void loop() { // Read pressure sensors and store values pressureValue1 = analogRead(pressurePin1); pressureValue2 = analogRead(pressurePin2); pressureValue3 = analogRead(pressurePin3); // Hack: If pressure sensor 3 reaches 1023, store a permanent value of 1 if (pressureValue3 == 1023) { permValue3 = 1; } // Check to see if button is pressed, if so, write 1 to serial port to activate AppleScript via Processing buttonState = digitalRead(buttonPin); if(buttonState == HIGH) { //digitalWrite(ledPin, HIGH); Serial.print(1, BYTE); } else if(buttonState == LOW) { Serial.print(0, BYTE); } delay(100); // Wait 100 milliseconds // Add up values of all the pressure sensors totalPressure = pressureValue1 + pressureValue2 + pressureValue3; // Map total pressure sensor to fan pressure fanPressure = map(totalPressure, 1600, 3500, 0, 1023); // Set minimum threshold for turning on fan if (fanPressure > 66) { analogWrite(fanPin, fanPressure); } else if (fanPressure < 66) { digitalWrite(fanPin, LOW); } // Print input values for debugging Serial.print ("1: "); Serial.print(pressureValue1); Serial.print(" "); Serial.print ("2: "); Serial.print(pressureValue2); Serial.print(" "); Serial.print ("3: "); Serial.print(pressureValue3); Serial.print(" "); Serial.print ("4: "); Serial.print(buttonState); Serial.print(" "); Serial.print ("Total: "); Serial.print(totalPressure); Serial.print(" "); Serial.print ("Fan: "); Serial.println(fanPressure); }
Processing Code
//Import Serial Libary
import processing.serial.*;
//Import com Library
import com.apple.cocoa.foundation.*;
Serial zPort; // Create object from Serial class
int buttonState; // Data received from the serial port
void setup()
{
size(200, 200);
background(0);
//Create serial port object - choose 1st serial port from list
String portName = Serial.list()[0];
//Create instance of port named zPort
zPort = new Serial(this, portName, 9600);
}
void serialEvent (Serial zPort) {
if (zPort.available() > 0) { // If data is available,
buttonState = zPort.read(); // read it and store it in val
}
if (buttonState == 1) { // If the serial command is "1,"
String script = "tell application \"iTunes\" to play" + "\n"; // Run applescript
background(0, 255, 0); // Change background color to green
println(script);
executeScript(script);
}
else {
fill(255, 0, 0); // Otherwise, fill with red.
}
}
// Function to execute script
void executeScript(String script) {
NSAppleScript myScript = new NSAppleScript(script);
NSMutableDictionary errors = new NSMutableDictionary();
myScript.execute(errors);
}
void draw() {
println(buttonState); // Print buttonState value below for debugging
}




Cool Project! A few words of advice for you:
1. You can resolve your analog sensor resolution problem by looking at each force sensor independently, instead of stringing them to together like you have done. Like this: http://itp.nyu.edu/physcomp/sensors/uploads/Schematics/VoltageDividerSchematic.jpg
2. You’ll get better performance from the speaker if you drive it off the 9V rail using a transistor instead of driving it using the Arduino. You should generally not drive speakers from a microcontroller directly.
Looks awesome otherwise!
Thanks for the advice Jeremy!
I managed to get better performance off the speakers by reducing the number of resistors I was using to 1, but will try driving them off the 9V in the future.