# Theory and Practice of Tangible User Interfaces

### Announcements

November 24, 2007
Reading for November 27th, are now posted. Enjoy!

October 2, 2007
To upload your thoughtless acts, create a new assignment page like any other lab. You'll see "Thoughtless Acts" listed as one of the assignment options.

May 24, 2008
This site has been archived and is no longer editable. Stay tuned for the next version, coming in the fall!

# Jug Hero

Project Members:
k7lim
Lora Oehlberg
Seung Wan Hong
Shawna Hein

### Description

Haven't you always wanted to play Guitar Hero... But with Jugs?? Enter Jug Hero. This little program allows the user to blow on various jugs, following along with a computer-generated screen which gives the user direction for which jugs to blow.

As a bonus, the user can determine the speed of the computer program depending on how fast or slow they want to blow by tapping the beat out on an FSR at the beginning of the game.

### Components Used

• 4 Glass Jars
• 4 Condenser Microphones
• 4 Resistors (72 kOhms)
• Arduino
• Force sensor

### Arduino Code (Jugs)

/*
* by DojoDave <http://www.0j0.org>
*
* Turns on and off a light emitting diode(LED) connected to digital
* pin 13. The amount of time the LED will be on and off depends on
* the value obtained by analogRead(). In the easiest case we connect
* a potentiometer to analog pin 2.
*
*/
int jugWPin = 1; // select the input pin for the potentiometer
int jugXPin = 2;
int jugYPin = 3;
int jugZPin = 4;

int ledPinW = 13; // select the pin for the LED
int ledPinX = 12;
int ledPinY = 11;
int ledPinZ = 10;

int valW = 0; // variable to store the value coming from the sensor
int valX = 0; // variable to store the value coming from the sensor
int valY = 0; // variable to store the value coming from the sensor
int valZ = 0; // variable to store the value coming from the sensor

int valuesW[] = { 0, 0, 0, 0, 0};
int valuesX[] = { 0, 0, 0, 0, 0};
int valuesY[] = { 0, 0, 0, 0, 0};
int valuesZ[] = { 0, 0, 0, 0, 0};

int i = 0;

void setup() {
pinMode(ledPinW, OUTPUT); // declare the ledPin as an OUTPUT
pinMode(ledPinX, OUTPUT); // declare the ledPin as an OUTPUT
pinMode(ledPinY, OUTPUT); // declare the ledPin as an OUTPUT
pinMode(ledPinZ, OUTPUT); // declare the ledPin as an OUTPUT
Serial.begin(9600);
}

void loop() {

//Serial.print("W");
//Serial.print(valW);

//Serial.print("X");
//Serial.print(valX);

//Serial.print("Y");
//Serial.print(valY);

//Serial.print("Z");
//Serial.print(valZ);

for (i=0; i++; i=3){
valuesW[i+1] = valuesW[i];
}
valuesW[0] = valW;

for (i=0; i++; i=3){
valuesX[i+1] = valuesX[i];
}
valuesX[0] = valX;

for (i=0; i++; i=3){
valuesY[i+1] = valuesY[i];
}
valuesY[0] = valY;

for (i=0; i++; i=3){
valuesZ[i+1] = valuesZ[i];
}
valuesZ[0] = valZ;

int averageW = (valuesW[0] + valuesW[1] + valuesW[2] + valuesW[3] + valuesW[4])/5;
int averageX = (valuesX[0] + valuesX[1] + valuesX[2] + valuesX[3] + valuesX[4])/5;
int averageY = (valuesY[0] + valuesY[1] + valuesY[2] + valuesY[3] + valuesY[4])/5;
int averageZ = (valuesZ[0] + valuesZ[1] + valuesZ[2] + valuesZ[3] + valuesZ[4])/5;

// SEND OUT TO SERIAL PORT...
// FOR JUG 1 = ON, Serial.print("W"); Serial.println("11"); IF OFF, Seria.print("W"); Serial.println("99");
// FOR JUG 2 = ON, X
// FOR JUG 3 = ON, Y
// FOR JUG 4 = ON, Z

if (valW < 639 || valW > 650){
Serial.print("W");
Serial.println("1");
digitalWrite(ledPinW, HIGH); // turn the ledPin on
}
else{
digitalWrite(ledPinW, LOW); // turn the ledPin off
}

if (valX < 600 || valX > 611){
Serial.print("X");
Serial.println("1");
digitalWrite(ledPinX, HIGH); // turn the ledPin on
}
else{
digitalWrite(ledPinX, LOW); // turn the ledPin off
}

if (valY < 38 || valY > 52){
Serial.print("Y");
Serial.println("1");
digitalWrite(ledPinY, HIGH); // turn the ledPin on
}
else{
digitalWrite(ledPinY, LOW); // turn the ledPin off
}

if (valZ < 43 || valZ > 55){
Serial.print("Z");
Serial.println("1");
digitalWrite(ledPinZ, HIGH); // turn the ledPin on
}
else{
digitalWrite(ledPinZ, LOW); // turn the ledPin off
}
}

### Arduino Code (Tapping)

/*
* sends serial out from a pot and a FSR
*/
int FSRPin = 0; // select the input pin for the FSR
int FSRVal = 0; // variable to store the value coming from FSR
int lastFSRVal = 0;

int lastTapTime = 0;
int tapTime = 0;
int numtaps = 0;
int difference = 0;
int average = 0;
double seconds = 0;
int THRESHOLD = 5;
unsigned long FINISHEDTIME = 500;

int delaytime = 0; //variable that keeps track of how long someone is not pressing the FSR
boolean startedTapping = false;

void setup() {
Serial.begin(9600);
//Serial.println("Start Tapping!");
}

void loop() {
FSRVal = analogRead(FSRPin); // read the value from FSR, between 0 - 1024

Serial.print("V");
Serial.println(FSRVal);
Serial.print("L");
Serial.println(lastFSRVal);
//Serial.print("M");
//Serial.println(average);

if(FSRVal>THRESHOLD && lastFSRVal<THRESHOLD){ //If the person is starting a new tap
startedTapping = true;
delaytime = 0; //delaytime gets set back to zero
tapTime = millis();
numtaps++;

//Serial.print("How many taps have happened?");
//Serial.println(numtaps);
//delay(500);

if(numtaps>1){ //if its not the first tap

difference = tapTime - lastTapTime; //calculates the difference in milliseconds between taps
average = (average+difference)/numtaps; //calculates the average

/*Serial.print("D");
Serial.println(difference);

Serial.print("M");
Serial.println(average);*/

}

lastTapTime = tapTime; //set current taptime to lasttaptime variable

}

if(FSRVal<THRESHOLD && (startedTapping)){ //if the person is not tapping and they have already tapped at least once
delaytime++; //increment delaytime
Serial.println("T");
Serial.println(delaytime);
}

//Serial.println(average);

if(delaytime>FINISHEDTIME && (startedTapping)){ //if its been awhile with the person not tapping
Serial.print("F");
Serial.println(average); //print seconds to the serialport
//delay(1000);
}

lastFSRVal = FSRVal; //set current FSRVal to lastFSR variable

}

### Processing Code

import java.util.Random;

import processing.serial.*;
// Change this to the portname your Arduino board
String portname = "/dev/ttyUSB0"; // or "COM5"
Serial port;
String buf="";
int cr = 13; // ASCII return == 13
int lf = 10; // ASCII linefeed == 10

int board_width = 400;
int board_height = 800;
int num_jugs = 4;
int num_rows = 8;
Random rand;
boolean[][] board;
int jug_width;
int jug_height;
PFont font;
boolean pause;
int points;
int milliseconds;
float seconds;
float fps;
float BPM = 0;
char code = 'Z';

void setup()
{
port = new Serial(this, portname, 9600);

while (port.available()<1){
System.out.println("There is nothing in the Serial Port");
}

while(code!='F'){
while (port.available() > 0) {

//System.out.println("HELLO");
if (c != lf && c != cr) {
buf += char(c);
}
if (c == lf) {
String val = buf;
code = val.charAt(0);
String s = val.substring(1);
milliseconds = int(s);
println("code="+code);
println("number="+milliseconds);
buf="";
}
}
}

//milliseconds = 1000;
System.out.println("milliseconds again = "+milliseconds);
milliseconds = milliseconds+500; //ADJUSTING FOR ERROR, LAG TIME....
float m = float(milliseconds);
seconds = (m/1000);
System.out.println("Seconds = " +seconds);
BPM = seconds*60;
size(board_width, board_height);
fps = 1/seconds;
System.out.println("fps = " +fps);
frameRate(fps);
board = new boolean[num_rows][num_jugs];
rand = new Random();
jug_width = board_width / num_jugs;
jug_height = board_height / num_rows;
pause = false;
points = 0;
textFont(font);
newRow();
}

void newRow()
{
int next_jug = rand.nextInt(num_jugs+1);
if(next_jug == num_jugs) return;
board[0][next_jug] = true;
}

void draw()
{
if(!pause)
{
background(0);
drawBoard();
updateBoard();
}
}

void updateBoard()
{
copyDown();
clearTop();
newRow();
}

void copyDown()
{
for(int col=0; col < num_jugs; col++)
{
for(int row=num_rows-1; row > 0; row--)
{
board[row][col] = board[row-1][col];
}
}
}

void clearTop()
{
for(int i=0; i < num_jugs; i++)
{
board[0][i]=false;
}
}

void drawBoard()
{
for(int col=0; col < num_jugs; col++)
{
color c = color(col, 255, 255);
drawOutline(num_rows-1, col, c);
}
colorMode(HSB, num_jugs, 255 ,255);
for(int col=0; col < num_jugs; col++)
{
color c = color(col, 255, 255);
for(int row=0; row < num_rows; row++)
{
if(board[row][col]) drawJug(row, col, c);
}
}

}

void drawOutline(int row, int col, color c)
{
noFill();
stroke(c);
int x = (jug_width * col) + (int) (jug_width * .5);
int y = (jug_height * row) + (int) (jug_height * .5);
ellipse(x,y, jug_width, jug_height);

}

void drawJug(int row, int col, color c)
{
int x = (jug_width * col) + (int) (jug_width * .5);
int y = (jug_height * row) + (int) (jug_height * .5);
fill(c);
ellipse(x,y, jug_width, jug_height);

fill(0, 102, 153);
text("" + row + "," + col, x-(jug_width/4), y);
}

void scorePoint()
{
points++;
System.out.println("Points: " + points);
}

void togglePause()
{
pause = !pause;
}

void serialEvent(Serial p) {
if (c != lf && c != cr) {
buf += char(c);
}
if (c == lf) {
String val = buf;
code = val.charAt(0);
String s = val.substring(1);
milliseconds = int(s);
println("code="+code);
println("number="+milliseconds);
buf="";
}

int key_num = 0;

switch(code){

case 'W':
println("W Jug has been blown");
key_num = 1;
break;
case 'X':
println("X Jug has been blown");
key_num = 2;
break;
case 'Y':
println("Y Jug has been blown");
key_num = 3;
break;
case 'Z':
println("Z Jug has been blown");
key_num = 4;
break;
}

if(key_num > 0 && key_num <= num_jugs) tryKey(key_num);

}

void tryKey(int key_num)
{
if(board[num_rows-1][key_num-1])
{
scorePoint();
//System.out.println("row " + (num_rows-1) + ", jug " + (key_num-1));
}
}