Making a Globe Interactive

This is the documentation for my final project.

I wrote a book with step-by-step instructions on how to make an interactive globe using conductive fabric.

Contents will also be uploaded to instructables.com

jpr_making_a_globe_interactive

Advertisements

Project – See, See

Get Arm here

Massive Arduino Code:

Note: this is for Arduino 0011’s servo library

————————————————————————————–

#include <Servo.h>

// base sweep range
int base_limit_low = 20;
int base_limit_high = 80;
int base_center = 50;

//shoulder sweep range
int shoulder_limit_low = 60; //foward
int shoulder_limit_high = 90; //back
int shoulder_center = 50;

//elbow sweep range
int elbow_limit_low = 60; //up
int elbow_limit_high = 90; //down
int elbow_center = 75;

//wrist sweep range
int wrist_limit_low = 10; //down
int wrist_limit_high = 90;//up
int wrist_center = 60;

//turn sweep range
int turn_limit_low = 30;  //CW
int turn_limit_high = 80; //CCW
int turn_center = 50;

//grip sweep range
int grip_close = 20; //close
int grip_open = 60; //open

//servo attatchments
Servo base; //analogue 0
Servo shoulder; //analogue 1
Servo elbow; //analogue 2
Servo wrist; //analogue 3
Servo turn; //analogue 4
Servo grip; //analogue 5

//joint positions
int base_pos;
int shoulder_pos;
int elbow_pos;
int wrist_pos;
int turn_pos;
int grip_pos;

//IR stuffs
int lowEnd = 90;
int IRsensor = 5;//analogue pin 5

//video stuffs
int cam1 = 1; //digital 1
int cam2 = 3; //digital 3
int cam3 = 5;  //digital 5
int flash = 250;//blink time
boolean coin = false; //flash counter

//misc
int increment = 1; //degree increment for the servos
int sweep_direction_base = 1; //directional tokens
int sweep_direction_shoulder = 1;
int sweep_direction_elbow = 1;
int sweep_direction_wrist = 1;
int sweep_direction_turn = 1;
int sweep_direction_grip = 1;
boolean reset = false; //reset token
int pulse1 = 30;
int pulse2 = 50;
int reset_time = 5000; //initial reset time
unsigned long time;

void setup()
{
base.attach(14); //analog pin 0
shoulder.attach(15); //analog pin 1
elbow.attach(16); //analog pin 2
wrist.attach(17); //analog pin 3
turn.attach(18); //analog pin 4
//grip.attach(19); //analog pin 5

base.setMaximumPulse(2200); //set max pulse
shoulder.setMaximumPulse(2200); //set max pulse
elbow.setMaximumPulse(2200); //set max pulse
wrist.setMaximumPulse(2200); //set max pulse
turn.setMaximumPulse(2200); //set max pulse
Serial.begin(9600);

//initialize joint positions
base_pos = base_center;
shoulder_pos = shoulder_center;
elbow_pos = elbow_center;
turn_pos = turn_center;
wrist_pos = wrist_center;
//grip_pos = grip_open;

//cameras
pinMode(cam1, OUTPUT); //arm cam
pinMode(cam2, OUTPUT);
pinMode(cam3, OUTPUT);
}

void loop()
{
time = millis();
if(reset == false)
{
while(time<reset_time)
{
reset_all();
time = millis();
}
reset = true;
}

int val = readVal(IRsensor);// read in IR
//Serial.println(val);
//sweep_all();

int i = time % flash;
Serial.println(i);

if(isValid(val)) //if in proximity
{
freezeALL();

if((time % 5) == 0) //mod for the flshing so it won’t interfere with the arm
{
Serial.println(“flash mode”);
flsh_mode();
}
}
else //not in proximity
{
digitalWrite(cam1, HIGH); //default camera setup
digitalWrite(cam2, LOW);
digitalWrite(cam3, LOW);

sweep_all(); //do the sweep with the arm
}
}

///////////////RESET FUNCTIONS
void reset_all()
{
base_reset();
//delay(250);
shoulder_reset();
// delay(250);
elbow_reset();
//delay(250);
wrist_reset();
// delay(250);
turn_reset();
//delay(250);
grip_reset();

delay(pulse1);
Servo::refresh();
}

void base_reset()
{
base.write(base_center);
Servo::refresh();
}

void shoulder_reset()
{
shoulder.write(shoulder_center);
Servo::refresh();
}

void elbow_reset()
{
elbow.write(elbow_center);
Servo::refresh();
}

void wrist_reset()
{
wrist.write(wrist_center);
Servo::refresh();
}

void turn_reset()
{
turn.write(turn_center);
Servo::refresh();
}

void grip_reset()
{
grip.write(grip_open);
Servo::refresh();
}

//////////// SWEEP FUNCTIONS
void sweep_all()
{
base_sweep();
delay(pulse1);
Servo::refresh();

shoulder_sweep();
delay(pulse1);
Servo::refresh();

elbow_sweep();
delay(pulse1);
Servo::refresh();

wrist_sweep();
delay(pulse1);
Servo::refresh();

turn_sweep();
delay(pulse1);
Servo::refresh();
}

void base_sweep()
{
if(base_pos <= base_limit_low)
{
sweep_direction_base = 1; //go east
//delay(pulse2);
}
if(base_pos >= base_limit_high)
{
sweep_direction_base = -1; //go west
//delay(pulse2);
}
if(sweep_direction_base == 1) //east
{
base_pos = base_pos+increment;
base.write(base_pos);
}
if(sweep_direction_base == -1) //west
{
base_pos = base_pos-increment;
base.write(base_pos);
}
}

void shoulder_sweep()
{
if(shoulder_pos <= shoulder_limit_low)
{
sweep_direction_shoulder = 1; //go up
//delay(pulse2);
}
if(shoulder_pos >= shoulder_limit_high)
{
sweep_direction_shoulder = -1; //go down
//delay(pulse2);
}
if(sweep_direction_shoulder == 1) //up
{
shoulder_pos = shoulder_pos+increment;
shoulder.write(shoulder_pos);
}
if(sweep_direction_shoulder == -1) //down
{
shoulder_pos = shoulder_pos-increment;
shoulder.write(shoulder_pos);
}
}

void elbow_sweep()
{
if(elbow_pos <= elbow_limit_low)
{
sweep_direction_elbow = 1; //go up
//delay(pulse2);
}
if(elbow_pos >= elbow_limit_high)
{
sweep_direction_elbow = -1; //go down
//delay(pulse2);
}
if(sweep_direction_elbow == 1) //up
{
elbow_pos = elbow_pos+increment;
elbow.write(elbow_pos);
}
if(sweep_direction_elbow == -1) //down
{
elbow_pos = elbow_pos-increment;
elbow.write(elbow_pos);
}
}

void wrist_sweep()
{
if(wrist_pos <= wrist_limit_low)
{
sweep_direction_wrist = 1; //go up
//delay(pulse2);
}
if(wrist_pos >= wrist_limit_high)
{
sweep_direction_wrist = -1; //go down
//delay(pulse2);
}
if(sweep_direction_wrist == 1) //up
{
wrist_pos = wrist_pos+increment;
wrist.write(wrist_pos);
}
if(sweep_direction_wrist == -1) //down
{
wrist_pos = wrist_pos-increment;
wrist.write(wrist_pos);
}
}

void turn_sweep()
{
if(turn_pos <= turn_limit_low)
{
sweep_direction_turn = 1; //go up
//delay(pulse2);
}
if(turn_pos >= turn_limit_high)
{
sweep_direction_turn = -1; //go down
//delay(pulse2);
}
if(sweep_direction_turn == 1) //up
{
turn_pos = turn_pos+increment;
turn.write(turn_pos);
}
if(sweep_direction_turn == -1) //down
{
turn_pos = turn_pos-increment;
turn.write(turn_pos);
}
}

//freeze arm at the current position
void freezeALL()
{
shoulder.write(shoulder_pos);
//Servo::refresh();
elbow.write(elbow_pos);
//Servo::refresh();
wrist.write(wrist_pos);
//Servo::refresh();
turn.write(turn_pos);
//Servo::refresh();
base.write(base_pos);
delay(pulse1);
Servo::refresh();
}

/////////////////////////////////IR stuff
int readVal(int sensorNum) //mass sampling to blur out noise
{
int val = analogRead(sensorNum);
val+= analogRead(sensorNum);
val+= analogRead(sensorNum);
val+= analogRead(sensorNum);
val+= analogRead(sensorNum);
val = val/5;
return(val);
}

boolean isValid(int input) //check to see if something is in proximity
{
if(input>lowEnd)
{
Serial.println(“true”);
return true;
}
else
{
Serial.println(“false”);
return false;
}
}

////////////////////// camera control
void flsh_mode()
{
if(coin == false) //all off
{
digitalWrite(cam1, LOW);
digitalWrite(cam2, LOW);
digitalWrite(cam3, LOW);
coin = true; //flip
Serial.println(“flash mode 1”);
}
else //all on
{
digitalWrite(cam1, HIGH);
digitalWrite(cam2, HIGH);
digitalWrite(cam3, HIGH);
coin = false; //flip
Serial.println(“flash mode 2”);
}
}

Memory game

For the first project, I created a game that would play a pattern of LEDs, which the user would then have to replicate by pressing the corresponding buttons.  If the user successfully completed the task, the LEDs would flash to show the user has won.  I tried to implement a randomizer to create a new pattern each time, but it didn’t end up working so for now there is only one pattern of lights for the user to play.

Code:

int red = 11;                 // red LED connected to digital pin 11
int blue = 12;                // blue LED connected to digital pin 12
int green = 13;              // green LED connected to digital pin 13
int redButton = 2;          // button for red LED connected to pin 2
int blueButton = 3;          // button for blue  LED connected to pin 3
int greenButton = 4;        // button for green LED connected to pin 4
int val1 = 0;
int val2 = 0;
int val3 = 0;
int prev1 = LOW;
int prev2 = LOW;
int prev3 = LOW;
long time = 0;
long debounce = 200;

boolean playing = false;
boolean won;

long num1;
long num2;
long num3;
long num4;
long num5;

void setup()
{
pinMode(red, OUTPUT);      // sets the LED pins as output
pinMode(blue, OUTPUT);
pinMode(green, OUTPUT);
pinMode(redButton, INPUT);  //sets the button pins as input
pinMode(greenButton, INPUT);
pinMode(blueButton, INPUT);
}

//set up play pattern array
int pattern[]={
red,blue,blue,green,red};
int results[]={
};

void loop()
{
if (playing==false){
playPattern();
playing=true;
}
else {
playerTurn();
}

/* TEST LEDS CODE
if(val1==LOW) {
digitalWrite(red, HIGH);
} else {
digitalWrite(red, LOW);
}

if(val2==LOW) {
digitalWrite(blue, HIGH);
} else {
digitalWrite(blue, LOW);
}

if(val3==LOW) {
digitalWrite(green, HIGH);
} else {
digitalWrite(green, LOW);
}
*/
}

void playPattern()
{
digitalWrite(pattern[0], HIGH);   // sets the LED on
delay(1000);                  // waits for a second
digitalWrite(pattern[0], LOW);    // sets the LED off
delay(500);
digitalWrite(pattern[1], HIGH);
delay(1000);                  // waits for a second
digitalWrite(pattern[1], LOW);
delay(500);
digitalWrite(pattern[2], HIGH);
delay(1000);
digitalWrite(pattern[2], LOW);
delay(500);
digitalWrite(pattern[3], HIGH);
delay(1000);
digitalWrite(pattern[3], LOW);
delay(500);
digitalWrite(pattern[4], HIGH);
delay(1000);
digitalWrite(pattern[4], LOW);
delay(500);
digitalWrite(pattern[5], HIGH);
delay(1000);
digitalWrite(pattern[5], LOW);
delay(1000);
}

void playerTurn()
{
for(int i=0; i<5; i++) {

val1 = digitalRead(redButton);
val2 = digitalRead(greenButton);
val3 = digitalRead(blueButton);

if(val1==HIGH && prev1==LOW && millis() – time > debounce) {
//red was pressed
digitalWrite(red, HIGH);   // sets the LED on
delay(500);                  // waits for a second
digitalWrite(red, LOW);    // sets the LED off
results[i]=red;
time = millis();
}
if(val2==HIGH && prev2==LOW && millis() – time > debounce) {
//green was pressed
digitalWrite(green, HIGH);   // sets the LED on
delay(500);                  // waits for a second
digitalWrite(green, LOW);    // sets the LED off
results[i]=green;
time = millis();
}
if(val3==HIGH && prev3==LOW && millis() – time > debounce) {
//blue was pressed
digitalWrite(blue, HIGH);   // sets the LED on
delay(500);                  // waits for a second
digitalWrite(blue, LOW);    // sets the LED off
results[i]=blue;
time = millis();
}
prev1=val1;
prev2=val2;
prev3=val3;
}

for(int j=0; j<5; j++) {
if (pattern[j] != results[j]) {
won=false;
}
}

if (won==false) {
//play pattern again
}
else {
//flash lights
for(int k=0; k<5; k++) {
digitalWrite(red, HIGH);   // sets the LED on
digitalWrite(green, HIGH);    // sets the LED on
digitalWrite(blue, HIGH);    // sets the LED on
delay(100);                  // waits for a second
digitalWrite(red, LOW);    // sets the LED off
digitalWrite(green, LOW);    // sets the LED off
digitalWrite(blue, LOW);      // sets the LED off
delay(100);                  // waits for a second
}
}

}

Free Fall Elevator

So yeah, wasn’t really supposed to be the free fall elevator, but thats what it became. My very original idea was to make a catapult, and the point of the arduino was to note that a load was present, make the motor pull back the arm, check that there was still a load, and release the arm to fire. I also wanted to try and map the amount of pull to a distance of load travel, so that the user could tell it how far to launch something. Where did I go wrong?

Basically, the motors weren’t strong enough to pull against almost any of my springs. So idea gets re-designed.

So next I decided to make an elevator, where the user could tell the elevator to go to a specific floor, and the elevator would respond accordingly. There would be levels of state and response. For example, if you told the elevator to go to its current floor, it would ding and light up that floor’s LED. If you told it to go to another floor, it would light up the new floor’s LED and say whether it was going up or down. Since it knew where it was, it knew how far to go, whether it was going up/down one/two floors. Where did I go wrong?

Basically, it took me way too long to get to this idea, and I had a major malfunction during the night that brought the project to a halt. When this happened, I had built the elevator, and had made the elevator motors capable of both forward and reverse. Then I had just programmed the up and down buttons when my computer crapped out.

Below are some photos and the code. Obviously the code isn’t the final product, but what I had when I had to stop.

 

Here is my code:
 
int motorPinA = 8;                // LED connected to digital pin 13
int motorPinC = 9;
int motorPinB = 10;
int motorPinD = 11;
int signalPinUp = 3;
int signalPinDown = 2;
int valUp = HIGH;
int valDown = HIGH;

 
void setup()                    // run once, when the sketch starts
{
  pinMode(motorPinA, OUTPUT);      // sets the digital pin as output
  pinMode(motorPinB, OUTPUT);
  pinMode(motorPinC, OUTPUT);
  pinMode(motorPinD, OUTPUT);
  pinMode(signalPinUp, INPUT);
  pinMode(signalPinDown, INPUT);
  //Serial.begin(9600);
 
}
 
void runUp() {
  digitalWrite(motorPinA, HIGH);   // sets motor to forward
  digitalWrite(motorPinB, LOW);
  digitalWrite(motorPinC, LOW);
  digitalWrite(motorPinD, HIGH);
}
 
void runDown() {
  digitalWrite(motorPinA, LOW); 
  digitalWrite(motorPinB, HIGH);
  digitalWrite(motorPinC, HIGH);
  digitalWrite(motorPinD, LOW);  
}
 
 
void loop()                     // run over and over again
{
  valUp = digitalRead(signalPinUp);  // read input value
  valDown = digitalRead(signalPinDown);
  //Serial.println(val);
  if (valUp == HIGH && valDown == HIGH) {
  digitalWrite(motorPinA, LOW);    // sets motor to reverse
  digitalWrite(motorPinB, LOW);
  digitalWrite(motorPinC, LOW);
  digitalWrite(motorPinD, LOW);    
  }
  
  if (valUp == LOW) {
    runUp();
    valUp = HIGH;
    valDown = HIGH;  
  }
  if (valDown == LOW) {
    runDown();
    valUp = HIGH;
    valDown = HIGH;
  }
}

Interactive Tigger

about the project: interactive-tigger

code:

// Tigger Hide and Seek
// by Jason Read
int play = 12;       // choose the pin for the play pause function
int skip = 8;        // chose the pin for the skip function
int back = 10;       // chose the pin for the back function
int repeat1 = 0;     // keeps track from repeating
int repeat2 = 0;     // keeps track from repeating
int repeat3 = 0;     // keeps track from repeating
int repeat4 = 0;     // keeps track from repeating
int interactions = 0;        // keeps track of interactions
void setup() {
Serial.begin(9600); // connect to the serial port
pinMode(play, OUTPUT);      // sets the digital pin as output
pinMode(skip, OUTPUT);      // sets the digital pin as output
pinMode(back, OUTPUT);     // sets the digital pin as output
pinMode(0, INPUT);      // sets the digital pin as output
}

void loop() {
 
char flag = 1; 
int  val = 0;
char code[10];
int bytesread = 0;
char target [][10] = {{0,0,’1′,’5′,’0′,’0′,’D’,’0′,’2′,’A’},
                      {0,0,’1′,’5′,’0′,’0′,’D’,’0′,’3′,’A’},
                      {0,0,’1′,’5′,’0′,’0′,’C’,’F’,’D’,’B’},
                      {0,0,’1′,’5′,’0′,’0′,’D’,’0′,’1′,’4′}};
                     
                          

if(interactions == 0) {
  Serial.print(“introduction”);
  interactions = 1;                       // inhibits repetition                         
  digitalWrite(play,HIGH);                // hits play
  delay(375);                              // waits for a second
  digitalWrite(play,LOW);                 // stops pushing play
  delay(375);
  digitalWrite(play,HIGH);                // hits play
  delay(375);                              // waits for a second
  digitalWrite(play,LOW);                 // stops pushing play
  delay(2000);                            // delays program until sounds program is finished
  digitalWrite(play,HIGH);                // hits pause
  delay(375);                              // waits for a second
  digitalWrite(play,LOW);                 // stops pushing pause
  delay(875);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
}

if(interactions == 4) {
  Serial.print(“Finale”);
  delay(500);
  interactions = 1;                       // inhibits repetition
  repeat4 = 1;                            // inhibits repetition
    digitalWrite(skip,HIGH);                // skips a track
  delay(375);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(375);                              // waits for a second
  digitalWrite(skip,HIGH);                // skips a track
  delay(375);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(375);                              // waits for a second
  digitalWrite(skip,HIGH);                // skips a track
  delay(375);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(375);                              // waits for a second
  digitalWrite(skip,HIGH);                // skips a track
  delay(375);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(375);                              // waits for a second
  digitalWrite(play,HIGH);                // hits play
  delay(375);                              // waits for a second
  digitalWrite(play,LOW);                // stops pushing play
  delay(13900);                            // delays program until sounds program is finished
  digitalWrite(play,HIGH);                // hits play
  delay(275);                              // waits for a second
  digitalWrite(play,LOW);                // stops pushing pause
  delay(575);
  digitalWrite(skip,HIGH);                // hits back
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing back
  delay(575);
  digitalWrite(skip,HIGH);                // hits back
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing back
  delay(575);
  digitalWrite(skip,HIGH);                // hits back
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing back
  repeat1 = 0;
  repeat2 = 0;
  repeat3 = 0;
  repeat4 = 0;
  interactions = 1;
  delay(10000);
}
 
  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          
          bytesread++;                   // ready to read next digit 
        }
      }
      if(bytesread == 10) {              // if 10 digit read is complete
//        Serial.print(“TAG code is: “);   // possibly a good TAG
//        Serial.println(code);            // print the TAG code //
      }
      bytesread = 0;
    }
  }
  for (int i=2;i<10 && flag==1;i++)
    if(code[i]!=target[0][i])
     flag = 0;
    
     if(flag==1 && repeat1==0) {
     Serial.print(“interaction 1 “);
  repeat1 = 1;                            // inhibits repetition
  digitalWrite(skip,HIGH);                // skips a track
  delay(375);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(375);                              // waits for a second
  digitalWrite(play,HIGH);                // hits play
  delay(175);                              // waits for a second
  digitalWrite(play,LOW);                // stops pushing play
  delay(13750);                            // delays program until sounds program is finished
 digitalWrite(play,HIGH);                // hits play
  delay(175);                              // waits for a second
  digitalWrite(play,LOW);                // stops pushing play
  delay(875);                            // delays program until sounds program is finished
  digitalWrite(skip,HIGH);                // hits skip
  delay(475);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(475);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(475);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(475);
  digitalWrite(skip,HIGH);                // hits skip
  delay(475);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(475);
  digitalWrite(skip,HIGH);                // hits skip
  delay(475);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(875);
  interactions = interactions + 1;
     }
    
flag = 1;
    
    for (int i=2;i<10 && flag==1;i++)
    if(code[i]!=target[1][i])
     flag = 0;

     if(flag==1 && repeat2==0) {
     Serial.print(“Interaction 2”);
  repeat2 = 1;                            // inhibits repetition
  digitalWrite(skip,HIGH);                // skips a track
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);                              // waits for a second
  digitalWrite(skip,HIGH);                // skips a track
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(375);                              // waits for a second
  digitalWrite(play,HIGH);                // hits play
  delay(175);                              // waits for a second
  digitalWrite(play,LOW);                // stops pushing play
  delay(6500);                            // delays program until sounds program is finished
  digitalWrite(play,HIGH);                // hits pause
  delay(175);                              // waits for a second
  digitalWrite(play,LOW);                // stops pushing pause
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  interactions = interactions + 1;
     }
    
flag = 1;
    
  for (int i=2;i<10 && flag==1;i++)
    if(code[i]!=target[2][i])
     flag = 0;
 
     if(flag==1 && repeat3==0) {
  Serial.print(“Interaction 3”); 
  repeat3 = 1;                            // inhibits repetition
  digitalWrite(skip,HIGH);                // skips a track
  delay(375);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);                              // waits for a second
  digitalWrite(skip,HIGH);                // skips a track
  delay(375);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(375);     
  digitalWrite(skip,HIGH);                // skips a track
  delay(375);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);                              // waits for a second
  digitalWrite(skip,HIGH);                // skips a track
  delay(375);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(375);     
  digitalWrite(play,HIGH);                // hits play
  delay(175);                              // waits for a second
  digitalWrite(play,LOW);                // stops pushing play
  delay(13000);                            // delays program until sounds program is finished
  digitalWrite(play,HIGH);                // hits pause
  delay(575);                              // waits for a second
  digitalWrite(play,LOW);                // stops pushing pause
  delay(675);
  digitalWrite(skip,HIGH);                // hits back
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing back
  delay(675);
  digitalWrite(skip,HIGH);                // hits back
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing back 
  delay(800);
  interactions = interactions + 1;
     }

flag = 1;

    for (int i=2;i<10 && flag==1;i++)
    if(code[i]!=target[3][i])
     flag = 0;

     if(flag==1 && repeat4==0) {
       repeat4 = 1;
  Serial.print(“introduction”);
  interactions = 1;                       // inhibits repetition
  digitalWrite(play,HIGH);                // hits play
  delay(375);                              // waits for a second
  digitalWrite(play,LOW);                 // stops pushing play
  delay(375);
  digitalWrite(play,HIGH);                // hits play
  delay(375);                              // waits for a second
  digitalWrite(play,LOW);                 // stops pushing play
  delay(2000);                            // delays program until sounds program is finished
  digitalWrite(play,HIGH);                // hits pause
  delay(375);                              // waits for a second
  digitalWrite(play,LOW);                 // stops pushing pause
  delay(875);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  delay(575);
  digitalWrite(skip,HIGH);                // hits skip
  delay(575);                              // waits for a second
  digitalWrite(skip,LOW);                 // stops pushing skip
  repeat1 = 0;
  repeat2 = 0;
  repeat3 = 0;
  repeat4 = 0;
  interactions = 0;
  delay(5000);
     }
 
  if (bytesread>0)
     Serial.print(“it wasn’t any”);
 
}

Sense glove

 

Fingerless glove with adjustable proximity dector

Fingerless glove with adjustable proximity dector

This is an investigation of how we might use interactive technology to extend our senses. I mounted the Arduino (with mini project board) on a wrist brace, along with an ultrasonic range-finder, a custom-built flexible rotary input device, a thermistor (embedded on the inside), an LED, a piezo element and a small pager buzzer. In addition, a thermistor (mounted in soft foam) was connected by a length of flexible cable so that it could be placed in the wearer’s armpit. The Arduino was programmed to periodically “chirp” the piezo with two tones corresponding to the levels of the wearer’s core (armpit) and distal (hand) temperatures. Secondly, when the range-finder detects an object closer than the distance set by the rotary input device, the pager buzzer vibrates and an LED lights up.

 

Sensors and Arduino mounted on a wrist brace.

Sensors and Arduino mounted on a wrist brace.

My first goal was to mount all of the hardware on the glove so that the user experience was unencumbered by any tethering to external components such as the Arduino or battery pack. This required building mounting brackets for the Arduino and battery pack out of popsicle sticks and twine. The mini project board was mounted to the top of the Arduino using another stick to support one side. That stick was further used as a strain-relief for some of the wires, and as a mounting platform for two RJ-11 jacks (salvaged from small inline DSL filters). The rangefinder and rotary input device were fitted with RJ-11 plugs on short tails so they could be securely connected but easily detached. The thermistor was threaded into a channel on the inside of the wrist (which previously held a metal stiffener) and fed through a slit, then sewn into the inside of the glove. The pager buzzer was inserted into the same channel and both sets of wires were run along the outside of the glove to the project board. The rangefinder was glued and wired to a stiff piece of plastic with velcro on the back, to mate with the existing velcro covering the back of the glove. The rotary input device (a small potentiometer with a short length of flexible rubber tubing slid over the knob) was mounted to a clothespin so it could be clipped into position and adjusted until the end was just in reach of the wearer’s fingers.

Glove mount for Arduino and battery pack
RJ-11 jacks

Glove mount for Arduino and battery pack (above) and RJ-11 jacks

While this configuration allowed the hardware to be fully mounted on the glove, there were several lessons learned:

  • wires must be run so that they allow full movement, including opening and closing the item; in this case, that was complicated by the way the Arduino was mounted on the strap, which ran through grommets so that the apparent length of the strap changed as it was pulled tight. However, if the wires at least ran in the same direction as the strap, it could have been fully loosened without detaching the wires. As it was, I ran the wires in the opposite direction, so there was barely enough slack to loosen the strap enough to remove my hand.
  • comfortable wearables demand much smaller/lighter components, and would benefit from embedded wiring so you can move freely without fear of everything falling apart–ideally the user is thinking about the function of the item, not the implementation.
  • RJ-11 connectors are a little bulky for wearables, but it’s easy to find extension cables; perhaps these connectors are better used for household installations (for example, I don’t use any land-line phones in my house, so the in-wall phone wiring could be used for other purposes, such as a one-wire network.)
  • (and on a related topic) RJ-11 connectors are not consistent about the position of different colors of wire.
range-finder (upper left), Arduino (upper right), and rotary input

Side view: range-finder (upper left), Arduino (upper right), and rotary input

The range-finder presented some challenges when I first began communicating with it through the Arduino. While I could detect objects placed with a few inches of the device, once it was more than about 6 inches away from the nearest object it consistently reported the same distance. Eventually I concluded that the receiver must be “hearing” the transmitter directly, without the signal first bouncing off of any object. I placed a small piece of open-cell foam between the two ultrasonic elements and extending approximately 1/2″ beyond the ends of those elements, which solved the problem. I also had intermittent trouble with the thermistors; the one mounted in the glove seemed to occasionally lose contact with the wearer’s hand (causing a temperature drop), and might have benefitted from some foam placed behind it in the channel to maintain pressure (though this might have caused discomfort if it pressed too hard on the wrong part of the wrist). The thermistor in the armpit sometimes seemed to give erratic readings, which I suspect may have been caused by perspiration on the wearer’s skin shorting the conductors and lowering the resistance. The foam thermistor mount was also a little to thick, and could be uncomfortable in the armpit; again, wearable devices place a high premium on small form-factor.

Schematic

Schematic

Another challenge was how to get enough information to the user through ambient buzzing and beeping. The pager buzzer was supposed to buzz more strongly as it detected objects closer to the glove, but it was difficult to perceive the different levels of buzzing, so the rotary input was used to set a minimum distance threshold. I believe that modulating the buzzer and mapping distance to the rate of buzzing would have been easier to interpret, but I did not test this theory. Similarly, the core-distal chirping did not succeed at giving clear feedback about the relative temperature of the two sensed points. It’s possible that mapping a smaller temperature range to a larger tonal range would make it easier to detect different conditions (chiefly, out-of-norms conditions like too-cold hands). Additionally, since the core temperature is unlikely to change (unless the wearer is getting sick), the tone or tones could simply indicate the difference between core and distal temperatures. Perhaps the first tone could be set to a pre-calibrated “normal” difference, an the second tone could indicate the current difference. Also, mounting the distal temperature sensor on a fingertip rather than the wrist might have exposed it to greater fluctuations and produced a more sensitive indicator, but it seemed awkward to mount on a fingerless “glove”. Perhaps a short study with armpit, wrist, and fingertip temperature sensors could be conducted to establish the relationship between the three.

Thermistor in foam block (aprox. 1"x1"x4") for armpit-mounting

Thermistor in foam block (aprox. 1

 

 

You will be sensed...

You will be sensed...

The clearest conclusion from this project is that walking around with a small computer, numerous wires, and assorted strange-looking hardware strapped to one’s wrist and beeping at regular intervals–basically, your typical cyborg getup–is a good conversation-starter. However, it was not clear from the beginning of the project exactly what extra-sensory information was needed and how it would be used, so the project was more of a guided exploration of several interesting pieces of hardware and programming notions.

View sense_glove code for Arduino

Wearable Alarm Clock

In this project, I worked on a shirt that also acts are your alarm clock. The motivation behind it was I wanted to create an alarm clock that is not so easy to get rid of in the morning. If alarm clock is embedded in your clothing, hopefully it will “alarm” you more in the morning and also be harder to get rid of.

 

I used 12 button keypad to set the time duration until alarm sets off, and used buzzer + vibrator as the output device. Biggest challenge I had was trying to figure out the 12 button keypad input, because the documentation provided online wasn’t consistent with the device I used.  

Photos:

 

 

Here’s the code I used:

 

/*

 * Author: Sungjoon Steve Won (stevewon@gmail.coM)

 */

 

//Pin indicator for the keypad matrix

int row1 = 10;

int row2 = 7;

int row3 = 8;

int row4 = 9;

int col1 = 12;

int col2 = 13;

int col3 = 11;

 

//Variables declared to deal with keypad input

int val1 = 0;

int val2 = 0;

int val3 = 0;

int val4 = 0;

int val5 = 0;

int val6 = 0;

int val7 = 0;

 

 

int vibratorPin = 2; //output pin for vibrator

int buzzerPin = 3; //output pin for buzzer

int ledPin = 4; //pin for LED

 

//Other indicators

int alarmOff = 0; //If set to 1, alarm should go off

int setAlarmNext = 0; //If set to 1, set alarm next time loop comes around

 

void setup() {

  pinMode(row1, INPUT);

  pinMode(row2, INPUT);  

  pinMode(row3, INPUT);  

  pinMode(row4, INPUT);     // declare pushbutton as input

  pinMode(col1, OUTPUT);

  pinMode(col2, OUTPUT);  

  pinMode(col3, OUTPUT);  

 

  pinMode(buzzerPin, OUTPUT); //Buzzer pin

  Serial.begin(9600);

 

}

 

void loop(){

  int thisKey = getKey(); //Detect input from keypad

 

 

  if (thisKey == 10) { //If input if “*”, use it to set Alarm.

 

    digitalWrite(ledPin, HIGH);   // sets the LED on

    delay(1000);                  // waits for a second

    digitalWrite(ledPin, LOW);    // sets the LED off

    delay(1000);                  // waits for a second

 

    setAlarmNext = 1;

    Serial.println(“3”);

 

    thisKey = getKey();

    int alarmDuration = thisKey * 1000; //For the purposes of demonstration, make alarm keypad number seconds

    delay(alarmDuration); 

 

    int wakeUpSteps = 10; //steps used to determine how strong wake-up alerts should be

    do {

      wakeUp(wakeUpSteps);

      thisKey = getKey();

      wakeUpSteps–; //Make it stronger & faster next time

    }

    while (thisKey != 11);

    analogWrite(vibratorPin, 0); //turn off vibrator

 

 

    Serial.println(“2”);   

   }

}

 

//Function that calls buzz and vibrate functions.

void wakeUp(int stepNum) {

    if (stepNum <= 1) {

      analogWrite(vibratorPin, (2000));  //Vibrate 

      buzz(buzzerPin, 2500, 500); // buzz the buzzer on pin 4 at 2500Hz for 1000 milliseconds

      delay(100); // 1 second delay

    }

    else {

      analogWrite(vibratorPin, (1000-stepNum*100));  //Vibrate 

      buzz(buzzerPin, 2500, 500); // buzz the buzzer on pin 4 at 2500Hz for 1000 milliseconds

      delay(stepNum*100); // 1 second delay

    }

}

 

 

//10 = *

//11 = #

int getKey() {

  digitalWrite(col1, HIGH);

  digitalWrite(col2, LOW);

  digitalWrite(col3, LOW);

 

 

  if (digitalRead(row1) == HIGH) {

     Serial.print(“Num 1\n”); 

     return 1;

  }

  if (digitalRead(row2) == HIGH) {

     Serial.print(“Num 4\n”); 

     return 4;

  }

  if (digitalRead(row3) == HIGH) {

     Serial.print(“Num 7\n”); 

     return 7;

  }

  if (digitalRead(row4) == HIGH) {

     Serial.print(“Num *\n”); 

     return 10;

  }

 

  digitalWrite(col1, LOW);

  digitalWrite(col2, HIGH);

  digitalWrite(col3, LOW);

 

 

  if (digitalRead(row1) == HIGH) {

     Serial.print(“Num 2\n”); 

     return 2;

  }

  if (digitalRead(row2) == HIGH) {

     Serial.print(“Num 5\n”); 

     return 5;

  }

  if (digitalRead(row3) == HIGH) {

     Serial.print(“Num 8\n”); 

     return 8;

  }

  if (digitalRead(row4) == HIGH) {

     Serial.print(“Num 0\n”); 

     return 0;

  }

 

 

  digitalWrite(col1, LOW);

  digitalWrite(col2, LOW);

  digitalWrite(col3, HIGH);

 

 

  if (digitalRead(row1) == HIGH) {

     Serial.print(“Num 3\n”); 

     return 3;

  }

  if (digitalRead(row2) == HIGH) {

     Serial.print(“Num 6\n”); 

     return 6;

  }

  if (digitalRead(row3) == HIGH) {

     Serial.print(“Num 9\n”); 

     return 9;

  }

  if (digitalRead(row4) == HIGH) {

     Serial.print(“Num #\n”); 

     return 11;

  }

 

  digitalWrite(col1, LOW);

  digitalWrite(col2, LOW);

  digitalWrite(col3, LOW);

 

  return -1;

}

 

//Imported from http://rob.faludi.com/itp/arduino/buzzer_example.pde

void buzz(int targetPin, long frequency, long length) {

  long delayValue = 1000000/frequency/2; // calculate the delay value between transitions

  //// 1 second’s worth of microseconds, divided by the frequency, then split in half since

  //// there are two phases to each cycle

  long numCycles = frequency * length/ 1000; // calculate the number of cycles for proper timing

  //// multiply frequency, which is really cycles per second, by the number of seconds to 

  //// get the total number of cycles to produce

 

  for (long i=0; i < numCycles; i++){ // for the calculated length of time…

    digitalWrite(targetPin,HIGH); // write the buzzer pin high to push out the diaphram

    delayMicroseconds(delayValue); // wait for the calculated delay value

    digitalWrite(targetPin,LOW); // write the buzzer pin low to pull back the diaphram

    delayMicroseconds(delayValue); // wait againf or the calculated delay value

  }

}