Final Project
Making Furniture Interactive
Carnegie Mellon University
Fall 2007

Abstract

The more complex the artifacts we interact with become, the more we personify their behavior. The goal of this project was to explore interacting with a small, playful form and the emotional connection between a person and an artifact. I chose a lamp, and used RFID, a motion sensor, muscle wire, and computing for the interaction. Unfortunately, the muscle wire did not exert the strength needed to move the form, and it was abandoned for the final artifact.

How It Works

Lampie likes it when people are around. When Lampie is not turned on but detects motion through a PIR sensor, the three LEDs alternate in a soothing pattern. If no motion is detected, Lampie becomes agitated, which results in rapid blinking lights. After a certain amount of time, Lampie’s agitation elevates. Motion calms him, but ultimately, Lampie wants to be turned on. His agitation has memory, so that if he is calmed after being really agitated he will return to his previous state as soon as no motion is detected.

Lampie can be turned on and off only by a specific RFID tag. You can watch the video to see how this all works.

[wp_youtube]HynsbLjcq-c[/wp_youtube]

Lampie’s thinking is a result of Processing code run within the Arduino development environment.

Materials

  • Arduino microprocessor
  • Breadboard
  • Parallax RFID Reader
  • Passive RFID tags
  • Parallax PIR Sensor
  • 5mm While LED 3.6V 20mA 1100mcd
  • Jumbo Super-Bright Red LED 2.4V 20mA 5000mcd
  • 5mm Yellow LED 2V 20mA
  • 3 15o-Ohm resistors
  • 22-gauge solid wire
  • MacBook Pro (for power)
  • Foam core
  • Vellum
  • Electrical tape

Not in final, but used extensively throughout the process:

  • .008 inch actuactor wire (muscle wire)
  • 2 1-watt 10-Ohm resistors

Process

I started with the RFID reader, thinking that would be the main challenge. Originally, I started with a Phidgets RFID reader lent to me by my professor. But it needed to be connected to the computer to work, and I hoped the lamp would not need to be connected to a computer in the end. So instead I ordered an RFID reader from Parallax that used a serial connection to the Arduino board. I then used code from the Arduinio Playground to get the reader working. One problem that I never perfected was having the reader stop reading after identifying the correct RFID tag. (I suspect it might have something to do with the slow serial speed: 2,400 baud.) So sometimes it would turn the lamp off after turning it on, or vice versa. But I chalked that up to Lampie having a mind of his own.

RFID Reader

The muscle wire proved much more challenging, largely because it needed a precise amp current and I did not understand how circuits worked. After a lot of frustration, a lot of seared foam core, and a lot of time looking at All About Circuits, I got it working.

I used code for the PIR sensor again from the Arduino Playground. No problems there.

With the technology working, I turned to out to be my greatest challenge: form. Here are some early sketches of what I imagined.

Lampie sketches

Having little experience in physical prototyping, bringing everything together proved to be a hurdle I could not overcome completely, as I could not implement the muscle wire in a way that would have an forcible impact on the lamp. Also, the size of the Arduino processor, breadboard, and RFID reader meant the form could not be as small as I hoped. Like all design, I learned in the actual making, and iterated as needed.

I built a box out of foam core that had a raised shelf, on which the breadboard sat. Rather than hide the wires for the LEDs, I used them as part of the design, and created an LED flower garden aesthetic. The breadboard was covered with vellum, as were the LEDs.

Attempts to use the muscle wire and its requirement of precise current meant I stuck with the laptop as a power source. You can still the muscle wire in this prototype.

But ultimately, the muscle wire was removed.

I programmed Lampie to have an on and off state, and I used to timer to increase his excitement level if there was no motion detected during the off state. Turning Lampie on resets the timer.

Download Arduino Source Code

[sourcecode language=’cpp’]
/////////////////////////////
//VARS
//the time we give the sensor to calibrate (10-60 secs according to the datasheet)
int calibrationTime = 30;

//the time when the sensor outputs a low impulse
long unsigned int lowIn;

//the amount of milliseconds the sensor has to be low
//before we assume all motion has stopped
long unsigned int pause = 5000;

boolean lockLow = true;
boolean takeLowTime;

int timerLimit = 50000;
int timer = 0;
int noOwnerLimit = 5;
int noOwner = 0;

int pirPin = 11; //the digital pin connected to the PIR sensor’s output

// RFID reader for Arduino
// Wiring version by BARRAGAN
// Modified for Arudino by djmatic

int val = 0;
char code[10];
int bytesread = 0;
char message[6] = “hello”;
// char worldtag[12] = “0415D8A2BCC”;
char worldtag[12] = “0F02F2D2EAA”;
int digit = 0;
int led1 = 9;
int led2 = 5;
int led3 = 6;
int rfidPin = 2;
int blinkDelayOn = 10;
int blinkDelayOff = 30;
boolean lampieOn = false;
boolean motion = false;

void setup() {

Serial.begin(2400); // RFID reader SOUT pin connected to Serial RX pin at 2400bps
pinMode(rfidPin,OUTPUT); // Set digital pin 2 as OUTPUT to connect it to the RFID /ENABLE pin
pinMode(led1, OUTPUT); // sets the digital pin as output
digitalWrite(rfidPin, LOW); // Activate the RFID reader
pinMode(led2, OUTPUT); // declare the led1 as an OUTPUT
pinMode(led3, OUTPUT); // declare the led1 as an OUTPUT

pinMode(pirPin, INPUT);
digitalWrite(pirPin, LOW);

//give the sensor some time to calibrate
Serial.print(“calibrating sensor “);
for(int i = 0; i < calibrationTime; i++){ Serial.print("."); quickBlink(led3); delay(1000); } Serial.println(" done"); Serial.println("SENSOR ACTIVE"); digitalWrite(led3, LOW); } void loop() { // Code for the PIR Sensor if(digitalRead(pirPin) == HIGH){ motionDetected(); if(lockLow){ //makes sure we wait for a transition to LOW before any further output is made: lockLow = false; Serial.println("---"); Serial.print("motion detected at "); Serial.print(millis()/1000); Serial.println(" sec"); delay(50); } takeLowTime = true; } if(digitalRead(pirPin) == LOW){ noMotion(); if(takeLowTime){ lowIn = millis(); //save the time of the transition from high to LOW takeLowTime = false; //make sure this is only done at the start of a LOW phase } //if the sensor is low for more than the given pause, //we assume that no more motion is going to happen if(!lockLow && millis() - lowIn > pause){
//makes sure this block of code is only executed again after
//a new motion sequence has been detected
lockLow = true;
/*
Serial.print(“motion ended at “); //output
Serial.print((millis() – pause)/1000);
Serial.println(” sec”);
*/
delay(50);
}
if (timer == timerLimit) {
timer = 0;

if (lampieOn == false && noOwner < noOwnerLimit) { getAngry(); noOwner++; } else if (lampieOn == false && noOwner >= noOwnerLimit) {
getReallyAngry();
noOwner++;
}
}
timer++;
//Serial.println(timer);
}

// Code for the RFID Reader

if(Serial.available() > 0) { // if data available from reader
if((val = Serial.read()) == 10) { // check for header
bytesread = 0;
while(bytesread<10) { // read 10 digit code if( Serial.available() > 0) {
val = Serial.read();
if((val == 10)||(val == 13)) { // if header or stop bytes before the 10 digit reading
break; // stop reading
}
code[bytesread] = val; // add the digit
//Serial.println(code);
bytesread++; // ready to read next digit

}
}
if(bytesread == 10) { // if 10 digit read is complete

if(code[6] == worldtag[6]) {
/*
Serial.print(“World Tag: “); // possibly a good TAG

Serial.print(code); // print the TAG code
Serial.print(” vs “);
Serial.println(worldtag);
*/
if(lampieOn == false) {
turnLampieOn();
}
else {
turnLampieOff();
}
}
else {

Serial.print(code);
Serial.print(” vs “);
Serial.println(worldtag[6]);

}
}
bytesread = 0;
// wait for a second
}
}
else {
//digitalWrite(led1, LOW);
//blink(led2);
//blink(led3);
}
}

void quickBlink(int pin) {
digitalWrite(pin, HIGH);
delay(50);
digitalWrite(pin, LOW);
}

void blink(int pin) {
fadeIn(pin);
delay(blinkDelayOn);
fadeOut(pin);
delay(blinkDelayOff);
}

void fadeIn(int pin) {
//Serial.println(pin);
for(int value = 0 ; value <= 255; value+=5) // fade in (from min to max) { analogWrite(pin, value); // sets the value (range from 0 to 255) delay(10); // waits for 30 milli seconds to see the dimming effect } } void fadeOut(int pin) { //Serial.println(pin); for(int value = 255; value >=0; value-=5) // fade out (from max to min)
{
analogWrite(pin, value);
delay(10);
}
}

void turnLampieOff() {
digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
digitalWrite(led3, LOW);
lampieOn = false;
Serial.println(“Lampie off”);
digitalWrite(2, HIGH); // deactivate RFID reader
delay(2000);
digitalWrite(rfidPin, LOW); // Activate the RFID reader
}
void turnLampieOn() {
noOwner = 0; // reset back to 0;
Serial.println(timer);
for (int i = 0; i < 3; i++) { quickBlink(led1); quickBlink(led2); quickBlink(led3); delay(200); } digitalWrite(led1, HIGH); // sets the LED on digitalWrite(led2, HIGH); digitalWrite(led3, HIGH); lampieOn = true; Serial.println("Lampie on"); digitalWrite(2, HIGH); // deactivate RFID reader delay(5000); digitalWrite(rfidPin, LOW); // Activate the RFID reader } void motionDetected() { //Serial.println("motion detected"); //digitalWrite(led2, HIGH); //the led visualizes the sensors output pin state if(lampieOn == false) { getExcited(); } } void noMotion() { //Serial.println("no motion"); //digitalWrite(led2, LOW); //the led visualizes the sensors output pin state } void getExcited() { blink(led1); blink(led2); blink(led3); } void allBlink() { quickBlink(led1); quickBlink(led2); quickBlink(led3); } void getAngry() { Serial.println("angry"); for (int i = 0; i < 3; i++) { allBlink(); delay(50); } } void getReallyAngry() { Serial.println("really angry"); for (int i = 0; i < 10; i++) { allBlink(); delay(50); } } [/sourcecode]