In 2022 I plan to do my first Bike MS event. This cause hits close to home, as two people I am close with have been diagnosed with MS. If you are reading this before May 14, 2022, donations would be greatly appreciated at my Bike MS page.
In order to raise more donations, I had an idea to stream the whole ride to Twitch. I investigated some existing products that could do this, but they were very expensive. I also thought it would be cool to have some data embedded in the video feed, such as speed, distance traveled, heart rate, and power. Some of the existing products could add that data to the video after it was recorded, but none would embed that data into a live stream. So, I created this little gadget to connect to my phone's Wi-Fi tethering and stream the ride exactly as I imagined it:
As with all of my projects, this one is open source. You can find the source code on Github, and the whole project is published as a Snap called "twitch-cycling-jawn"
Why Use a Snap?
I know snaps have been controversial, but this is the perfect example to demonstrate their utility. If I'm strapping something to my helmet for 150 miles, I want it to be as light as possible. This means I want to use a Raspberry Pi Zero 2, but the 512MB of RAM could be problematic. Especially considering that the GPU will need 128MB of RAM, I need the host operating system to have the smallest memory footprint possible. That's where Ubuntu Core comes in. With it being a completely snap based operating system, it uses very little memory, and can happily allocate 128MB of RAM to the GPU without missing a beat. In order to have this application run on Ubuntu Core, it must be packaged as a snap.
Build Your Own
In order to replicate this project, you will need the following
- A Raspberry Pi Zero 2
- A Raspberry Pi Camera Module
- A Raspberry Pi Zero compatible ribbon cable
- An Adafruit Ultimate GPS Breakout
- A battery pack to power the Raspberry Pi. I am using a 10 Ah battery for BikeMS
- A 3D printer or some other creative way of mounting the Pi to your helmet
- 4x DuPont cables
- 2x M4x16mm bolts with nuts
- 2x M3x6mm bolts with nuts
- Optional: BLE heart rate monitor
- Optional: BLE power meter
Since I already owned the heart rate monitor and power meter I ended up spending about $75 on this project.
Setting Up the Operating System
If you already have Ubuntu Core 22 set up on a Raspberry Pi, skip to the next paragraph. Otherwise, please see these Instructions for installing Ubuntu Core 22 on a Raspberry Pi. Since the Pi Zero 2 only has 512MB of RAM, please use the armhf version of Ubuntu Core 22.
Before booting the Pi, we need to enable the camera and increase the amount of RAM allocated to the GPU. To accomplish this, plug your SD card into another computer, use your favorite text editor to open the file
<sd_card_mountpoint>/ubuntu-seed/config.txt, and uncomment the following lines:
By default, Ubuntu Core has a serial console enabled. In order to use the serial pins for the GPS modules instead, we will need to disable it. To do so, open the file
<sd_card_mountpoint>/ubuntu-seed/cmdline.txt and change the section
Before removing the SD card, be sure to cleanly unmount it!
Ubuntu Core has no login console and is accessed via
ssh only. It is easier to set up
ssh access before assembling the case, as the case provides no access for an HDMI cable or USB keyboard. After the Pi boots up, there will be a TUI for setting up Wi-Fi and
ssh access. Since the streaming software needs a Wi-Fi hotspot, I recommend configuring the Wi-Fi to use whatever hotspot you will be using out on the road. After testing that
ssh access works, it is time to assemble the rest of the hardware.
If you're using my 3D printed case, start printing it. It can be found on Thingiverse.
When that finishes printing, we can solder the wires connecting the GPS module and the Raspberry Pi as in the following diagram:
I went ahead and soldered the DuPont cables straight into the Pi and GPS module so I didn't have to worry about them coming loose. If you are doing that, learn from my mistakes and put the wires through the top part of the case before soldering them in! Now assemble the rest of the case. I left a slot for Velcro in the sides of the case, which is how I'm attaching this to my helmet. The camera module's ribbon case is meant to go under the camera mount, as in the pictures. The M3 bolts are used to keep the camera and GPS enclosures tight. The M4 bolts connect the camera and GPS enclosures to the top of the Pi case. The pictures below show the completed project from a variety of angles to show how it all goes together.
Now that the project has been physically assembled the OS has been configured, plug the Pi in and
ssh into it. Before using the
twitch-cycling-jawn snap, we'll need to install the
pi-bluetooth snaps. We will also need to connect the
twitch-cycling-jawn plugs to a few system slots to allow access to Bluetooth, the serial port, and the camera. To learn more about plugs and slots see one of my other blog posts. To install the snaps and connect the plugs and slots, run the following commands:
sudo snap install bluez pi-bluetooth twitch-cycling-jawn sudo snap connect twitch-cycling-jawn:bluez bluez:service sudo snap connect twitch-cycling-jawn:serial-port pi:serial0 sudo snap connect twitch-cycling-jawn:camera :camera sudo bluetoothctl power on
Now we can configure the BLE devices (if any) and your Twitch account information! There are two ways to set up the BLE devices - by scanning for them or by manually setting the MAC address of your BLE devices. To scan for nearby devices, use the command
sudo twitch-cycling-jawn.configjawn --scan-hr --scan-power. This will scan BLE devices advertising heart rate and power services. Once found, it will save the information about the in a configuration file for the stream to use. If you have multiple devices nearby and want to set a specific one in the configuration file, you can use the command
sudo twitch-cycling-jawn.configjawn --hr-mac <MAC_ADDRESS_OF_DEVICE> --power-mac <MAC_ADDRESS_OF_DEVICE>. To set up streaming to Twitch, you will first need your Stream key. To find your Stream key:
- Navigate to the Twitch website and log in
- Select "profile" in the top right, and click on "Settings"
- Select the section "Channel and Videos" to be brought to the creator dashboard
- In the "CREATOR DASHBOARD" pane on the left, click on "Stream" under the "Settings" header
- Click the "Copy" button in the "Primary Stream key" row
Now using the recently copied Stream key, run the command
sudo twitch-cycling-jawn.configjawn --twitch-id <your_stream_key>.
You're now ready to start streaming! To start the stream without rebooting, run
sudo systemctl restart snap.twitch-cycling-jawn.stream-with-data.service. Otherwise, you can shut down the Pi, and next time you power it on it will start streaming automatically!