This year we are again adding audio to our mini dasher-bot. In a similar fashion to last year we started off using the same mini class D 5v amp ( see last year’s post). By hooking it up to 5v + GND pins to drive some 4W speakers. The sound was fine and plenty loud. But instead of simply playing back a folder full of mp3’s I wanted to create a (command line) simplified mp3 player using momentary buttons (turn-off and on-able). So that’s what we’ve done; a two button mp3 player – linked via an external USB sound card to the Pi-Zer0W. This means we don’t need to fit a DAC – and we don’t have the room on this smaller model to add a second Pi just to play audio. One button plays random mp3s, the other button kills the process (mpg123). The player script runs continuously in the background.
Here’s the build for a command line mp3 player.
Software set up
- Install mpg123 player (after running a system update && upgrade)
sudo apt-get install mpg123
- Add mp3’s to a folder on the pi.
- Test mpg123 by simply typing (within the audio-clips folder)
- Test it plays a folder of files by typing
mpg123 /home/pi/audio-clips –Z *.mp3
This will play all files in the audio clips folder on a continuous random play. Not to be confused with:
mpg123 /home/pi/audio-clips –z *.mp3
Which will shuffle play! Subtle use of –z or –Z switches. See mpg123 documentation for more of these useful switches.
Audio should now play from the HDMI or audio jack – whichever you configured. We need it to play from the audio jack. Refer to RPi documentation to configure audio via headphone jack.
Create a python script to enable momentary buttons to play a folder of mp3s or kill the process (stop playing). Adafruit came to the rescue here with a couple of scripts I combined to create this short but highly effective script. Go to: https://learn.adafruit.com/playing-sounds-and-using-buttons-with-raspberry-pi/fancier-code-a-very-simple-jukebox
So my code ended up like this:
import os import subprocess from time import sleep import RPi.GPIO as GPIO GPIO.setmode(GPIO.BCM) GPIO.setup(23, GPIO.IN) # button plays the folder of mp3s GPIO.setup(24, GPIO.IN) # button stops the play while True: if (GPIO.input(23) == False): # can use a 0 in place of False os.system('mpg123 /home/pi/audio-clips –Z *.mp3 &') sleep(0.1); # should eliminate button bounce / multiple mpg123 calls if (GPIO.input(24) == False): # can use a 0 in place of False subprocess.call(['killall', 'mpg123'])
Save (Ctrl +X) & exit
Then give it full permissions by typing
chmod +x yourscript.py
Then edit the /etc/rc.local file to make this run at boot. Full instructions on using this method here. Type
sudo nano /etc/rc.local
Add the full path of your script and don’t forget the & at the end of the line to ensure it runs in the background i.e.
python /home/pi/mp3script.py &
You can store/set/save the volume of Alsamixer by using the following command after setting the desired volume, followed by a sudo reboot. This will load the desired volume settings on start-up.
sudo alsactl store
Refer back to last year’s post on the class D amp’ we are using again.
As we’re using a Pi-Zer0W – we need an easy way to get audio out. The easiest way is to use an external USB soundcard connected to the mini OTG USB port on the pi. One like this:
Then plug in (amplified) speakers to the headphone jack on the external card. You’ll need to use a mini USB to normal USB shim to fit the external soundcard onto the OTG (data) port – so it will look something like this:
Next, you simply have to disable the internal BCM soundcard to force your Pi to pump audio out of the new external sound card. This took me ages to find out – but I’m glad I did, as it’s just one line of code to alter.
Edit the config.txt file (sudo nano), then scroll right down to the bottom of the file where you’ll see this parameter:
# Enable audio (loads snd_bcm2835) dtparam=audio=on
Just turn it off, so the Pi uses the external card. That line should now read:
NOTE: you can also try commenting out this line altogether.
The internal sound card is now disabled. Save, exit, then reboot. Plug a speaker (or headphones into your external sound card to test). It should work a charm.
Again I referred to the Adafruit tutorial above to correctly configure momentary buttons to ensure that they are correctly set to ensure the Pi is protected. Using internal pull _up resistors is not sufficient to protect the Pi, so you’ll need a 10k pull-up resistor for each button. Each button connection looks like:
3.3v –> 10k Pull-up Resistor –> GPIO –> Button –> GND
These images may prove easier to understand:
Image ref: Adafruit
And the Fritzing schematic which I could actually understand:
Image ref: Adafruit
This button tutorial from Glamorgam uni’ explains the need for a pull up resistor better than I could:
“When a GPIO pin is set as an input it is “floating” and has no defined voltage level. For us to be able to reliably detect whether the input is high or low we need to tie it so that it is always connected and either reads high or low.
To tie the pin we connect either a Pull Up or Pull Down resistor. A Pull down resistor connects the pin to ground through a large resistor, this means that when the switch is open there is a path to ground and so it will read low. When the switch is pressed (with the other side connected to 3.3V) there is a lower resistance path to high and so the pin will read high. The large (10kΩ) resistor ensures that only a little current is drawn when the switch is pressed.”
Can someone tell me why the GPIO musicbox tutorial does not mention this – at all? Am I missing something?
I wired it all up on a breadboard, then transferred the wiring to a reclaimed printer button panel salvaged from a skip. It works well… apart from the occasional button bounce whereby I get two streams of audio playing at the same time! Stopping and restarting the player does fix this, but I’m sure there’s a much better way? Perhaps reducing the sleep time from 0.1 to 0.001 might work??
This year I pulled apart a rather stubborn bluetoothed portable speaker to extract the 4W mini drivers. They worked a treat. As did a salvaged laptop tiny speaker. I’ve set the entire rig up on a test robot chassis to try it out. It’s quite a rat’s nest of wires! Because we’ve got a much smaller robot this year, space is at a premium. So I might have to eliminate the 2 x (roof rack) mounted) speakers for the trusty powered Pringles speaker (again) to remove some of the extra wires, free up some GPIO pins and help conserve current draw!
Here it is in action.
Next step was to transfer to PiZer0W chassis – but those speakers look way too big! It may have to be Pringles flashy speaker after all!