Projects‎ > ‎

Cyber-Jabba (in-progress; ignore!)


Goal

Take a crappy toy and make it less crappy, using an Arduino, LEDs, a servo, and minimal tools.  In my case, the toy-in-question is a late 90's vintage Jabba the Hutt.  It's been sitting in my office for some time and frankly, I never really liked it.  I'm pretty sure I picked it up cheap back in my "buy everything Star Wars that wasn't nailed down" days.  The likeness is based on the previously-deleted-but-now-restored scene in Star Wars: A New Hope that features a computer-generated Jabba talking to Han Solo in the Millenium Falcon hanger.  The bad CGI alone qualifies this for "crappy toy" status.

I'm going to use a servo to move the head back and forth and animate the eyes with two red LEDs.

Materials

  • Arduino UNO
  • (2) small red LEDs
  • (2) 330-ohm resistors
  • hobby servo
  • Power of the Force Deluxe Jabba the Hutt
  • a bunch of jumper wires
  • breadboard
  • push button
  • potentiometer
  • scrap Plexiglass
  • scrap foam core posterboard
Tools
  • Soldering iron
  • Hot glue gun
  • hacksaw
  • hammer
  • flathead screwdriver
  • scratch awl
  • mini phillips screwdriver

Part 1: Non-interactive Jabba

Step 1.1: Disassembly

Jabba main body is two molded plastic halves joined together with adhesive (or maybe heat-welded).  I used a hammer, screwdriver, and scratch awl to work my way into the seam and gradually split it open.  In the process I broke some internal supports as well.  Just go slow -- I bloodied at least one knuckle getting it apart.  Remove the head and then split it open as well.  Remove the tail and the connecting "ropes" that make the tail move when the head is rotated.

(Originally I'd hoped to keep the tail and have it animated along with the head but I stripped the gears on a servo when I tried this, so the tail was eliminated from the final product.)

Once the body is "gutted", hot glue the halves back together.  Electrical tape may also be useful here (hey, I'm not paid extra for pretty).

Step 1.2: Install the LEDs

I bent two small red LEDs as shown in the picture and soldered their negative leads (the short ones) together.  To each of the positive leads I soldered a 330-ohm resistor.



Then I soldered a long piece of jumper wire to the (combined) negative terminals that will connect to the system's common ground.  I did the same to the other lead of each resistor, for a total of three jumper wires coming out of the head.

I drilled a small hole in  the head's base and ran the wires out of it.

I used hot glue to secure the LEDs in place, then put the two head-halves back together with hot glue.

Step 1.3: Install the Servo

I attached the 2-blade servo mount to the servo, securing it in place with the included very-tiny screw.  I used the other two screws to attach the servo mount to the bottom of the head's swivel base.

I cut a small piece of foam-core posterboard the size of the "hold" where Jabba's neck used to be and hot-glued it to the body.  The base of the servo is hot-glued to the foam-core.

Step 1.4: Connecting to the Arduino

Use the following connections to the Arduino:
  • LED "eye" #1: pin 12
  • LED "eye" #2: pin 11
  • LEDs' common ground: GND
  • Servo's power lead (red wire): +5
  • Servo's ground lead (black wire): GND (the other one -- an Arduino UNO has two)
  • Servo's signal lead (white wire): pin 6

Step 1.5: Programming

In this phase of the build, the head swivels from side to side and the eyes "blink" without any external control.  The Arduino code is below.

Part 1 Arduino Code

// Servo code adapted from: Sweep
// by BARRAGAN <http://barraganstudio.com> 
// This example code is in the public domain.


#include <Servo.h>
#include <MsTimer2.h>
 
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
 
int deflection = 75;
int servowait = 25;


int eyesState = LOW;
void animateEyes()
{
  if(eyesState==LOW)
  {
    eyesState = HIGH;
  }
  else eyesState = LOW;
  
  digitalWrite(12, eyesState);
  digitalWrite(11, eyesState);
}
 
void setup() 
  myservo.attach(6);  // attaches the servo on pin 9 to the servo object 
  myservo.write(90);
  pinMode(12, OUTPUT);
  pinMode(11, OUTPUT);
  digitalWrite(12, LOW);
  digitalWrite(11, LOW);
  
  MsTimer2::set(250, animateEyes);
  MsTimer2::start();
 






void loop() 
  // turns jabba's head back and forth from 60 degrees to 120 degrees
  for(int pos=90-deflection; pos<90+deflection; pos++)
  {
    myservo.write(pos);
    delay(servowait);
  }
 
  
  for(int pos = 90+deflection; pos > 90-deflection; pos--)
  {  
    myservo.write(pos);
    delay(servowait);
  }
    
  //delay(1000);
}

Part 2: Simple Interaction

In this part, I add the following:
  • a button that changes the blink pattern of the eyes (from "both blinking" to "alternating blinking")
  • a potentiometer that alters the speed at which Jabba turns his head

Step 2.1: Attach the button

I found a scrap piece of clear acrylic (also known as Plexiglass) and cut it using a hacksaw to be approximately 1 inch wide by 1.5 inches long.  I drilled a hole in one end large enough to through-mount a pushbutton and then hot-glued the whole thing to a convenient spot (see the picture).


Step 2.2: Attach the potentiometer

You know that spot where Jabba's tail used to be? Yep, it's perfect for adding a potentiometer.  I had to cut a slot out of the top for the shaft to stick through (see picture).  The whole thing is, again, secured with hot glue.


Step 2.3: Connect to Arduino

The potentiometer's middle lead is connected to analog pin 5 (A5).  One outside lead is connected to +5; the other is connected to GND.  (At this point, I'm running out of GND pins on the Arduino itself so I've jumpered across to a breadboard to add more GND connections.  It is also helping me to organize other connections now, too.)

One lead of the button is connected to ground, the other to Arduino digital pin 3.

Step 2.4: Modified Arduino Code

The code for this phase of the project is below:

Part 2 Arduino Code

#include <Bounce.h>

// Servo code adapted from: Sweep
// by BARRAGAN <http://barraganstudio.com> 
// This example code is in the public domain.


#include <Servo.h>
#include <MsTimer2.h>

 
 
#define buttonPin (3)
#define eyePin1 (10)
#define eyePin2 (11)
#define potPin (5) // analog pin 5
#define photocellPin (0) // analog pin 0 
 
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
 
int deflection = 75;
int servowait = 25;

Bounce myButton(buttonPin, 50);

int eyesState = LOW;
int alternateEyes = HIGH;
void animateEyes()
{
  if(eyesState==LOW)
  {
    eyesState = HIGH;
  }
  else eyesState = LOW;
  
  if(alternateEyes)
  {
    digitalWrite(eyePin1, eyesState);
    digitalWrite(eyePin2, eyesState);
  }
  else
  {
    digitalWrite(eyePin1, eyesState);
    digitalWrite(eyePin2, !eyesState);
  }
}
 

 
long lastServoUpdate;

void setup() 
  myservo.attach(6);  // attaches the servo on pin 9 to the servo object 
  myservo.write(90);
  lastServoUpdate = millis();

  // set the eyes for PWM-capable pins
  pinMode(eyePin1, OUTPUT);
  pinMode(eyePin2, OUTPUT);
  
  // use the internal pull-up resistors
  digitalWrite(eyePin1, LOW);
  digitalWrite(eyePin2, LOW);
  
  MsTimer2::set(250, animateEyes);
  MsTimer2::start();
  
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH);

 

void loop() 
  updateHeadPosition();
    
  checkButton();
  checkPotentiometer();
}

void checkButton()
{
  myButton.update();
  alternateEyes = myButton.read();
}

void checkPotentiometer()
{
  int val = analogRead(potPin);
  servowait = val/8;
}

int dir = 1;
int pos = 90;
void updateHeadPosition()
{
  // check to see if it is time to update our position
  long now = millis();
  if(now < lastServoUpdate + servowait) return;
  
  // reset our timer
  lastServoUpdate = now;
  
  // moving one way
  if(dir==1 && pos < 90+deflection)
  {
    pos++;
    myservo.write(pos);
    if(pos >= 90+deflection) dir = -1;
    return;
  }
  // moving the other
  else if(dir == -1 && pos > 90-deflection)
  {
    pos--;
    myservo.write(pos);
    if(pos <= 90-deflection) dir = +1;
    return;
  }
}

Part 3: More Interactivity

In this part, I add a light sensor and use it to make Jabba "nervous" when something gets closer to him.

Step 3.1: Build the light sensor

I took a photoresistor and soldered a piece of red jumper wire to one lead, a piece of green jumper wire and a 100K-ohm resistor to the other lead, and a black jumper wire to the other lead of the resistor.


Step 3.2: Connecting to the Arduino

The photoresistor is an analog sensor, so the red wire is connected to +5V, the green wire to analog pin 0, and the black wire to GND.

Step 3.3: Modified (again!) Arduino Code

Note that, due to a planned modification that ultimately never happened, I moved the LED originally connected to digital pin 12 to pin 10 in this code. (At one point I thought I might dim the eyes based on the light sensor, meaning I needed both LEDs on PWM pins...)

Now, in response to varying light levels, Jabba's eyes blink slower or faster.  Exciting, huh?

Part 3 Arduino Code

#include <Bounce.h>

// Servo code adapted from: Sweep
// by BARRAGAN <http://barraganstudio.com> 
// This example code is in the public domain.


#include <Servo.h>
#include <MsTimer2.h>

 
 
#define buttonPin (3)
#define eyePin1 (10)
#define eyePin2 (11)
#define potPin (5) // analog pin 5
#define photocellPin (0) // analog pin 0
 
Servo myservo;  // create servo object to control a servo 
                // a maximum of eight servo objects can be created 
 
int deflection = 75;
int servowait = 25;

Bounce myButton(buttonPin, 50);

int eyesState = LOW;
int alternateEyes = HIGH;
long lastEyeCheck = millis();
long eyeBlinkSpeed = 250;
void animateEyes()
{
  long now = millis();
  if(lastEyeCheck + eyeBlinkSpeed > now) return;
  lastEyeCheck = now; 
  if(eyesState==LOW)
  {
    eyesState = HIGH;
  }
  else eyesState = LOW;
  
  if(alternateEyes)
  {
    digitalWrite(eyePin1, eyesState);
    digitalWrite(eyePin2, eyesState);
  }
  else
  {
    digitalWrite(eyePin1, eyesState);
    digitalWrite(eyePin2, !eyesState);
  }
}
 

 
long lastServoUpdate;

void setup() 
  myservo.attach(6);  // attaches the servo on pin 9 to the servo object 
  myservo.write(90);
  lastServoUpdate = millis();

  // set the eyes for PWM-capable pins
  pinMode(eyePin1, OUTPUT);
  pinMode(eyePin2, OUTPUT);
  
  // use the internal pull-up resistors
  digitalWrite(eyePin1, LOW);
  digitalWrite(eyePin2, LOW);
  
  pinMode(buttonPin, INPUT);
  digitalWrite(buttonPin, HIGH);
  
  Serial.begin(9600);

 

void loop() 
  updateHeadPosition();
  animateEyes();
  checkButton();
  checkPotentiometer();
  checkPhotocell();
}

void checkButton()
{
  myButton.update();
  alternateEyes = myButton.read();
}

void checkPotentiometer()
{
  int val = analogRead(potPin);
  servowait = val/8;
}

long lastPhotoCellCheck = millis();
void checkPhotocell()
{
  long now = millis();
  if(now > lastPhotoCellCheck + 2000) return;
  int val = analogRead(photocellPin);
  Serial.println(val);
  eyeBlinkSpeed = val - 700;
  lastPhotoCellCheck = now;
}

int dir = 1;
int pos = 90;
void updateHeadPosition()
{
  // check to see if it is time to update our position
  long now = millis();
  if(now < lastServoUpdate + servowait) return;
  
  // reset our timer
  lastServoUpdate = now;
  
  // moving one way
  if(dir==1 && pos < 90+deflection)
  {
    pos++;
    myservo.write(pos);
    if(pos >= 90+deflection) dir = -1;
    return;
  }
  // moving the other
  else if(dir == -1 && pos > 90-deflection)
  {
    pos--;
    myservo.write(pos);
    if(pos <= 90-deflection) dir = +1;
    return;
  }
}


Comments