Published on 2020-05-15 by Kenneth Flak
Back to Tech Research
Recently we got a request to perform on a street-festival in Pärnu, which gave us the impetus to get a bit more mobile with our technology. We already own a battery-powered boombox, so now we needed something a bit smaller than a laptop to deliver sensor-triggered sound to the box. An obvious candidate for this is the Raspberry Pi 4, which, if rumors are correct, has become quite a powerful little beast.
This is a record of the steps I took to set the rpi up with my Linux distro of choice Arch, make it possible to receive data from our minibees and trigger stuff in SuperCollider using it. Let's get to it! Much of the information is taken from Mads Kjeldgaard's blog and translated to Arch equivalents. Additionally there is a lot of good information in Niklas Adam's blog.
Arch ARM is actually a separate distro targeted at the ARM architecture. I followed this guide for the basic setup.
First of all: figure out what my SD card is called:
$ lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 1 28.9G 0 disk
└─sda1 8:1 1 28.9G 0 part
The card is called sda
, which means it will be available at /dev/sda
.
Next, partition the card:
sudo fdisk /dev/sda
For the rest, follow the instructions.
Now on to the interesting stuff: connect to the Rpi through your network. As I intend to use the Rpi in headless mode, I want to set it up for remote control. So, plug an ethernet cable into the appropriate pi-hole and connect it to the local network. Then run nmap -sP 192.168.1.0/24
to get a full list of the active ip addresses on your network. In my case this returned 192.168.1.125
for alarmpi.lan
.
This is where your inner Hollywood hacker gets to shine. Run the following command:
ssh alarm@192.168.1.125
and when prompted for the password type the default alarm
.
In order to get anything done while in the depths of you Rpi, you need to become a root user. At first I tried sudo
, but this didn't fly, so I had to do su
instead, and, when prompted, punch in the default root password root
. From here I was able to do
pacman-key --init
pacman-key --populate archlinuxarm
which are essential to turn your Rpi into a computer.
Update your system and the pacman
database:
pacman -Syy
pacman -Syu
We need to make a ssh
session behave like a normal terminal session. The first thing I noticed was that every backspace was read like a space in the Rpi, which is not very conducive to hard labor. So me being a termite
user I had to go:
pacman -S termite-terminfo
Log out and log out again. Now your ssh
should behave properly.
su
-ing every time you want to perform system administration tasks soon becomes both tedious and unsustainable, so you want to enable sudo
. pacman -S sudo
to the rescue. Then visudo
, uncomment the line that says # %wheel ALL=(ALL) ALL
, save and exit the editor. Next, let's get our toolbox in order.
sudo pacman -S neovim tmux git git-lfs zsh man fzf trash-cli base-devel python python-pynvim w3m
Get yourself an aur helper:
git clone https://aur.archlinux.org/yay.git
cd yay
makepkg -si
From now on you will be able to search and install from the arch repos and aur by typing yay <package>
Keeping the default alarm
user around might be nifty for the initial setup, but I prefer to be myself and use the same username for my main computer and the Rpi:
sudo useradd -m <user> -p <password>
sudo usermod -a -G wheel,audio <user>
Log out of the session, and log back in again as your new user. You should be able to use sudo
. If you can't get in, then go back in as alarm
and run
sudo passwd <user>
to make sure you have the correct login credentials. It is also a VERY good idea to change passwords for both alarm
and root
.
sudo hostnamectl set-hostname <new_hostname>
Next, sudoedit /etc/hosts
and fill in this:
127.0.0.1 localhost
::1 localhost
127.0.1.1 <new_hostname>.localdomain <new_hostname>
This sets up an alternative address for the computer for the ssh session. IP addresses can change, but this name won't.
sudoedit /etc/locale.gen
Uncomment the locale you want to use and run:
sudo locale-gen
If /etc/localtime does not exist you need to create the symlink:
ln -s /usr/share/zoneinfo/Europe/Tallinn /etc/localtime
Replace with appropriate timezone.
I prefer zsh
to bash
. To change the default shell, run chsh -s /bin/zsh
(if, that is, you have installed it). To get syntax highlighting in the shell (highly recommended), run this:
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git
echo "source \
${(q-)PWD}/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh" \
>> ${ZDOTDIR:-$HOME}/.zshrc
To get your prompt a bit more beautiful than default zsh, you can do worse then pure. Run these commands to get hold of it:
mkdir $HOME/.zsh
cd .zsh
git clone https://github.com/sindresorhus/pure
To enable the prompt add these lines to .zshrc
:
fpath+=$HOME/.zsh/pure
autoload -U promptinit; promptinit
prompt pure
Exit the ssh session, log back in again, and you should be good to go.
I keep my dotfiles in a gitlab repo, so that they are but a git clone https://gitlab.com/kflak/dots.git
away. My strategy is simply to keep all the dotfiles I want to track in a central repo and symlink them to the necessary locations.
However, a lot of my laptop-specific stuff is specific to the laptop, and i don't need it on my Rpi. So instead of messing too much with an existing .zshrc, I opted to scavenge the dots repo, copying ~/dots/init.vim
to ~/.config/nvim/init.vim
, dots/zshrc
to ~/.zshrc
and edit them to fit Rpi's more modest requirements.
Next up: getting my nvim-plugs to work! I use vim-plug as my plugin manager. Installing it should be a simple matter of running:
sh -c 'curl -fLo \
$HOME/.local/share/nvim/site/autoload/plug.vim --create-dirs \
https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim'
Be aware that there are security risks involved in piping curl to a script, so only do this if you are ok with the risk. Otherwise do it the proper way: download the script and inspect it before running it.
After a while of ssh-ing it gets a bit tedious to keep typing your password every time you want to log in to the rpi. Enter ssh-agent and friends! First of all you need to generate a pair of keys on your work computer (not the rpi) with the command ssh-keygen
. You will be asked for a password. The keys will be created in ~/.ssh/
. Next you need to copy the public key over to the rpi:
ssh-copy-id '<user>@<ip-address-of-pi'
Next, run:
eval $(ssh-agent)
ssh-add ~/.ssh/id_rsa
Enter password and that should be it! Now you can ssh into the rpi without password! More detailed information can be found in this tutorial.
To make the ssh-agent run for the entire session, I put this into my ~/.zlogin
file:
eval $(ssh-agent)
ssh-add
From now on I have to type the password once per user session, instead of every time I fire up a new terminal window.
A realtime kernel is pretty much essential when working with realtime audio. Luckily a readymade kernel is available so you don't have to go through the troubles of compiling one for yourself. Thom Johansen over at Notam has done all the hard work, and you can download it from here. The next bit is a little bit fiddly, but if you keep your head straight, it should work without a hitch. I assume that the tar.gz file lands in your ~/Downloads
folder. I followed the instructions from this tutorial. As the kernel is already compiled, I only had to do the last bit. On my main computer:
scp ~/Download/rt-kernel.tar.gz <user>@<ip-of-rpi>:/tmp
On the Rpi:
cd /tmp
tar xzf rt-kernel.tar.gz
cd boot
sudo cp -rd * /boot/
cd ../lib
sudo cp -dr * /lib/
cd ../overlays
sudo cp -d * /boot/overlays
cd ..
sudo cp -d bcm* /boot/
Next, edit the boot parameters:
sudoedit /boot/config.txt
and add kernel=kernel7l.img
to the end of the boot parameters. sudo reboot
, grab a coffee, and return to your computer when the rpi is back. Verify that you are running the rt-kernel by typing uname -r
. If it says something like 4.19.71-rt24-v7l+
you are good to go!
Install realTimeConfigQuickscan
, an essential tool for diagnosing your audio setup.
yay -S realtimeconfigquickscan-git
Look around and see what is needed. The official way of setting cpupower to "performance" is to put it in the /etc/default/cpugovernor
file, but this didn't seem to stick on reboot, so I created a systemd service instead.
/etc/systemd/system/cpupower.service
---
[Install]
WantedBy=multi-user.target
[Unit]
Description=Set cpugovernor to performance
[Service]
Type=simple
ExecStart=/usr/bin/cpupower frequency-set -g performance
Start the service and enable it on startup:
sudo systemctl enable --now cpupower.service
Install alsa-utils, jack and realtime-privileges:
sudo pacman -S alsa-utils jack2 realtime-privileges
# add user to realtime-group
sudo usermod -a -G realtime <user>
In order to use the onboard audio device you need to add
dtparam=audio=on
Reboot and run aplay -l
to confirm that alsa
sees the soundcard. The output should look something like this:
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
Subdevices: 7/7
Subdevice #0: subdevice #0
Subdevice #1: subdevice #1
Subdevice #2: subdevice #2
Subdevice #3: subdevice #3
Subdevice #4: subdevice #4
Subdevice #5: subdevice #5
Subdevice #6: subdevice #6
...
At first I was very happy to learn that SuperCollider is just a sudo pacman -S supercollider sc3-plugins
away. However, there was a hickup: the mesa
dependency couldn't be downloaded. It turned out to be a simple matter of updating the pacman
database: sudo pacman -Syy
. Something I should have done immediately upon installation, of course...
The next major obstacle was to get SuperCollider to run in a headless environment using the distribution-provided version. Luckily this is not as difficult as it used to be, with a recent qt bugfix. Simply set the QT_QPA_PLATFORM environment variable to offscreen, either in your terminal session or, more permanently, in your .zshrc:
export QT_QPA_PLATFORM=offscreen
source ~/.zshrc
Test your supercollider setup with this little snippet:
~/test.scd
---
s.waitForBoot({{SinOsc.ar}.play});
and run it:
sclang ~/test.scd
If all is well, you should now hear a 440hz sinewave in your left speaker.
In a headless environment you will not be able to use the official SuperCollider IDE. I highly recommend David Granström's scnvim for Neovim. Check out the github repo for installation instructions!
Now that we have SuperCollider up and running, the next step is to get MiniBees to talk to it. The commandline client for receiving data from MiniBee is called pydon-cli
and is written in python 2. This is not included in the base installation, so:
sudo pacman -S python2
Next, we need to clone the repo and run the installation script. I do this in ~/build
, but it's up to you where you want to put it.
mkdir ~/build
cd ~/build
git clone https://github.com/sensestage/ssdn_python.git
cd ssdn_python
# invoke script as root with python2, otherwise it won't work
sudo ./installation.sh python2
Connect the receiver to the usb port and run pydoncli.py
in a directory where you have a pydon-config. If you get a lot of scrolling text complaining that pydoncli could not open serial port, the first thing to do is to check which port the receiver is connected to. Run ls /dev/tty*
without the receiver plugged in, and once more with it plugged in. The extra port that shows up is the correct one. In my case it is /dev/ttyUSB0, so I try once more to run pydoncli.py -s /dev/ttyUSB0
. If this still doesn't work you are probably experiencing a permissions problem. Verify this by running
sudo chmod 666 /dev/ttyUSB0
and try once more. You should now have a working board.
You definitely don't want to do this every time you connect your minibee receiver, so add this udev rule to your system:
/etc/udev/rules.d/52-xbee.rules
---
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", GROUP="users", MODE="0666"
And that should be it! If all is well you now have a working installation of Arch Linux ARM on your Raspbery Pi 4 as well as a SuperCollider environment.
If you have feedback or questions, feel free to get in touch!