Saturday, March 10, 2012

The Head - Part 1


Some people have skeletons in their closet.  We had a mannequin head. While shopping for a halloween costume 2 or maybe even 3 years ago, there was a bin of styrofoam heads for sale.  At less than $3 it seemed like a worthwhile purchase... for some project... some day.

That day came last weekend.  This winter has been one of the warmest in years here in Calgary but warm winters in Calgary usually brings March snow... lots and lots of wet snow. And thats exactly what happened last weekend.  It was a perfect time to organize the bins of electronic parts I've been hoarding from previous projects and either sort them or use them.  Not sure how The Head made it's appearance but at some point that morning it was mentioned too.  Suddenly everything came together, figuratively speaking.


It was early on Sunday morning and we weren't sure if anything was going to come of this project but we had the basic idea to core out the styrofoam head, stick a webcam in the eye socket, and maybe light it up with some LED's. This project was fun because we had no real set goals... just to use up whatever parts there were laying around in whatever way seemed unique or interesting at the time.

2 lessons were learned during this project:
  1. Don't bother gluing a moving part to styrofoam - the styrofoam quickly tears away.
  2. Motion detection from the perspective of an object in motion is HARD. Instead, use object detection, shape detection, face detection (or even face recognition if possible).  If you're going to try motion detection, do it from a fixed perspective.
Parts used:
  • TMP36 temperature sensor $2
  • RGB LED (with common anode) $3
  • 2 x basic servos $10 each
  • Styrofoam head $3
  • 2 light up shoelaces $1.50 each
  • Arduino $30
  • Wire, solder, and heatshrink tubing
  • Original Logitech webcam $5
See the video at the top for the full build process but the next steps should prove even more interesting... Integrating it with the home automation system, linking to various services on our phones (not so much to 'control' the head but more to provide the head with more information), and giving it access to knowledge repositories such the open source Cyc project and other AI scripts.  Stay tuned!

Arduino Code if you're interested:
#include

#define aref_voltage 3.3 // we tie 3.3V to ARef and measure it with a multimeter!

int tmpInteger = 0;
Servo servoPan;
Servo servoTilt;
int temperature = 0;
char instruction;
boolean boolWaitingForInput;

//************* PINS *****************
//RGB LED with common-anode (CA)
//With CA, the led pin has constant 5v power, and the ground lead is tied to the digital i/o pin through a resistor,
//therefore you sink the digital pin to LOW, which effectively grounds the led and it lights up.
//Set the pin HIGH to turn it off.
//A common-cathode (CC) LED would work the reverse where digital i/o pin HIGH turns on the LED.
//Adafruit currently only sells the CA version of the RGB LED.
int redRGBPin = 4;
int greenRGBPin = 3;
int blueRGBPin = 2;
//2 standard servos
int servoPanPin = 9;
int servoTiltPin = 10;
//TMP36
int temperaturePin = 0;
//************************************

void setup() {
Serial.begin(9600);

pinMode(redRGBPin,OUTPUT);
pinMode(greenRGBPin, OUTPUT);
pinMode(blueRGBPin, OUTPUT);

digitalWrite(redRGBPin, HIGH); // all OFF (common anode: high=potential of 0v)
digitalWrite(greenRGBPin, HIGH);
digitalWrite(blueRGBPin, HIGH);

servoPan.attach(servoPanPin); // pan servo is on pin 9
servoTilt.attach(servoTiltPin); // tilt servo is on pin 10
servoPan.write(90); // home both servos to center
servoTilt.write(90); // home both servos to center

// If you want to set the aref to something other than 5v
analogReference(EXTERNAL);

//cycle through all possible eye colors
for(int i=LOW;i<=HIGH;i++){ digitalWrite(redRGBPin,i); delay(1000); for(int j=LOW;j<=HIGH;j++){ digitalWrite(greenRGBPin,j); delay(1000); for(int k=LOW;k<=HIGH;k++){ digitalWrite(blueRGBPin,k); delay(1000); } } } Serial.println("Head is ready."); Serial.println(); Serial.println("Commands you can use are:"); Serial.println(); Serial.println("Movement (l)eft"); Serial.println(" (r)ight"); Serial.println(" (u)p"); Serial.println(" (d)own"); Serial.println(" (h)ome resets head to center"); Serial.println(" (p)ositions for pan and tilt"); Serial.println("Eye color (0) off"); Serial.println(" (1) white"); Serial.println(" (2) aqua"); Serial.println(" (3) magenta"); Serial.println(" (4) yellow"); Serial.println(" (5) red"); Serial.println(" (6) green"); Serial.println(" (7) blue"); Serial.println("Senses (t)emperature"); Serial.println(); Serial.println("Followed by a . Note that multiple commands can be entered on a single line.");
Serial.println();
}

void loop() {
if( Serial.available() >= 1 ) { // byte waiting for us
boolWaitingForInput = false; //reset the flag to display the > prompt once the rx buffer is empty
instruction = Serial.read();
Serial.print("Received: [");
Serial.print(instruction);
Serial.println("]");
switch (instruction){
case 'l':
servoPan.write(servoPan.read() - 5);
break;
case 'r':
servoPan.write(servoPan.read() + 5);
break;
case 'u':
tmpInteger = servoTilt.read();
if (tmpInteger > 70) {
servoTilt.write(tmpInteger - 1); }
break;
case 'd':
tmpInteger = servoTilt.read();
if (tmpInteger < 110) { servoTilt.write(tmpInteger + 1); } break; case 'h': servoPan.write(90); // home both servos to center servoTilt.write(90); // home both servos to center break; case 'p': //servo positions Serial.print("Tilt servo: "); Serial.print(servoTilt.read()); Serial.println(" degrees."); Serial.print("Pan servo: "); Serial.print(servoPan.read()); Serial.println(" degrees."); break; case '0': //off digitalWrite(redRGBPin,HIGH); digitalWrite(greenRGBPin,HIGH); digitalWrite(blueRGBPin,HIGH); break; case '1': //white color digitalWrite(redRGBPin,LOW); digitalWrite(greenRGBPin,LOW); digitalWrite(blueRGBPin,LOW); break; case '2': //aqua color digitalWrite(redRGBPin,HIGH); digitalWrite(greenRGBPin,LOW); digitalWrite(blueRGBPin,LOW); break; case '3': //magenta color digitalWrite(redRGBPin,LOW); digitalWrite(greenRGBPin,HIGH); digitalWrite(blueRGBPin,LOW); break; case '4': //yellow color digitalWrite(redRGBPin,LOW); digitalWrite(greenRGBPin,LOW); digitalWrite(blueRGBPin,HIGH); break; case '5': //red color digitalWrite(redRGBPin,LOW); digitalWrite(greenRGBPin,HIGH); digitalWrite(blueRGBPin,HIGH); break; case '6': //green color digitalWrite(redRGBPin,HIGH); digitalWrite(greenRGBPin,LOW); digitalWrite(blueRGBPin,HIGH); break; case '7': //blue color digitalWrite(redRGBPin,HIGH); digitalWrite(greenRGBPin,HIGH); digitalWrite(blueRGBPin,LOW); break; case 't': //temperature temperature = analogRead(temperaturePin); Serial.print("Temperature: "); // temperature conversion code was used from adafruits website // converting that reading to voltage, which is based off the reference voltage float voltage = temperature * aref_voltage; voltage /= 1024.0; // now print out the temperature float temperatureC = (voltage - 0.5) * 100 ; //converting from 10 mv per degree wit 500 mV offset //to degrees ((volatge - 500mV) times 100) Serial.print(temperatureC); Serial.println(" degrees C."); break; } } else //no chars waiting in rx serial queue { if(boolWaitingForInput == false) //don't want the > character to print on every loop
{
boolWaitingForInput = true;
Serial.print(">");
}
}
}

3 comments:

  1. I saw your video on Hackaday. I liked the way you involved your son with this project. I hope you're introducing him to code too.

    ReplyDelete
  2. Indeed a nice project using a good range of technologies.
    Liked the vision and tracking bit.
    As per the previous poster I'm particularly taken that you have chosen to include your son into the project and hopefully get him interested in this stuff.
    Good Luck with your project.

    ReplyDelete
  3. Part 2 has been posted, check the projects list at the top right of the screen.

    ReplyDelete