Interactive Desktop Robot

At last, the robot is in full swing, or rather poke. I worked on the code to slow down it’s movement, remove it’s awkward lifting-up, and allow it to search for missed keys. I documented the robot and its interaction in a video. I also considered that the part of the project most useful to future students is how to read an angle from a servo motor, so a made a special tutorial for how modify a servo for that too.

Video and source code here

Toturial here

Proposal for Desktop Coworker

Objective:
Robots traditionally exist in the workplace strictly in the subordinate service of humans. The objective of this project is to create a small robot that fulfills a workplace role of coworker, capable of working alongside its human counterparts. Like real colleagues, this robotic coworker should be capable of accomplishing tasks (or at least appearing to), but may also be susceptible to distractions.
 
Approach:
Create a arm-like robot that sits at a desk and types on a computer keyboard. The robot occasionally looks up and stares at interesting things. Arduino will control three servo motors to position the robot, relative to positions sent from processing. Processing will receive a signal directly from a web camera mounted to the end of the “arm” and process the image, as well as verify input on the keyboard. Interesting distractions will be determined as points of high contrast and/or intensely-moving things.

Sketch + Diagram:

Precedents:
Double-Taker (Snout) by Golan Levin. A rooftop robot arm “looks at” visitors entering the Pittsburgh center of the arts. 

ASIMO Robot by Honda. Robot intended to be a humanoid aid in the workplace.

Typing Robot by “pacoliketaco” (alias). Typing robot based on cartesian axis positioning.

Skills List:
– Control multiple servo motors from an arduino
– Use trigonometry to dynamically position the end of the arm in 3D space
– Control Arduino through serial signals from Processing
– Create a virtual internal representation of the physical robot
– Use image processing to determine points of interest
– Move three-dimensionally, based on a 2-D image coordinate and the known 3-D position and angle of the camera

Parts list:
– 3 servo motors capable of supporting moderate torque.
– Macally Portable Goose Neck USB Video Web Cam (currently on order)
– piano wire and tubing for frame

Minimum Conditions:
– Robot capable of typing gibberish on a keyboard.
– Robot looks up in an arbitrary direction to simulate distraction.

Maximum Condition:
– Robot capable of composing legible text on a keyboard.
– Robot looks around for moving and shinny things.

Week 1:
– Spec and order motors
– create scale diagram of robot
– calculate positioning algorithms
– start working on image processing using built-in camera

Week 2:
– Get arduino to control 3 servos simultaneously
– Assemble robot based on diagrams
– Write and test positioning code

Week 3:
– Write higher level control functions to press keys and look in a particular direction
– Write an auto-composing text program in processing (have some experience with this already)
– Test image processing with external camera

Week 4:
– Link the auto-composing text program with the robot to type words
– Program in periodic “distraction time” for robot
– Get robot to look at areas of interest

Servo Necktie

For this project, I wanted to create a device that would allow the user to silently show shock and surprise.

Vimeo video in the link below (WordPress won’t seem to let me imbed it).

Servo Operated Tie from Eamae Mirkin on Vimeo.
I soldered a small armature to fit inside a shirt collar, that holds the servo motor in place so that it can lift the tie. The tie is supported by a wire frame, shown connected to the servo with thin copper wide.


/*
* Servo Necktie.
*
* operates a servo motor based on input from a small
* trigger switch
*
*/

#include

// define three different modes
#define NEUTRAL 0
#define TRIGGER_OPEN 1
#define TIE_RAISED 2

// define time delays
#define TRIGGER_DELAY_DURATION_MS 100
#define TIE_RAISED_DURATION_MS 3000

// define tie angles
#define NEUTRAL_POS 180
#define RAISED_POS 40

Servo tieServo;           // initialize servo for tie;
int triggerPin = 2;       // Set the trigger switch to pin 2
int triggerState = LOW;   // The trigger state is defaulted to LOW;
int ledPin = 13;          // Set the led to pin 13

unsigned long timeStamp = 0; // sets the time stamp to zero seconds;
int mode = NEUTRAL;          // set the mode to NEUTRAL

void setup(){
pinMode(triggerPin, INPUT); // set the trigger pin to input
pinMode(ledPin, OUTPUT);

tieServo.attach(9);             // servo is connected to PWM pin 9
tieServo.setMinimumPulse(600);  // 0° = 600
tieServo.setMaximumPulse(2400); // 180° = 2400

//Serial.begin(9600);
//Serial.print("Ready");

}

void loop(){

switch(mode){
case NEUTRAL:
checkTrigger();
break;
case TRIGGER_OPEN:
waitForTriggerDelay();
break;
case TIE_RAISED:
waitForRaisedDuration();
break;
}

Servo::refresh();

}

void checkTrigger(){

//Serial.println("0");

triggerState = digitalRead(triggerPin); // read the trigger state
if(triggerState == HIGH){ // if the trigger is open
mode = TRIGGER_OPEN; // change the mode to trigger open
timeStamp = millis(); // reset the time stamp

//Serial.println("trigger is open");
digitalWrite(ledPin, HIGH);
}
else{
digitalWrite(ledPin, LOW);
}
}

void waitForTriggerDelay(){

//Serial.println(1);

triggerState = digitalRead(triggerPin); // read the trigger state
if(triggerState == LOW){ // if the trigger is cloaws again
mode = NEUTRAL; // set the mode back to neutral
}
else if(millis() > (timeStamp + TRIGGER_DELAY_DURATION_MS)){ // if the delay duration has elapsed since the time stamp was set
raiseTie(); // raise the tie
mode = TIE_RAISED; // change the mode to tie raised
timeStamp = millis(); // reset the time stamp
}
}

void waitForRaisedDuration(){

//Serial.println(2);

if(millis() > (timeStamp + TIE_RAISED_DURATION_MS)){
lowerTie();
mode = NEUTRAL;
}
}

void raiseTie(){
tieServo.write(RAISED_POS);
}

 

 

 

void lowerTie(){
tieServo.write(NEUTRAL_POS);
}

Sock Puppet

For this project I used a bend sensor to read the state of a sock puppet’s “mouth” and turn a motor accordingly to produce an acoustic noise to act as it’s voice.


/*
* Flex Sensor Puppet
*
* based on:
* AnalogInput by DojoDave
*
*
* http://www.arduino.cc/en/Tutorial/AnalogInput
*/

#define NUM_FLEX_READINGS 15

int flexPin = 2; // the analog input pin for the flex sensor
int gLEDPin = 3; // the pin for the green LED
int yLEDPin = 5; // the pin for the yellow LED

int motorPin = 6; // the pin for the transistor that activates the motor

int flexReadings[NUM_FLEX_READINGS];
int currentReadingIndex = 0;
int flexReadingsSum = 0;

int flexVal = 0; // variable to store the value coming from the flex sensor
int flexMin = 1019; // minimum flex sensor value
int flexMax = 1022; // maximum flex sensor value

void setup(){
pinMode(gLEDPin, OUTPUT); // declare the gLEDPin as an OUTPUT
pinMode(yLEDPin, OUTPUT); // declare the yLEDPin as an OUTPUT
pinMode(motorPin, OUTPUT); // declare the motorPin as an OUTPUT

for(int k=0; k< NUM_FLEX_READINGS; k++){
flexReadings[k] = 0; // init the flexReadings to 0;
}

digitalWrite(motorPin, LOW); // set the motor to off

//Serial.begin(9600); // begin serial communication via port 9600;
}

void loop(){
flexReadingsSum -= flexReadings[currentReadingIndex];
flexReadings[currentReadingIndex] = analogRead(flexPin); // read the value from the flex sensor
flexReadingsSum += flexReadings[currentReadingIndex];
currentReadingIndex++;

currentReadingIndex %= NUM_FLEX_READINGS;

flexVal = flexReadingsSum / NUM_FLEX_READINGS;

//Serial.println(flexVal); // print out the raw value of the flex sensor

flexVal = map(flexVal, flexMin, flexMax, 0, 255); // remap the flex value
flexVal = constrain(flexVal, 0, 255);

digitalWrite(gLEDPin, flexVal); // turn the gLEDPin on to represent the value
digitalWrite(yLEDPin, 255 - flexVal); // turn the yLEDPin on to represent the inverse

 

digitalWrite(motorPin, 255-flexVal); // turn on the motor proportional to the flex
}

Pants Switch

Imbedding  a switch into the button of a pair of pants.

The following code works in a circuit with two switches wired, but  I had some difficulty imbedding a switch within the zipper. The intent was to get a good estimate for when the user’s zipper or button is accidently left open.

 

/*

 * Pants Switch

 *

 * Reads two switches connected to the fly of a

   pair of pants, to approximate wether the user

   has accidently left his/her fly open. If fly is

   open (zipperDown) but the button is undone too,

   then the program assumes the user has conciously

   opened the fly. If only one is open, than the program

   assumes this is an accident. The program alerts the 

   user with a blinking LED.

 */

 

int buttonSwitchPin = 2;        // pants button switch connected to digital pin 2

int zipperSwitchPin = 3;        // pants zipper switch connected to digital pin 2

int ledPin = 13;                // LED connected to digital pin 13

 

boolean buttonUndone;           // state of the pants button

boolean zipperDown;             // state of the zipper

 

//long prevMillis = 0;            // stores the last millis value of the blinkLED function

long blinkInterval = 200;       // milliseconds per blink of the led

 

void setup(){                          // run once, when the sketch starts

  pinMode(buttonSwitchPin, INPUT);     // sets the digital pin as input

  pinMode(zipperSwitchPin, INPUT);     // sets the digital pin as input

  pinMode(ledPin, OUTPUT);             // sets the digital pin as output

 

}

 

void loop(){                           // run over and over again

  buttonUndone = (digitalRead(buttonSwitchPin) == HIGH);   // check if the pants button is open

  zipperDown = (digitalRead(zipperSwitchPin) == HIGH);     // check if the zipper is down

 

  if( buttonUndone != zipperDown){                         //check if the two states are dissimilar

    blinkLED();

  }

  else{

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

  }  

}

 

void blinkLED(){

  if(millis() % (2*blinkInterval) > blinkInterval){

    digitalWrite(ledPin, HIGH);

  }

  else{

    digitalWrite(ledPin, LOW);

  }

}