Sunday, December 10, 2017

Monster in a Box

Unfortunately this blog post will be slightly incomplete. I have pictures of all the woodworking but I failed to take pictures of any of the electronics and it's now packed away since Halloween is over. I will still try to describe everything that was done.

This project started with an e-mail from a friend of mine. It was a video of a very similar project and I have wanted to get into some electronics projects and this seemed like a good start.
We ended up doing two boxes. One for each of us. I needed to replace a portion of my fence so it seemed like a good time to get some old looking wood. We had enough for his box but not enough for mine. Another technique I was interested in trying was aging old wood. A bit of vinegar with some steel wool was put in a jar for three days and I gave everything a first coat before building the box. I waited a few months for the second coat which in hindsight was a bit late. The steel wool had rusted so I got an look that was a bit more orange than I would have preferred.
I added three stencils once the box was fully aged. This included a 'Danger' sign on the top, a 'Do Not Feed' on the front and a 'This Side Up" sign on the back. I'm more of a precise woodworker then a Disney imagineer so all of my stencils were very neat. For the other box he just held it roughly and spray painted quickly. I think it made his look a bit more natural. The bars and hinges were all given a coat of black spray paint meant to look like black metal and I added chains and a lock. The handles were braced rope. Now it was time for the electronics.

I'll lay out all the electronic bits and include precise model numbers where I can. This is a pretty straight forward Arduino project and doesn't have to be perfect to still be scary.
Bouncing Lid - The lid bounces via a wooden wheel with randomly spaced cogs. It runs off a windshield wiper motor and uses a high voltage motor shield. I also had to add a few springs to get the lid moving up and down.
Lid Lights - The lights for the lid are LED stick on lights that require a 9v power supply. If you're going to get into electronics I recommend you keep every power supply you've ever owned. They are all different voltages and you can cut off the end and use them for a lot of projects. (Susay® Waterproof Red LED 3528 SMD 300LED 5M Flexible Light Strip 12V 2A 24W 60LED/M) I used a relay to allow me to turn them off and on. (SainSmart 4-Channel Relay Module)
LED Eyes - The eyes are just two simple LEDs. These are slightly brighter than your average LEDs but were easy to install and program.
Sound - The sound shield we used was the standard one for Arduino and allows us to directly connect speakers. This was attempted but in the end I went with a set with a subwoofer from Walmart. Only $30 and gave much louder sound with good bass. (http://www.robotshop.com/ca/en/cytron-easy-mp3-shield.html)
Lid Sensor - The lid sensor is a door bell. Simple but effective. (Almost. More on that later.)
Remote - The remote was a Gikfun IC2262/2272 4 Channel Wireless Remote Control. It has four buttons and allows me to have various 'scenes' from just lights to full on lid lifting.
Lock - We got a very authentic looking lock for only $20. You can probably find cheaper but this was solid metal. (2 of Deco 79 01101 Metal Brass Lock and Keys Wall Hanging, 4" x 2.5")

I have made note of a few things for next Halloween that weren't quite working. The range for the remote is very short. Will either need to find something more powerful or create a better antenna. The lid sensor works but doesn't stay turned on long enough. I started to experiment with slowing the motor down a bit before trying to see if the lid was closed but didn't get it working in time.

This was a fun project and here is the video of it in action. The very simple code is below that.




#include <SoftwareSerial.h>

// ------------------------------------------------------------------
// Include Sound drivers.
// ------------------------------------------------------------------
#include <CytronEZMP3.h>
CytronEZMP3 mp3;

// ------------------------------------------------------------------
// Pin Designations
// ------------------------------------------------------------------
// Remote Input Pins
const int remoteInputA = 11;
const int remoteInputB = 13;
const int remoteInputC = 12;
const int remoteInputD = 10;

// Sounds Shield
const int soundReceivePin = 2;
const int soundTransmitPin = 3;

// Motor Pins
const int motorDirPin = 4;
const int motorSpeedPin = 5;

// Park Pin
const int parkPin = 7;

// Lid Lights
const int lidPin = 8;

// Eyes
const int eyePin = 9;

// ------------------------------------------------------------------
// Random Variables
// ------------------------------------------------------------------
int debugMode = true;
int park = true;
int remoteReadState = 0;
int monsterVolume = 75;
int monsterFrequency = 5000;

// ------------------------------------------------------------------
// One Time Setup Code
// ------------------------------------------------------------------
void setup() {
  // Initiate the debug window.
  Serial.begin(9600);

  // Setup Remote
  pinMode(remoteInputA, INPUT);
  pinMode(remoteInputB, INPUT);
  pinMode(remoteInputC, INPUT);
  pinMode(remoteInputD, INPUT);
  digitalWrite(remoteInputA, LOW);
  digitalWrite(remoteInputA, LOW);
  digitalWrite(remoteInputA, LOW);
  digitalWrite(remoteInputA, LOW);

  // Setup Eyes
  pinMode(eyePin, OUTPUT);

  // Setup Lid
  pinMode(lidPin, OUTPUT);
  digitalWrite(lidPin, LOW);

  // Set up Parking Switch
  pinMode(parkPin, INPUT);

  // Set up the sounds
  if(!mp3.begin(soundReceivePin, soundTransmitPin))
  {
    Serial.println("Init failed");
    //while(1);
  }
  mp3.setVolume(monsterVolume);

  // Set up the motor. Make sure it's going in the right direction.
  pinMode(motorSpeedPin, OUTPUT);
  pinMode(motorDirPin, OUTPUT);
  digitalWrite(motorDirPin, LOW);
  digitalWrite(motorSpeedPin, LOW);
}

// ------------------------------------------------------------------
// Listening Loop
// ------------------------------------------------------------------
void loop() {
  // Testing
  testMonster();

  // Weak Monster
  if (digitalRead(remoteInputA) == HIGH)
  {
    executeWeakMonster();
  }

  // Mild Monster
  if (digitalRead(remoteInputB) == HIGH)
  {
    executeMildMonster();
  }

  // Crazy Monster
 if (digitalRead(remoteInputC) == HIGH)
  {
    executeCrazyMonster();
  }

  // Random Monster
  if (digitalRead(remoteInputD) == HIGH)
  {
    executeRandomMonster();
  }

}

// ------------------------------------------------------------------
// Debug and Testing Methods
// ------------------------------------------------------------------
void debugPrintLn(char* debugMessage) {
 if(debugMode == true)
  {
    Serial.println(debugMessage);
  }
}

void testMonster()
{
  debugPrintLn("TESTING");
  delay(5000);
  executeWeakMonster();
  delay(1000);
  executeMildMonster();
  delay(5000);
  executeWeakMonster();
  delay(1000);
  executeCrazyMonster();
  delay(monsterFrequency);
}

// ------------------------------------------------------------------
// Monster Eye Actions
// ------------------------------------------------------------------
void turnEyesOn()
{
  debugPrintLn("TURNING EYES ON");
  digitalWrite(eyePin, HIGH);
}

void turnEyesOff()
{
  debugPrintLn("TURNING EYES OFF");
  digitalWrite(eyePin, LOW);
}

void executeGlowingEyes()
{
  debugPrintLn("MAKING EYES GLOW");

  for(int brightnessCount=0; brightnessCount <= 255; brightnessCount++){
    analogWrite(eyePin, brightnessCount);  
    delay(10);
  }
  for(int brightnessCount=255; brightnessCount >= 0; brightnessCount--){
    analogWrite(eyePin, brightnessCount);
    delay(10);
  }
}

// ------------------------------------------------------------------
// Monster Growling Actions
// ------------------------------------------------------------------
void lowGrowlOne()
{
  debugPrintLn("LOW GROWL ONE");
  mp3.playTrack(1);
}

void lowGrowlTwo()
{
  debugPrintLn("LOW GROWL TWO");
  mp3.playTrack(2);
}

void lowGrowlThree()
{
  debugPrintLn("LOW GROWL THREE");
  mp3.playTrack(3);
}

void mediumGrowlOne()
{
  debugPrintLn("MEDIUM GROWL ONE");
  mp3.playTrack(5);
}

void mediumGrowlTwo()
{
  debugPrintLn("MEDIUM GROWL TWO");
  mp3.playTrack(5);
}

void mediumGrowlThree()
{
  debugPrintLn("MEDIUM GROWL THREE");
  mp3.playTrack(6);
}

void crazyGrowlOne()
{
  debugPrintLn("CRAZY GROWL ONE");
  mp3.playTrack(7);
}

void crazyGrowlTwo()
{
  debugPrintLn("CRAZY GROWL TWO");
  mp3.playTrack(8);
}

void crazyGrowlThree()
{
  debugPrintLn("CRAZY GROWL THREE");
  mp3.playTrack(9);
}

// ------------------------------------------------------------------
// Monster Lid Light Actions
// ------------------------------------------------------------------
void turnLidLightsOn()
{
  debugPrintLn("TURNING LID LIGHTS ON");
  digitalWrite(lidPin, LOW);
  delay(750);
}

void turnLidLightsOff()
{
  debugPrintLn("TURNING LID LIGHTS OFF");
  digitalWrite(lidPin, HIGH);
}

// ------------------------------------------------------------------
// Monster Lid Lifting Actions
// ------------------------------------------------------------------
void startSlowMotor()
{

  debugPrintLn("STARTING SLOW MOTOR");
  analogWrite(motorSpeedPin, 255);
}

void startFastMotor()
{

  debugPrintLn("STARTING FAST MOTOR");
  analogWrite(motorSpeedPin, 255);
}

void stopMotor()
{
  debugPrintLn("STOPPING MOTOR");
  analogWrite(motorSpeedPin, 0);
}

void parkMonster()
{
  debugPrintLn("ATTEMPTING TO PARK MONSTER");
  int parkCounter = 0;
  while (digitalRead(parkPin) == LOW)
  {
    parkCounter = parkCounter + 1;
    if (parkCounter == 2000)
    {
      break;
    }
  }
  debugPrintLn("PARKING MONSTER");
  stopMotor();
}

// ------------------------------------------------------------------
// Monster Definitions
// ------------------------------------------------------------------
void executeWeakMonster() {
  debugPrintLn("CALLING WEAK MONSTER");
  int randomNumber = random(0,3);
  if(randomNumber == 0)
  {
    int eyeCounter = 0;
    while (eyeCounter < 5)
    {
      eyeCounter = eyeCounter + 1;
      executeGlowingEyes();
    }
  }
  else if(randomNumber == 1)
  {
    int eyeCounter = 0;
    while (eyeCounter < 20)
    {
      eyeCounter = eyeCounter + 1;
      turnEyesOn();
      delay(100);
      turnEyesOff();
      delay(100);
    }
  }
  else if(randomNumber == 2)
  {
    int eyeCounter = 0;
    while (eyeCounter < 1)
    {
      eyeCounter = eyeCounter + 1;
      executeGlowingEyes();
      turnEyesOn();
      delay(100);
      turnEyesOff();
      delay(100);
      turnEyesOn();
      delay(100);
      turnEyesOff();
      delay(100);
      turnEyesOn();
      delay(100);
      turnEyesOff();
      delay(100);
    }
  }
}

void executeMildMonster()
{
  debugPrintLn("CALLING MILD MONSTER");
  int randomNumber = random(0,3);
  if(randomNumber == 0)
  {
    turnLidLightsOn();
    mediumGrowlOne();
    executeGlowingEyes();
    turnLidLightsOff();
  }
  else if(randomNumber == 1)
  {
    turnLidLightsOn();
    mediumGrowlTwo();    
    int eyeCounter = 0;
    while (eyeCounter < 10)
    {
      eyeCounter = eyeCounter + 1;
      turnEyesOn();
      delay(100);
      turnEyesOff();
      delay(100);
    }
    turnLidLightsOff();
  }
  else if(randomNumber == 2)
  {
    turnLidLightsOn();
    mediumGrowlThree();
    int eyeCounter = 0;
    while (eyeCounter < 1)
    {
      eyeCounter = eyeCounter + 1;
      turnEyesOn();
      delay(100);
      turnEyesOff();
      delay(100);
      turnEyesOn();
      delay(100);
      turnEyesOff();
      delay(100);
      executeGlowingEyes();
    }
    turnLidLightsOff();
  }
}

void executeCrazyMonster()
{
  debugPrintLn("CALLING CRAZY MONSTER");
  int randomNumber = random(1,2);
  if(randomNumber == 0)
  {
    crazyGrowlOne();
    executeGlowingEyes();
    turnLidLightsOn();
    turnEyesOn();
    delay(500);
    turnLidLightsOff();
    turnEyesOff();
    delay(500);
    turnLidLightsOn();
    turnEyesOn();
    delay(500);
    turnLidLightsOff();
    turnEyesOff();
    delay(500);
    turnLidLightsOn();
    turnEyesOn();
    delay(500);
    turnLidLightsOff();
    turnEyesOff();
    delay(500);
    turnLidLightsOn();
    turnEyesOn();
    delay(500);
    turnLidLightsOff();
    turnEyesOff();
    executeGlowingEyes();
  }
  else if(randomNumber == 1)
  {
    crazyGrowlTwo();
    executeGlowingEyes();
    turnLidLightsOn();
    turnEyesOn();
    startFastMotor();
    delay(3000);
    stopMotor();
    turnLidLightsOff();
    executeGlowingEyes();
    startFastMotor();
    turnLidLightsOn();
    delay(3000);
    startSlowMotor();
    delay(1000);
    parkMonster();
    turnLidLightsOff();
    turnEyesOff();
    executeGlowingEyes();
  }
}

void executeRandomMonster()
{
  debugPrintLn("CALLING RANDOM MONSTER");
  int randomNumber = random(0,3);
  if(randomNumber == 0)
  {
    executeWeakMonster();
  }
  else if(randomNumber == 1)
  {
    executeMildMonster();
  }
  else if(randomNumber == 2)
  {
    executeCrazyMonster();
  }
}

Thursday, March 9, 2017

Campaign Style Bookcase

Before I started following Chris Schwarz I had never formally heard about campaign furniture although I always knew I liked the furniture stylings of the Indian Jones movies and the vignettes at the ride in Disneyland is the most interesting part of the ride for me. I followed Chris' blog closely in the months leading up to the release of his book 'Campaign Furniture' and bought it as soon as it came out. It's one of the few woodworking books I've ever read from cover to cover rather than just using it as a reference.

The project I had in mind when I heard about the book was a bookcase for my son. I will admit I was temporarily disappointed when I saw the bookcase in 'Campaign Furniture' since it was much smaller than I had in mind. That disappointment faded quickly however for two reasons.
1) The bookcase Chris did would be perfect for a complete set of Hardy Boy books so it's on the list for a future project.
2) The book focused as much on techniques as it did on specific pieces of furniture so it gave me everything I needed to design and build my own.
The design process for me ranges from detailed measured full size drawings to sketches on a piece of scrap paper. This project was the latter. I knew three 'units' would give me good height and storage capacity and the measurements flowed quickly based on the size of the wood I had available. In this case it was 8 foot lengths of African Mahogany ranging from 8 1/2 to 9 inches in width. That put the width of each box at a little under 32 inches and the height at 16 inches.

With basic measurements in hand the boxes came together quickly with half blind dovetails. 'Campaign Furniture' preaches full blind dovetails and I do like the idea, however I don't get to do as many woodworking projects as I would like and if I'm going to do dovetails I want to show them off at least a little bit. All three boxes are identical and I toyed with different designs for the insides. I drilled shelf pins in all three but only the middle unit has a shelf. The top unit got a bank of three drawers and the bottom unit has a pair of doors.
I had a few crazy ideas for the base of the unit. At one pint I was considering stealing the brass kick plate from my front door and replacing it with a stainless steel one from the home centre so that I had a piece of brass to cover the front of the base. In the end I had the perfect amount of wood left over to do a simple dovetailed frame with a couple of cross members to allow me to bolt it to the bottom. I went with full dovetails here and at first I wasn't sure you'd even notice them but in the end they elevate the case nicely and are fairly visible.
The drawer unit in the top gave me an opportunity to add a few fun bits. In this case three hidden compartments. The first is simply a small recessed area in one of the drawers. The second is a false bottom on the middle drawer and the final one is a small box behind a short drawer. As with many secret compartments, once you know they exist they aren't hard to find however if you don't know to look there isn't anything obvious indicating the treasures hidden within.


I will admit that the scariest part of the build for me was all the inset hardware. I fretted over creating jigs and various other options but in the end I went with a relatively straight forward approach.
1) Mark the heights with a marking gauge and the roughly mark the width.
2) Use a handheld trim router free hand to route out the bulk before cleaning up with a chisel.
3) Hold the hardware in place to mark the width and finish up with a chisel.
All 24 pieces were done in an evening.

The finish I originally had in mind was a darker stain and pre-aging the brass. When I did some test samples of the African Mahogany with a wipe-on poly however I liked the look and decided to keep things simple.  I figure after a few sea voyages to India it will darken on it's own and develop the patina I am looking for.

This was a fun project and I'm hooked on Campaign Furniture.















Shut the Box Times Six

Each Christmas I try to make at least a few of my Christmas gifts, especially the ones for the kids teachers. In the past they've been simple cutting boards, small boxes and clipboards. This year I saw plans for a game called Shut the Box which fit with my theme of trying to build a game for the kids each Christmas. It was a bit more involved then a cutting board but I figured if I batched them out it would be worth the effort. In hindsight, even batching them out takes time when you are doing something like this six times. I got the two for the kids school done on time but the rest didn't get mailed quite in time.
Construction is straight forward with finger jointed corners, plywood bottom and floating panel solid top. I have a jig that is permanently set up for 3/8 fingers on the table saw with a flat bottomed dado blade so set up is quick. Making the box is actually quite quick. Most of the time is spent in the glue up and finishing. For the prototype (a 7th box) I hand wrote the numbers but for the next six I bought an inexpensive set of stamps for the numbers. Felt bottoms on a 1/8 inch plywood substrate, brass piano hinges and a wipe on poly finish things up. Easy construction and should last a life time of fun.

For plans you can go to http://www.rockler.com/diy-projects/shut-the-box.