Christmas fun for makers
Maker Christmas
Make your own Christmas music box with a microcontroller, servomotor, NeoPixel LED ring, and mini-MP3 player.
Music boxes and Christmas pyramids are among the top sellers in Germany during the Advent season. Expensive, hand-carved items can fetch four-figure sums, whereas cheap imitations sell for EUR20 (~$17). Christmas pyramids are often powered by the heat of candles, and the cheaper ones in particular have such an unfavorable candle-to-propeller ratio that the pyramid will not turn without mechanical help. Music boxes are driven by fragile springs, but the constant need to rewind them spoils the fun.
My idea of building a music box of my own design was born from these frustrations. In terms of the electronics, you do not need many components. The following sections are intended to give you some ideas for your own projects; the parts used in this example can easily be replaced by whatever delving into the depths of your lumber box reveals. The only important elements in this project are light, motion, and music.
Controls
To control the project, I used a Trinket M0 microcontroller [1] by Adafruit (Figure 1), which runs CircuitPython, a minimalist Python that supports a wide range of peripherals with its many libraries. The price of the controller is in the same range as a Pi Zero, including an SD card, but it is easier to put into operation because you do not need to install and configure an operating system.
Another advantage of a microcontroller is that you do not have to boot it, and you can simply switch it off without damaging the installation. The biggest advantage, though, is the CircuitPython support. The examples offered here illustrate how little code is needed to implement your ideas. Independently, the project could also be implemented with a Pi Zero, but some tweaks would be necessary at various points, such as the power supply.
Let There Be Light
In this project I use LEDs – more precisely, NeoPixel LEDs [2] – to create the illumination effects. NeoPixel LEDs are available in all shapes and sizes, from long strips through rings and arrays to individual LEDs. The components already contain the driver chips, which make them a bit more expensive than normal LEDs, but make controlling the LEDs far simpler.
NeoPixels normally require 5V. Three connections are all you need: supply voltage, ground, and data. If the cables are short and the number of pixels is low, 3.3V might be sufficient for the power supply and control. The maximum brightness is reduced a little, but because the LEDs are very bright anyway, the low voltage doesn't matter in practical terms. Regardless of the selected voltage, it is important to check that the NeoPixels do not overload the voltage source. The Raspberry Pi's 3.3V pins are not designed to deliver high currents. The Trinket's 3.3V rail has fewer problems: The built-in converter outputs 500mA.
I chose to use a 24-pixel RGBW LED ring (Figure 2). This device could easily be supplied with 3.3V from the Trinket M0 and controlled directly. The power consumption with the LEDs turned down is about 60mA maximum. The LED ring is the most expensive single component in the project ($17/EUR21). When soldering the cables, avoid creating a solder bridge to the adjacent LEDs.
In the minimal application program (Listing 1), the neopixel library for CircuitPython (imported in line 3) expects the code in the lib/
subdirectory. However, the library has a bug: When initializing the object (lines 8-12), you have to specify the pixel_order=neopixel.GRBW
argument, even though the value you are passing in is the default.
Listing 1
NeoPixel Control
01 import time 02 import board 03 import neopixel 04 05 pixel_pin = board.D2 06 num_pixels = 24 07 08 pixels = neopixel.NeoPixel(pixel_pin, 09 num_pixels, 10 pixel_order=neopixel.GRBW, 11 brightness=0.05, 12 auto_write=False) 13 14 def colorwheel(pos): 15 if pos < 0 or pos > 255: 16 return (0,0,0,0) 17 if pos < 85: 18 return (255 -- pos * 3,pos * 3,0,0) 19 if pos < 170: 20 pos -= 85 21 return (0,255 -- pos * 3,pos * 3,0) 22 pos -= 170 23 return (pos * 3,0,255 -- pos * 3,0) 24 25 def rainbow(wait): 26 for j in range(255): 27 for i in range(num_pixels): 28 rc_index = (i * 256 // num_pixels) + j 29 pixels[i] = colorwheel(rc_index & 255) 30 pixels.show() 31 time.sleep(wait) 32 33 while True: 34 rainbow(0.1)
The program generates rainbow colors across all pixels and rotates more or less slowly, depending on the wait
parameter (lines 25 and 31). CircuitPython does not support interrupts, so if you want to connect an additional button to the Trinket M0 (e.g., for an on/off switch or to switch between effects), you have to query the switch at a suitable point. In the example, this would be either inside the while
loop (lines 33-34) or before line 31.
In Motion
A continuous rotation servomotor rotates the music box. In contrast to stepper motors, which support precise positional control, only speed and direction can be specified for rotating servos. In this project, I use a Fitec FS90R [3] ($5, EUR6; Figure 3), which is available from various vendors.
Again, a few lines of code are all you need for control (Listing 2). First, a pulse-width modulation (PWM) object is created in line 6, along with a control object for the motor in line 7. The throttle
parameter controls the direction (sign) as well as the speed and expects values between -1
and 1
. Depending on the model and power supply, the motor does not stop for a value of
. In my lab, it stopped for values between 0.05
and 0.10
.
Listing 2
Servomotor Control
01 import time 02 import board 03 import pulseio 04 from adafruit_motor import servo 05 06 pwm = pulseio.PWMOut(board.D0, frequency=50) 07 my_servo = servo.ContinuousServo(pwm) 08 my_servo.throttle = 0.01 09 10 while True: 11 time.sleep(1)
Without a while
loop, the program ends and the microcontroller resets the hardware – hence lines 10 and 11. You can start, stop, or change the speed of the motor within this loop, but for this project, no further support after startup would be practical, because you will be manipulating the LEDs in the while
loop of the main program (Listing 1).
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
TUXEDO Computers Unveils Linux Laptop Featuring AMD Ryzen CPU
This latest release is the first laptop to include the new CPU from Ryzen and Linux preinstalled.
-
XZ Gets the All-Clear
The back door xz vulnerability has been officially reverted for Fedora 40 and versions 38 and 39 were never affected.
-
Canonical Collaborates with Qualcomm on New Venture
This new joint effort is geared toward bringing Ubuntu and Ubuntu Core to Qualcomm-powered devices.
-
Kodi 21.0 Open-Source Entertainment Hub Released
After a year of development, the award-winning Kodi cross-platform, media center software is now available with many new additions and improvements.
-
Linux Usage Increases in Two Key Areas
If market share is your thing, you'll be happy to know that Linux is on the rise in two areas that, if they keep climbing, could have serious meaning for Linux's future.
-
Vulnerability Discovered in xz Libraries
An urgent alert for Fedora 40 has been posted and users should pay attention.
-
Canonical Bumps LTS Support to 12 years
If you're worried that your Ubuntu LTS release won't be supported long enough to last, Canonical has a surprise for you in the form of 12 years of security coverage.
-
Fedora 40 Beta Released Soon
With the official release of Fedora 40 coming in April, it's almost time to download the beta and see what's new.
-
New Pentesting Distribution to Compete with Kali Linux
SnoopGod is now available for your testing needs
-
Juno Computers Launches Another Linux Laptop
If you're looking for a powerhouse laptop that runs Ubuntu, the Juno Computers Neptune 17 v6 should be on your radar.