Software apps and online services
This is a semi-sponsored project, although the project idea and product opinions are entirely on my own.
This is an audio visualizer with an independent Bluetooth 5.0 audio module, both powered from a 5V3A charger. The visualizer use 45 NeoPixels (WS2812 RGB LEDs) and a 0.96" OLED to display strength levels at high/middle/bass frequencies, read by a MSGEQ7 analyzer module. It can be connected to any external speakers with a 3.5mm jack.
Everything is fitted inside the inner space of a 2004 Hasbro Millennium Falcon toy set, replacing rear engine lights and add cab/interior lights. The original front and laser LEDs are also connected to the SAMD21 microcontroller. Also, a "M3" MP3 module connects to the onboard 0.5W 8 Ohms speaker to play start-up/shutdown sound effects. A relay module turns the MP3 module off when it's not needed.
A capacitive touch sensor installed in the cockpit serves as the start-up/shutdown switch. Two potentiometers are used to adjust the levels of NeoPixel brightness level and onboard speaker volume.
In December 2020, I received a message from DFRobot, asking me if I'd like to try some of their new sensor modules. I said sure, and choose some stuff. And then they asked: will you make some projects with them?
I replied, "but I don't know what to do with them right now." And I don't want to make projects simply for the sensors' sake.
Then I had an idea: "I do have a project in mind. How about I choose something for this project?" And they agreed.
I picked a few things that are not easy to buy in Taiwan. So this has become my first (semi-)sponsored project.Converting the Falcon
The 2004 Falcon is surprising easy to disassemble. Unscrew every screw underneath it, and it will open up easily.
When I was fixing one of the Hasbro lightsaber with Arduino Nano last summer, I also found that one of our 2004 Millennium Falcon (My brothers and I own two) has broken engine lights. At that time, I have already planned to convert it into a music visualizer. But how?
One common solution is Fast Fourier Transform - translate audio signals into different frequency levels. There are FFT libraries, but how to use it is still way beyond my comprehension.
Only after DFRobot contacted me, I discovered the MSGEQ7 sensor on their website. This chip can measure audio strengths at 7 bands - 63Hz, 160Hz, 400Hz, 1kHz, 2.5kHz, 6.25kHz.
- Pull high RESET, wait 100 us, then pull down, wait 72 us.
- Pull high STROBE, read the analog value from OUTPUT, wait 36 us, then pull down STROBE, wait 36 us again. Repeat this 7 times to get readings of all 7 bands.
For Arduino IDE users, you can dwnlo their MSGEQ7 driver here. You'll need to manually move it into the Arduino library directory.Bluetooth receiver
The audio source comes from a Bluetooth receiver module. Actually I asked for two of them (both are not made by DFRobot): MH-M38 and XY-WRBT. The MH-M38 (Bluetooth 4.2) can directly power two 5W speakers, but the signal is too messed up to be read by MSGEQ7.
So I decided to use the XY-WRBT with external speakers. An one-to-two 3.5mm output cable send the audio to both the speakers and MSGEQ7. I don't have the knowledge to build nice ones on my own, and there's not enough room anyway."M3" MP3 module
I have this "M3" MP3/WAV playback module from a couple of years ago made by some unknown Chinese maker. It's not sophisticated like the DFPlayer mini, but simple enough to be controlled by any languages. (Make a "01" directory in the micro SD card and name the song files as 001.xxx, 002.xxx, etc.)
It has two operating modes:
- Direct mode: pull down pin A1-A9 to play song 1-9.
- Binary mode: pull down A10 and use A5-A1 as binary signal (A5 is MSB). Pull all five pins up, then pull down the ones need to be 1. For example, 10110 (A5, A3, A2 pulled down) is 16 + 4 + 2 = 22nd song. So this mode supports total 31 songs.
Here I only need to play two songs, so I use the direct mode.How I ended up choosing TinyGo
As for the microcontroller, I asked for a Firebeetle Board-M0, a beautifully-made SAMD21 board with castellated holes. Their ESP boards also looks nice...but SAMD21 boards are still uncommon in Asia.
But my main reason was (I'm sorry, DFRobot) - it looks kind of like the Adafruit Feather M0 Express. I wondered, is it possible to upload Feather M0's CircuitPython firemware onto it?
Yes you can.
(Of course, Firebeetle M0 is not a copy of Feather M0 Express -it's longer and has more GPIOs available.In fact, it's more similar to Arduino Zero than any of the Feather M0s.)
Firstly, I download a Feather M0 .ino UF2 bootloader and upload it via Arduino IDE.
To use Firebeetle M0 in Arduino IDE, you'll need to add the following link in preference: http://download.dfrobot.top/FireBeetle/package_DFRobot_index.json. More install detail here. Be noted that the English wiki listed the wrong URL, at least at the time I wrote this.
With the UF2 bootloader installed, I can now flash CP firmwares. Actually, now three new options have opened up:
- CircuitPython is really nice, with the best ecosystem of all three, but it is also the slowest. The audio visualizer has to be highly responsive, but time.sleep() in CP can only goes as far as 1 ms. (Also, only CP firmwares for Feather M0 Basic and Arduino Zero works well.)
- MakeCode Maker (TypeScript) is interesting but still highly experimental, even more so than TinyGo. I've tried to use it to control the MSGEQ7 with no success.
- ...And I always wanted to try building something with TinyGo. Arduino C++ is still reliable, but I just don't like it much these days. I've been learning Go for some time, and TinyGo is also fast, with pretty good support to SAMD21 boards.
There's another (accidental) advantage of TinyGo: its board definition of Adafruit ItsyBitsy M0 has all pins listed, including the GPIO 6 and 8 that is not on ItsyBitsy M0. (Firebeetle M0 does not have GPIO 8, but it is connected to an onboard NeoPixel).
Why this is important? Because as Arduino Zero, TinyGo would use BOSSA to upload the code, and upload time is a bit slower. As ItsyBitsy M0 with its pre-loaded UF2 bootloader, TinyGo simply copies the.bin file onto it.
So: after changing the bootloader, now I have an fully-functional ItsyBitsy M0 which is not an ItsyBitsy M0. Of course, I have to manually press reset twice every time before upload (not able to auto-reset), but that was fine by me.
However, the biggest challenge I've faced in this project is not TinyGo - but how exactly to convert audio level readings to RGB LED effects.
So I was stuck for a month, without knowing how to proceed. I also installed an OLED display (it was not in the original plan) to see how MSGEQ7 works. In the end I decided simply to use the video below as my example:
Without any audio input, the readings from MSGEQ7 are always has about 1/4-1/8 of the max values. And this turned out to be a good thing: since there are always some value, the NeoPixels will never truly be dark, maintaining a sense of continuity. So I don't even need to cut out the low value. Simply convert them to brightness levels would do.
The LEDs are mapped to MSGEQ7's 7 bands as the following:
- Main NeoPixels (engine exhaust, 32 leds) - bands 3-5 (middle)
- Inner NeoPixels (under turret window, 12 leds) - bands 1-2 (bass)
- Cockpit NeoPixel (1 led) - band 6 (high)
I decided to ignore band 7 since it's rarely used by songs. I added a slow rainbow rotation effect as well, based on Adafruit's example code.
The routine is very simple:
- Press the touch pad in the cockpit to "start it up". You can skip the light and sound effects by pressing the pad a bit longer.
- Now it's in the audio visualizer mode. The Bluetooth receiver works independently, with or without the visualizer. A relay turns of MP3 module's power during this mode.
- Press the pad again to "shut it down" (can be skipped as well).
This is the flashing command I used in the terminal:
tinygo flash -target itsybitsy-m0 -scheduler coroutines -port COMxx main
-scheduler coroutines is needed, otherwise it would cause a goroutine stack overflow error. This might be fixed in the future.
This project is compiled with TinyGo 0.16.0 and Golang 1.15.8. Future versions of TinyGo might not be compatible with this code.P.S. A Note about Go Modules
Note: started from Go 1.16 the Go Modules is default on. From now on third-party packages (including TinyGo drivers, etc.) will be put in $GOPATH/pkg/mod.
You will have to create a module path for your own project so that Go can find these packages correctly:
<project dir>\> go mod init <module name>
This will generate a go.mod in the directory. Then
go get -u tinygo.org/x/drivers
go get -u tinygo.org/x/tinydraw
go mod tidy
That should do it.
BTW, Solo is a good Star Wars movie as long as you don't watch the part after the MAW.