Brian Chamberlain
Published © CERN-OHL

RoboPup - Robotic Hand Puppet

I found this hand puppet on Etsy and thought it would make a good companion, so I built it into a robot to control it over the internet.

IntermediateShowcase (no instructions)12 hours3,831
RoboPup - Robotic Hand Puppet

Things used in this project

Hardware components

Raspberry Pi 1 Model B+
Raspberry Pi 1 Model B+
×1
Seeed Studio Alamode board for RaspberryPi
×1
Adafruit Arduino Servo Shield
×1
Hitec HS-645MG high performance hobby servo
These plus the cabling and brakets
×4
x-mini speaker
So the puppet can "speak"
×1
Dual 2.4Amp USB power supply
×1

Hand tools and fabrication machines

Hack Saw
Something to cut the PVC pipe
Vice
Something to hold the PVC while you cut it
Hot glue gun (generic)
Hot glue gun (generic)
screw driver

Story

Read more

Schematics

System Diagram

High level system component view

Code

moves.rb

Ruby
This is the Ruby class to create the DSL for moving the servo/puppet
require "rubygems"
require "arduino_firmata"

class Moves

  SERVOS= [
   {:name => "rotate",    :port => 7,  :range => (20..180), :home => 90},
   {:name => "pitch",     :port => 9,  :range => (10..120), :home => 80},
   {:name => "lower jaw", :port => 11, :range => (90..95),  :home => 90}, 
   {:name => "upper jaw", :port => 13, :range => (50..90),  :home => 90}
   ]  

  def connection
   @connection ||= ArduinoFirmata.connect "/dev/ttyS0"
  end

  def ver
    puts "firmata version #{connection.version}"
  end

  def laugh
    look_up
    open_mouth
    6.times do
      uj(40);lj(-5)
      uj(10);lj(5)
    end 
    close_mouth
    look_forward
  end

  def open_mouth
    uj(30)
    lj(-5)
  end

  def close_mouth
    uj(0)
    lj(0)
  end
 
  def look_left
    r(-30)
  end
  
  def look_right
    r(30)
  end
  
  def look_forward
    r(0)
    pt(0)
  end
 
  def look_up
    pt(20)
  end

  def look_down
    pt(-40)
  end
 
  def r(offset)
    s = SERVOS[0]
    ws(s[:port], s[:home]-offset) if s[:range].include?(s[:home]-offset)
  end

   def pt(offset)
    s = SERVOS[1]
    ws(s[:port], s[:home]+offset) if s[:range].include?(s[:home]+offset)
  end
     
  def uj(offset)
    s = SERVOS[3]
    ws(s[:port], s[:home]-offset) if s[:range].include?(s[:home]-offset)
  end

  def lj(offset)
    s = SERVOS[2]
    ws(s[:port], s[:home]-offset) if s[:range].include?(s[:home]-offset)
  end 
 
  def ws(p, a)
    puts "#{p} - #{a}"
    connection.servo_write p, a
    sleep(0.1)
  end	
  
end

moves.rb

Ruby
This was a simple test sequence to cycle through the movement patterns
require './moves'

mover = Moves.new
mover.ver

puts "opening mouth"
mover.open_mouth

sleep 1

puts "closing mouth"
mover.close_mouth

sleep 1

puts "looking left"
mover.look_left

sleep 1

puts "looking right"
mover.look_right

sleep 1

puts "looking forward"
mover.look_forward

sleep 1

puts "looking up"
mover.look_up

sleep 1

puts "looking down"
mover.look_down

sleep 1

puts "look forward"
mover.look_forward

test_servo.rb

Ruby
This in a "hello world" movement script that tests movement on the servos directly. This is executed from the command line on the raspberry pi. It uses the ArduinoFirmata gem
require "rubygems"
require "arduino_firmata"
ArduinoFirmata.connect "/dev/ttyS0" do
  puts "firmata version #{version}"

  servos = [
   {:name => "rotate",    :port => 7,  :range => (20..180), :home => 90},
   {:name => "pitch",     :port => 9,  :range => (10..120), :home => 90},
   {:name => "lower jaw", :port => 11, :range => (90..95),  :home => 90}, 
   {:name => "upper jaw", :port => 13, :range => (50..90),  :home => 90}
   ]  
 	
  servos.each do |servo|
    servo[:range].to_a.each do |angle|
      puts "servo #{servo[:name]} on port #{servo[:port]} @ #{angle} deg."
      servo_write servo[:port], angle
      sleep 0.5
    end
    # return to home
    servo_write servo[:port], servo[:home]
    sleep 3
    puts 'starting next servo'
    sleep 3 
  end
  
end

ServoFirmata.ino

C/C++
This is the very simple firmata code that's loaded onto the Arduino (atmel) on the Alamode
/*
 * Firmata is a generic protocol for communicating with microcontrollers
 * from software on a host computer. It is intended to work with
 * any host computer software package.
 *
 * To download a host software package, please clink on the following link
 * to open the download page in your default browser.
 *
 * http://firmata.org/wiki/Download
 */

/* This firmware supports as many servos as possible using the Servo library 
 * included in Arduino 0017
 *
 * TODO add message to configure minPulse/maxPulse/degrees
 *
 * This example code is in the public domain.
 */
 
#include <Servo.h>
#include <Firmata.h>

Servo servos[MAX_SERVOS];

void analogWriteCallback(byte pin, int value)
{
    if (IS_PIN_SERVO(pin)) {
        servos[PIN_TO_SERVO(pin)].write(value);
    }
}

void setup() 
{
    byte pin;

    Firmata.setFirmwareVersion(0, 2);
    Firmata.attach(ANALOG_MESSAGE, analogWriteCallback);

    for (pin=0; pin < TOTAL_PINS; pin++) {
        if (IS_PIN_SERVO(pin)) {
	    servos[PIN_TO_SERVO(pin)].attach(PIN_TO_DIGITAL(pin));
        }
    }
   
    Firmata.begin(57600);
}

void loop() 
{
    while(Firmata.available())
        Firmata.processInput();
}

Credits

Brian Chamberlain

Brian Chamberlain

11 projects • 21 followers
Hi! I am a software engineer who enjoys hacking on hardware on the side. My interests are in DIY projects for the home, IOT, and 3D printing

Comments