A. PROJECT TITLE – YOUR NAME – YOUR INSTRUCTOR’S NAME
Nature Band-Rain-Professor Eric Parren
B. CONCEPTION AND DESIGN:
The concept of my project Nature Band is to create a band whose members are all familiar natural figures around us. With interaction to trees, flowers, birds and so on, players will be able to make a song of nature by their own, and through the process, to discover the beauty of nature sounds and nature itself.
The idea comes into shape based on inspirations drawn from the fantastic interactive project Piano Staircase by the Fun Theory. I’ve been holding the idea that to express the beauty of nature by an interactive installation, but at the time, I couldn’t decide what kind of interaction fits the concept most. Until I saw people jumping up and down on the piano staircase to make their own step music, it suddenly occurred to me that: why not use musical interaction in my installation so that users can feel its meaning while having fun? As I suspect users would love to experience the interaction through gentle movement, I chose to use soft material in the design so that users may feel more comfort and relax. And I also believe adapting some interactions which happen between people and nature in real life might make the experience make more sense, so I include some basic movements that will come to us when we see a nature figure, such as shaking flowers and grasses, throwing stones into a lake.
But as there are too many different kinds of interaction included in my final installation, many people in the user testing session suggested to me to inform users of how they should do more directly. In order to keep the installation looks like a real natural environment to the largest extent, I just simply put the instructions on the poster, but it turns out at last that I should make them even more direct in the design.
C. FABRICATION AND PRODUCTION:
The fabrication of my final project is the most satisfying part to me. To make the installation look like the real nature more, I bought the true flowers and green bristle grass, together with grass power. At first, I wanted to use green color to paint the grasses, but the outcome was disappointing, so I rejected it. I also chose some soft material like feathers to make the tree, in order to make users enjoy the experience more, and all of these decisions turned out with positive feedback as they show the beauty of nature successfully. In order to express the idea that we have different ways to interact with the natural environment around us, I use a variety of sensors to make the experience more fun. The proposal is good, but I failed to choose a larger Arduino board to contain all of these sensors and wires. At last, I used three Arduino boards in total, and each of them needed a different Arduino and Processing window, which makes everything messy in the final presentation. At the same time, I was too stuck in the installation’s function of making music that I use some melodies and beats too heavy for the concept of nature, and this doesn’t fit my original design well.
D. CONCLUSIONS:
The final result meets part of my started goals successfully. The various ways to interact with the band and trigger different kinds of natural sounds, together with its great appearance, I believe it succeeds in making users have fun while exploring the model nature band. But because of the failures in choosing background melodies, the concept of making a completed music of nature wasn’t expressed to users efficiently.
During the whole process of doing the project, I also gain a deeper thought of the relationship between human and nature. At the same time, the skills of electronics and coding, and the idea of interaction and creativity I learnt from classes are developed through the self-making and thinking process. Different from group works I experienced before, finishing a design by my own also allows me for more spaces to reflect on the capacity and limit of myself. I realize there are still many spaces for me to improve, like self-learning skills and coding with more developed structure.
From the failure of choosing beats and melodies, I also realize that in the making process, we might be trapped in some small idea too often and lose track of our core concept for some time. In these cases, user testing and listening to others’ opinions might be crucial.
The project itself is an enjoyment for me, yet it’s also a valuable class for me. I’m much thankful for all I’ve got in this whole course!
E. TECHNICAL DOCUMENTATION:
Pics:
Videos:
Codes for Processing:
Part 1:
// IMA NYU Shanghai // Interaction Lab // For receiving multiple values from Arduino to Processing /* * Based on the readStringUntil() example by Tom Igoe * https://processing.org/reference/libraries/serial/Serial_readStringUntil_.html */ import ddf.minim.*; import ddf.minim.analysis.*; import ddf.minim.effects.*; import ddf.minim.signals.*; import ddf.minim.spi.*; import ddf.minim.ugens.*; AudioPlayer grasses; AudioPlayer flower; AudioPlayer bugu; AudioPlayer drum; Minim minim; import processing.serial.*; String myString = null; Serial myPort; int NUM_OF_VALUES = 7; /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/ int[] sensorValues; /** this array stores values from Arduino **/ int state=0; void setup() { size(500, 500); background(0); setupSerial(); minim = new Minim(this); grasses = minim.loadFile("na.mp3"); flower = minim.loadFile("flower.aiff"); bugu = minim.loadFile("bugu.mp3"); drum = minim.loadFile("drum.mp3"); } void draw() { updateSerial(); printArray(sensorValues); if (sensorValues[0]>=1000||sensorValues[1]>=1000) { grasses.play(); grasses.cue(0); } if (sensorValues[2]>=1000||sensorValues[3]>=1000) { flower.play(); flower.cue(0); delay(500); } if (sensorValues[4]>=50) { drum.play(); drum.cue(0);} if(sensorValues[5]>=300){ bugu.play(); bugu.cue(0);} if(sensorValues[6]==1){ grasses.pause(); flower.pause(); bugu.pause(); drum.pause(); } //use the values like this! //sensorValues[0] // add your code // } void setupSerial() { printArray(Serial.list()); myPort = new Serial(this, Serial.list()[ 2 ], 9600); // WARNING! // You will definitely get an error here. // Change the PORT_INDEX to 0 and try running it again. // And then, check the list of the ports, // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" // and replace PORT_INDEX above with the index number of the port. myPort.clear(); // Throw out the first reading, // in case we started reading in the middle of a string from the sender. myString = myPort.readStringUntil( 10 ); // 10 = '\n' Linefeed in ASCII myString = null; sensorValues = new int[NUM_OF_VALUES]; } void updateSerial() { while (myPort.available() > 0) { myString = myPort.readStringUntil( 10 ); // 10 = '\n' Linefeed in ASCII if (myString != null) { String[] serialInArray = split(trim(myString), ","); if (serialInArray.length == NUM_OF_VALUES) { for (int i=0; i<serialInArray.length; i++) { sensorValues[i] = int(serialInArray[i]); } } } } }
Part 2:
// IMA NYU Shanghai // Interaction Lab // For receiving multiple values from Arduino to Processing /* * Based on the readStringUntil() example by Tom Igoe * https://processing.org/reference/libraries/serial/Serial_readStringUntil_.html */ import ddf.minim.*; import ddf.minim.analysis.*; import ddf.minim.effects.*; import ddf.minim.signals.*; import ddf.minim.spi.*; import ddf.minim.ugens.*; AudioPlayer tree1; AudioPlayer tree2; AudioPlayer pond1; AudioPlayer pond2; AudioPlayer pond3; AudioPlayer bird; AudioPlayer rain; AudioPlayer thunder; AudioInput microphone; AudioRecorder record; Minim minim; import processing.serial.*; String myString = null; Serial myPort; int NUM_OF_VALUES = 7; /** YOU MUST CHANGE THIS ACCORDING TO YOUR PROJECT **/ int[] sensorValues; /** this array stores values from Arduino **/ int[] hands = new int[100]; int stateN=0; int stateO=0; void setup() { size(500, 500); background(0); setupSerial(); minim = new Minim(this); microphone = minim.getLineIn(); tree1 = minim.loadFile("windStreet.mp3"); tree2 = minim.loadFile("tree.mp3"); pond1 = minim.loadFile("guqin.mp3"); pond2 = minim.loadFile("waterflow.mp3"); pond3 = minim.loadFile("pond3.mp3"); bird = minim.loadFile("bird.mp3"); rain = minim.loadFile("rain2.mp3"); thunder = minim.loadFile("thunder.mp3"); record=minim.createRecorder(microphone, "myrecording.wav"); } void draw() { updateSerial(); printArray(sensorValues); if (sensorValues[5]==1) { stateO=stateN; stateN=1-stateO; } if (sensorValues[1]<=6&&sensorValues[1]>=1) { tree1.play(); tree1.cue(0); } //tree1.cue(0); if (sensorValues[2]<=6&&sensorValues[2]>=1) { tree2.play(); tree2.cue(0); } if (sensorValues[0]>=20&&sensorValues[0]<=330) { pond3.play(); pond3.cue(0); } if (sensorValues[0]>=331&&sensorValues[0]<=800) { pond2.play(); pond2.cue(0); } if (sensorValues[0]>=801) { pond1.play(); pond1.cue(0); } if (sensorValues[3]>=12) { delay(500); bird.play(); } if (sensorValues[4]<=7||sensorValues[4]!=0) { rain.play(); rain.cue(0); if (sensorValues[4]<=6) { thunder.play(); thunder.cue(0); delay(500); } } if (stateN==1) { record.beginRecord(); delay(500); } if (stateN==0&&stateO==1) { record.endRecord(); record.save(); delay(500); } if (sensorValues[6]==1) { tree1.pause(); tree2.pause(); pond1.pause(); pond2.pause(); pond3.pause(); bird.pause(); rain.pause(); thunder.pause(); } if (mousePressed==true) { tree1.pause(); tree2.pause(); pond1.pause(); pond2.pause(); pond3.pause(); bird.pause(); rain.pause(); thunder.pause(); } } void setupSerial() { printArray(Serial.list()); myPort = new Serial(this, Serial.list()[5], 9600); // WARNING! // You will definitely get an error here. // Change the PORT_INDEX to 0 and try running it again. // And then, check the list of the ports, // find the port "/dev/cu.usbmodem----" or "/dev/tty.usbmodem----" // and replace PORT_INDEX above with the index number of the port. myPort.clear(); // Throw out the first reading, // in case we started reading in the middle of a string from the sender. myString = myPort.readStringUntil( 10 ); // 10 = '\n' Linefeed in ASCII myString = null; sensorValues = new int[NUM_OF_VALUES]; } void updateSerial() { while (myPort.available() > 0) { myString = myPort.readStringUntil( 10 ); // 10 = '\n' Linefeed in ASCII if (myString != null) { String[] serialInArray = split(trim(myString), ","); if (serialInArray.length == NUM_OF_VALUES) { for (int i=0; i<serialInArray.length; i++) { sensorValues[i] = int(serialInArray[i]); } } } } }
Codes for Arduino
Part 1:
/* AnalogReadSerial Reads an analog input on pin 0, prints the result to the Serial Monitor. Graphical representation is available using Serial Plotter (Tools > Serial Plotter menu). Attach the center pin of a potentiometer to pin A0, and the outside pins to +5V and ground. This example code is in the public domain. http://www.arduino.cc/en/Tutorial/AnalogReadSerial */ // the setup routine runs once when you press reset: void setup() { // initialize serial communication at 9600 bits per second: Serial.begin(9600); } // the loop routine runs over and over again forever: void loop() { // read the input on analog pin 0: int vib1 = analogRead(A1); int vib2 = analogRead(A2); int vib3 = analogRead(A3); int vib4 = analogRead(A4); int pressureVal = analogRead(A5); int pressureVal2 = analogRead(A0); int button = digitalRead(2); // print out the value you read: Serial.print(vib1); Serial.print(","); Serial.print(vib2); Serial.print(","); Serial.print(vib3); Serial.print(","); Serial.print(vib4); Serial.print(","); Serial.print(pressureVal); Serial.print(","); Serial.print(pressureVal2); Serial.print(","); Serial.print(button); Serial.println(); delay(200); // delay in between reads for stability }
Part 2:
const int buttonPin1 = 13; // the number of the pushbutton pin const int buttonPin2 = 2; // variables will change: int button1State = 0; int button2State = 0; void setup() //程序初始化 { Serial.begin(9600);//设置波特率9600 pinMode(buttonPin1, INPUT); pinMode(buttonPin2, INPUT); } void loop()//程序主体循环 { button2State = digitalRead(buttonPin2); int bigPress = analogRead(A1); uint16_t value1 = analogRead (A4); double distance1 = get_IR (value1); uint16_t value2 = analogRead (A5); double distance2 = get_IR (value2); uint16_t value3 = analogRead (A3); double distance3 = get_IR (value3); uint16_t valueB = analogRead (A0); double distanceB = get_IR (valueB); Serial.print(bigPress); Serial.print(","); Serial.print(distance1); Serial.print(","); Serial.print (distance2); Serial.print(","); Serial.print (distanceB); Serial.print(","); Serial.print (distance3); Serial.print(","); Serial.print (button1State); Serial.print(","); Serial.print (button2State); Serial.println(); delay(200); //延时500ms } double get_IR (uint16_t value) { if (value < 16) value = 16; return 2076.0 / (value - 11.0); }