Well, this has been quite a journey. Obviously, working together with Nisala was quite a lot of desperate laughing, excited high fives and cries for help that both Jack and Aaron patiently listened to- so big big thank you!
The IM show itself was a lot of fun. We managed to fix most of the bugs/imperfections that we caught during the user testing – we fixed the descriptions, colors, adjusted the mapped values and got an iMac to manage the load of data. Eventually, we decided for two colors on the screen only (red for the shapes that are being adjusted and submitted, and white for the already submitted ones). This helped to increase clarity for the user.
We adjusted the mapped values for volume right at the start of the show, so it would take into account the amount of noise in the room – which was quite significant. The only issue was the light – because we changed our location last minute into the corner behind a curtain (where people could scream privately and shamelessly). Therefore, we wanted a light leading people into the corner, but we did not consider that it would interfere with the readability of the descriptions. Me and Nisala’s ambition to be sustainable and laser-cut cardboard waste for the descriptions was a good step for the environment, however, in a dark corner, with the wrong angle of light, it did not facilitate the best conditions for the desired interaction. So, if installing this next time, this would be the first thing to carefully consider. Together with the height of the stand, since we unintentionally discriminated short people.
People, however, had a lot of fun screaming into the microphone. When they left the space, they were smiling a lot – and giving them the private corner to do so was definitely a good choice as they could loosen up a little more. This was quite a success as our intention was not only to collect data on how people feel at this stressful time of the year but also to relief a little of the stress.
Though to some people, a further explanation had to be given about the meaning of what they have seen on the screen, most people understood the concept. The interaction for most people was smooth – just getting them to actually read the instructions first instead of pressing random buttons was a bit of a challenge (but this is where better light could help us if displayed next time).
Here is the video of the final data that we collected from the show.
Here is our final setup:
Close up of the interface:
Sadly, people did not feel THAT much better to support our efforts financially (of course this was a joke – or wasn’t it?). They reacted to this humorous touch really well.
The Arduino code:
const int ledWHITE = 12; const int ledRED = 13; int buttonConfirmArdi = 8; int buttonHoldArdi = 9; int buttonConfirmState = 0; int buttonHoldState = 0; void setup() { // put your setup code here, to run once: Serial.begin(9600); Serial.println("0,0,0,0,0,0,0,0"); pinMode(2, INPUT); pinMode(3, INPUT); pinMode(4, INPUT); pinMode(5, INPUT); pinMode(6, INPUT); pinMode(8, INPUT); pinMode(9, INPUT); pinMode(12, OUTPUT); pinMode(13, OUTPUT); } void loop() { if (Serial.available() > 0) { char inByte = Serial.read(); delay(0); int sadButton = digitalRead(2); int fearButton = digitalRead(3); int joyButton = digitalRead(4); int angerButton = digitalRead(5); int disgustButton = digitalRead(6); int potentiometer = analogRead(A0); int buttonConfirm = digitalRead(8); int buttonHold = digitalRead(9); delay(0); Serial.print(sadButton); Serial.print(','); Serial.print(fearButton); Serial.print(','); Serial.print(joyButton); Serial.print(','); Serial.print(angerButton); Serial.print(','); Serial.print(disgustButton); Serial.print(','); Serial.print(potentiometer); Serial.print(','); Serial.print(buttonHold); Serial.print(','); Serial.println(buttonConfirm); } buttonConfirmState = digitalRead(buttonConfirmArdi); buttonHoldState = digitalRead(buttonHoldArdi); if (buttonConfirmState == HIGH) { // turn LED on: digitalWrite(ledRED, HIGH); } else { // turn LED off: digitalWrite(ledRED, LOW); } if (buttonHoldState == HIGH) { // turn LED on: digitalWrite(ledWHITE, HIGH); } else { // turn LED off: digitalWrite(ledWHITE, LOW); } }
Processing Code:
//calling the class. ArrayList<DrawCircle> circles; ArrayList<DrawSquare> squares; ArrayList<DrawTriangle> triangles; ArrayList<DrawLine> lines; ArrayList<DrawHexagon> hexagons; //establishing the communication with arduino import processing.serial.*; Serial myPort; //Emotion Buttons int sadButton=0; int prevSadButtonState=0; int fearButton =0; int prevFearButtonState =0; int joyButton =0; int prevJoyButtonState =0; int angerButton =0; int prevAngerButtonState =0; int disgustButton =0; int prevDisgustButtonState =0; int potentiometer; //For Button int buttonState=0; int prevButtonState = 0; //for Held Button int buttonStateHold = 0; boolean confirmColor= false; //Audio stuff, from mic. import processing.sound.*; Sound s; AudioIn audioInput; Amplitude analyzer; float volume; boolean readyToDraw; void setup() { //size(640, 480); fullScreen(); noFill(); blendMode(ADD); //stuff for Arduino. printArray(Serial.list()); String portname=Serial.list()[11]; println(portname); myPort = new Serial(this, portname, 9600); myPort.clear(); myPort.bufferUntil('\n'); //AUDIO INITIALIZATION // Create an Audio input and grab the 1st channel audioInput = new AudioIn(this, 0); println("here is the input " + audioInput); // start the Audio Input audioInput.start(); // create a new Amplitude analyzer analyzer = new Amplitude(this); // Patch the input to an volume analyzer analyzer.input(audioInput); //initialize the arrayList circles = new ArrayList <DrawCircle>(); squares = new ArrayList <DrawSquare>(); hexagons = new ArrayList <DrawHexagon>(); lines = new ArrayList <DrawLine>(); triangles = new ArrayList <DrawTriangle>(); } void draw() { //if (confirmColor == false) { // if (buttonState==1) { // confirmColor=true; // fill(255); // } else { // fill(0, 255, 0); // } // } background(0); // fill(20,30); //rect(0,0, width,height); //pushStyle(); //fill(100,50); //rect(0,0, height, width); //popStyle(); // Get the overall volume (between 0 and 1.0) volume = analyzer.analyze(); //update and display the circles, squares, etc. updateDisplayForLoop(); //Only draw the shape that corresponds with the button. clickEmotionButton(); } void serialEvent(Serial myPort) { String s =myPort.readStringUntil('\n'); s=trim(s); if (s!=null) { int values[]=int(split(s, ',')); sadButton = values[0]; fearButton = values[1]; joyButton = values[2]; angerButton = values[3]; disgustButton = values[4]; potentiometer= values[5]; buttonStateHold = values[6]; buttonState= values[7]; } println(sadButton, fearButton, joyButton, angerButton, disgustButton, potentiometer, buttonState, buttonStateHold); myPort.write(0); } void clickEmotionButton() { //ONLY DRAW THE CIRCLE IF THE SAD BUTTON PRESSED. if (prevSadButtonState==1 && sadButton==0) { circles.add(new DrawCircle()); if (prevButtonState==1 && buttonState==0) { fill(0, 0, 255, 40); circles.add(new DrawCircle()); } } //ONLY DRAW THE SQUARE IF THE FEARBUTTON PRESSED if (prevFearButtonState==1 && fearButton==0) { squares.add(new DrawSquare()); if (prevButtonState==1 && buttonState==0) { squares.add(new DrawSquare()); } } //ONLY DRAW THE HEXAGON IF THE JOYBUTTON PRESSED if (prevJoyButtonState==1 && joyButton==0) { hexagons.add(new DrawHexagon()); if (prevButtonState==1 && buttonState==0) { hexagons.add(new DrawHexagon()); } } //ONLY DRAW THE LINE IF THE ANGERBUTTON PRESSED if (prevAngerButtonState==1 && angerButton==0) { lines.add(new DrawLine()); if (prevButtonState==1 && buttonState==0) { lines.add(new DrawLine()); } } //ONLY DRAW THE TRIANGLE IF THE DISGUSTBUTTON PRESSED if (prevDisgustButtonState==1 && disgustButton==0) { triangles.add(new DrawTriangle()); if (prevButtonState==1 && buttonState==0) { triangles.add(new DrawTriangle()); } } prevSadButtonState= sadButton; prevFearButtonState= fearButton; prevJoyButtonState = joyButton; prevAngerButtonState = angerButton; prevDisgustButtonState = disgustButton; prevButtonState = buttonState; } void updateDisplayForLoop() { for (DrawCircle circle : circles) { circle.update(potentiometer, buttonState, buttonStateHold); fill(255, 40); circle.display(); } for (DrawLine line : lines) { line.update(potentiometer, buttonState, buttonStateHold); line.display(); } for (DrawSquare square : squares) { square.update(potentiometer, buttonState, buttonStateHold); square.display(); } for (DrawHexagon hexagon : hexagons) { hexagon.update(potentiometer, buttonState, buttonStateHold); hexagon.display(); } for (DrawTriangle triangle : triangles) { triangle.update(potentiometer, buttonState, buttonStateHold); triangle.display(); } } class DrawCircle { PVector center; float angle; float radius;// radius if rotation float circleSize; float x; float y; float lineWeight; float energyLevel; boolean confirm; float speedModifier; //the center oof the imaginary circle int centerX; int centerY; int circleColor; int circleStrokeColor; DrawCircle() { centerX= width/2 + width/3; centerY = height/2-height/16; center = new PVector(centerX, centerY); radius = 300; circleSize = 30; lineWeight=1; speedModifier=120; confirm=false; circleColor = color(216, 29, 68); circleStrokeColor=color(216, 29, 68); ; } void update(int _potentiometer, int buttonState, int buttonStateHold) { //if (confirmVolume==true) { // if(button2State==) //} if (confirm==false) { if (buttonState==1) { confirm=true; circleColor= color(255, 255, 255, 70); circleStrokeColor=color(255); } radius = map(_potentiometer, 0, 1023, 100, 50);//radiusModifier speedModifier = map(_potentiometer, 0, 1023, 150, 5); if (buttonStateHold==1) { //If the button is held, then change these things. lineWeight = map(volume, 0, 1, 1, 20); circleSize = map(volume, 0, 1, 10, 1000); } } x = center.x + cos(angle)*radius; y = center.y + sin(angle)*radius; angle += PI/speedModifier; // speedModifier } void display() { fill(circleColor); stroke(circleStrokeColor); noStroke(); //strokeWeight(3); ellipse(x, y, circleSize, circleSize); } } class DrawHexagon { PVector center; float angle; float radius;// radius if rotation float scaleSize; float x; float y; float lineWeight; float energyLevel; boolean confirm; float speedModifier; //the center oof the imaginary circle float centerX; float centerY; int hexagonColor; int hexagonStrokeColor; DrawHexagon() { centerX= width/2 - width/6; centerY = height/2 +height/3.5; center = new PVector(centerX, centerY); radius = 300; scaleSize = 10; lineWeight=1; speedModifier=120; confirm=false; hexagonColor = color(216, 29, 68); hexagonStrokeColor = color(216, 29, 68); } void update(int _potentiometer, int buttonState, int buttonStateHold) { if (confirm==false) { if (buttonState==1) { confirm=true; hexagonColor = color(255, 255, 255, 70); hexagonStrokeColor = color(255); } radius = map(_potentiometer, 0, 1023, 100, 50);//radiusModifier speedModifier = map(_potentiometer, 0, 1023, 150, 5); if (buttonStateHold==1) { //If the button is held, then change these things. lineWeight = map(volume, 0, 1, 1, 20); scaleSize = map(volume, 0, 1, 10, 500); } } x = center.x + cos(angle)*radius; y = center.y + sin(angle)*radius; angle += PI/speedModifier; // speedModifier } void display() { fill(hexagonColor); stroke(hexagonStrokeColor); noStroke(); //strokeWeight(3); pushMatrix(); translate(x, y); scale(scaleSize/50); beginShape(); vertex(0 - 44, 0 - sqrt(3) * 44); vertex(0 + 44, 0 - sqrt(3) * 44); vertex(0 + 2 * 44, 0); vertex(0 + 44, 0 + sqrt(3) * 44); vertex(0 - 44, 0 + sqrt(3) * 44); vertex(0 - 2 * 44, 0); endShape(CLOSE); popMatrix(); } } class DrawLine { PVector center, point1, point2; float angle; float radius;// radius if rotation float circleSize; float x1, x2; float y1, y2; float lineWeight; float energyLevel; boolean confirm; float speedModifier; //the center oof the imaginary circle float centerX; float centerY; int lineColor; DrawLine() { point1 = new PVector(x1, y1); point2 = new PVector(x2, y2); centerX= width/2 + width/6; centerY = height/2 + height/3.5; center = new PVector(centerX, centerY); radius = 300; circleSize = 10; lineWeight=10; speedModifier=120; confirm=false; lineColor = color(216, 29, 68); } void update(int _potentiometer, int buttonState, int buttonStateHold) { if (confirm==false) { if (buttonState==1) { confirm=true; lineColor = color(255, 255, 255, 90); } radius = map(_potentiometer, 0, 1023, 100, 50);//radiusModifier speedModifier = map(_potentiometer, 0, 1023, 150, 5); if (buttonStateHold==1) { //If the button is held, then change these things. lineWeight = map(volume, 0, 1, 3, 5); circleSize = map(volume, 0, 1, 10, 500); } } x1 = center.x + cos(angle)*radius; y1 = center.y + sin(angle)*radius; angle += PI/speedModifier; // speedModifier } void display() { //fill(lineColor); stroke(lineColor); //noStroke(); strokeWeight(5); //strokeWeight(5); pushMatrix(); translate(x1, y1); scale(circleSize/20); line(0, 0, 60, 0); popMatrix(); } } class DrawSquare { PVector center; float angle; float radius;// radius if rotation float squareSize; float x; float y; float lineWeight; float energyLevel; boolean confirm; float speedModifier; //the center oof the imaginary circle int centerX; int centerY; int squareColor; int squareStrokeColor; DrawSquare() { centerX=width/2- width/3; // the place where the object is drawn changes depending on what we input. centerY=height/2-height/16; center = new PVector(centerX, centerY); squareSize = 10; lineWeight=1; speedModifier=120; confirm=false; squareColor = color(216, 29, 68); squareStrokeColor = color(216, 29, 68); } void update(int _potentiometer, int buttonState, int buttonStateHold) { if (confirm==false) { if (buttonState==1) { confirm=true; squareColor = color(255, 255, 255, 70); squareStrokeColor = color(255); } radius = map(_potentiometer, 0, 1023, 100, 50);//radiusModifier speedModifier = map(_potentiometer, 0, 1023, 150, 5); if (buttonStateHold==1) { //If the button is held, then change these things. lineWeight = map(volume, 0, 1, 1, 20); squareSize = map(volume, 0, 1, 10, 1000); } } x = center.x + cos(angle)*radius; y = center.y + sin(angle)*radius; angle += PI/speedModifier; // speedModifier } void display() { rectMode(CENTER); fill(squareColor); stroke(squareStrokeColor); noStroke(); //strokeWeight(3); rect(x, y, squareSize, squareSize); } } class DrawTriangle{ PVector center; float angle; float radius;// radius if rotation float circleSize; float x1, x2, x3; float y1, y2, y3; float lineWeight; float energyLevel; boolean confirm; float speedModifier; //the center oof the imaginary circle int centerX; int centerY; int triangleColor; int triangleStrokeColor; DrawTriangle() { centerX= width/2; centerY = height/2-height/3; center = new PVector(centerX, centerY); radius = 300; circleSize = 10; lineWeight=1; speedModifier=120; confirm=false; triangleColor = color(216, 29, 68); triangleStrokeColor = color(216, 29, 68); } void update(int _potentiometer, int buttonState, int buttonStateHold) { if (confirm==false) { if (buttonState==1) { confirm=true; triangleColor = color(255, 70); triangleStrokeColor = color(255); } radius = map(_potentiometer, 0, 1023, 100, 50);//radiusModifier speedModifier = map(_potentiometer, 0, 1023, 150, 5); if (buttonStateHold==1) { //If the button is held, then change these things. lineWeight = map(volume, 0, 1, 1, 20); circleSize = map(volume, 0, 1, 10, 500); } } x1 = center.x + cos(angle)*radius; y1 = center.y + sin(angle)*radius; angle += PI/speedModifier; // speedModifier } void display() { fill(triangleColor); noStroke(); // stroke(triangleStrokeColor); //strokeWeight(1); pushMatrix(); translate(x1, y1); scale(circleSize/50); triangle(0, 0, 0, 90, 90, 0); popMatrix(); } }