Project tutorial
Monster in a Box

Monster in a Box © GPL3+

A Monster in a Box Halloween prop is a box or crate that appears to be jailing a monster which is on the verge of escaping.

  • 9,183 views
  • 52 comments
  • 64 respects

Components and supplies

About this project

I love Halloween props and have seen and read about some great Monster in a Box builds this past year and decided that I should build my own. The idea is pretty simple: create the illusion that some type of container is holding a dangerous monster that is on the verge of escaping. The illusion can be created with any combination of motion, sound, light, smoke and, of course, surprise.

What's in the Box!?!?

You want a box that is large enough that it appears to be capable of holding something big and scary. It also adds to the illusion if the box appears to be old, well worn, and just maybe only strong enough to keep the monster at bay. At first I shopped around at thrift stores and online for something but never something that I liked, so I build my own. It was not very difficult.

I used 15 6ft pine fence pickets from Home Depot to make a box that measured about 3ft x 2.5ft x 2.5ft. I cut all the board to length with a table saw and assembled the box using a pneumatic 18 gauge brad nailer. This appeared to work well, but later I realized that the brads were not strong enough to hold the box together due to all of the banging and bouncing it would be doing. To strengthen the box I later screwed it together with 1 inch dry wall screws (from the inside out so they would not show).

Once built I aged the wood with a process that used black tea, vinegar and steel wool. I then decorated it with stencils and labels that I found online and/or created and printed.

Brainzzzzz!!!

The prop has 2 operational states "Sleeping" and "Awake". While sleeping the box is relatively calm and only makes snoring and light growling sounds. The monster is awoken when a trick-or-treater trips a motion sensor. When the monster is awoken the monster roars, breaths smoke, bounces the lid, and the inside of the box glows red.

I used an Arduino Uno along with a WaveShield and a Relay Module to orchestrate the behavior of this prop. The WaveShield is loaded with a small collection of sleeping and roaring sounds. A PIR motion sensor provided input to the Arduino to switch the box between "sleeping" and "awake" modes. During awake mode the Arduino activates relay channels to run the lid motor, red lights, the smoke generator. and play the sounds on the WaveShield. One other feature that I added was a Pause Button. This allowed me to temporarily silence the monster when younger kids come by.

It's Aliiiiiive!

A lid lifter is a device that will quickly raise and lower the lid to make it bang and bounce as if the monster is trying to escape. There are several ways this can be done the most popular appear to be pneumatic actuators and rotating cams. Although I think an electronically controlled pneumatic actuator would have allowed me to make the lid motions much more random, I decided to go with the a rotating cam as it seemed to be the simpler and least expensive option.

I bough a used automotive windshield wiper motor from a local scrap yard for $15. It was kinda funny. I walked in and asked for a motor. The guy behind the counter asked "for what make and model car" when I said "I dont care" his head tilted to the side a bit and he gave me a bit of side eye. After I explained what I was up to he wanted to build one :)

These motors, regardless of make/model, run on 12 volts, spin at a reasonable rate and have great torque: perfect! Note. When you get one make sure it has some of the old wire harness it will make it much easier for you to splice your wire to it. also make sure it has its crank arm and offset post. If the main motor post is the only physical connection you have to work with your cam will likely slip.

Mount the motor somewhere inside your box. I put mine on one of the side walls. Remember there will be a large rotating cam connected to it and it needs to be able to rotate free and clear of any and all items, especially wires, that you are going to put in the box. There are several good tutorials on YouTube on working with these motors.

I cut a 12 inch diameter cam from a piece of 1/2 ply wood. first I cut a perfect circle. I mounted it on the motor and used this to determine the required height of the motor in the box. I only wanted the lid to lift about 2 inches. After doing this fitting I used a jig saw to randomly cut 'teeth' into the cam trying my best to keep them at random width and depths.

Lastly I mounted a roller to the under side of the lid using 2 metal L brackets, a 1 inch nylon spacer and a carriage bolt. The roller is positioned just above the cam so that it rides along the teeth of the cam.

I used the 12 volt rail of an ATX power supply to power the motor through the relay controlled by the Arduino. Yes, getting everything to line up does require a bit of trial and error. After re-positioning the roller once or twice... ok three times... everything lined up and the lid began bouncing as planned!

Breath of Fire : Smoke and Lights

I used a cheap 400 Watt smoke generator for smoke effects. Out of the box this was radio controlled. To control it with the Arduino I opened the receiver and soldered two lead lines to the trigger button pads. This provided me with lines that I connected to an Arduino controlled relay channel. It was a simple hack that I learn by watching a few YouTube videos. I also added an old vacuum cleaner hose to direct the smoke to come out as a stream from just under the lid. I liked the visual effect and it help reduce the vapor condensation on the electronics inside the box.

For lights I simple cut a light duty extension cord and wired it through a relay channel. The string of 100 red LED lights connected to this could then be switched on and off by the Arduino.

Use Your Outside Voice

The WaveShield has an 1/8 inch headphone jack as and output - as well as 2 i/o pins for a direct connection. I used an 1/8 inch patch chord to connect to a 30 Watt bass guitar amplifier that I borrowed from my practice room. Any number of amplified speakers would work - including PC speakers. But using something with solid low end is definitely a plus.

Chain It Up

I purchase some plastic chains from a Halloween store and 3D printed a pad lock. Wrapping these over the crate added to the depth and feel of the illusion.

Halloween!!!

Put the crate out in the yard and hide the motion sensor in a nearby bush. I used a long run of speaker wire to connect the sensor so that I could experiment with the positioning such that the monster would wake up when someone gets close (about 5 ft) to the crate.

As the evening grew darker I realized that all of the detail on the outside of the crate was becoming difficult to see. Eventually I illuminated it with a strobed floodlight and was very happy with the effect.

As trick-or-treaters walked up the driveway they notice the growling box: some with curiosity others were actually scared of it. As they approached and the monster roared to life they would up, and squeal some even applauded. It was a huge hit.

The Future

There are a few things that I will improve before next Halloween. I will add R/C control so that I can pause or trigger the monster from a distance. I will also add some type of feedback to the lid lifter so that the Arduino can 'know' when the lid is open or closed. Several times the lifter stopped at a high point in the cycle which made the 'guts' of the box visible until the next wake cycle. Lastly, I may connect the external lighting/strobes to the Arduino to allow them to be controlled by the program and or the R/C fob.

GitHub Repository

You will find the latest code and wiring diagrams Here on GitHub

Code

Monster_In_A_Box_V03.inoC/C++
Arduino code for the Monster in a Box prop
#include "MonsterSounds.h"

#define LID_BOUNCER 6   // Connect Digital Pin on Arduino to Relay Module
#define RED_LEDS    7   // Connect Digital Pin on Arduino to Relay Module
#define FOG_MACHINE 8   // Connect Digital Pin on Arduino to Relay Module
#define UNUSED      9   // Connect Digital Pin on Arduino to Relay Module

#define PIR_SENSOR      A0
#define ACTION_2_BUTTON A3
#define PAUSE_BUTTON    A4
#define DEBUG_BUTTON    A5
 
#define FRAMERATE          20
#define FRAMEDELAY         1000/FRAMERATE

#define WAKE_SECONDS_MIN    3 // Seconds
#define WAKE_SECONDS_MAX    5 // Seconds
#define WAKE_DELAY         30 // Seconds

#define WAKE_FRAMES_MIN     WAKE_SECONDS_MIN  * FRAMERATE
#define WAKE_FRAMES_MAX     WAKE_SECONDS_MAX * FRAMERATE
#define WAKE_DELAY_FRAMES   WAKE_DELAY  * FRAMERATE

MonsterSounds sounds;

void setup() 
{  
  // initialize serial communication:
  Serial.begin(9600);
  
  // Setup all the relay Pins
  pinMode(LID_BOUNCER, OUTPUT);
  pinMode(RED_LEDS,    OUTPUT);
  pinMode(FOG_MACHINE, OUTPUT);
  pinMode(UNUSED,      OUTPUT);

  // Force all Effects to OFF
  stopAllEffects();

  pinMode(PIR_SENSOR,      INPUT);
  pinMode(ACTION_2_BUTTON, INPUT_PULLUP);
  pinMode(PAUSE_BUTTON,    INPUT_PULLUP);
  pinMode(DEBUG_BUTTON,    INPUT_PULLUP);

  sounds.initialize(); // Monster Sounds
  
  sounds.playSystemReady();delay(1000);
  
  Serial.println();
  Serial.print("*** System Ready ***");
  Serial.println();
  
}

boolean monsterIsAwake = false;
int pauseCountdown         = 0;
int lidBounceCountdown     = 0;
int flashRedLightCountdown = 0;
int smokeCountdown         = 0;
int reawakeCountdown       = 0;

void loop() 
{ 
  if (pauseCountdown > -1 ) pauseCountdown--;
  
  // NOTE: All buttons are using pullups, thus LOW means the button is PRESSED
  
  if (pauseCountdown > 0 || digitalRead(PAUSE_BUTTON) == LOW) 
  {
    if (pauseCountdown <= 0 && digitalRead(PAUSE_BUTTON) == LOW)  Serial.println("PAUSED");
   
    stopAllEffects();
    sounds.stopAll();
    reawakeCountdown = WAKE_DELAY_FRAMES;

    if (digitalRead(PAUSE_BUTTON) == LOW) pauseCountdown = 50;
    
  
  } else {
    if (reawakeCountdown ==0) Serial.println("ARMED");
    if ((digitalRead(PIR_SENSOR) == HIGH || digitalRead(ACTION_2_BUTTON) == LOW) && reawakeCountdown <=0)   
    {
      wakeMonster();
    }
  
    if (monsterIsAwake) 
    {
      processAnimation();
    
    } else {
     
      sounds.playSnore();
      
      if (reawakeCountdown > -1 ) reawakeCountdown--;
    
    }
  }
  
  delay(FRAMEDELAY);
}


/*
 * Wake Monster
 */
void wakeMonster() 
{
  if (!monsterIsAwake)
  {
    int activityDuration = random(WAKE_FRAMES_MIN, WAKE_FRAMES_MAX); // this is how long the monster will be active

    Serial.print("WAKE UP : ");
    Serial.print(WAKE_FRAMES_MIN);
    Serial.print(" : ");
    Serial.print(WAKE_FRAMES_MAX);
    Serial.print(" : ");
    Serial.println(activityDuration);
    
    reawakeCountdown = isDebug() ? 0 : WAKE_DELAY_FRAMES;    // force a delay between wake cycles
    Serial.print("******"); 
    Serial.print(reawakeCountdown); 
    Serial.println( "******");
    
    monsterIsAwake = true;

    bounceLid(activityDuration);
    flashRedLight(activityDuration);
    activateSmoke(activityDuration);    // Hold the smoke button for 1 second 

    sounds.playRoar();
    
  }
}

 
/*
 * 
 */
void processAnimation()
{ 
  if (lidBounceCountdown % 10 == 0) {
    Serial.print(lidBounceCountdown);
    Serial.print("  -  ");
    Serial.print(flashRedLightCountdown);
    Serial.print("  -  ");
    Serial.print(smokeCountdown);
    Serial.println(" ");
  }
  
  monsterIsAwake = lidBounceCountdown > 0 || flashRedLightCountdown > 0 || smokeCountdown > 0;
  
  if (lidBounceCountdown <= 0) 
  {
    bounceLid(0);
  } else {
    lidBounceCountdown--;
  }
  
  if (flashRedLightCountdown <= 0) 
  {
    flashRedLight(0);
  } else {
    flashRedLightCountdown--;
  }
  
  if (smokeCountdown <= 0) 
  {
    activateSmoke(0);
  } else {
    smokeCountdown--;
  }
  
}


/*
 * Disable all of the Effects 
 * This effectively turns the monster off
 */
void stopAllEffects()
{
  openRelay( LID_BOUNCER );
  openRelay( RED_LEDS );
  openRelay( FOG_MACHINE );
  openRelay( UNUSED );
  
  lidBounceCountdown     = 0;
  flashRedLightCountdown = 0;
  smokeCountdown         = 0;
  reawakeCountdown       = 0;

  monsterIsAwake = false;
}


/*
 * Bounce the box lid
 *     duration of 0 means STOP
 */
void bounceLid(int duration)
{
  if (duration <= 0) 
  {
    openRelay(LID_BOUNCER);    
    
  } else {
    // start the lid bouncing
    closeRelay(LID_BOUNCER);
    
    // set a timeout to stop after duration
    lidBounceCountdown = duration;
  }
}


/*
 * Flash Red Lights
 *     duration of 0 means STOP
 */
void flashRedLight(int duration)
{
  if (duration <= 0) 
  {
    openRelay(RED_LEDS);
    
  } else {
    // start the light flashing
    closeRelay(RED_LEDS);
    
    // set a timeout to stop after duration
    flashRedLightCountdown = duration;
  }
  
}

/*
 * Activate Smoke
 */
 void activateSmoke(int duration)
 {
  // 'press' the smoke button
  // duration should be a fixed amount of time needed for the machine to respond to the action
  // set a timeout to stop after duration
  
  if (duration <= 0) 
  {
    openRelay(FOG_MACHINE);
    
  } else {
    // start the light flashing
    closeRelay(FOG_MACHINE);
    
    // set a timeout to stop after duration
    smokeCountdown = duration;
  }
 }

/* 
 *  Sets the Normally Open (NO) terminal to OPEN
 *  Normally Closed will become Closed
 */
 void openRelay(int channel)
 {
  digitalWrite(channel, HIGH);
 }

/* 
 *  Sets the Normally Open (NO) terminal to Closed.
 *  Normally Closed will become OPEN
 */
 void closeRelay(int channel)
 {
  digitalWrite(channel, LOW);
 }

/*
 * 
 */
bool isDebug()
{
  return digitalRead(DEBUG_BUTTON) == LOW;
}
MonsterSounds.hC/C++
Arduino header for the monster sounds library
/* NOTE ABOUT ARDUINO PINS
 * Pins 13, 12, 11 are always used by the SD card (they are the only pins that have a high speed SPI interface). 
 * Then there are 5 other pins used to talk to the DAC and SD card, but they can be set to connect to any arduino pin. 
 * However, by default, the library is configured to use pins 10 (for SD card) and pins 2, 3, 4 and 5 for the DAC. 
 * To chanage these pins requires modifying the library - the pins are referenced by their 'hardware' pin names (ie PORTD, etc) not by arduino pins. 
 * That means pins 6, 7, 8, 9 and the 6 analog in pins (also known as digital i/o pins 14-20) are available.
 * 
 */
 
#include <Arduino.h>
#include <Wire.h>
#include <WaveHC.h>
#include <WaveUtil.h>

    static const char roar0[] = "ROAR0000.wav";
    static const char roar1[] = "ROAR0001.wav";
    static const char roar2[] = "ROAR0002.wav";
    static const char * const roarSounds[] = {roar0, roar1, roar2};
    
    static const char sleep0[] = "SNORE000.wav";
    static const char sleep1[] = "SNORE001.wav";
    static const char sleep2[] = "SNORE002.wav";
    static const char * const sleepSounds[] = {sleep0, sleep1, sleep2};
    
    int previousRoarSound = -1;
  
class MonsterSounds 
{
  private:  

    SdReader  card; // This object holds the information for the card
    FatVolume vol;  // This holds the information for the partition on the card
    FatReader root; // This holds the information for the volumes root directory
    FatReader file; // This object represent the WAV file for a phrase
    WaveHC    wave; // A single wave object -- only one sound is played at a time
    
    void playfile(char *name);

  public:
    void initialize(); 
    void playSystemReady();
    void playRoar();    
    void playSnore();    
    void stopAll();
};
MonsterSounds.inoC/C++
Arduino code for the monster sounds library
/* NOTE ABOUT ARDUINO PINS
 * Pins 13, 12, 11 are always used by the SD card (they are the only pins that have a high speed SPI interface). 
 * Then there are 5 other pins used to talk to the DAC and SD card, but they can be set to connect to any arduino pin. 
 * However, by default, the library is configured to use pins 10 (for SD card) and pins 2, 3, 4 and 5 for the DAC. 
 * To chanage these pins requires modifying the library - the pins are referenced by their 'hardware' pin names (ie PORTD, etc) not by arduino pins. 
 * That means pins 6, 7, 8, 9 and the 6 analog in pins (also known as digital i/o pins 14-20) are available.
 * 
 */
 
void MonsterSounds::initialize()
{
  Serial.println("Initializing Sounds...");
  if(!card.init())        Serial.println(F("Card init. failed!"));
  if(!vol.init(card))     Serial.println(F("No partition!"));
  if(!root.openRoot(vol)) Serial.println(F("Couldn't open dir"));
  Serial.println(F("Files found:"));
  root.ls();

  randomSeed(analogRead(0));
}


void  MonsterSounds::playSystemReady()
{
  this->playfile("WELCOME0.WAV");
}

void  MonsterSounds::playRoar()
{
  int index = random(3);  // 0, 1, 2
  while (index == previousRoarSound)
  {
    index = random(3);
  }
  previousRoarSound = index;
  
  this->playfile(roarSounds[index]);
}

void  MonsterSounds::playSnore()
{
  if (!wave.isplaying) // Do not interupt an exising sound with snoring
  {
    int index = random(3); // 0, 1, 2
    this->playfile(sleepSounds[index]);
  }
}

void MonsterSounds::stopAll()
{
  wave.stop(); // Stop any currently-playing WAV
}

// -------------------------------------------------------------------
// playfile()    
// Open and start playing a WAV file
// -------------------------------------------------------------------
void MonsterSounds::playfile(char *name) 
{    
  PgmPrint("Playing sound: ");
  Serial.println(name); 
  
  if (wave.isplaying) {// already playing something, so stop it!
    wave.stop(); // stop it
  }

  if (!file.open(root, name)) {
    PgmPrintln("File not found ");
    return;
  }

  if (!wave.create(file)) {
    PgmPrintln("Not a valid WAV");
    return;
  }
  
  // ok time to play!
  wave.play();
}

Custom parts and enclosures

Monster Sounds Zip File
A Zip file containing all of the sounds for this project
monstersounds_AMfhWmvHpW.zip

Schematics

Monster In A Box Wiring
W5byc0bypoiv5jffeqte

Comments

Similar projects you might like

Spooky Candy Box

Project tutorial by Shoeb Ahmed

  • 752 views
  • 0 comments
  • 5 respects

Optical Illusion Box

Project tutorial by Patt Vira

  • 3,362 views
  • 0 comments
  • 21 respects

Mobile Vote Box

Project tutorial by benstr 🚀

  • 2,225 views
  • 8 comments
  • 10 respects

Temp/Humidity LCD Box

Project tutorial by YENFU CHEN

  • 2,257 views
  • 3 comments
  • 9 respects

Arduino Controlled Lock Box with Solenoid and RFID

Project tutorial by RobotGeek Projects Team

  • 5,474 views
  • 2 comments
  • 19 respects
Add projectSign up / Login