A high-quality, stand-alone, fast-prototyped, connected speaker
On a June hack Friday I decided to prototype a Raspberry Pi based speaker that could become a hack-friendly platform for the community. I was also interested in experimenting with a fast-prototyping approach involving resin.io.
My goals for the project were to:
- Achieve good sound quality, something that an audiophile could at least accept
- Power the whole system from a single, common 5V micro USB
- Make it stand-alone: the audio source needed to be the speaker itself, and only optionally cast from another device
- Make it from common and easy to find components
- Not require any special tools: screwdiver, solder iron and your own two hands
- Create a simple enclosure design - easy to modify, easy to make on a personal maker lab, a fablab/makerspace or from an online service
- No need to open the device to update any part of the software stack in order to speed up the SW prototyping cycles
- Keep the total cost under 100 £
Prototyping step 1: The components scouting
I knew I needed at least:
- A 3.3V to 5V logic DAC: the built-in audio output of the Raspberry Pi cannot be defined a good quality one, at least not for audiophile-oriented applications.
- A a 3.3V to 5V logic mono amplifier
- A Raspberry Pi
- A speaker
The DAC + amplifier choice
My research pointed to two possible solutions:
- Pimoroni PHAT Dac + Adafruit 2.5W class-D mono amplifier
- Adafruit I2S 3W Class D Amplifier
I opted for option 2 because it's cheaper, requires less soldering, and has a smaller footprint. Plus, the actual amplifier is more powerful (3W vs. 2.5W).
The Raspberry Pi choice
It was a tie between the rpi0 and the rpi3.
The rpi0 is smaller and less power-hungry, while the rpi3 is faster and has built-in WiFi/BT.
I ended up deciding to do both, starting with the rpi0 as a first reference prototype, adapting it to the rpi3 and then benchmarking the two variants
Given the requirement for good music quality, I decided that the enclosure should be made out of wood. That put 3D-printing out of the question, so I opted for a lasercut design.
Prototyping step 2: Breadboarding
I sketched the connections with Fritzing (loading the Adafruit library), then ordered the selected components to test. While I was ordering, I noticed this tiny LED Matrix and decided I wanted it on the setup as a way to give some visual feedback to the user.
I created a resin.io application for the rpi0 and flashed a device. I hooked all the components up on a breadboard and powered the rpi0 for the first time, provisioning the device and leaving it powered on. I also enabled Delta Updates fleet-wide.
I created a Docker application that used the templating system, since it was already clear that I may want to port the setup to different boards/architectures in the future.
I started on the Debian
node:slim base image, then:
- I skipped to the
jessieAdafruit instructions for the I2S 3W Class D Amplifier
- I added the dependencies listed in the LED matrix Backpack library README
- I added basic Alsa packages in my apt dependencies
- I ensured my application enabled the I2C module in order to test the LED Matrix backpack
- I pushed the application. After my device completed the OTA, I fired up a container ssh session via resin-cli
resin ssh <uuid>
- I cloned the LED matrix Backpack Python library and ran the 8x8 matrix example, it worked!
- I ran a simple
speaker-test -c2 -t wavand my devicee spoke to me!
I verified the setup worked - I was ready for the next step.
Prototyping step 3: Enclosure design
I already had a general idea in mind, I wanted a stacking design inspired by the Pimoroni Pibow (picture below thanks to http://www.jamesshead.co.uk )
First, I decided on the material and its width: 3mm Plywood. Then I gathered all the component measurements from the datasheets and by hand using a digital caliper
I downloaded the Vectorealism Adobe Illustrator starter kit and started drafting.
I tried to make it as compact as possible, double-checked the draft and tried to picture the assembly in my mind in order to spot potential flaws, then sent the design to be lasercut. The lasercut parts arrived just in time for the next hack Friday hack.
As soon as I started the assembly I noticed two flaws:
- I made an optional hole for a camera because why not, but without the camera the hole was very ugly, plus the actual utility of a camera in a speaker was unknown - I found myself being too greedy on the design.
- While the components fit, the space was so little that it was a tetris-like job to assemble the prototype, with the WiFi dongle almost touching the speaker magnet (not good, that thing would start vibrating at the first sign of bass, plus the magnet would have caused interference with the WiFi signal).
Lesson learned: better to go through an iterative design process.
Prototyping step 4: try, fail, repeat.
I updated the design with the following changes:
- I left more overall space between components, especially between the rpi0 and the speaker
- I removed the camera holes
- I positioned the rpi0 on the bottom of the frame and created a cavity in the design for the power supply to be easily plugged/unplugged.
Since I needed to wait for the lasercut delivery, I started implementing my application based on Mopidy with Spotify, Soundcloud and Google Music support.
I wrote a simple nodeJS application that dynamically changes the Mopidy configuration based on resin.io Environment Variables - this way, each user can safely configure credentials for the chosen cloud service.
Then the lasercut pieces arrived. While the new design was easier to assemble, I was still not satisfied with how it looked, so I tried another iteration. While it was a less drastic design change, the visual improvement was huge:
- The overall design looked more consistent, with same-radius curves and balanced components positioning
- The enclosure became more robust, fixing the problem with the delicate 1-layer feet
- The assembly was even easier!
I was satisfied. It was time for the rpi3.
Since I had learned about components, spacings, etc. I felt way more comfortable forking the design and implementing the rpi3 version. I also made part of the middle layer structurally stronger and switched to a better, smaller speaker.
The result made all the iterations worth it - it simply looked right to me.
I ended up loving the rpi3 version over the rpi0 one for the following reasons:
- Waaaay faster to boot and to start the Mopidy server
- Way faster GUI
- The Ethernet and USB ports are useful and will allow easy plug&play accessories in the future
I also ensured the HDMI port was accessible, so I could plug it to a display, if I wanted to.
I kept both version in the V1 release, so you can choose which one to build!
Prototyping step 5: Polishing
Now that I was satisfied with the overall design, I focused on the software, optimizing everything from the Docker image size to the application performance and resource usage.
I implemented a Supervisor status visual feedback on the LED Matrix (so you know when the device is recieving an OTA) and included YouTube as another cloud service.
Prototyping step 6: Ship it
I found myself becoming way more ambitious and holding out on a public release because of some additional features I wanted to implement.
I wrote an emoji drawing module, a Kodi-based fork for a touchscreen stereo version and a lot of other stuff meant to be merged in this project.
I decided I was risking a Duke Nukem Forever syndrome - I polished the documentation and released a
0.1.0 version that got featured on Hackaday
Prototyping step 7: Is it still a prototype?
0.1.0 release, I think I can call the project out of the prototyping phase and I am now able to focus on all the open tasks I left in step 6.
What I want to do for the next version?
- Get rid of a "pop" noise the speaker makes when switching from a song to another
- Implement synced audio: in a multi-device environment, I want the possibility to sync them and reproduce the same audio
- Implement emoji drawing module as a REST interface and consume its API from the GUI
- Implement Equalizer mode for the LED Matrix
- Embed a battery
What do YOU want for the next version?
You can find the Boombeastic project on github. I would love to hear feedback, suggestions and feature requests :)