User login

Powered by Drupal, an open source content management system

Theory and Practice of Tangible User Interfaces

Tron and a Chair Sensor

Submitted by npdoty on Wed, 10/01/2008 - 23:50

Assignment: Sensing PART II: Force sensors and photocells

Collaborators:

With our new-found ability to control screen graphics from physical sensors, I decided to create a potentiometer-controlled Tron game.  (See the Light Cycle article for the inspiration.)

Two players control their own colored lines, turning by using their own potentiometer.  Each player's colored trail persists as a wall and the loser is the first player to run into his own or his opponent's wall.  When a round ends, the Arduino board is lit up with the color of the winner's line.

The Arduino board sends potentiometer rotation readings out on the serial port, along with a letter to specify which player is which.  The Processing code reads these values in, creates thresholds to determine which direction the player's bike should move and updates the screen.  When a player crashes, Processing sends a color signal (the hue on a scale from 1 to 1023) back to the Arduino board, which fades in that color.

This is a pretty fun game, although the fact that the potentiometer can't rotate more than 360 degrees can be pretty frustrating.

 

Chair Sensor

I've always wanted my computer to know when I'm around.  Using a force sensor attached to the back of the chair, the Arduino board can recognize when I sit down at my chair and turn on a light to welcome me.

 

We might also be able to evaluate who's sitting at the chair based on how much force is put on the back of the chair.

Photo 11

Covering the sensor with a blanket makes it more comfortable and less noticeable.

Photo 10

Arduino Code


/*
 * npdoty rotation_passing
 *
 * pass rotation from two Pots across the serial port (good for playing Tron)
 *
 * started with:
 * one pot fades one led
 * modified version of AnalogInput
 * by DojoDave <http://www.0j0.org>
 * http://www.arduino.cc/en/Tutorial/AnalogInput 
 */
//int potPin = 0;   // select the input pin for the potentiometer

//int val = 0;      // variable to store the value coming from the sensor
int i = 0;

float angles[3];
float values[3];
int pins[3];
int potPins[2];
int potValues[2];
char playerLetters[2];


char buf[10];
int bufIndex = 0;

char escape = '@';

boolean DEBUG = false;

void setup() {
  Serial.begin(9600);
  
  pins[0] = 11;
  pins[1] = 10;
  pins[2] = 9;
  
  potPins[0] = 0;
  potPins[1] = 1;
  
  playerLetters[0] = 'A';
  playerLetters[1] = 'B';
}

void loop() {
  
  int pot;
  
  for (pot = 0; pot < 2; pot ++)
  {
    potValues[pot] = analogRead(potPins[pot]);    // read the value from the sensor, between 0 - 1024
  
    Serial.print(playerLetters[pot]); //label which player's value is being sent
    Serial.println(potValues[pot]);  //send rotation value to Processing
  }
  
  if (Serial.available())
  {
    char c = Serial.read();
    if (c != escape) 
    {
     buf[bufIndex++] = char(c);
     if (DEBUG)
     {
       Serial.print("BufIndex: "); Serial.print(bufIndex); Serial.print(" C: "); Serial.print(c);
     }
    }
    else
    {
     buf[bufIndex] = 0;  //terminate the string, just to be careful
     bufIndex = 0; //for future reads
     if (DEBUG)
     {
       Serial.print(" Buf: "); Serial.println(buf);
     }
     
     int color = atoi(buf);
     
     if (DEBUG)
     {
       Serial.println(color);
     }

     fadeInColor(color);
    }
  }
}

void fadeInColor(int color)
{
  hueToRgb((float)color / 1000.0);
  
  int pin;
  float numSteps = 50;

  
    int whichStep;
    for(whichStep = 0 ; whichStep <= numSteps; whichStep ++) // fade in (from min to max) 
    { 
        for (pin = 0; pin < 3; pin ++)
        { 
          analogWrite(pins[pin], values[pin] * 255.0 / numSteps * whichStep);           // sets the value (range from 0 to 255) 
        }
        delay(50);                            // waits for 30 milli seconds to see the dimming effect 
    }  
}


void printFloat(float num)
{
 Serial.print((long)(num*1000)); 
}

//takes a hue value between 0 and 1 and fills the values[] array with the rgb equivalents
//for more, see http://en.wikipedia.org/wiki/HSL_color_space
//assumes that Lightness is 0.5 and saturation is 1.0
void hueToRgb(float hue)
{
  printFloat(hue);
  
  angles[0] = hue + (1.0/3.0);
  angles[1] = hue;
  angles[2] = hue - (1.0/3.0);
 
  int i = 0;
 
 for (i = 0; i < 3; i++)
 {
   if (angles[i] < 0)
  {
   angles[i] ++;
  } else if (angles[i] > 1)
  {
   angles[i] --; 
  }
  
  float value = 0;
  
  if (DEBUG)
  {
    Serial.print(" Angle: ");
    printFloat(angles[i]);
  }
  
  if (angles[i] < (1.0/6.0))
  {
   value = angles[i] * 6; 
  }
  else if (angles[i] < (1.0/2.0))
  {
   value = 1.0; 
  }
  else if (angles[i] < (2.0/3.0))
  {
   value = 6 * ((2.0/3.0) - angles[i]); 
  }
  else
  {
   value = 0.0; 
  }
  
  values[i] = value;
  
  if (DEBUG)
  {
    Serial.print(" Value: ");
    printFloat(values[i]);
  }
 } 
 
 if (DEBUG)
 {
   Serial.println("");
 }
}

Processing Code


/*
 * Arduino Line Drawer
 * (Arduino Ball, modified 2008)
 * ---------------------- 
 *
 *
 * Receives an ASCII number over the serial port, 
 * terminated with a carriage return (ascii 13) then newline (10).
 * 
 * This matches what Arduino's " Serial.println(val)" function
 * puts out.
 *
 * Created 25 October 2006
 * copyleft 2006 Tod E. Kurt <tod@todbot.com
 * http://todbot.com/ 
 */
import processing.serial.*;
// Change this to the portname your Arduino board
String portname = "/dev/tty.usbserial-A7006ysf"; // or "COM5"
Serial port;
String buf="";
int cr = 13;  // ASCII return   == 13
int lf = 10;  // ASCII linefeed == 10
int currentPlayer = 0;

int x;
int y;

int[][] positions;

boolean gameOver;

int xBound = 500;
int yBound = 500;

int[][] board;

color[] playerColors;

color playerOne;
color playerTwo;

void setup() {
  size(500,500);
  
  colorMode(HSB, 1023);
  
  frameRate(10);
  smooth();
  //background(40,40,40);
  //noStroke();
  port = new Serial(this, portname, 9600); 
  
  setupGame();
}
void draw() {
}
void keyPressed() {
  if(key == ' ') {
    background(40,40,40);  // erase screen
  }
  else {
    int x = int(random(0,width));
    int y = int(random(0,height));
    drawball(x,y, 50);
  }
}
// draw balls
void drawball(int x, int y, int r) {
  for (int i=0; i<100; i++ ) {
    fill(255-i,i,240);
    ellipse(x,y,r,r);
  }

}

void setupGame()
{
    board = new int[xBound][yBound];
    positions = new int[2][2];
    playerColors = new color[2];
    playerColors[0] = color(500, 1023, 500);
    playerColors[1] = color(900, 1023, 500);
    
    positions[0][0] = xBound / 4; //player one, x position (left side)
    positions[1][0] = xBound / 4 * 3; //player two, x position (right side)
    
    positions[0][1] = yBound / 2;  //same vertical position
    positions[1][1] = yBound / 2;
  
    gameOver = false;
  
    background(40,40,40);
}

void drawLine(int val, int player)
{
  println("Player: " + player);
  
  int opponent = 0;
  if (player == 0)
  {
    opponent = 1; 
  }
  
  if (gameOver)
  {
    setupGame();
    
   return; 
  }
  
  stroke(playerColors[player]);
  
  int delta = 1;
  
  int oldx = positions[player][0];
  int oldy = positions[player][1];
  int x = oldx;
  int y = oldy;
  
  if ( (val > 128) && (val < 384))
  {
   y = oldy + delta; 
  }
  else if ( (val > 640) && (val < 896) )
  {
   y = oldy - delta; 
  }
  
  if ( ((val >= 0) && (val <= 128)) || ((val >= 896) && (val <= 1024))  )
  {
   x = oldx + delta; 
  }
  else if ( (val >= 384) && (val <= 640) )
  {
   x = oldx - delta; 
  }
  
  if (x < 0)
  {
   x = 0; 
  }
  if (x >= xBound)
  {
   x = xBound - 1; 
  }
  
  if (y <  0)
  {
   y = 0; 
  }
  
  if (y >= yBound)
  {
   y = yBound - 1; 
  }
  
  if ((board[x][y] > 0) && (!( (x == oldx) && (y == oldy) ) ) )
  {
   gameOver = true;
   println("Game ended at position: " + x + "," + y);
   String output = hue(playerColors[opponent]) + "@";  //show the opponent's color because he just won!
   port.write(output);
  }
  
  line(oldx, oldy, x, y);
  board[x][y] = player + 1;  //save the new location on the board
  
  positions[player][0] = x;
  positions[player][1] = y;
}

// called whenever serial data arrives
void serialEvent(Serial p) {
  int c = port.read();
  
  if (c == 'A')
  {
    currentPlayer = 0;
  }
  else if (c == 'B')
  {
   currentPlayer = 1; 
  }
  else if (c != lf && c != cr) {
    buf += char(c);
  }
  if (c == lf) {
    int val = int(buf);
    println("val="+val); 

    drawLine(val, currentPlayer);
    buf = "";
    //background(40,40,40);  // erase screen
  }
}