User login

Powered by Drupal, an open source content management system

Theory and Practice of Tangible User Interfaces

Chasing Casper the Ghost

Submitted by bobacita on Tue, 09/30/2008 - 14:47

Assignment: Sensing PART II: Force sensors and photocells

Collaborators:

Description

Programming:

I modified the SoftBody example code in Processing to take input from the FSR on my board and correlate squeezes (force) with the movement of the soft shape around the screen.  A squeeze causes the shape to move to another place on the screen.  The springing effect causes the shape to morph into cool shapes with different nodes.  Some of these nodes look like pieces of paper flying in the wind, or a ghost, flitting around.

 

Mechanical:

I constructed a coin jar that senses when it's time to take the coins to your neighborhood CoinStar machine to get bills.  When less than a third of the jar is full, the LEDs light up dimly.  When the jar is at least half full, the LEDs get very bright, signaling that now would be a good time to unload those coins.  To make up for the ledge space on the bottom of the jar, I attached cotton pads, and taped the sensor to the bottom of the cotton pads.

I had another idea to make a roach habitat refilling indicator.  My husband has a pet roach (deceased) who lives in a contact lens container full of rubbing alcohol.  The rubbing alcohol inevitably evaporates, leaving the roach unprotected, so I attached a quarter to the bottom of the container (to make up for the ledge space) and taped a sensor under the quarter.  We didn't have rubbing alcohol on hand though, so I couldn't test this out (without harming the roach!).  The idea was that if the container was full the green LED would glow; once it ceases to glow it's time to refill (a more developed version would probably flash or chime to notify us that the roach is in trouble).

 

Components

1 glass jar, with coins

1 roach

1 contact lens container

Several cotton pads

1 quarter

Tape

1 FSR

3 LEDs

3 220-ohm resistors

1 10-ohm resistor

2 black wires for ground

1 red wire for 5-V power

1 yellow wire from analog in pin 0

3 yellow wires from PWM pins 9, 10, 11

 

Code

 

/**

 * Soft Body 

 * Created by Carol Chen

 * Adapted from code by Ira Greenberg

 *

 * Softbody dynamics simulation using curveVertex() and curveTightness()

 */

 

 import processing.serial.*;

 

// SERIAL GLOBAL VARIABLES

String portname = "/dev/tty.usbserial-A4001nQ5"; // Modify here to your own arduino COM port

 

Serial port;

String buf="";

int cr = 13;  // ASCII return   == 13

int lf = 10;  // ASCII linefeed == 10

int loc = 0;

 

 

// center point

float centerX = 0, centerY = 0;

 

float radius = 45, rotAngle = -90;

float accelX, accelY;

float springing = .0085, damping = .98;

 

//corner nodes

int nodes = 5;

float nodeStartX[] = new float[nodes];

float nodeStartY[] = new float[nodes];

float[]nodeX = new float[nodes];

float[]nodeY = new float[nodes];

float[]angle = new float[nodes];

float[]frequency = new float[nodes];

 

// soft-body dynamics

float organicConstant = 1;

 

void setup() {

  size(200, 200);

  //center shape in window

  centerX = width/2;

  centerY = height/2;

  // iniitalize frequencies for corner nodes

  for (int i=0; i<nodes; i++){

    frequency[i] = random(5, 12);

  }

  noStroke();

  smooth();

  frameRate(30);

    port = new Serial(this, portname, 9600); 

 

}

 

// called whenever serial data arrives

void serialEvent(Serial p) {

  int c = port.read();

  if (c != lf && c != cr) {

    buf += char(c);

  }

  if (c == lf) {

    int val = int(buf);

    println("Location distance: "+val); 

    moveShape(val);

    buf = "";

  }

}

 

void draw() {

  //fade background

  fill(0, 100);

  rect(0,0,width, height);

  drawShape();

  moveShape(loc);

}

 

void drawShape() {

  //  calculate node  starting locations

  for (int i=0; i<nodes; i++){

    nodeStartX[i] = centerX+cos(radians(rotAngle))*radius;

    nodeStartY[i] = centerY+sin(radians(rotAngle))*radius;

    rotAngle += 360.0/nodes;

  }

 

  // draw polygon

  curveTightness(organicConstant);

  fill(255);

  beginShape();

  for (int i=0; i<nodes; i++){

    curveVertex(nodeX[i], nodeY[i]);

  }

  for (int i=0; i<nodes-1; i++){

    curveVertex(nodeX[i], nodeY[i]);

  }

  endShape(CLOSE);

}

 

void moveShape(int val) {

  //move center point

  float deltaX = val/200-centerX;

  float deltaY = val/200-centerY;

 

  // create springing effect

  deltaX *= springing;

  deltaY *= springing;

  accelX += deltaX;

  accelY += deltaY;

 

  // move predator's center

  centerX += accelX;

  centerY += accelY;

 

  // slow down springing

  accelX *= damping;

  accelY *= damping;

 

  // change curve tightness

  organicConstant = 1-((abs(accelX)+abs(accelY))*.1);

 

  //move nodes

  for (int i=0; i<nodes; i++){

    nodeX[i] = nodeStartX[i]+sin(radians(angle[i]))*(accelX*2);

    nodeY[i] = nodeStartY[i]+sin(radians(angle[i]))*(accelY*2);

    angle[i]+=frequency[i];

  }

}

 

Photos attached