Project tutorial
How to Build a DIY Animatronic Halloween Prop Using Arduino

How to Build a DIY Animatronic Halloween Prop Using Arduino © GPL3+

Arduino Halloween robot that can be controlled manually and autonomously. It can play terrifying Halloween soundtracks with light changing.

  • 1,343 views
  • 1 comment
  • 8 respects

Components and supplies

Necessary tools and machines

Saw
Red paint
Hy gluegun
Hot glue gun (generic)
Pilers
Electrical tape
screw driver
Wood glue
Drill

Apps and online services

About this project

Wooooow, guys! It's the Halloween tonight so are you ready for making it the most scared Halloween night ever? I have searched a lot for new Halloween tech ideas that are extremely terrified and funny to make.

Finally, I have ended with a Halloween Robot that can act like a spirit from the grave which has returned back to chaise and kill people in the Halloween night!

Yeaaaah!! That's a real Halloween robot that can move and controlled remotely from your smartphone with playing scary lights from his evil eyes and bloody mouth. And if you want to make it more deadly night then ask the robot to turn the autonomous mode on with playing the scary soundtrack you want..

All these things are done with just your smartphone.

So, let's get started with the making of this project...

Getting Started

I have used the lovely Arduino board with 1Sheeld. 1Sheeld is an Arduino shield that empowered me to use many of its easy-to-use 47 shields, like: Gamepad Shield, Voice Recognition Shield, Keypad Shield, Music Player Shield.

The greatness of 1Sheeld is that it has all these shields into only 1 board that makes use of your smartphone capabilities and sensors.

So, if this is your first time to deal with 1Sheeld or you want to learn more about it, I recommend checking this quick and easy getting started tutorial.

Step 1: Robot Body

I have designed the robot body frame from wood to be easy and cheap to laser cut it. All 2D laser cutter parts are attached as (.DXF) extension and the full open source (.SLDPRT) files too.

Note: you are going to cut some parts more than one to have multiple of them so that you glue them together to get a 3D-shaped part, like the joint part:

Once you have all the wooden parts glued then go ahead and fix all together with L shaped metal corner brace, screws and the screwdriver to a curtain tube of inner diameter 24.5 mm or less.

And I have used screws of 4mm with lengths between 10mm and 50mm.

If you got any problem with screw holes in the cutted wood, you can easily fix it by using the Drill for increasing a fault small hole diameter or even make a new hole.

Motors Installing:

make sure to use a proper geared motors with high torque that can carry the robot weight, like these:

And by using screws, attach motors with the free wheel also to the robot base using this 3D printed part:

Don't worry. All design parts files are included in the attachment of the project.

It should look like this:

Step 2: Hardware Connections

You will need Arduino Mega with 1Sheeld+ and a proper motor driver that can deliver the required current motors need. So, driver selection depends on your motors selection.

The driver in the previous image can deliver up to 4A for each motor of its 4 channel and uses fewer pins (1 PWM pin + 1 DIR pin) than traditional H-bridge motor drivers.

So, connect your components as showed up in the Schematics part below.

Step 3: Upload the Code

  • Hock the 1Sheeld to the Arduino Mega as illustrated in the video:
  • Connect the Arduino via your PC using Arduino USB cable.
  • Switch the 1Sheeld power to operate on 5v (Not the 3.3v):
  • 1Sheeld have 2 modes: Uploading mode and Operating mode. You can switch between them using the switch close to the Digital pins and is called “UART SWITCH” on 1Sheeld and “SERIAL SWITCH” on 1Sheeld+.

Firstly, you slide the switch towards the “SWITCH” notation which turns the 1Sheeld board into the Uploading mode to let you upload the Arduino code.

Secondly, after you finish uploading the code, slide the switch towards the “UART” notation (or “SERIAL” at 1Sheeld+ board) which turns the 1Sheeld board into the Operating mode to communicate with your smartphone 1Sheeld App.

  • Finally, pen the 1Sheeld app and connect it to the 1Sheeld board via Bluetooth.

Step 4: Finishing the Halloween Prop

Here comes the most exciting moment which is covering the robot skeleton we have made so far by using a cloak, Halloween hat, and a scary face.

Firstly, you will need to make a face support to act like the robot head.

I have made it from rectangular pieces of cardboard colored with a black spray.In addition, glue the RGB LED strip inside the head:

Then attach the head to the robot body:

And put the mask:

And the hat with the cloak:

And put some blood to make it more scary ")

Great! Now you finished it all!

Run It

Open the 1Sheeld App from your smartphone and connect to the 1Sheeld+ and select the Gamepad Shield, Voice Recognition Shield, Keypad Shield, Music Player Shield.

You have 4 directions to navigate the Halloween prop remotely, [up], [down], [left], [right].

And also 3 colors from the colored buttons, [red, green, blue] where the robot will change its eyes and mouth color accordingly!

Or press [orange button] to turn lights of.

In the music player shield screen, add the scary music track you want your Halloween robot play(up to 10 tracks).

Now you are ready to control your robot manually from the gamepad shield screen to get your friends pranked with playing horror music by selecting it from keys [0 - 9] from the keypad shield screen.

Or press the [#] key to stop the music playing.

Also, press any key from [A, B, C, D] to adjust the robot speed to one of the 4 leve speed [A the slowest and D is the fastest].

And for activating the autonomous mode of the robot, press the [*] key or get the voice recognition shield screen and say[drive] and your robot will drive itself autonomously using the servo motor with the obstacle avoiding sensor (the Ultrasonic).

Press the [*] again to stop the autonomous mode and back to the normal mode or say [stop] using the voice recognition shield again.

I have used the robot to prank our friend on his arrival. Here is a nice GIF for the prank and the full scary video is at the beginning of the page.

If you liked and tried it then let me know me how the reaction of your friend was hence ")

And let me know if you got any questions in the comments below...

"Happy Halloween, Guys..." with the voice of my halloween prop. :D

Code

CodeArduino
#define CUSTOM_SETTINGS
#define INCLUDE_VOICE_RECOGNIZER_SHIELD
#define INCLUDE_MUSIC_PLAYER_SHIELD
#define INCLUDE_GAMEPAD_SHIELD
#define INCLUDE_TERMINAL_SHIELD
#define INCLUDE_KEYPAD_SHIELD
#define INCLUDE_SLIDER_SHIELD


/* Include 1Sheeld library. */
#include <OneSheeld.h>

#include <Servo.h>          //Servo motor library. This is standard library

//sensor pins
#define TRIG_PIN         4
#define ECHO_PIN         5


// motor pins define
#define R_MOTOR            8
#define L_MOTOR            9
#define RIGHT_MOTOR_DIR    19
#define LEFT_MOTOR_DIR     20

#define SERVO_PIN          3

// LEDs pins defines
#define MANU_LED    10
#define AUTO_LED   11


#define RED_PIN     6
#define GREEN_PIN   7
#define BLUE_PIN    12


#define THRESHOLD    70
#define PREPARE_DISTANCE      80
#define TURN_SPEED  80
int AUTO_SPEED = 255;

boolean autonomous = false;

int distance;
int distanceRight = 0;
int distanceLeft = 0;

//Set commands to be recognized by the Arduino Voice Recognition Shield
const char autonomous_command[] = "drive";
const char manual_command[] = "stop";

int diff = 35;
int speed_value = 100;
Servo servo_motor; //our servo name


void setup()
{
  OneSheeld.begin();
  VoiceRecognition.setOnNewCommand(&myFunction);
  
  pinMode(TRIG_PIN , OUTPUT);
  pinMode(ECHO_PIN , INPUT);
  
  pinMode(MANU_LED , OUTPUT);
  pinMode(AUTO_LED , OUTPUT);

  
  pinMode(RED_PIN , OUTPUT);
  pinMode(GREEN_PIN , OUTPUT);
  pinMode(BLUE_PIN , OUTPUT);
  
  
  pinMode(R_MOTOR, OUTPUT);
  pinMode(L_MOTOR, OUTPUT);
  pinMode(RIGHT_MOTOR_DIR, OUTPUT);
  pinMode(LEFT_MOTOR_DIR, OUTPUT);
  
  servo_motor.attach(SERVO_PIN); //our servo pin
  servo_motor.write(90);
  colorModeOff();
  delay(500);
}

void loop()
{
  
  if(autonomous == true)
  {
    autonomousIndicator();
    //Terminal.println("before drive call");
    AutonomousDrive();
    //Terminal.println("after drive call");
  }
  else
  {
    //Terminal.println("manual started");
    manualIndicator();
    moveStop();
      if (GamePad.isUpPressed())
      {
         moveStop();
         moveForward( speed_value );
         delay(50);
         moveStop();
      }
    
      if (GamePad.isDownPressed())
      {
         moveStop();
         moveBackward( speed_value);
         delay(50);
         moveStop();
      }
    
      if (GamePad.isRightPressed())
      {
         moveStop();
         turnRight();
         delay(50);
         moveStop();
      }
    
      if (GamePad.isLeftPressed())
      {
         moveStop();
         turnLeft();
         delay(50);
         moveStop();
      }
      //Terminal.println("manual finished");
  }

  
  // check for color modes
  if (GamePad.isOrangePressed())
  {
    colorModeOff();
  }

  // check for color modes
  if (GamePad.isRedPressed())
  {
    colorModeOne();
  }

  // check for color modes
  if (GamePad.isBluePressed())
  {
    colorModeThree();
    
  }

  // check for color modes
  if (GamePad.isGreenPressed())
  {
    colorModeTwo();
  }

  // check keypad for playing music
  /* If keypad's button 1 is pressed. */
  if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(0))
  {
    MusicPlayer.stop();
    MusicPlayer.play(1);
  }

  /* If keypad's button 2 is pressed. */
  if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(1))
  {
    MusicPlayer.stop();
    MusicPlayer.play(2);
  }

  /* If keypad's button 3 is pressed. */
  if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(2))
  {
    MusicPlayer.stop();
    MusicPlayer.play(3);
  }

  /* If keypad's button 4 is pressed. */
  if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(0))
  {
    MusicPlayer.stop();
    MusicPlayer.play(4);
  }

  /* If keypad's button 5 is pressed. */
  if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(1))
  {
    MusicPlayer.stop();
    MusicPlayer.play(5);
  }

  /* If keypad's button 6 is pressed. */
  if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(2))
  {
    MusicPlayer.stop();
    MusicPlayer.play(6);
  }

  /* If keypad's button 7 is pressed. */
  if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(0))
  {
    MusicPlayer.stop();
    MusicPlayer.play(7);
  }

  /* If keypad's button 8 is pressed. */
  if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(1))
  {
    MusicPlayer.stop();
    MusicPlayer.play(8);
  }

  /* If keypad's button 9 is pressed. */
  if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(2))
  {
    MusicPlayer.stop();
    MusicPlayer.play(9);
  }

  /* If keypad's button 0 is pressed. */
  if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(1))
  {
    MusicPlayer.stop();
    MusicPlayer.play(0);
  }

   /* If keypad's button # is pressed. */
  if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(2))
  {
    MusicPlayer.stop();
  }


  // check for speed
  /* If keypad's button A is pressed. */
  if(Keypad.isRowPressed(0) && Keypad.isColumnPressed(3))
  {
    speed_value = 120;
  }

  /* If keypad's button B is pressed. */
  if(Keypad.isRowPressed(1) && Keypad.isColumnPressed(3))
  {
    speed_value = 160;
  }

  /* If keypad's button C is pressed. */
  if(Keypad.isRowPressed(2) && Keypad.isColumnPressed(3))
  {
    speed_value = 210;
  }

  /* If keypad's button D is pressed. */
  if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(3))
  {
    speed_value = 255;
  }

  // check for autonomous switching
  /* If keypad's button * is pressed. */
  if(Keypad.isRowPressed(3) && Keypad.isColumnPressed(0))
  {
    if (autonomous == true)
    {
      autonomous = false;

    }
    else
    {
      autonomous = true;
    }
    delay(200);
  }
}
/*******************************************************************************************/
void AutonomousDrive()
{
  //Terminal.println("begin of drive call");
  moveForward(AUTO_SPEED);
  //Terminal.println("after move forwar call");
  delay(100);
  //Terminal.println("before ultrasonic read");
  distance = getUltrasonicDistance();
  //Terminal.println(distance);
  //Terminal.println("before distance check");


  // prepare robot to slow down if a probable obstacle detected
  if( distance > THRESHOLD && distance <= PREPARE_DISTANCE )
  {
    prepareForObstacle();
  }

  // return speed to its max value if the probable obstacle has removed
  if(distance > PREPARE_DISTANCE)
  {
    AUTO_SPEED = 255;
  }

  // check an obstacle detected on  adistance equal or less than the threshold
  if (distance <= THRESHOLD)
  {
     moveStop();
     delay(500);
     distanceRight = lookRight();
     distanceLeft = lookLeft();

     // turn right if right distance is greater
     if ( (distanceRight > THRESHOLD) && (distanceLeft <= THRESHOLD) )
     {
       moveBackward(AUTO_SPEED);
       delay(800);
       moveStop();
       delay(500);
       turnRight();
       delay(1000);
       moveStop();
       delay(500);
     }

     // or turn left
     else if ( (distanceLeft > THRESHOLD) && (distanceRight <= THRESHOLD) )
     {
       moveBackward(AUTO_SPEED);
       delay(800);
       moveStop();
       delay(500);
       turnLeft();
       delay(1000);
       moveStop();
       delay(500);
     }

     // or turn towards the biggest direction
     else if ( (distanceLeft > THRESHOLD) && (distanceRight > THRESHOLD) )
     {
        if(distanceLeft > distanceRight)
        {
          moveBackward(AUTO_SPEED);
          delay(800);
          moveStop();
          delay(500);
          turnLeft();
          delay(1000);
          moveStop();
          delay(500);
        }
        else
        {
          moveBackward(AUTO_SPEED);
          delay(800);
          moveStop();
          delay(500);
          turnRight();
          delay(1000);
          moveStop();
          delay(500);
        }
     }

     // or turn 180 degree if right and left are small
     else if ( (distanceLeft <= THRESHOLD) && (distanceRight <= THRESHOLD) )
     {
       moveBackward(AUTO_SPEED);
       delay(800);
       moveStop();
       delay(500);
       turnRight();
       delay(2000);
       moveStop();
       delay(500);
     }
  }
  //Terminal.println("end of drive call");
  
}
/*****************************************************************************************************/
int lookRight()
{  
  servo_motor.write(0);
  delay(300);
  int distance = getUltrasonicDistance();
  delay(100);
  servo_motor.write(90);
  delay(300);
  return distance;
}
/*****************************************************************************************************/
int lookLeft()
{
  servo_motor.write(180);
  delay(300);
  int distance = getUltrasonicDistance();
  delay(100);
  servo_motor.write(90);
  delay(300);
  return distance;
}
/*****************************************************************************************************/
void moveStop()
{
  digitalWrite(LEFT_MOTOR_DIR, HIGH);
  digitalWrite(RIGHT_MOTOR_DIR, HIGH);
  analogWrite(R_MOTOR , 0);
  analogWrite(L_MOTOR , 0);
}
/*****************************************************************************************************/
void moveForward(int motor_speed)
{
  digitalWrite(LEFT_MOTOR_DIR, HIGH);
  digitalWrite(RIGHT_MOTOR_DIR, HIGH);
  analogWrite(R_MOTOR , motor_speed);
  analogWrite(L_MOTOR , (motor_speed-diff) );
}
/*****************************************************************************************************/
void moveBackward(int motor_speed)
{
  digitalWrite(LEFT_MOTOR_DIR, LOW);
  digitalWrite(RIGHT_MOTOR_DIR, LOW);
  analogWrite(R_MOTOR , motor_speed);
  analogWrite(L_MOTOR , (motor_speed-diff) );
  
}
/*****************************************************************************************************/
void turnRight()
{
  digitalWrite(LEFT_MOTOR_DIR, HIGH);
  digitalWrite(RIGHT_MOTOR_DIR, LOW);
  analogWrite(R_MOTOR , TURN_SPEED);
  analogWrite(L_MOTOR , TURN_SPEED);
}
/*****************************************************************************************************/
void turnLeft()
{
  digitalWrite(LEFT_MOTOR_DIR, LOW);
  digitalWrite(RIGHT_MOTOR_DIR, HIGH);
  analogWrite(R_MOTOR , TURN_SPEED);
  analogWrite(L_MOTOR , TURN_SPEED);
}
/*****************************************************************************************************/
void autonomousIndicator()
{
  digitalWrite(AUTO_LED , HIGH);
  digitalWrite(MANU_LED , LOW);
}
/*****************************************************************************************************/
void manualIndicator()
{
  digitalWrite(MANU_LED , HIGH);
  digitalWrite(AUTO_LED , LOW);
}
/*****************************************************************************************************/

void colorModeOne()
{
  analogWrite(RED_PIN , 255);
  analogWrite(GREEN_PIN , 0);
  analogWrite(BLUE_PIN , 0);
}
void colorModeTwo()
{
  analogWrite(RED_PIN , 0);
  analogWrite(GREEN_PIN , 255);
  analogWrite(BLUE_PIN , 0);
}
void colorModeThree()
{
  analogWrite(RED_PIN , 0);
  analogWrite(GREEN_PIN , 0);
  analogWrite(BLUE_PIN , 255);
}
void colorModeOff()
{
  analogWrite(RED_PIN , 0);
  analogWrite(GREEN_PIN , 0);
  analogWrite(BLUE_PIN , 0);
}
/*****************************************************************************************************/
/* A function that makes the whole operation of the ultrasonic and returning the detected distance */
int getUltrasonicDistance(void)
{
  /* Variable to save the sound wave travel time in microseconds */
  long duration;

  /* Variable to save the detected distance in cm */
  int distanceReturned;

  /* Clears the TRIG_PIN */
  digitalWrite(TRIG_PIN, LOW);

  /* delay 2 micro seconds */
  delayMicroseconds(2);

  /* Sets the TRIG_PIN on HIGH state for 10 micro seconds */
  digitalWrite(TRIG_PIN, HIGH);

  /* delay 10 micro seconds */
  delayMicroseconds(10);

  /* Sets the TRIG_PIN on LOW state */
  digitalWrite(TRIG_PIN, LOW);

  /* Reads the ECHO_PIN, returns the sound wave travel time in microseconds */
  duration = pulseIn(ECHO_PIN, HIGH);


  /* Calculating the distance */
  distanceReturned = duration * 0.034 / 2;

  /* Returning the detected distance in cm */
  return distanceReturned;
}
/**************************************************************************************/
/* This function will be invoked each time a new command is given. */
void myFunction (String commandSpoken)
{
  char buff[200];
  unsigned int len = VoiceRecognition.getLastCommandLength() + 1;
  commandSpoken.toCharArray(buff, len);
  
  /* Print out the command spoken. */
  //Terminal.println(buff);
  
  //Compare the last command received by the Arduino Voice Recognition Shield with the command "activate autonomous"
    if(!strcmp(autonomous_command,buff))
    {
      autonomous = true;
      //Terminal.println("true");
    }
    //Compare the last command received by the Arduino Voice Recognition Shield with the command "activate manual"
    else if(!strcmp(manual_command,buff))
    {
      autonomous = false;
      //Terminal.println("false");
    }
}
/*************************************************************************************/
void prepareForObstacle()
{
  AUTO_SPEED = AUTO_SPEED - 5;
}
    

Custom parts and enclosures

Body design files
body_design_files_JAtqiUE6Ah.rar

Schematics

Schematic
Untitled bjgbkladln

Comments

Similar projects you might like

How to Build a DIY Arduino-Based Smart Home Hub with 1Sheeld

Project tutorial by amrmostaafaa

  • 5,722 views
  • 1 comment
  • 29 respects

DIY Portable Distance Detection Device

Project tutorial by Viktor S

  • 5,901 views
  • 5 comments
  • 16 respects

DIY Vending Machine using Arduino & 1Sheeld

Project tutorial by Mahmoud Ahmed

  • 6,961 views
  • 7 comments
  • 32 respects

Arduino Uno Autonomous Car

Project tutorial by hannahmcneelyy

  • 7,147 views
  • 0 comments
  • 22 respects

Talking Raven - Animatronic for Halloween

Project showcase by pibyte

  • 3,938 views
  • 1 comment
  • 16 respects

ATmega Alien Themed Slot Machine

Project tutorial by Dan Murphy

  • 1,081 views
  • 5 comments
  • 14 respects
Add projectSign up / Login