Project Title: How well can you binary?
Video showing a run through of the piece
Video showing a run through of the piece fast enough to be judged as “good”
Video showing what happens if you try to press both buttons
Simple narrative description:
There is a podium with two buttons on it in front of a projection. When the user presses a button the “test” begins, asking the user to choose between two different options. If the user tries to press both buttons at once a loud buzzer goes off and the projection flashes “AND is not an option.” Each time the user answers a question a ticking noise gets faster. After the last question the test/projection tells the user if they were “BAD” or “GOOD” based on how fast they were able to answer the questions.
Process Images:
Process Reflection:
Surprisingly for me the easier aspect of the project was the technical parts. In the past I have struggled the most with the coding and the wiring of the piece but I think I did an okay job giving myself a project that was relatively approachable for someone with my level of experience. It was difficult enough coding-wise where I definitely learned something (I’ve never used Processing before) but not so difficult that I saw it as a major challenge.
I think the biggest hurdle that I had to tackle was conceptual: how do I make sure my piece is meaningful? Or maybe: how do I make sure what I imagined as being “good” about the project comes through? This, for me, was more of a design problem than anything else. I wanted to make sure the piece had an element of absurdity while still making the message meaningful, and I didn’t know if there was any way to test whether or not I had crossed that line until I actually presented the thing. I think something akin to the 90% critique we are going to have for the next project would have helped me resolve this problem/these doubts before the final presentation. I think what was interesting to find out during the final critique was how people wanted to explore the piece more in terms of figuring out the different outcomes (ie rushing through the questions to get to the “you are…GOOD” outcome) as opposed to focusing on the meaning behind the questions themselves. I wonder if there is some element of the “game” that could have been changed to focus more thoroughly on the conceptual meaning behind the piece.
Elements such as messing with the question format and making the podium a binary in and of itself, suggestions I received during the critique from our guest critics, definitely might have improved this aspect of the “game.” In the end I learned that the design of the thing (the appearance of the interface, how it moved between questions, what the podium looked like) for me at least, ended up being the biggest hurdle, and something I needed more feedback on, than the technical problems I expected to struggle with more. In the future I need to focus more on getting the technical stuff out of the way earlier so that I can have people interact with the piece earlier on in order to incorporate design feedback to the functionality of the piece before the final critique.
Arduino Code:
/* How well can you binary? Kirman Hanson - The code reads the input coming from the buttons and through the "AND" gate circuit (set to the 8,7, and 4 pins on the arduino) and sends the information to the processing code as either a "0", "2", "3", or "4" depending on the input. - code is based on the basic "digital button" sketch provided with the arduino */ // constants won't change. They're used here to set pin numbers: const int leftButtonPin = 8; // the number of the left pushbutton pin const int rightButtonPin = 7; // the number of the right pushbutton pin const int andPin = 4; // variables will change: int leftButtonState = 0; // variable for reading the left pushbutton status int rightButtonState = 0; // variable for reading the right pushbutton status int andState = 0; void setup() { // initialize the pushbuttons + AND gate pin as inputs: pinMode(leftButtonPin, INPUT); pinMode(rightButtonPin, INPUT); pinMode (andPin, INPUT); Serial.begin(9600); } void loop() { // read the state of the pushbutton value: leftButtonState = digitalRead(leftButtonPin); rightButtonState = digitalRead(rightButtonPin); andState = digitalRead(andPin); if (andState == HIGH) { // if the and gate is activated... Serial.write(3); //send a 3 to Processing Serial.write(0); //delay (500); // check if the pushbutton is pressed. If it is, the buttonState is HIGH: } else if (leftButtonState == HIGH) { //send a 4 to processing if the left button is pressed delay(100); // delays help prevent the code from sending out "double presses" Serial.write(4); Serial.write(0); //Serial.print("left"); // these are commented out but used them to test the button input //Serial.print("off"); delay(500); } else if (rightButtonState == HIGH) { // send a 2 to processing if the right button is pressed delay(100); Serial.write(2); Serial.write(0); //Serial.print("right"); // Serial.print("off"); delay (500); } else { Serial.write(0); // if nothing is happening send 0 to Processing } delay(50); // Wait 50 milliseconds
Processing Code:
/* How well can you binary? Kirman Hanson Code draws up the interface for the game/test of the piece and it changes the interface in response to the button presses as inputs being read by the arduino code. Basic structure for code is based off the basic "serial read" example that comes with Processing Zach + classmates helped with troubleshooting, Erin with the design elements */ import processing.serial.*; import processing.sound.*; Serial myPort; // Create object from Serial class int buttonVal; // Data received from the serial port PFont f, qFont, andFont, startFont; StringList qInventory, firstAInventory, secondAInventory; int qCount = 0; boolean andTrigger = false; // this bool is used to trigger the "AND" state (ie the buzzer) boolean leftHighlight = false; boolean rightHighlight = false; boolean buttonPressed = false; boolean flickerLoad = false; int warningStart = 100000; SoundFile ticker, endBeep, endBeep2, wrongNoise; float tickerRate = 2.0; String tickerFile = "tick2.0.wav"; float amp = 0; float questionStart; float timeToAnswer; float totalTime; boolean endStart = false; float endTime; void setup() { // draws the basic interface size(1400,900); f = createFont("KohinoorDevanagari-Bold", 40); qFont = createFont("KohinoorDevanagari-Regular", 54); andFont = createFont("KohinoorDevanagari-Bold", 90); startFont = createFont("KohinoorDevanagari-Regular", 30); // all "inventories" are string lists containing the questions and/or answers. Change as you wish. qInventory = new StringList("The lights are...", "It is...", "I am...", "I am...","The sky is...", "I am a student", "I am in a ___ mood", "I am...", "I am only good at...", "I am a...", "I ___ therefore I am", "I am good at making decisions", "I am...", "Carngie Mellon is...", "I am a...", "I am...", "I am...", "I am...", "I am...", "I am..."); firstAInventory = new StringList("on", "cold", "inside", "left-handed", "up", "yes", "good", "being", "art", "good person","think", "yes", "strong", "ethical", "success", "lucky", "not fun", "spiritual", "natural", "on"); println(firstAInventory.size()); // helps to diagnose whether you have enough answers for your questions secondAInventory = new StringList("off", "hot", "outside", "right-handed", "down", "no", "bad", "becoming", "science", "bad person", "feel", "no", "weak", "unethical", "failure", "hard-working", "fun", "rational", "unnatural", "off"); ticker = new SoundFile(this, tickerFile); ticker.loop(1,amp); // initializes the "ticking" noise println(qInventory.size()); println(secondAInventory.size()); // button input String portName = Serial.list()[4]; myPort = new Serial(this, portName, 9600); } void draw() { background(255); fill(0); textAlign(CENTER); if ( myPort.available() > 0) { // If data is available, buttonVal = myPort.read(); // read it and store it in val } if (buttonPressed == false){ // tests whether or not the button has been pressed background(255); amp = 0; // if not ticker is silent if (buttonVal == 4 || buttonVal == 2){ //gets the interface out of "start" mode buttonPressed = true; println("button pressed now true"); amp = 0.05; // ticker is now able to be heard } else if (second()%2 == 0){ // sets up the "start mode", uses modulus to "blink" the text fill(0); textFont(startFont); text("How well can you binary?", width/2, height*0.333); // every 2 seconds flip the bool in order to create "flicker" effect if (flickerLoad == false){ //println("flipped to true"); delay(10); flickerLoad = true; delay(10); } else if(flickerLoad==true){ flickerLoad = false; } } else if(flickerLoad == true){ fill(0); textFont(qFont); text("PRESS ANY BUTTON TO START", width/2, height/2); } } else if (buttonVal == 3) { // if the arduino sends out a 3,triggers the "AND" state println("and triggered"); fill(255); warningStart = millis(); if (millis() - warningStart < 1200){ //only displays for 1.2 seconds andTrigger = true; //play dramatic tone here } else { andTrigger = false; // automatically ends after 1.2 seconds } } else if ((buttonVal == 4 || buttonVal== 2)&& buttonVal!=3 && endStart == false) { //moves onto next question + triggers end state if we are at the end of the list of questions delay(100); qCount +=1; // the q count counts the number of questions answered andTrigger = false; println("tickerRate", tickerRate); if (qCount < qInventory.size()) { tickerRateIncrease(buttonVal); //increases the speed of the ticker everytime question is answered } else { // triggers the "end game" function once at end of the questions endTime = millis(); ticker.stop(); endBeep = new SoundFile(this, "endbeep.mp3"); endBeep2 = new SoundFile(this, "endbeep_extra.wav"); endBeep.playFor(2.0); endStart = true; println("endStart set to true"); } } else if (qCount < qInventory.size()) { //displays the different questions so long as there are questions left background(255); textFont(qFont); text(qInventory.get(qCount), width* 0.5, height*0.333); textFont(f); //set up highlights when button pressed if (leftHighlight==true && millis()- questionStart < 300 && andTrigger==false){ println("left Highlight", leftHighlight); rectMode(CENTER); fill(0); rect(width*0.333, height*0.666, 200, 80); fill(255); text(firstAInventory.get(qCount), width*0.333, height*0.666);//retrieves the correstpodning answer from the list println(qCount); } else if (rightHighlight==true && millis()- questionStart < 300 && andTrigger==false){ println("right highlight", rightHighlight); rectMode(CENTER); fill(0); rect(width*0.666, height*0.666, 200, 80); fill(255); text(secondAInventory.get(qCount), width*0.666, height*0.666);//retrieves the correstpodning answer from the list println(qCount); } else{ // "normal" question display fill(0); text(secondAInventory.get(qCount), width*0.666, height*0.666); text(firstAInventory.get(qCount), width*0.333, height*0.666); //if neither is picked don't highlight it rightHighlight = false; leftHighlight = false; } } // this function sets up the "AND" state if (millis() - warningStart < 1200 && andTrigger==true){ wrongNoise = new SoundFile(this, "wrong.wav"); wrongNoise.play(); delay(90); fill(255,0,0); background(255); textFont(andFont); text("AND is not an option", width/2, height/2); } // this sequence is the end state if (endStart == true){ println("end state"); ticker.stop(); if (endStart==true && millis()-endTime < 2500){ println("end game displayed"); textFont(andFont); text("END GAME", width/2, height/2); println("endTime", endTime); println("endStart", endStart); println("millis-endTime", millis()-endTime); println("millis", millis()); } if (millis()-endTime < 8000 && millis()-endTime >= 2500){ println("calculating score displayed"); textFont(qFont); text("Calculating results...", width/2, height/2); } if (endStart==true && millis()-endTime < 10000 && millis()-endTime >= 8000){ println("you are..."); textFont(qFont); text("You are...", width/2, height/2); } if (endStart==true && millis()-endTime < 12000 && millis()-endTime >= 10000 && totalTime <= 30000){ textFont(andFont); background(0,255,0); fill(255); text("GOOD", width/2, height/2); } if (endStart==true && millis()-endTime < 12000 && millis()-endTime >= 10000 && totalTime > 30000){ textFont(andFont); background(255,0,0); text("BAD", width/2, height/2); } if(endStart == true && millis()-endTime >= 14000){ println("went to no loop"); println(endTime); text("", width/2, height/2); fill(0); noLoop(); } } } void tickerRateIncrease(int buttonVal) { //this function controls the ticker rate println("click"); if (buttonVal == 4){ leftHighlight = true; } if (buttonVal== 2){ rightHighlight = true; } //increase rate + loudness tickerRate -= 0.1; amp += 0.05; // endstate calculations timeToAnswer = millis() - questionStart; totalTime += timeToAnswer; questionStart = millis(); //changing rates String rateString = nf(tickerRate, 1, 1); println("new ticker rate", tickerRate); String[] tickerParts = new String[3]; tickerParts[0] = "tick"; tickerParts[1] = rateString; tickerParts[2] = ".wav"; String tickerFile = join(tickerParts, ""); //sets up new ticker file name to be retrieved ticker.stop(); ticker = new SoundFile(this, tickerFile); ticker.cue(0.3); ticker.loop(1,amp);//plays new, faster, ticker file }