Chatting Animatronic Halloween Skulls

by copperdogma in Circuits > Arduino

251 Views, 3 Favorites, 0 Comments

Chatting Animatronic Halloween Skulls

2A3C6B68-6A3B-4EFD-BD23-DC49E8905D6F_1_201_a.jpeg
7C560875-6B3D-46BD-8C52-79150D1A2940_1_201_a.jpeg
05F6B392-814F-4801-A0AF-67EBFBB664C3_1_201_a.jpeg
C67ED7AC-06ED-41AF-9CC1-E558DC0D0366_1_201_a.jpeg
2024 Halloween Skulls: Movie
2024 Halloween Skulls: Ju Jubes

My 11 year old daughter and I decided to make a pair of animatronic skulls for Halloween that chat back and forth in skits we recorded ourselves. The idea came from the Statler and Waldorf muppets heckling from the theatre box. My daughter didn’t know what I was talking about, proving I’m a terrible father;)

Want to build your own? We had a blast and everyone loved them during Halloween! The eyes and jaws animate with the audio and you can easily record your own skits. They connect to portable Bluetooth speakers so the sound is fantastic.

Neither of us had any skill in hardware and, although I’m a programmer, I’d never programmed in C++ before. It took us a long time, but 90% of that was trial and error. I’d guess we could recreate a single skull in a single day now if we put our minds to it.


Skills Required


It’s our first electronics project so we had to learn a ton of stuff, most of it from scratch.

  1. Basic soldering
  2. How to use a multimeter (for verification/debugging the circuits)
  3. Writing code in C++ (optional. We provide the code here!)
  4. Childlike enthusiasm and delight (this project was super fun to watch come together)

Supplies

I’ll link to the products I used when I can. I’m using affiliate links so I might get a little bonus if you use them, but mostly I find it easiest to understand what a product is and what alternatives I can use from a product listing.

Tools

  1. Soldering Iron/Station - I used a Hakko similar to this one which was great
  2. Multimeter - I use a basic KleinTools model, but any will do.
  3. Drill with ¼” and ⅛” bits
  4. Dremel
  5. Helping Hands - for soldering
  6. Wire strippers
  7. Precision Tweezers - some of the parts are tiny!
  8. Needle Nosed Pliers
  9. Heat Gun - (optional) for shrink tubing; I just used the soldering iron
  10. Utility knife
  11. Ultra-Fine Tip Sharpie Markers - to tape components on to the perfboard before soldering


Basic Components

  1. 2x Human-Sized Plastic Skull With Movable Jaws - We got one from a full skeleton from Home Depot that was already wired for LED eyes and another at a grocery store 1000 miles away that happened to use the exact same mold as our first one, which was bizarre;) The second one was sealed and didn’t have LED eyes so we had to do way more work on that one.
  2. 2x Bluetooth speakers - I’m using the JBL Flip 5 and JBL Flip 6. I bought one years ago and got another from a local seller.
  3. 2x battery power banks - I used these GTOCE models which were great. You’ll need something that can put out 4-5A from a single port. This is important. See Lessons Learned for details.
  4. Micro SD Card Adapter - to write the files to the card from your computer. We used this USB-C hub, but anything will work.
  5. 2x USB-C splitter cable - to connect the two USB-C ports on the circuit boards to the battery power banks


Structural

  1. 2x broomsticks - we mounted the skulls on these in front of our house, but you can mount them however you want!
  2. 2x pole stabilizer prongs - to hold the broomsticks/skulls solidly in the earth
  3. 10x neodymium magnets - to hold the skull halves together
  4. Double-sided hook and loop strap - for holding skull halves together and strapping cables to the poles (love this stuff)
  5. Dark linen-like fabric (thin enough to be “transparent” to the ultrasonic sensor)
  6. 1m/3’ of stiff wire - we used 22 gauge/0.025”/0.65mm brass wire, but coat hanger wire might work (harder to bend, though)
  7. 4x M3 Brass Female Hot Melt Knurled Nuts
  8. 4x M3 Screws
  9. Polymer clay (any colour)
  10. 2x 1” PVC coupling - large enough to fit the broomstick inside. You could also use a 1” PVC pipe cut down to size.
  11. Elastic band or barbed cord fasteners - I actually found the latter holding together a pair of socks I bought.
  12. ¾”-1” hose clamps
  13. 2x picture hanger hooks
  14. Plastic wrap (like Saran Wrap or similar)
  15. Two-part epoxy putty - I used J-B Weld SteelStik
  16. Super Glue (Cyanoacrylate)
  17. Original Gorilla Glue
  18. E6000 glue
  19. Masking tape


Electronics

  1. 2x Freenove ESP32-WROVER CAM Board - many board would probably work, but it has to be fast enough, have enough pinouts, support A2DP and BLE (Bluetooth Low Energy) Bluetooth profiles, and have a USB-C power plug on it (unless you want to the work powering it differently)
  2. 2x 3kg 5v servo - I used Power HD HD-1160A servos but they’re noisy
  3. 1x HC-SR04 Ultrasonic Sensor Distance Module
  4. 2x Micro SD Card Module
  5. 2x USB-C 5v Power Module
  6. 4x LEDs - we used 2 red and 2 blue so the skulls had different personalities
  7. 4x 100 ohm resistor - for LED eyes
  8. 22 awg solid hookup wire
  9. 24 awg flexible silicone-sheathed wire and/or 24 awg flexible plastic-sheathed wire
  10. 4-wire 24 awg cable - optional, you can make your own
  11. Dupont connector kit + crimper
  12. Male and female headers
  13. 5cm x 5cm (minimum dimension) perfboard with 2.54mm / 0.1in pitch - similar to this
  14. Male-Male Dupont Wires - for prototyping/testing
  15. Test Hook Clips/Alligator Clips - for prototyping/testing
  16. Heat shrink tubing
  17. Rosin core solder
  18. Desoldering wick - I’m bad at soldering;)

Overview

There is a Primary and Secondary skull, each driven by its own microcontroller, each of which is responsible for:

  1. Controlling the LED eyes
  2. Controlling the jaw servo
  3. Reading the SD card (mp3 audio files and settings file)
  4. Connecting and streaming audio to the Bluetooth speakers
  5. Connecting to the other skull to synchronize audio playing
  6. Detect motion via the ultrasonic sensor to trigger a skit to begin
  7. Synchronizing the LED eyes and jaw servo to the audio when the skull is speaking


The Primary skull is the only one with an ultrasonic sensor and is responsible for telling the Secondary skull what audio file to play.


When each skull is started the following happens:

  1. Initialize hardware
  2. Read skits (audio) and settings from the SD card
  3. Connect to its own Bluetooth speaker (the speaker name is set in SD card settings)
  4. Determine if it’s Primary or Secondary (as set in SD card settings)
  5. If Secondary, set itself up as a BLE server, ready to be commanded
  6. If Primary, connect to the Secondary’s BLE server
  7. If Primary, start listening to the ultrasonic sensor. If it detects someone, randomly choose a skit that hasn’t been played in a while, tell Secondary to play it, and start playing it itself.


Note that the instructions below are to create a single skull, but this project as designed is for two skulls. Any time you’re making anything below, make two copies of it.

Minimum Viable Product

TwoSkulls_schematic.png

It’s much easier to get the electronics and programming working and assemble it at the end. Debugging hardware mounted in tight spaces is very difficult.

The microcontroller (I chose a Freenove ESP32-WROVER CAM Board) is the brain of the operation, controlling absolutely everything.

I’m sure you can use almost anything, but for this project it needs to support:

  1. 5v USB-C power in (but only to match our instructions; you could in theory choose a board that can be powered any way you like)
  2. Minimum 16 pins to control everything
  3. BLE (Bluetooth Low Energy)
  4. A2DP (Bluetooth audio)


NOTE: All pins in these instructions assume you’re using the ESP32-WROVER, but you can change what pins drive what in the code.

This was our first electronics project so we started with a breadboard and a lot of wires to make sure everything was hooked up correctly and working before we permanently soldered everything to a perfboard.

We went with USB-C for everything (microcontroller, cables, power supply) because it’s easy and ubiquitous. With a little effort you can change this to pretty much anything you like (plugged in power supply, USB-A, micro-USB, AAA battery pack, etc).

To prototype this we pushed the microcontroller into the middle of the board and attached the peripherals (LEDs, servo, SD card reader, ultrasonic sensor) one by one.

The circuit diagram shows which pins each peripheral is connected to.


But let’s start with something simple. I like the idea of a Minimum Viable Product when building things. What’s the simplest thing I can make that will provide something useful? In this case the MVP would be the microcontroller being powered, loaded up with code, and driving a LED. If we have that we have a known-good working platform on which we can build everything else.

Downloads

MVP: Wiring the LED

IMG_4360.jpeg
IMG_4361.jpeg
TwoSkulls-MVP_schematic.png

Use male-male Dupont wires for connections to make everything easier.

  1. Push the microcontroller into the breadboard
  2. Attach one black wire to GND on the microcontroller
  3. Clip a 100 ohm resistor to the end of the black wire
  4. Clip the end of that resistor to the negative (shorter) leg of an LED
  5. Attach a red wire to pin 32 (left eye) of the microcontroller
  6. Clip the other end of that red wire to the positive (longer) leg of the LED

MVP: Setting Up the IDE

We’ll go into far more detail on the code later, but for now these basic instructions will get you up and running with the IDE (integrated development environment; where you write code).

  1. Download and install Arduino IDE
  2. Install the esp32 board support via Tools->Board->Boards Manager. I used v2.0.17: esp32
  3. Install component libraries via Tools->Manage Libraries. I used the following versions:
  4. v5.0.2 : ESP32 ESP32S2 AnalogWrite
  5. v2.0.0 : HCSR04
  6. v1.6.1 : arduinoFFT
  7. v1.8.3 : ESP32-A2DP
  8. Use these settings under the Tools menu:
  9. Board: "ESP32 Wrover Module"
  10. Port: "/dev/cu.usbserial-1430" (this was mine; you might have to try each of the options to figure out which is your computer’s USB port, see “Upload the Code to the MIcrocontroller” below)
  11. Core Debug Level: "None"
  12. Erase All Flash Before Sketch Upload: "Disabled"
  13. Flash Frequency: "80MHz"
  14. Flash Mode: "QIO"
  15. Partition Scheme: "Huge APP (3MB No OTA/1MB SPIFFS)" (originally "Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)" but I ran out of space)
  16. Upload Speed: "460800"


If you’re fancy you can use Visual Studio Code (or if you’re extra fancy, Cursor) as your IDE and install the PlatformIO plugin, but that’s a little more advanced.

MVP: Download Code (aka Cloning the Repository)

It’s all up on GitHub: https://github.com/copperdogma/TwoSkulls

You can download it using the command line or the GitHub Desktop client. Github has some good instructions for both here.

Essentially you download the code and open it up in the Arduino IDE.

MVP: Upload Code to Microcontroller

Plug a USB-C cable into the microcontroller and then into your computer. The microcontroller will power up and probably do nothing because there’s no code on it. This is fine.

Next you’ll have to figure out what port it’s plugged into and set that in the Arduino IDE (Tools->Port). This is a bit of trial and error but the Arduino site has instructions and you probably only have four ports to try.

Now click Sketch->Upload in the IDE to compile and upload the code. It will restart once it’s uploaded and the LED should turn on.

If you open the Serial Monitor tab in the IDE you can see the code starting up and complaining over and over that it can’t find the SD Card. Understandable, seeing as we haven’t connected it yet.

If your LED is on we’re good! Congratulations. We have our MVP up and running. Now we’re going to add the rest of the components.

Prototyping & Wiring Harnesses Overview

IMG_4362.jpeg

It’s not really prototyping seeing as I did the prototyping, but it’s still useful to wire it all up on a breadboard first to make sure it works before soldering everything in place, especially if you’re making any changes to the hardware.

We’re going to make wiring harnesses for everything because it will make the breadboarding much easier and they’re the same harnesses we’ll be using with the final soldered board.


Wire Choices


I used three different types of wires for the project, each for a different purpose:

  1. 22 awg solid hookup wire - for bus bars and jumpers on the perfboard (see “Soldering Everything Onto the Perfboard” below)
  2. 24 awg flexible silicone-sheathed wire - for wires that will flex a lot, especially ones connected directly to peripherals
  3. 24 awg flexible plastic-sheathed wire - also for peripherals, usually when it’s a larger bundle of wires because the silicone wires are really floppy. Really you can use all silicone, all plastic, or a mix.


Harnesses and Soldering

 

I made two-part harnesses for everything. The first part of the harness was inside the skull. This then connects to the second part of the harness which connects to the microcontroller. This allows you to leave the tricky-to-get-to wires permanently attached to the skull components and just disconnect the harness for debugging.

We’re going to solder all wire connections. I can’t count the number of times, even with my limited electronics experience, I’ve just twisted wires together and then spent hours realizing the connection wasn’t solid.

I like to use red wires for power, black for ground, and whatever random fun colour I decide for control wires.

I typically use the helping hands to hold the wires in place, thread the shrink tubing onto the wires, twist the wires together so everything is straight, solder, then seal it all up with the shrink tubing.

NOTE: Put shrink tubing on first! You WILL forget over and over to put shrink tubing on the wires before soldering. I cannot help you with this aside from saying I’m sorry, I’ve been there, it sucks, and you should probably un-solder, put the shrink tubing on, and re-solder.

I found Dupont connectors work the best. They give you a pretty solid connection and they’re simple to plug in and out. It takes a bit of practice to get good with the Dupont crimp tool but it’s pretty quick once you get the hang of it.

Pay attention to the wire orders, because often I swapped the order between the peripheral end and the microcontroller end to make it easier to solder up on the perboard.

Once you’ve finished a harness, use your multimeter’s continuity tester to make sure each wire works properly.

Servo Harness

IMG_4366.jpeg

This is the simplest harness. It’s just a 3-wire male Dupont connector to a female Dupont connector. The Servo has its own Dupont harness hard-wired into it, so our harness will mate up perfectly.

Servo end (male Dupont): mine was black, red, control (yellow) but make sure you match whatever your servo has.

Microcontroller end (female Dupont): red (5V VCC), black (GND), yellow (pin 15)

SD Card Reader Harness

IMG_4398.jpeg

Exactly the same as the servo but more wires. The SD card reader doesn’t mount permanently to the skull, it just sort of flops around. I probably should have mounted this to the perfboard or something come to think of it.

SD Card Reader end (female Dupont): yellow (CS), blue (SCK), orange (MOSI), purple (MISO), red (3.3V VCC ), black (GND)

Microcontroller end (female Dupont): yellow (pin 5), blue (pin 18), purple (pin 19), black (GND), red (3.3V VCC), orange (pin 23)

Ultrasonic Sensor Harness

IMG_4368.jpeg

Because I wanted flexibility in where I put the ultrasonic sensor, the four wires connecting it were going to be quite long. Mine ended up being about 1m (3’). I didn’t want four wires flopping all over so I found a four-wire cable at an electrical supply store and used that. It worked perfectly.

I just stripped the gray outer casing, stripped the four individual wires within, and added female Dupont connectors to each end. The ultrasonic sensor has male pins coming out of it which is why we need two female connectors in this case for our harness. But you could easily use four individual wires and wrap them in electrical tape or shrink tubing or something and be just as good.

The secondary skull doesn’t need the ultrasonic sensor so you only need one of these harnesses.


Ultrasonic Sensor end (female Dupont): black (GND), white (ECHO), green (TRIG), red (5V VCC)


Microcontroller end (female Dupont): black (GND), red (5V VCC), white (pin 22), green (pin 2)

LEDs + Harness

IMG_4364.jpeg
IMG_4365.jpeg
TwoSkulls-LEDs_schematic.png

Each LED gets their own power/control wire but they share a ground wire. Each ground wire coming from the LEDs gets its own resistor before joining the common ground wire. I didn’t actually do this. I just put a single resistor on the common ground wire, which works, but can result in inconsistent brightness and a single point of failure. Use two resistors.

WIthout the resistors the LEDs (a type of diode) will draw as much current as the power supply can give, burning itself out. You might not notice when powering them with batteries as the batteries may not be able to supply enough current to burn one out, but when supplying power from USB, which often supplies 3A, will burn it out for sure.


Skull LED end (female Dupont): black (GND), red (pin 22/left eye), red (pin 23/right eye)

Harness LED end (male Dupont): black (GND), red (pin 22/left eye), red (pin 23/right eye)

Harness Microcontroller end (male Dupont): black (GND), red (pin 22/left eye), red (pin 23/right eye)

Downloads

Harness/Peripheral Testing

TwoSkulls_schematic.png
IMG_5240.jpeg

Now let’s make sure everything works.

Connect each of the peripheral harnesses to the breadboard on their appropriate pins using male-male Dupont wires. See the schematic for what goes where.

Note that we have two different levels of power required:

  1. 3V: LEDs, SD card reader
  2. 5V: servo, ultrasonic sensor


The microcontroller can provide the 3V the LEDs and SD card reader needs, but we can’t rely on it to provide 5V of power as the current draw when the SD card reader and ultrasonic sensor are running at the same time is too high for the microcontroller to handle. Ask me how I know;) (See “Lessons Learned” below.)

So we’ll also introduce our USB-C 5v Power Module. Connect its ground to the GND pin of the microcontroller and the power lines for the ultrasonic sensor and servo to the VCC of the power module.

I’m sorry I don’t have great photos of this step and the ones I have just look like a mass of coloured wires (which is what yours will look like). When I was breadboarding it I didn’t realize I needed the power module yet, so that wasn’t added until the perfboard stage and you won’t see it at all in these photos.

Plug in the power module first and then the microcontroller. Note that you’ll want to plug these into a continuous power source like a laptop, wall wart, etc and not a battery pack at this stage (see “Lessons Learned” below).

Everything should power up. If you’ve connected the USB-C cable from your computer to the microcontroller to power it, you should see exactly the same thing as last time in the Serial Monitor: it can’t find the SD card.

That’s because we haven’t written any data to it yet!

Downloads

Writing Data to the SD Card

Format your SD card as FAT16.

The github repository you downloaded with this project’s code includes a folder called sd_card_files.

Copy the contents of this folder to the SD card.

On the card itself, you should now see two files in the root level: config_primary.txt and config_secondary.txt

Let’s set this skull up as Primary.

  1. Delete config_secondary.txt
  2. Rename config_primary.txt to config.txt


If you’re setting up the secondary skull you should rename config_secondary.txt to config.txt

Now pop that SD card into the SD card reader attached to the microcontroller and restart it. The easiest way to do this on the ESP32-WROVER microcontroller we’re using is to press the tiny button labelled EN/RST on the microcontroller itself.

After it starts should be a lot more action:

  1. The LEDs should blink
  2. The servo should move and then move back
  3. The Serial Monitor in the IDE should show a ton of initialization and then attempt to connect to a Bluetooth speaker over and over.
  4. The servo should slowly move and then move back over and over.


The Serial Monitor should show it reading the skit files.

Connecting to the Bluetooth Speaker

Edit your SD card again, this time opening the config.txt in the root folder. It should look something like this:

role=primary
speaker_name=JBL Flip 5
speaker_volume=100
ultrasonic_trigger_distance=1000


The ultrasonic_trigger_disance is in centimetres.

“JBL Flip 5” is the name of my Bluetooth speaker. Change that to the name of your Bluetooth speaker and restart the skull.

You can find the name of your speaker by attempting to hook your phone up to the speaker to play music. Check your Bluetooth speaker’s instructions on how to pair it with a device (usually holding down the power/Bluetooth button for a bit) which should make it visible to your phone. You’ll see the name in the list. I wouldn’t actually pair it, though, or you might have to explicitly unpair from it before the skull can use it,

Now restart the microcontroller (using the tiny EN/RST button).

When the skull reboots it will attempt to connect to your speaker. You’ll probably have to put your speaker in pairing mode before the skull will connect, which is something you only need to do once per skull.

It will keep trying to connect. When it does it will play the /audio/Initialized - Primary.wav file from the SD card, which is actually my voice saying “Anthony Initialized.”

Oh, it’ll be at full blast because speaker_volume=100. You might want to turn it down first. Too late? Did it scare the crap out of you? Well, it’s a Halloween project so it’s par for the course;)

If everything’s working you now have a single functionally complete skull. Now let’s turn it into something that’s not a mess of wires on a breadboard.

Soldering Everything Onto the Perfboard

I used a perfboard. In theory you could design your own PCB, but I only need two of these things and I was still learning so I just hand soldered everything.

Everything I know about this I learned by trial and error, so my practices may be less than ideal. Caveat emptor.

The best tips I discovered while doing this:

  1. Hold components in place using masking tape while soldering them.
  2. Use a lot of Sharpie to mark which pin is which.
  3. When soldering larger components (like 20 pin headers), you really just need to get one pin perfectly soldered to start. It’ll be solid enough to hold everything exactly where it should be while you solder the other pins.

Downloads

Soldering the Microcontroller Headers

TwoSkulls_schematic.png
IMG_4369.jpeg
IMG_4370.jpeg

I want to be able to use this microcontroller on other projects, so instead of soldering it to the board I soldered headers to the board so I could plug it in and out. These are female headers, so pins on the bottom and holes on the top.

  1. Snap off a length of header that’s 20 pins long. Do it again; we need two.
  2. Test-fit the microcontroller onto the middle of your perfboard flush to one edge.
  3. Mark where the pin-line is.
  4. Insert the 20-pin headers where the microcontroller was sitting.
  5. Tape them into place with masking tape.
  6. Flip the perfboard over and solder the first and last pin of each header in place. We’ll be soldering only the ones we need as we go, but this will keep the header solid and in place for now.

Soldering the Harness Headers

FMN8E4LM3BLW3L9.png
F7JAGT5M3BLW3NX.jpg
FSP39FYM3BLW3MW.jpg

These are male headers, with pins on the bottom and top. These will be the connection points for the female ends of the harnesses we made earlier. We’ll need 4, so snap them to length:

  1. 3 pins for LEDs
  2. 3 pins for servo
  3. 4 pins for ultrasonic sensor
  4. 6 pins for SD card reader


Note that the secondary skull doesn’t need the ultrasonic sensor, so you can skip that skull’s header.

In theory you could use a single strip of 7 pins for the servo + ultrasonic sensor pins because they’re side by side.

Tape each in place with the longer pins pointing up and solder every single pin in place on the backside.

Soldering the Power Module

FMN8E4LM3BLW3L9.png
F7JAGT5M3BLW3NX.jpg
FSP39FYM3BLW3MW.jpg

Now we’ll solder the USB-C 5v Power Module in place. I realized this would fit within the footprint of the microcontroller, and due to the height of the microcontroller’s headers, it could just live under the microcontroller itself. It was very satisfying.

This is a little different kind of soldering job because the power module has no pins. So we’ll make some.

  1. Cut two one-inch lengths of stripped, solid wire.
  2. Solder each wire so it’s hanging down from the bottom of the power module, one through the VCC hole and one through the GND hole (I used the ones closer to the centre of the board, not the ones at the edges).
  3. Place the power module between the microcontroller headers so the USB-C port sticks out slightly from the end of the perfboard with the two wires hanging down.
  4. Solder the wires in place.
  5. Clip off the excess.

Soldering the Connections

FQVU1YCM3BLW3XW.png
FBKR69RM3BLW3XX.jpg
FDRUHDAM3BLW3XY.jpg

Now we connect every header pin to their appropriate microcontroller pin, power source (careful of the 3V vs 5V power), and ground.

Everything can share a common ground.

I am not great at this step, as evidenced by my soldering job. It all works and it’s not terribly hard to follow, but it feels like it could be a lot more optimized.

Before you start, ensure you use the Sharpie to label each relevant pin on the front and back of the perfboard. For the bottom they’re just guides to help you figure out what to solder to what. For the top, make them very clear as you’ll need them every time you plug in a harness to ensure you get everything in the right order. I marked the ground pins with a dark black line to help me see the tiny marks.

Tips:

  1. Triple check what you’re connecting to what before you solder. It’s a huge pain to un-solder things.
  2. Use desoldering wick when you’ve messed up and you’re unsoldering things.
  3. I tried to make the 3V, 5V, and ground more central and easy to connect to because they’re servicing multiple endpoints.
  4. Use a busbar (long piece of solid stripped wire) when you think it’s useful to make a common power or ground line for multiple components to connect to.
  5. Use jumper wires when you need to cross an existing solder line with a different line (you can see I did this with yellow and red wires). The solid wires are easiest to do this with because you can bend them to shape and pre-fit them before soldering.
  6. Use your multimeter’s continuity feature for every solder you finish, ensuring there’s a solid electrical connection between each of the points you soldered together, and it doesn't accidentally connect to anything nearby.

Testing Again

It’s a good idea to test before we move on.

  1. Plug in all of the wiring harnesses, plug in the two USB-C power plugs (power module first, microcontroller USB-C into your computer).
  2. Verify the startup sequence works (LEDs, servo motion).
  3. Verify the IDE’s Serial Monitor is reporting that it can read the SD card.
  4. Verify it connects to the Bluetooth speaker.
  5. Verify it plays the initialization audio file.

The Skull

IMG_4388.jpeg
IMG_4389.jpeg

We had two different skulls. One was already wired for LED eyes and you could unscrew the back to open it up. We re-used the LEDs in that one and the screws made it super easy to get into.

The other skull was a sealed plastic skull with no LEDs. This is how we prepared that one:

  1. Using a small cutting wheel on your Dremel, follow the biological “crack” line of the skull so your cut line is somewhat hidden. Watch your Dremel speed: too fast and you’ll melt the plastic which is hard to clean up.
  2. Clean up the edges afterward using the Dremel, a utility knife, or sandpaper.


There’s no way to close it for now but we’ll get to that later.

Mount the LEDs

IMG_4373.jpeg
IMG_4377.jpeg
IMG_4393.jpeg
IMG_4374.jpeg

In the first skull it already had LEDs, but the second just had regular sockets with no LED holes. This is how we prepared that one:

  1. Drill holes in the sockets big enough for the LEDs to just pass through.
  2. Use a Sharpie to black out the edges of your holes otherwise the LED will highlight your ragged white holes when turned on.
  3. Take some plastic wrap and put a bit inside the skull, covering the back of the skull’s eye socket.
  4. Form polymer clay into a little “volcano” shape about 2 cm wide and 1 cm “high” with a rounded top and press it into the back of the skull eye socket from inside the skull. It will completely cover your newly drilled hole. This is fine.
  5. Repeat for the other eye.
  6. Bake the polymer clay according to the instructions so it hardens.
  7. Using the same drill bit, drill a hole in each piece of clay so it will line up with your skull’s eye hole.
  8. Rough up the back of the eye sockets from within the skull with a utility knife or a file to help the glue adhere in the next step.
  9. Glue them in place with Super Glue (Cyanoacrylate). They should fit perfectly because they’re a perfect mold of the back of the eye socket.

Carefully push your LEDs into your new mounts. Don’t force them too much. Use your drill to widen the hole slightly until you can snugly push them into place.

Note that we’re going to mount the servo in the exact same way, so you may want to do the LED mount and servo mount at the same time so you can bake them together (step 24).


Jaw Closing (Elastic)

IMG_4372.jpeg
IMG_4374.jpeg
IMG_4400.jpeg
IMG_4402.jpeg
IMG_4401.jpeg

The theory behind this design is it’s safe by default but because of that it’s a little more complicated. An elastic band is just tight enough to keep the jaw closed by default and the servo’s job is to push it open.

In a fixed design where the servo drives the skull both open and closed, someone could get a finger between its teeth and the servo would clamp the jaw down hard. It’s not a big concern in reality, but originally this design was for another project where little kids were supposed to put their fingers in the mouth and it would snap shut, but only with the strength of the very weak elastic, making it startling but not dangerous.

We’re basically making a piece of elastic with tiny rods on the ends to keep it from coming out of the holes. You can also use barbed cord fasteners if you can find them or want to buy them, but they’re pretty easy to make.


Jaw Adjustment


Before you do anything, ensure the jaw opens and closes freely. If it doesn’t take it out of its socket and slowly carve down the plastic posts until it does.


Jaw Elastic


  1. Cut two ¾” (2cm) lengths of brass wire.
  2. Cut the elastic band so it’s a strip.
  3. Apply Super Glue (Cyanoacrylate) to the last ½” (1 cm) of the elastic band.
  4. Lay the rod centered and in the middle of your glue.
  5. Wrap the glued elastic around your rod, ensuring the elastic glues to itself, not just the rod. CA glue seems to stick really well to elastic, so this worked better than I expected.
  6. Drill a ¼” hole in the jaw bone of the skull (see photo for location).
  7. Smooth out the front and back sides of the hole as much as possible. It’s going to be moving constantly and a sharp edge will end up cutting your elastic band over time.
  8. Once dry, push your glued elastic-rod through the hole, threading it like a needle and then straightening it out once through the hole so it can’t go back through (see photo).
  9. Go straight up from the inside of the jaw, where your elastic comes through, and find where it would go into the skull (somewhere below the cheekbone) and mark it.
  10. Drill a hole under the cheekbone where you marked. You should move the drill back and forth while it’s running to cut a slot wide enough for the elastic to pass through without deforming (see photo).
  11. Smooth the edges of this hole as well.
  12. Determine how much elastic you need so the tension closes the jaw without fail but with minimal force. It should be very easy to open the jaw with your fingers with the elastic at the ideal tension.
  13. Mark where this is on the elastic.
  14. Glue the second brass rod on the end of the elastic as you did with the first one, cutting off any excess elastic.
  15. Once dry, thread it through the hole in the bottom of the cheek.


Your skull jaw should now be held shut with the elastic, and if you open it manually it should softly snap shut.

Jaw Opening (Mounting the Servo)

IMG_4377.jpeg
IMG_4375.jpeg
IMG_4378.jpeg
servo-wire-diagram-front.jpg
servo-wire-diagram-side.jpg
IMG_3620.jpeg
IMG_4373.jpeg
IMG_4390.jpeg
IMG_4393.jpeg

Now that we have the jaw closing, we need to make it open.

I’m not going to lie, this is an annoying step. It’s a lot of fiddling and test-fitting and cutting and adapting it to the exact shape of your skull and servo.

The servo needs to be mounted inside the skull on the opposite side of the elastic, just above the bottom of the cheek and behind the eye. It will lay inside the skull, nestled in the hollow of the cheek, on its side with the servo horn toward the outside front of the skull and the back of the servo toward the inside of the skull. See photo.

We’ll fashion a rod to be driven by the servo that will poke out of a hole in the bottom of the cheek and push the jawbone down.

The servo needs to be mounted firmly in place and we’re going to use the same technique we did with the LEDs which ended up working really well: polymer clay.


Set Up The Servo


  1. Hook up the servo to the microcontroller and power it and the power module. By default the servo will initialize by moving from 0 degrees to 70 degrees and back. Unplug the power. Your servo is now at zero degrees. This is important to mount it at the correct angle. As you mess around with the servo you may turn it off 0 degrees, so you’ll either want to mark where zero is on the servo so you can manually turn it back or plug it back into the microcontroller to reset it. Also make note of where 70 degrees is, perhaps marking it on the servo as well.
  2. Mount a one-arm horn on the servo. I only had a two-arm horn so I cut off the other arm.
  3. Consider the full sweep of the servo horn between 0 and 70 degrees. Hook it up to the microcontroller again to see it initialize through this range to get a better idea if it will help.
  4. With the servo held into place inside the skull with your hand, visualize the sweep of that servo horn. The bottom of the cheek may be in the way depending on how you mount it. On one skull I managed to mount it so the full 70 degree sweep was possible within the hollow of the cheekbone. On the other I couldn’t manage it and had to cut some of the bottom of the cheek away so it the servo horn wouldn’t hit it. Try to mount the servo in such a way that you don’t have to cut any cheek.


Make the Jaw Push Rod


  1. Try to visualize the vertical path of the servo’s horn within the cheek and drill a ¼” hole so the brass rod, when attached to the servo horn, will go basically straight up and down from the servo hole down to the jaw.
  2. Cut a 3” / 8 cm piece of brass rod.
  3. Bend it according to the diagram. It should have a little jog on one end that will keep it in the servo horn and a bracket on the bottom that will cradle the top of the skull and allow it to push it down. This is the most annoying and error-prone step. Keep testing it over and over until it moves smoothly through the hole attached to the servo and pushes open the jaw. It may slip on the jaw when opening it, but that’s okay, we’ll fix that next.
  4. Once the jaw is opening smoothly via the servo and rod, carve a channel across the top of the jawbone where the bottom of the rod presses to keep it from sliding when it opens.


Mounting the Servo


  1. This is the same technique we used to make the LED mount out of polymer clay.
  2. Push a piece of plastic wrap into the cavity of the cheek.
  3. Press polymer clay in a single lump into the areas necessary to keep the servo solidly in place, ensuring a good amount lies under the servo mounting holes because we’ll need to drill through them in a future step.
  4. Put another piece of plastic wrap over the polymer clay.
  5. Press the servo firmly into the polymer clay exactly where you determined it should be mounted in previous steps.
  6. Gently pull out the polymer clay being careful not to deform it, and remove the plastic wrap
  7. Bake the polymer clay according to the instructions.
  8. The servo should fit snugly in your new polymer clay mount. Fit in into the mount and mark where the mounting holes are.
  9. Drill a hole ever so slightly smaller than the 4x M3 Brass Female Hot Melt Knurled Nuts for each servo mounting hole (my servo had two holes).
  10. Use your hot soldering iron to slowly push the M3 nut into your drilled hole. The heat of the soldering iron will heat up the nut and melt the polymer clay enough to let you push the nut down into the hole and it will be held firmly in place when the polymer cools and re-solidifies. This clever trick courtesy of the 3D printing community. You may need to push a second nut into the hole if it’s deep enough.
  11. Only do one nut at a time, quickly test fitting the M3 Screws each time before the polymer re-solidifies, with the servo in place to ensure everything lines up nicely.
  12. Rough up the location you’re going to glue the mount with a knife or sandpaper.
  13. Once the nuts are in place and the polymer has cooled and re-solidified you can glue the mount in place inside the cheek using Super Glue (Cyanoacrylate). Note that because of the geometry there’s no guarantee you’ll be able to reach the back screw ever again, so make sure you can reach it before glueing the mount in place. You may have to screw the servo to the mount and then glue the whole assembly in place, even if that means unscrewing it again may be impossible.

You should now be able to hook the servo back up to the microcontroller, power it, and watch the skull jaw open and close on initialization.


Gear Noise


The only other consideration is noise. As I mentioned at the beginning, the Power HD HD-1160A servos I used are pretty cheap and use plastic gears which makes them noisy. That plus the fact we’re hard-mounting them within a hollow plastic skull that acts as a resonator, the gear noise is far more audible than I’d like. In practice it’s not that bad because this is a Halloween prop and the speakers can be turned up quite loud so you can’t really hear the gears. 


See the videos and see if the gear noise bothers you. If it does you could try mitigating it by buying servos with metal gears (these ones look pretty good but I haven’t tried them). You could also attempt to put soft gaskets in before screwing down the servo to isolate the vibrations or pack foam around the servo, neither of which I’ve tried.

Cable Hole

IMG_4379.jpeg

Drill another hole just behind the pole mount hole, about ½” / 2cm in diameter. The power cables (and ultrasonic sensor cable if it’s the Primary skull) will exit through here.

Skull Closure

IMG_4379.jpeg
IMG_4380.jpeg
IMG_4382.jpeg
IMG_4390.jpeg
IMG_4390.jpeg
IMG_4404.jpeg
IMG_4405.jpeg

If you got a skull that screws together, good work! Skip this part.

If you bought a skull you needed to cut it apart, we need a way to put it back together for display.

Honestly I was NOT good at this part. I couldn’t find any great solution to easily join two hemispheres back together in a way that’s easy to take apart but secure enough not to fall apart.


Bottom Closure


  1. Cut four 2” / 5 cm strips of double-sided hook and loop strap.
  2. Cut two 4” / 10 cm strips of the same.
  3. Using E6000 glue, bond the 2” strips (loop/soft side down) to the bottom inside of the skull right on either side of the broomstick hole, remembering to scuff up the skull where you’ll be glueing to create a better bond. When done, all four strips should be glued down, each in a pair glued right up to the cut edge of the skull. I tried CA glue first and it’s too brittle when cured to do a good job. This glue is flexible and survives the flexing caused by removing the upper strip in the future.
  4. Now the top 4” strips can be used to securely join the two halves of the skull at the bottom. This makes a good hinge point so when the skull opens it will open from the top and can hang from these straps.


Top Closure


This part didn’t work great. I only used three pairs of magnets total (I suggest using five pairs) and it’s very difficult to mount them so they’ll perfectly mate up. They’re very difficult to pull apart and very tiny, so I found the use of precision tweezers invaluable here.

  1. Make five pairs of neodymium magnets, letting each pair naturally attach to its mate.
  2. Use the Sharpie to mark both backs of the magnets and draw a line across the top of the pair. This will help us orient them when making their mounts. If we mount them at the incorrect angle they’ll repel instead of attracting.
  3. Knead up a bunch of two-part epoxy putty. We’ll have to work quickly from now on before it cures.
  4. At the very top edge of the skull, on the opposite side of the hook and loop straps, put a small piece of epoxy putty and embed a magnet in it, ensuring the marked back is pushed into the putty (so the unmarked face is facing out) and ensure the line you drew on the side is facing straight up, away from the surface of the skull. This will ensure the magnet on the other side mates properly. Make sure the magnet and epoxy do not protrude beyond the edge of the skull or it won’t close properly. Also make sure it’s not too far back or it won’t be close enough to attract its mate. This is finicky and I never did master it. The cut-edge of the putty should be as perfectly flat as possible.
  5. Then do its mate in the exact same way at the top of the other half of the skull.
  6. Do only one pair at a time so you don’t get the pairs mixed up.
  7. Keep going, spacing them out at 2” or so intervals, working on one hemisphere of the skull and then the other.
  8. After the epoxy putty cures, test fit the two halves together. Hopefully they all attract properly. If not you’ll have to redo whichever pair isn’t correct.
  9. If they’re sticking out too far to allow a proper closure, pare the epoxy down with a utility knife.
  10. The epoxy doesn’t bond very well with the plastic, but it does create an excellent hard mount and bonds well with the magnets.
  11. Once you think they’re all good, mark each with a number on both the epoxy and the inside of the skull so you know where they each go.
  12. Then pop off each one (they weren’t going to stay anyway) by flexing the plastic of the skull.
  13. Rough up each place they sat and re-bond them with E6000 glue. The flexibility of the glue will definitely ensure they stay put.
  14. After the glue dries you may need to tweak them again by paring the epoxy if you didn’t mount them quite exactly as you did the first time.


Now you should be able to easily pop open the back of the skull and snap it back shut, magnets holding it in place.

Assemble!

IMG_4147.jpeg
IMG_4320 (1).jpeg
IMG_4395.jpeg

You should now have a fully working skull, mountable on your pole. To make it display-ready:

  1. Attach the circuit board to all of the peripherals inside the skull via the wiring harnesses.
  2. Feed the USB-C splitter cable up into the back of the skull through the small hole. The one listed has four ends but we’ll only need two. You can stuff all four into the skull or leave the two unused hanging down. We’ll hide them anyway.
  3. Plug the USB cables into the circuit board, one into the microcontroller and one into the power module.
  4. Run the ultrasonic sensor cable out of the same hole.
  5. Plug the USB-A end of the cable into the battery bank. I used these GTOCE models which have one higher output (5A) port which is necessary to drive everything. Everything should light up and start working. There’s nothing more annoying than buttoning it up 100% and then finding out it doesn’t work. I tested it every few steps to make sure nothing went wrong.
  6. Stuff the circuit board and all wires into the skull. There’s probably a way better way to mount this, but space is tight inside the skull so I didn’t bother. Ensure the path is clear to put the broomstick all the way into the skull without hitting any wires/circuit board.
  7. Attach the pole stabilizer prongs to the bottom of the broomstick
  8. Mount the skull on the broomstick.
  9. About 1” below the skull, use a  hose clamp to attach a picture hanger hook securely to the broomstick. We will hang our Bluetooth speaker from this. You could also hide it somewhere nearby, but I liked it mounted to the pole so it sounded like it was coming from the skull itself.
  10. About 1’ / 30 cm below where the speaker would hang down to use another hose clamp to mount a little platform to support the battery’s weight. I made one out of the curved bottom of a plastic Coke bottle. Anything that sits at a 90 degree angle and you can clamp to the broomstick should work.
  11. Cut strips of the double-sided hook and loop strap to attach the various things to the broomstick.
  12. Hang the speaker from the picture hanger hook and strap it to the broomstick.
  13. Strap the battery to the broomstick, resting its weight on the little platform you made.
  14. Strap the ultrasonic sensor to the broomstick pointing wherever you want it to detect people.
  15. Wrap the dark linen-like fabric around the broomstick just below the skull. This will hide everything, including the ultrasonic sensor that should properly work through your cloth if it’s “transparent” enough to the ultrasonic pulses.
  16. The cloth should be about 2’ / 0.6m wide and long enough to hang from the bottom of the skull to the ground. Strap it to the broomstick at the very top and anywhere else you feel it needs.


When ready you can shove it into the ground with the prongs.

Of course that’s only one skull.

Make Another One!

As mentioned in the Overview, you need to make two skulls as you go.

There are a few minor difference between them:

  1. Pick a different colour of LED for the eyes to give them a more distinct character.
  2. The secondary skull doesn’t need the ultrasonic sensor, so you can skip that skull’s ultrasonic sensor harness and circuit board header.
  3. When setting up the SD card, rename config_secondary.txt to config.txt
  4. Set the speaker name in config.txt to your second Bluetooth speaker name.

Test Them in Sync

Once you’ve built two and written the files to their SD cards, you can turn them both on. Expect the following:

  1. Each starts up and connects to its own speaker, saying “Anthony initialized” (Primary) or “Jeff Initialized” (Secondary).
  2. Primary will start saying “Marco” every few seconds while it searches for the Secondary’s BLE server.
  3. When Secondary detects Primary has connected to its BLE server it will say “Polo.”
  4. The skulls are now ready.
  5. When Primary detects something via the ultrasonic sensor it will pick a random skit and they’ll perform it, streaming audio to the speakers with their LED eyes and jaw animating in sync with the audio as they speak it.


This is your first test of the ultrasonic sensor in action.

Code Overview

This won’t be a coding tutorial by any means, but let’s run through the code to see how it works.


Hardware Coding


Although I’ve been a programmer for a long time, this was my first attempt at hardware coding. I had to learn Arduino IDE, C++, and the concepts central to hardware programming.

The most important thing I had to wrap my head around was how hardware works as reflected in code.

The basics are pretty simple. There’s a setup and a loop. The setup contains all of the... well... setup: loading and initialization of code and modules.

The loop took me longer to get my head around. Hardware just... runs. Constantly. In the programs I usually write, the application sits there and waits for some sort of input and then reacts. In hardware programming you’re directly exposed to the reality of computers, which is they’re constantly running in a loop. This loop gets called thousands (or more?) times per second, so most of the time your code in the loop isn’t doing much or anything. If you tried to do something every single loop you’d probably use up all of your CPU bandwidth pretty quickly. I realized this when trying to print out debug statements.


High-Level Overview


  1. Skulls start up, read skits/settings from SD card file, initialize everything, determine if they’re Primary or Secondary.
  2. Attempt to connect to Bluetooth speaker, playing their initialization audio when they do so.
  3. Primary keeps saying “Marco!” as it attempts to connect to secondary’s BLE server.
  4. Secondary says “Polo!” when Primary connects.
  5. Both “breathe” if nothing is going on.
  6. If Primary’s ultrasonic sensor is triggered it chooses a random skit, tells Secondary to play it, and they both start playing the skit at the same time, saying only their parts.
  7. Their eyes and jaws are synced to only be on/animating during their parts of the skits.


Note that they’re actually both playing the exact same audio in sync. They just mute the parts that aren’t theirs and stop animating. Sometimes due to Bluetooth/CPU delays they start slightly out of sync, but usually it’s not noticeable.

Code: Modules

My instinct as a programmer was to break the functionality down into classes, so that’s what I did.

AudioPlayer: Reads files from the SDCardManager, queues up audio files to play, handles audio buffering, and provides raw audio data ready to be played on a device.

BluetoothController: Handles both A2DP audio streaming to the Bluetooth speaker and BLE (Bluetooth Low Energy) for skull-to-skull communication. Probably should be two classes to separate those features, but they’re both interacting directly with the same hardware.

ConfigManager: Reads the config.txt file from the SD card and parses the settings within.

LightController: Controls the LED eyes so you can make them blink and set their brightness.

SDCardManager: Reads the skits from the SD card, validating and processing them.

ServoController: Lets you set the position of the servo and how smoothly it should get there.

SkitSelector: Random skit picker. It won’t play the same skit twice in a row and tries to play those that haven’t been played in a while so you hear them all.

SkullAudioAnimator: Reads the raw audio frames, determines the skit being played, determines if this skull should be speaking, and if it should it turns on the LED eyes and attempts to match the jaw motions with the audio. If it shouldn’t be speaking it mutes the audio and doesn’t animate.

Code: Setup

  1. Initializes LightController and SDCardManager.
  2. Attempts to read the SD card until successful. If it can’t it will just keep trying forever because without the skits/settings there’s really nothing to do. Also if you need to wiggle a wire or push in the SD card it will suddenly start working for you because it was just sitting here, checking constantly.
  3. Loads and parses SD card skits and settings.
  4. Initializes SkitSelector and ServoController.
  5. Determines, from the settings, its role: Primary or Secondary.
  6. Initializes the AudioPlayer and Bluetooth A2DP.
  7. Plays the Initialization audio.
  8. Initializes the ultrasonic sensor (this will do nothing on secondary as it doesn’t have one), getting a baseline of what it can “see” so it knows when something changes.
  9. Turns on the LED eyes.
  10. Sets up a bunch of callbacks so it knows when audio starts/ends playing, knows when Bluetooth is connected/disconnected, knows when the BLE characteristic has changed (this is Primary telling Secondary what audio file to play), can handle new audio data when it’s time to play it, and whether the current skull is speaking or not.

Code: Loop

  1. Checks if audio is playing.
  2. Debug logging. Only happens every few seconds, because if you do this every loop it will print out millions of lines in no time and bog down the CPU.
  3. Primary: Play “Marco!” every 5 seconds while searching for Secondary.
  4. Let the BLE process so it can react to BLE events.
  5. Initialize the BLE server once the Bluetooth speaker has been connected and the initialization audio plays. This is done here instead of setup because I was worried the two would conflict given they’re using the same Bluetooth radio.
  6. Primary: Checks the ultrasonic sensor, choosing a playing a random skit if it detects someone, with a minimum break of 10 seconds between skits so it doesn’t just talk constantly.
  7. Make the jaw “breathing” movement. This was originally for debugging something else but it looked like the skull was breathing and was so creepy I just left it in.

Code: Skit Format/Customizing

Skits are made up of an audio file (PCM (wav) formatted as 44.1kHz sampling rate, two-channel 16-bit sample data) and a text file indicating which parts of the audio is to be spoken by the Primary skull and which is for Secondary.

This is one of the skits, milkshakes.txt:

B,0,2570
A,2570,1880
B,4450,1680
A,6130,1030
B,7160,2510
A,9670,1850
B,11520,2000
B,15000,1760


A=Primary skull, B=Secondary skull, and the numbers are all in milliseconds.

The jaw defaults to closed when it starts, and closes at end of every sequence assigned to it. There’s not much to it.

We created these skit text files by listening to the audio, writing down the time indices when the speaker changed, and calculating the difference to get the duration. In theory it could calculate the duration itself, but setting the duration allows for more flexibility if the skulls are “talking over each other” slightly (which doesn’t work very well) or you want to have breaks where neither is talking.


For instance, you can see at the end of this sequence that skull B (Secondary) has two lines in a row. This is so it can say “Oh yeah, I forgot,” and then a few seconds later “Can we still get milkshakes?” Without the duration, the eyes stay lit and you expect it to say more. With the duration in it feels like the end of the skit, and then a few seconds later it lights back up and says “Can we still get milkshakes?” which is objectively more funny;)

To make the audio files we recorded a single file of us performing the skit using Voice Memos on iPhone, exported them to my computer, and used a simple shell file to convert them to the proper format:

for file in *.m4a; do
  ffmpeg -i "$file" -ar 44100 -ac 2 -y "${file%.m4a}.wav"
done


Pretty much any way you want to record and convert the audio will be fine, but the final file must be in PCM (wav) format as 44.1kHz sampling rate, two-channel 16-bit sample data. The code expects exactly that format and won’t work with anything else.

Note, if you try this and your audio sounds like it’s playing at double speed, you’ve converted it to one-channel data. Convert it to two-channel data instead.

If you want to listen to all of the skits we wrote and performed for the skulls, have at it. They're all attached.

Lessons Learned

This was our first hardware project, our first time programming a microcontroller, our first time using C++, and our first time using servos. We made a lot of mistakes;)


Power Budget


We barely understood electricity when we started, and definitely not electronics. We spent days trying to figure out why the SD card reader would almost always crash after initializing. We were powering everything from the microcontroller (LEDs, SD card reader, servo, and ultrasonic sensor) and turns out the higher loads (especially the 5V ultrasonic sensor and servo) would end up pulling too many amps and the SD card reader got the short end of the stick. After realizing this we added the separate 5V power module to feed the ultrasonic sensor and servo and everything worked perfectly.


Continuity Testing


It was so difficult to figure out where I’d mis-soldered something before discovering this feature on my multimeter. Touch two points in continuity mode and it will tell you if it’s a continuous circuit. No? Maybe I didn’t solder it right. Is it continuous between two things that aren’t supposed to be continuous, like adjacent pins? Well I suck at soldering so I probably soldered them together by accident. Desolder and try again.


JWT Connectors Suck


These things. We knew nothing about electronics so we had no idea how to even connect things. Research told us Dupont connectors are great for average use and JWT connectors are better for things if there’s motion/tugging/etc because they clip in. We’d already had a bunch of issues with wires coming out when prototyping with the breadboard, so JWT sounded great. I don’t know if my wire gauge was too fat, I wasn’t good at using the crimping tool, or if we had bad JWT connectors, but they were terrible. The wires would come out of them, the connectors would just disconnect, etc. I still think it was me, but Dupont worked way better for us.


Know Your Board Specs


Originally we planned the skulls to communicate with Wi-Fi and spent far too many days trying to get Bluetooth audio and Wi-Fi communication working at the same time. Turns out they share the same radio and can not operate at the same time. But, oddly enough, using multiple Bluetooth specs (A2DP and BLE) at the same time, despite also using the single radio on the board, works just fine. I think the Bluetooth library handles any conflicts and sharing at a much lower level.


Not Invented Here Syndrome


I may have fallen for this;) You can buy separate mp3-playing modules that would have saved a couple of weeks of programming time, but I’m stubborn and kept telling myself “I know the hardware can do it.” In retrospect I could have used a cheaper microcontroller and a cheap mp3 player board for the same result. Maybe. The code does read the live audio stream for animation, so maybe that might not have been possible with a separate mp3 board.


Ground Wires Can Be Shared


This is how little I knew about electronics. Because each peripheral needed its own power line I assumed each needed its own ground line. Nope. Mostly you want to share all of the ground lines. Not only is it simpler, but it creates a stable reference voltage and minimizes noise. There are special cases where you want separate ground paths, but sharing is usually the right choice.


Battery Pack Shutdown Circuitry


We also spent days debugging why the new power module would start up fine and then lose power within 20 seconds. Turns out most battery packs use similar circuitry that shuts down the battery if the load is too small for too long (10 seconds or so). This makes sense because when charging a phone it will draw less and less power as it gets closer to fully charged. Eventually it’s “done” so instead of letting the phone infinitely draw smaller and smaller loads, the battery just shuts off. This also prevents low-level vampiric drain in case of other issues. But our power module runs the ultrasonic sensor and servo, and unless something large is happening (like the skull actively speaking), it doesn’t draw enough charge to keep the battery awake. This is why we’re using a USB splitter and only pulling power from one high-power port on the battery. The load from the microcontroller/other peripherals is enough to keep the battery awake even when the servo/ultrasonic sensor aren’t drawing enough current to do so on their own.

Enhancement Ideas

We had a ton of ideas we could have added but there’s only so many hours in a day.

  1. Add more skulls, each with their own part in the skits.
  2. Insead of back-and-forth skits, it could be several animatronic creatures along a path, each performing their own part.
  3. Use a different trigger mechanism: sound, laser, pressure plate, remote trigger, camera where you process the audio images and detect people/faces.
  4. Remote control: change the code so you can connect with your phone and trigger specific skits, like a sound board.
  5. Speaker mode: change the code so you can stream your voice directly to each skull, even reacting to whoever is in front of it if you can see them.
  6. Camera: The ESP32-WROVER-CAM has a camera on board but we never used it. You could position it in the nose cavity and remotely watch video of people reacting to the skulls from the POV of the skull.
  7. AI: Use the camera to take pictures every few seconds, send them to an AI model like ChatGPT, get it to generate text based on who it can see (“Is that a witch? What a great costume!”) and then generate audio (like from ElevenLabs) which can be streamed back and spoken/animated.

Staging

IMG_4394.jpeg
IMG_4395.jpeg
IMG_4396.jpeg
IMG_4397.jpeg

We set this up in front of our house with the skulls about 5’ apart, mostly facing forward but slightly facing each other.

We also built tombstones out of pink house insulation with the skulls’ original names (Anthony and Tobias) and their new names (as played out in a skit) written over in glow in the dark paint (The Demon of Park Hill and... Jeff!). We built a low, third tombstone with LED black lights powered by another battery pack that shone on the tombstones, lighting up their new names.

Kids and adults both gathered around on Halloween, some standing there until they heard all nine skits. Big hit!

If you build this we’d love to hear how it went and any improvements you can think of and I hope you have as much fun as we did making them. What names did you give each skull? Please post pictures and videos!