Skip to content

Setting up a Horus Binary Chase‐Car Raspberry Pi

Mark Jessop edited this page Dec 28, 2024 · 8 revisions

Last Updated: 2024-12-28

These are some rough notes I put together while building up a Raspberry Pi for use by a visitor who was wanting to chase a balloon launch flying a Horus Binary tracking payload. They describe the steps required in setting up a Raspberry Pi from scratch with both ChaseMapper and the horusdemodlib decoder.

Warning: The latest version of Raspbian (Bookworm) may have stability issues. I'd probably recommend using the previous version (Bullseye - listed as 'Raspberry Pi OS - Legacy' in the RPI Imager) for now.

Hardware Used

  • Raspberry Pi 3B or newer
    • A RPi 3B or newer will work fine.
    • Watch out with the newer higher-power units, as these can overheat.
    • Also make sure whatever unit you buy will work on the WiFi band your hotspot uses! Some RPi's won't do 5GHz WiFi.
  • RTLSDR
    • I generally use the RTLSDR v3 units.
    • Other brands/versions will probably work OK, just watch out for driver issues with the very recent units (e.g. the RTLSDR v4) that may require you to compile the rtlsdr drivers from source. With the v3 you won't have these problems.
  • Antenna for 434 MHz
    • Lots of options to choose from here. I'd suggest something with lower gain like a 1/4-wave. Too high gain and you may have trouble receiving signals from very high elevations.
    • Commercial antennas from Diamond, e.g. the MR77 are suitable.
    • Even cheapie 1/4-wave magmounts from Aliexpress can be good enough for this!
  • USB GPS Receiver
  • Some kind of power supply for your RPi
    • Various USB battery banks will work. Make sure you have some idea of how long they will last!
  • A 3G/4G/5G WiFi hotspot for your RPi to connect to.
  • A tablet computer or some other computer (7" or bigger screen recommended) to display the ChaseMapper webpage.

Installing Raspbian

  • I used the Raspberry Pi Imager
  • I used the Raspbian 32-bit Lite OS (available from the Operating system selection, under "Raspberry Pi OS (Other)". If you're running a RPi 3B+ or a Pi 4 then you can use the 64-bit image. I'd probably suggest using the Legacy version of Raspberry Pi OS for now.
  • Within the Imager options (gear icon) I also configured:
    • Enabled SSH, and set the user to pi and password to raspberry.
    • Enabled WiFi, and configured my home wifi network. The RPi3 only does 2.4 GHz WiFi.
    • Set the hostname to chasebox (so I can spot the RPi easily on my DHCP server)
  • I then wrote the image to a 32GB Sandisk Pro MicroSD Card.

RPi Initial Setup

  • Found the RPi's IP address from my local DHCP server info.
  • SSH'd into the RPi from another machine (ssh pi@ip-address). If you're lucky then hostname lookup might work and you can use ssh pi@chasebox.local

You could do all the following setup by plugging in a screen and keyboard, but since we're not going to have that available in the car, I find it best to log in via SSH.

Update APT repositories and upgrade any out-of-date packages:

sudo apt-get update
sudo apt-get upgrade

Install the packages we need for HorusBinary:

sudo apt-get install cmake build-essential libusb-1.0-0-dev git python3-venv python3-crcmod python3-requests python3-pip sox bc rtl-sdr libatlas-base-dev libopenblas-dev screen

Install docker (which we need for Chasemapper):

curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh

Setup some permissions required for the pi user to be able to access serial ports, docker, and the RTLSDR:

sudo usermod -aG docker $(whoami)
sudo usermod -aG dialout $(whoami)
sudo wget -O /etc/udev/rules.d/20-rtlsdr.rules https://raw.githubusercontent.com/osmocom/rtl-sdr/master/rtl-sdr.rules

Plug in the RTLSDR and the GPS receiver, and reboot (sudo reboot).

Testing the RTLSDR and GPS Receiver

SSH back into the RPi.

Test the RTLSDR using rtl_test. Ctrl-C to stop the testing.

$ rtl_test
Found 1 device(s):
  0:  Nooelec, NESDR SMArt v5, SN: 00000001

Using device 0: Generic RTL2832U OEM
Detached kernel driver
Found Rafael Micro R820T tuner
Supported gain values (29): 0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 
[R82XX] PLL not locked!
Sampling at 2048000 S/s.

Info: This tool will continuously read from the device, and report if
samples get lost. If you observe no further output, everything is fine.

Reading samples in async mode...
Allocating 15 zero-copy buffers
lost at least 76 bytes
^CSignal caught, exiting!

User cancel, exiting...

Test the GPS output using cat /dev/ttyACM0:

$ cat /dev/ttyACM0
$GPRMC,013316.00,A,3443.00000,S,13841.00000,E,0.089,,250424,,,D*67

$GPVTG,,T,,M,0.089,N,0.164,K,D*24

$GPGGA,013316.00,3443.00000,S,13841.00000,E,2,07,1.54,103.1,M,-2.8,M,,0000*5A

$GPGSA,A,3,03,21,02,31,04,16,28,,,,,,2.98,1.54,2.56*09

$GPGSV,3,1,10,02,35,339,38,03,70,193,43,04,54,245,36,06,05,213,25*73

$GPGSV,3,2,10,16,15,046,26,21,24,353,38,26,27,080,19,28,20,138,29*7F

$GPGSV,3,3,10,31,50,127,38,50,48,340,38*75

... Ctrl-C to exit.

Setup Chasemapper

Setup the required directories with:

mkdir -p ~/chasemapper/log_files
mkdir -p ~/Maps
curl -o ~/chasemapper/horusmapper.cfg https://raw.githubusercontent.com/projecthorus/chasemapper/master/horusmapper.cfg.example

Configuration

Edit the horusmapper.cfg file with nano ~/chasemapper/horusmapper.cfg. I changed:

  • default_profile to 2 (which is the Horus Binary profile)
  • In the [serial] section changed gps_port to /dev/ttyACM0
  • In the [predictor] section, changed model_download to python3 -m cusfpredict.gfs --lat=-33 --lon=139 --latdelta=10 --londelta=10 -f 24 -m 0p50 -o gfs (which is appropriate for the Adelaide area)
  • In the [offline_maps] section, set tile_server_enabled to True
  • In the [offline_maps] section, comment out the tile_server_path that points to /home/pi/Maps, and uncomment the one lower down pointing to /opt/chasemapper/Maps
  • In the [habitat] section, set habitat_call to CHASEBOX

You can grab a modified horusmapper.cfg file with the above changes by running:

curl -o ~/chasemapper/horusmapper.cfg curl -o test.cfg https://gist.githubusercontent.com/darksidelemm/323872f897881845e5e68315fd563833/raw/bc0895ef9cc0c144b98cad6d6744cc58fb27730c/horusmapper.cfg

... though please change the habitat_call setting!!!

Offline Maps (Offline)

There's some notes on offline map downloading here: https://github.com/projecthorus/chasemapper?tab=readme-ov-file#offline-mapping

If you have downloaded maps, these need to be placed into the /home/pi/Maps/ directory.

Startup

Download and startup the chasemapper docker container with the multi-line command:

docker run \
  -d \
  -t \
  --name chasemapper \
  --restart="always" \
  --device=/dev/ttyACM0 \
  --network=host \
  -v ~/chasemapper/horusmapper.cfg:/opt/chasemapper/horusmapper.cfg:ro \
  -v ~/chasemapper/log_files/:/opt/chasemapper/log_files/ \
  -v ~/Maps/:/opt/chasemapper/Maps/ \
  ghcr.io/projecthorus/chasemapper:latest

The log output from the docker image can be checked for errors using:

docker logs chasemapper

Confirm the chasemapper web interface is accessible by visiting http://<your_pi_ip>:5001 in a web browser.

Things worth testing now:

  • Confirm the chase car position is appearing on the map (this will require GPS lock). You can also check the number of SVs tracked in the 'car' settings.
  • Confirm you can download a GFS model. (The 'Current Model' text should change to 'Started Downloader'). It may take quite a while for the GFS model to download, and depending on how broken the NOMADS grib-filter is on any particular day it may fail altogether. After a while it should change to something like 2024042418z (Offline)
  • If you have added any offline map layers, check you can select them from the map layer list.
  • If you want, check you can upload your position to the SondeHub-Amateur tracker by enabling 'Chase Car Position Upload' in the car settings. By default this setting is disabled, so it will need to be turned on if you restart the RPi or Chasemapper.

If you need to change any configuration settings, you can restart chasemapper with docker restart chasemapper

Setting up Horus Binary Reception

Downloading, Compiling, Installing

git clone https://github.com/projecthorus/horusdemodlib.git
cd horusdemodlib
mkdir build
cd build
cmake ..
make
ctest   (which should result in output ending in '100% tests passed', though it appears the RTTY ctests are currently failing. As long as the horus-binary ones pass we're OK...)
sudo make install
cd ../
python3 -m venv venv
. venv/bin/activate
pip install -r requirements.txt
pip install horusdemodlib

Configuration

cp user.cfg.example user.cfg

Edit user.cfg (nano user.cfg):

  • callsign - This should match whatever you set for habitat_call when setting up Chasemapper further above.
  • station_lat and station_lon - Leave these at 0.0 for a chase car! Your position will be uploaded by Chasemapper
  • radio_comment and antenna_comment as desired...

For our flights we're going to use the start_dual_4fsk.sh script as-is. If you are running different frequencies you may need to modify the frequency settings.

Testing the Decoder

Startup a test Horus Binary payload on an appropriate frequency. Then, run start_dual_4fsk.sh:

./start_dual_4fsk.sh 
Found horus_demod.
Found bc.
Entering venv.
Using SDR Centre Frequency: 434195000 Hz.
Using MFSK1 estimation range: 2500 - 7500 Hz
Using MFSK2 estimation range: 12500 - 17500 Hz
Using AGC.
Setting estimator limits to 12500 to 17500 Hz.
Setting estimator limits to 2500 to 7500 Hz.
Found 1 device(s):
  0:  Nooelec, NESDR SMArt v5, SN: 00000001

Using device 0: Generic RTL2832U OEM
Detached kernel driver
Found Rafael Micro R820T tuner
Tuner gain set to automatic.
Tuned to 434579000 Hz.
Oversampling input by: 32x.
Oversampling output by: 1x.
Buffer size: 5.33ms
Allocating 15 zero-copy buffers
Sampling at 1536000 S/s.
Output at 48000 Hz.
2024-04-25 11:47:10,427 INFO: Opened log file telemetry.log.
2024-04-25 11:47:10,429 INFO: Attempting to download latest payload ID list from GitHub...
2024-04-25 11:47:10,435 INFO: Opened log file telemetry.log.
2024-04-25 11:47:10,436 INFO: Attempting to download latest payload ID list from GitHub...
2024-04-25 11:47:11,485 INFO: Attempting to download latest custom field list from GitHub...
2024-04-25 11:47:11,495 INFO: Attempting to download latest custom field list from GitHub...
2024-04-25 11:47:12,478 INFO: Payload list contains 438 entries.
2024-04-25 11:47:12,480 INFO: Custom Field list contains 15 entries.
2024-04-25 11:47:12,480 INFO: Payload list contains 438 entries.
2024-04-25 11:47:12,481 INFO: Custom Field list contains 15 entries.
2024-04-25 11:47:12,483 INFO: Sondehub Amateur Uploader - Started Sondehub Amateur Uploader Thread.
2024-04-25 11:47:12,485 INFO: Sondehub Amateur Uploader - Started Sondehub Amateur Uploader Thread.
2024-04-25 11:47:12,486 INFO: Using User Callsign: CHASEBOX
2024-04-25 11:47:12,484 INFO: Using User Callsign: CHASEBOX
2024-04-25 11:47:12,497 INFO: Started Horus Demod Uploader. Hit CTRL-C to exit.
2024-04-25 11:47:12,498 INFO: Started Horus Demod Uploader. Hit CTRL-C to exit.
2024-04-25 11:47:14,205 INFO: Sondehub Amateur Uploader - Uploaded station information to Sondehub.
2024-04-25 11:47:14,607 INFO: Sondehub Amateur Uploader - Uploaded station information to Sondehub.
2024-04-25 11:47:16,437 INFO: Received raw binary packet: <Removed>
2024-04-25 11:47:16,468 INFO: Decoded Binary Packet (SNR 14.3 dB): $$FLIGHTDESIGN2,52,02:17:11,-34.00000,138.00000,106,0,6,33,1.41,-0.01,0.0,0,0.0*9AC4
2024-04-25 11:47:18,110 INFO: Sondehub Amateur Uploader - Uploaded 1 telemetry packets to Sondehub Amateur in 1.5 seconds.

You can then Ctrl-C this.

This should also upload telemetry which should be visible on the SondeHub-Amateur tracker, assuming your payload has GPS lock.

Starting up the decoder on boot

Refer horusdemodlib guide to startup using systemd here: https://github.com/projecthorus/horusdemodlib/wiki/1.2--Raspberry-Pi-'Headless'-RX-Guide#systemd-based-startup

Now, reboot (sudo reboot), then once rebooted, open up the ChaseMapper web interface and confirm you are receiving telemetry!

Final Setup and Usage on the day

Adding another WiFi Network (Raspbian Bullseye)

Once you know what wifi network you're going to run the RPi off on the day (e.g. some kind of 4G hotspot), you're going to need to setup the RPi to connect to this.

Under Bullseye adding another Wifi network is fairly easy. All we have to do is edit the /etc/wpa_supplicant/wpa_supplicant.conf file, e.g. sudo nano /etc/wpa_suplicant/wpa_supplicant.conf

Add a new section to the file like this:

network={
	ssid="YourWifiSSID"
	psk="yourwifipassword"
priority=2
}

A higher priority number makes your RPi preferentially connect to that network. Useful if you want to test connecting to a mobile hotspot while at home where your 'setup' network is still active!

Save and reboot for this to take effect.

Adding another WiFi Network (Raspbian Bookworm)

Under Raspbian Bookworm, things have changed and we now have to deal with Network Manager...

If you can somehow get into your RPi via SSH (e.g. via ethernet), the you may be able to use the nmcli utility to connect

Otherwise, we're going to have to mess about with Network Manager configuration files.

Create a new wifi connection setting file: sudo nano /etc/NetworkManager/system-connections/wifi.nmconnection

[connection]
id=wifi
uuid=95b17351-297c-4d9c-90f9-669d3ab81464
type=wifi
autoconnect_priority=2
[wifi]
mode=infrastructure
ssid=YOUR_SSID_HERE
hidden=false
[ipv4]
method=auto
[ipv6]
addr-gen-mode=default
method=auto
[proxy]
[wifi-security]
key-mgmt=wpa-psk
psk=YOUR_PASSWORD_HERE

Note: The autoconnect_priority setting tells Network Manager to prefer this connection over the default connection you set up with RPi Imager. Higher number = higher priority, with the default value being 0.

This file then need to have its permissions modified for Network Manager to be happy with it:

sudo chmod -R 600 /etc/NetworkManager/system-connections/wifi.nmconnection
sudo chown -R root:root /etc/NetworkManager/system-connections/wifi.nmconnection

If you want to add multiple connection options, you can create multiple .nmconnection files. e.g. wifi2.nmconnection. You will also need to modify the id field in the file, and change the uuid to something unique (e.g. just bump the last character by one).

Reboot, and hopefully your RPi will jump onto the right network.

Things to do/check before you launch your balloon!

  • Turn on your tracking payloads a good 30 min before launch.
  • Set the wind model downloading.
  • Update the expected burst altitude and descent rate. This is important for accurate predictions during the ascent part of your flight.
  • ~20-10 min before launch, check they are being received by your system and showing up on ChaseMapper.
  • Check the SNR you are seeing off the payloads looks 'right'. If you're very near the payloads, then the SNR should be very high, like >20 dB.
  • On the SondeHub-Amateur Tracker:
    • Check your payloads are showing up.
    • Check the number of satellites used in the position solution (Unfortunately you can't yet do this on ChaseMapper). Do the payloads have decent GPS lock?
  • Just before launch, re-check you are receiving the payloads and that they have GPS lock still. Don't launch if the payloads don't have GPS lock!

After launch

  • You can expect the receive SNR to drop down as the payloads go further away, and end up in negative numbers. You will probably see low SNR if you end up directly beneath the payload due to antenna pattern nulls.
  • Keep an eye on the predicted landing location, and head that way ASAP!
  • After balloon burst, the prediction will go a bit wild while the payloads are in their initial descent. This will stabilise after a few minutes.
  • Keep following that predicted landing location! With luck you'll be in place to either watch the payloads land, or at least be close enough to get a telemetry position very close to the landing spot.