If This Then That - Duck Animatronic

by Oxyhadron in Circuits > Arduino

333 Views, 11 Favorites, 0 Comments

If This Then That - Duck Animatronic

20230508_172224.jpg

ive always had a facination with animatronics so this is my attempt at a simple duck head animatronic.

The animatronic moves forwards backwards and side to side, opens and closes its mouths and makes a quack noises based on joystick inputs.


Supplies

arduino_uno_smd_rev3_-_overview.jpg
61yfIwAxe0L._SL1421_.jpg
s35-0910p02wc.jpg
128726_1384265420.jpg
Spruce_plywood.JPG

Supplies

  • Arduino Uno + cable
  • 3 servos (sg90 or mg90s)
  • small speaker (8ohm 0.2W worked fine for me)
  • thumbstick
  • enough wood to make a box (or if you have already have a project box that will also work)
  • metal wire (1mm thick)
  • conductive wire
  • rubber mat the size of the arduino
  • 4.5mm rod (i used brass but it doesnt matter what material)
  • solder
  • electrical tape (or heat shrink tubing)
  • 10mm rod ~ 7cm long
  • 14 small screws
  • a bunch of zipties

Tools used

  • 3D printer
  • Drillpress
  • Bandsaw
  • Hammer
  • Soldering iron
  • needle nose pliers
  • wire cutters
  • Screwdriver
  • Knife

Designing the Animatronic

design.png
first design.JPG
second design.JPG

the idea was to design an animatronic, at first i wanted it to move the head front to back side to side and rotate horizontaly

but about halfway though designing it i decided to have a moving mouth as it would make it more lifelike.

my first design was way smaller and more fragile, i also made a huge oversight when modeling, that being that the arm where the servos connect must connect 90 degrees at the same radius above the pivot point otherwise it would lock up when moving in a circle.

looking back on the design process i learned how valuable plannig things out from the start can be, instead of improvising all the way through, as is my usual method.

This project also made me brush up on my arduino programming skills

i now know how to use the servo and pcm libraries

aswell as making memore familiar with fusion360.


3D Print All the Parts

duckmodell.JPG

Printed in cura with a 0.8 mm nozzle

settings used in cura

  • 0.32 mm line width
  • 3 walls
  • 20% infill
  • printed with supports
  • 20% support infill

total print time (with these settings) if everything prints fine in one go ~ 5 hours and 48 minutes.

83 grams of fillament

cleanup

  • some parts of the 3d print might have the right tolerances, you can use a knife to clean up and shave away some materiak
  • if you have the wrong servos wires dont route properly so you might have to cut out a few slots, using a lighter and a cheap knife you dont care about you can melt away part of the plastic, this is easier than cutting

Make Wooden Enclosure

dimensionsbox.JPG
cut wood.JPG
chisel.JPG
testfit.JPG
glueup.JPG

instructions for making the enclosure


there are multiple ways to make a box but this is how i did it:

  • cut the wood to the approximate dimensions of the drawing
  • for the part where the joystick goes its important to clear away wood where the pins are gonna go
  • hammer in temporary nails
  • testfit everything so you know everything fits
  • pull apart wood so the nails are possible to place back
  • put glue on the places where it has to stick
  • hammer back down all the temporary nails (this acts as allignent and clamping force
  • clamp down the work piece for extra pressure
  • remove clamps
  • sand down imperfections and finish with a neutral oil or a clear varnish

Program the Arduino

install FlagPCM library (this is an edited version of the PCM library that avoids conflicts between internal timers) FlagPCM: https://github.com/codemee/FlagPCM

how to install library

  1. download FlagPCM
  2. in Arduino IDE Sketch>Include library>Add .zip library
  3. select FlagPCM

copy the code and upload it to your arduino

#include <FlagPCM.h>
#include <Servo.h>

float sm; // float for smoothing servo 1
float sm2; // float for smoothing servo 2

const int Y_pin = A0; // analog pin connected to Y output
const int X_pin = A1; // analog pin connected to Y output

int val;
int val2;
int angle = 2;   // initial angle  for servo (beteen 1 and 179)
int angleStep = 30; // servo step size
const int minAngle = 0;  //min angle
const int maxAngle = 31; //max angle
const int type = 2; // either 1 or 2 changes servo direction on button click
int buttonPushed = 0; // int for button push logic

Servo myservo; // create servo object to control a servo
Servo myservo2; // create servo object to control a servo
Servo myservo3;  // create servo object to control a servo

#define servoPin 6 // attaches servo 3 on pin6
#define pushButtonPin 2 // attaches button on pin 2


// programs sound file as array
const unsigned char sample[] PROGMEM = {
  129, 128, 128, 127, 128, 128, 128, 128, 128, 128, 127, 127, 126, 126, 126, 126, 127, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 127, 127, 127, 128, 128, 128, 127, 126, 127, 128, 128, 127, 127, 127, 126, 127, 128, 128, 128, 127, 127, 128, 128, 127, 127, 127, 128, 129, 129, 128, 126, 126, 127, 129, 129, 127, 126, 127, 127, 127, 127, 127, 126, 127, 128, 128, 128, 127, 128, 129, 129, 128, 127, 127, 127, 127, 127, 128, 129, 129, 130, 129, 128, 127, 126, 127, 127, 127, 128, 128, 128, 128, 127, 127, 127, 127, 126, 126, 126, 127, 128, 127, 127, 125, 124, 126, 126, 124, 121, 120, 123, 126, 128, 128, 127, 127, 129, 132, 134, 136, 137, 139, 141, 139, 130, 119, 110, 106, 108, 112, 116, 118, 116, 115, 109, 102, 99, 97, 99, 108, 116, 123, 130, 134, 132, 128, 123, 121, 121, 126, 134, 141, 146, 148, 147, 142, 135, 129, 127, 129, 133, 143, 154, 163, 170, 170, 164, 148, 116, 91, 88, 100, 124, 146, 160, 164, 153, 127, 97, 81, 84, 101, 123, 140, 150, 150, 138, 121, 108, 99, 101, 111, 119, 122, 118, 109, 101, 96, 100, 105, 109, 111, 107, 104, 101, 102, 108, 116, 126, 135, 144, 151, 151, 149, 144, 146, 156, 171, 192, 208, 220, 206, 148, 81, 50, 75, 135, 182, 196, 183, 151, 97, 46, 33, 61, 118, 169, 179, 164, 143, 123, 115, 119, 134, 156, 164, 150, 127, 113, 117, 129, 135, 134, 123, 97, 68, 50, 51, 76, 100, 112, 109, 91, 76, 76, 90, 115, 135, 142, 144, 141, 139, 145, 156, 174, 203, 229, 245, 228, 145, 50, 26, 83, 176, 226, 199, 144, 95, 60, 51, 68, 113, 156, 151, 118, 102, 119, 153, 177, 175, 156, 132, 113, 112, 135, 168, 184, 166, 123, 90, 77, 76, 84, 91, 87, 79, 68, 67, 76, 83, 89, 91, 94, 98, 102, 115, 136, 158, 169, 175, 185, 194, 223, 245, 196, 95, 36, 68, 154, 212, 192, 135, 103, 80, 61, 72, 99, 113, 100, 83, 105, 157, 181, 170, 141, 111, 111, 131, 155, 178, 175, 155, 139, 139, 142, 128, 104, 84, 76, 75, 77, 84, 86, 86, 83, 81, 87, 91, 102, 119, 129, 130, 141, 160, 189, 223, 238, 240, 180, 56, 33, 137, 229, 233, 151, 89, 106, 130, 128, 108, 65, 39, 55, 104, 171, 186, 134, 101, 115, 142, 156, 149, 138, 131, 134, 158, 186, 172, 119, 86, 98, 117, 109, 84, 68, 75, 90, 100, 91, 75, 87, 114, 130, 129, 124, 139, 177, 214, 238, 239, 157, 37, 59, 195, 255, 182, 78, 96, 170, 168, 136, 80, 19, 29, 88, 159, 171, 103, 67, 119, 170, 156, 116, 97, 119, 154, 173, 179, 145, 90, 94, 146, 158, 114, 76, 77, 100, 107, 96, 92, 79, 79, 114, 134, 128, 124, 146, 205, 239, 228, 200, 111, 38, 125, 239, 234, 136, 63, 139, 215, 154, 82, 40, 38, 103, 153, 149, 99, 67, 124, 180, 148, 100, 104, 145, 168, 149, 136, 137, 131, 144, 150, 120, 83, 81, 112, 120, 101, 89, 95, 106, 109, 118, 123, 115, 142, 192, 214, 235, 209, 88, 51, 165, 239, 197, 103, 92, 187, 196, 109, 58, 58, 106, 147, 116, 77, 66, 110, 181, 149, 75, 90, 144, 167, 142, 111, 119, 136, 156, 168, 126, 74, 91, 140, 126, 74, 61, 90, 123, 122, 100, 107, 130, 146, 188, 221, 210, 139, 35, 98, 234, 190, 100, 78, 145, 235, 154, 56, 69, 80, 121, 148, 95, 55, 83, 156, 171, 85, 46, 116, 157, 134, 113, 109, 123, 141, 147, 138, 113, 101, 109, 117, 101, 87, 96, 105, 114, 115, 126, 145, 151, 175, 208, 208, 114, 31, 144, 246, 164, 86, 103, 178, 212, 140, 71, 73, 107, 147, 143, 88, 75, 134, 171, 124, 59, 86, 152, 144, 105, 105, 136, 148, 136, 128, 121, 116, 120, 126, 110, 93, 111, 123, 101, 92, 117, 136, 147, 166, 187, 209, 147, 37, 96, 224, 193, 94, 90, 179, 218, 141, 77, 76, 99, 145, 134, 72, 77, 139, 183, 136, 55, 87, 158, 147, 97, 78, 117, 154, 144, 124, 114, 116, 121, 119, 104, 89, 102, 124, 116, 102, 117, 132, 155, 170, 168, 186, 114, 29, 137, 229, 141, 65, 101, 183, 190, 108, 69, 91, 118, 141, 107, 61, 112, 171, 161, 114, 74, 118, 166, 128, 94, 101, 134, 164, 146, 123, 122, 126, 126, 121, 121, 106, 97, 126, 139, 137, 140, 136, 160, 182, 189, 173, 75, 78, 208, 190, 100, 95, 131, 190, 164, 80, 83, 114, 137, 137, 78, 82, 159, 165, 115, 86, 100, 144, 135, 94, 96, 122, 142, 139, 121, 115, 121, 129, 119, 112, 112, 108, 124, 133, 136, 148, 157, 173, 179, 182, 137, 65, 134, 212, 138, 88, 124, 161, 165, 120, 89, 100, 116, 128, 116, 83, 102, 158, 151, 98, 82, 120, 148, 112, 82, 108, 131, 125, 118, 117, 117, 115, 112, 110, 113, 105, 104, 113, 115, 133, 140, 148, 171, 174, 190, 122, 48, 171, 215, 108, 100, 134, 163, 170, 111, 93, 109, 118, 133, 110, 83, 123, 165, 133, 91, 99, 139, 154, 103, 81, 130, 144, 124, 124, 126, 128, 131, 115, 107, 113, 110, 121, 128, 122, 130, 143, 161, 177, 183, 131, 68, 153, 224, 132, 89, 137, 167, 164, 131, 107, 116, 127, 121, 110, 103, 117, 151, 143, 109, 106, 126, 138, 114, 95, 124, 141, 120, 123, 146, 137, 121, 114, 104, 119, 127, 113, 110, 126, 143, 146, 148, 158, 178, 142, 55, 116, 216, 139, 86, 140, 164, 159, 130, 107, 121, 135, 125, 108, 109, 125, 152, 149, 114, 113, 133, 135, 117, 96, 114, 134, 125, 126, 139, 140, 125, 114, 115, 125, 124, 109, 114, 136, 146, 141, 137, 156, 187, 149, 58, 104, 210, 152, 92, 137, 159, 157, 139, 110, 116, 132, 127, 111, 112, 127, 142, 146, 126, 118, 131, 137, 125, 108, 115, 134, 133, 126, 130, 134, 128, 114, 112, 128, 125, 110, 118, 136, 152, 144, 129, 159, 193, 123, 49, 144, 211, 122, 95, 147, 169, 157, 119, 107, 124, 135, 126, 102, 113, 140, 144, 133, 114, 117, 137, 133, 110, 104, 124, 134, 118, 115, 128, 127, 124, 124, 111, 109, 123, 121, 105, 114, 140, 131, 124, 143, 150, 163, 126, 76, 148, 173, 97, 117, 151, 142, 152, 129, 111, 125, 123, 119, 112, 109, 131, 141, 124, 117, 122, 127, 130, 112, 103, 121, 127, 117, 115, 124, 129, 119, 103, 113, 128, 114, 104, 119, 132, 130, 122, 131, 165, 171, 98, 65, 160, 174, 74, 80, 144, 149, 127, 110, 112, 121, 122, 108, 100, 118, 128, 131, 131, 118, 121, 132, 130, 116, 112, 130, 133, 122, 124, 129, 133, 128, 113, 120, 130, 108, 106, 125, 119, 116, 122, 128, 138, 129, 140, 174, 133, 70, 121, 179, 123, 87, 130, 164, 156, 121, 109, 120, 129, 132, 109, 109, 138, 139, 127, 117, 117, 133, 134, 115, 111, 128, 136, 126, 119, 128, 143, 134, 116, 122, 123, 107, 120, 129, 100, 114, 143, 123, 120, 127, 133, 150, 148, 155, 125, 94, 166, 169, 92, 123, 169, 152, 130, 117, 127, 135, 123, 121, 118, 119, 131, 130, 119, 119, 127, 130, 126, 119, 122, 137, 134, 123, 130, 137, 131, 123, 116, 120, 132, 121, 100, 105, 126, 129, 105, 102, 129, 132, 123, 117, 119, 147, 157, 150, 132, 101, 147, 184, 118, 111, 160, 155, 137,
};


void setup() {

  myservo.attach(7);
  myservo2.attach(8);
  myservo3.attach(servoPin);  // attaches the servo on pin 3 to the servo object

  Serial.begin(9600);          //  setup serial

  pinMode(pushButtonPin, INPUT_PULLUP);

  myservo3.write(angle);//initial position

}

void loop() {
  if (digitalRead(pushButtonPin) == LOW) // if button pressed change buttonpushed to 1 {
    buttonPushed = 1;

  }
  if ( buttonPushed ) {
    // change the angle for next time through the loop:
    angle = angle + angleStep;


    // reverse the direction of the moving at the ends of the angle:
    if (angle >= maxAngle) {

      angleStep = -angleStep; //makes servo move back
      if (type == 1)
      {
        buttonPushed = 0;
      }
    }

    if (angle <= minAngle) {
      playback(sample, sizeof(sample)); //plays back sound at the moment the mouth reaches the bottom
      angleStep = -angleStep;
      if (type == 2)
      {
        buttonPushed = 0;
      }
    }

    myservo3.write(angle); // move the servo to desired angle
    delay(100); // waits for the servo to get there
  }
  val = analogRead(Y_pin); //reads analog value ypin
  val = map(val, 0, 1023, 170, 0); //converts joystick data to servo angle
  sm = (val * 0.05) + (sm * 0.95); // smoothes servo angle value

  val2 = analogRead(X_pin); //reads analog value pin
  val2 = map(val2, 0, 1023, 0, 170); //converts joystick data to servo angle
  sm2 = (val2 * 0.05) + (sm2 * 0.95);// smoothes servo angle value

  myservo.write(sm); //writes smoothed value to servo
  myservo2.write(sm2); // writes smoothed value to servo 2
  delay(5); ads delay to servo
}


Assemble Parts

universal joint

  • cut the swivel rod for universal joint ~ 12mm and 17mm
  • push the 12mm part through the middle and top part to the end. then you can route the 17mm part through the hole of the middle and bottom parts of the universal joint
  • glue down one side of the 17mm rod to the side of the bottom part of the universal joint

connection to box

  • route the 10mm diameter rod through the 3d printed parts
  • glue the bottom of the universal joint and the base together onto the 10mm rod
  • screw down the base onto the box

connect servos to 3d printed parts

  • screw down the servos using the standard servo mounting points
  • if the screws wont go in you can heat up the screw using a lighter so that it will melt the pla around the screw
  • the top servo is just a pressfit, you can screw it down but its not necessary, at the step you can attach the bottom part of the mouth which is also pressfit.

connect servo to the top part of the unversal joint using steel wire

  • using needle nose pliers you can bend a cirular shape in the steel wire that you route through the designated holes in the top part
  • measuring where the top part of the universal joint would sit flat you bend the bottom of the steel wire 90 degrees you can the push the steel wire though the holes in the servo arm (if the steel wire is too big you can use a lighter to melt the hole bigger) then you can bend the arm another 90 degrees upwards so its snug
  • trim excess of the wire

mount the joystick

  • it might be wise to do this after wiring as you likely cant wire it when its firmly in place
  • push the 3d printed plate through the hole cut in the front of the enclosure
  • screw in screws at the back of the joystick
  • push the 3d printed joystick knob onto the joystick component

mount the arduino to the bottom of the enclosure

  • not strictly necessary but its wise to use some sort of squishy non conductive material on the bottom of the arduino not to damage it when screwing in the arduino.
  • screw in the arduino

mount speaker

  • glue down the speaker ontop of the speaker holes



Wire the Electronics

schematic.JPG
wire.JPG

wire the electronics according to the diagram ( if unclear ):

  • the bottom servos are connected to digital pin 7 and 8, ground, and 5v
  • the top servo is connected to digital pin 6, ground, and 5v
  • the button is connected to digital pin 6 and ground
  • the speaker is connected to digital pin 11 and ground

use zipties to tidy up the wires

  • you can use zipties to tidy up bundles of wires
  • if you solder wires together, dont forget to put electrical tape around it to prevent short circuits

(optional) push the wires of the top servo through a maluable rubber tube so it looks neater

  • put zipties on both ends of the tube. one underneath the enclosure so it doesnt come out


The Ducks Appearance

birb.JPG

my lovely mother knitted the duck out of wool for me,so i cant give instructions on how she did it because i dont know how to knit.

alternatively you can glue apropriately colored fabric onto the 3D printed parts.

Done!