Muhahahaha! Aaaaargh! Trick or Treat. Be so sweet. Give me something good to eat.
I wanted to build something cool and scary for Halloween. Here in Germany Helloween is just about to become a trend. Meet the ScareOS, a thingy to spice up Halloween.
- Moving eyes (object tracking perhaps in version 2 - have to figure out how to integrate motion tracking)
- Discover if someone is around by using a ranging sensor
- Plays Halloween sounds when it's awake
- Sleep state if no one is around for a while
- Whines when someone comes too close
ScareOS is an Arduino-based thingy with eyes, sound and a range sensor. ScareOS tends to be sleepy. It there's no one around, it sleeps and snores. As soon as someone comes into range, it awakens. Then the things looks at its visitor, triggers a series of Halloween sounds and, moves its eyes. But beware! It starts to cry like a baby when you approach too close.
Hint: The video interferences are some recording issues.
Step 1: Ingredients
- 1x Arduino (I used the Ardunino Mini Pro because of its form factor)
- 1x Ultrasonic HC-SR04 Ranging Sensor
- 2x 8X8 LED Matrix with I2C Backpack
- 1x Audio FX Sound Board - WAV/OGG Trigger with 2MB Flash
- 1x 470µF Capacitor
- 1x 470Ω - 560Ω Resistor
- 1x 330Ω - 360Ω Resistor
- a whole bunch of wire connectors
- 1x Speaker
- 1x Breadboard (or a circuit board)
- Once you have all parts together, you can start wiring them.
Step 2: Wiring
The common ground and common VCC of the breadboard comes handy to provide current for the involved components. The diagram shows you how to connect the particular components.
The two resistors protect the circuit from a signal that won't come back. I originally built the ranging sensor circuit on RaspberryPi and took kept the design. The Arduino pulseIn() function also accepts a timeout so basically the circuit would work without the resistors.
The capacitor stabilizes the circuit. I discovered that the LED matrices cause some interference and instabilities within the VCC. The effect: The ranging sensor works only until some 80cm once both LED matrices are turned on. If the matrices are switched off or do not display anything, the ranging sensor works fine. My solution: Connect a capacitor to GND and VCC.
Step 3: Sounds
Once all parts are connected, upload the sounds from the sounds folder to the soundboard. Connect the soundboard to a USB port and copy all files to the flash disk using your favorite file copy tool.
There are four sounds/categories of sounds:
- T01 Wake-up sound: Played once the ScareOS awakes from the sleep state
- T02RANDnn sounds: Collection of sounds that are played randomly in the awake state. Therefore, the special suffix RAND00 to RAND99
- T03 sound: Whining/crying if someone approaches in the near zone of the device
- T04HOLDL: Snoring sound, plays as long as the trigger is held, therefore, the special suffixHOLDL
Step 4: Arduino Code
You need some code to run ScareOS. The code controls the components and handles wake/sleep, triggering sounds and displaying the eyes on the LED matrix. You can find the full code at https://github.com/mp911de/scare-os-halloween-iot
The code is located in scare-os/scare-os.ino. You need two additional libraries:
The Adafruit site has a nice tutorial how to install Arduino libraries. So open the Sketch, compile it and upload it to your Arduino. You can adopt the code to use different pins or adjust the distance/timing:
#define PIN_SONIC_TRIGGER 3
#define PIN_SONIC_ECHO 2
#define PIN_SND_TRIGGER_WAKE 9 #define PIN_SND_TRIGGER_REGULAR 8 #define PIN_SND_TRIGGER_NEAR 7 #define PIN_SND_TRIGGER_SLEEPING 6 #define PIN_SND_ACTIVE 5
// ms #define SOUND_INTERVAL_MS 20000 #define WAKE_DURATION_MS 180000
#define ACTIVATION_DISTANCE_CM 280 #define NEAR_DISTANCE_CM 100
Threading with Arduino
Arduino code runs only single-threaded, meaning your Arduino can do only one thing at a time. The sound trigger module, for instance, does not occupy the Arduino once a sound plays. So sounds play in the background within this terminology.
Why am I telling you that?
Displaying and animating graphics, like it is done with the matrix eyes, requires the Arduino to execute code, sleep a while, then execute code again and so on. One animation cycle lasts between 0.5sec and 10sec. In this time, the Arduino is occupied with the animation. If someone walks by the range sensor really fast, we would not notice it, because we're occupied with animating and not with measuring distance.
But that's not fully true. Most of the time, the Arduino "sleeps" which means we could use that time to do different things - things like triggering a sound or measuring distance. The code is written to utilize these delays. You'll find lots of calls to a bgProcessing() method. This method is called with a delay parameter. If the delay is long enough to measure the distance (measuring the distance needs time and triggering sound, too), the distance is measured and the sound processing is invoked there. It's not exactly a task scheduler like a Windows or MacOS use to emulate multi-threading on one CPU (core), but it interleaves tasks in a similar way.
Some words about measuring distance
The ranging sensor uses the physics of speed of sound to determine the distance. An ultrasonic sound is triggered and the microphone records the echo. The speed of sound in dry air is about one kilometer in 2.914 sec. Since the sound needs to hit an object that bounces it back, the way is crossed twice. This means, that the duration to measure the distance is
DISTANCE * Speed of Sound * 2
Sometimes, the ranging sensor reports an echo after a shorer or longer time. The result of that are flickering distances of up to 100cm. These are outliers and falsify the result (the assumption of distance). The code, therefore, performs a series of measures, sorts the results and takes some middle result. It works pretty good and the implementation is quite simple (easier than calculating a quantile).
Step 5: Done.
And now, it's time to scare