-
Notifications
You must be signed in to change notification settings - Fork 10
Wenet TX Payload Instructions
Last Updated: 2024-12-24
This page documents the steps required to set up a Raspberry Pi (3, ZeroW, ZeroW2) as a Wenet transmitter. These instructions assume that you already have a Raspbian installation set up on a Raspberry Pi, and have SSH access to it.
Wenet transmitters have been successfully run using RPi 3, Zero W and Zero W2 units. For the latest versions of Wenet, we recommend the Pi Zero W2 for the multi-core CPU. Note that these can get quite warm on the ground, but will generally cool down in flight.
The Wenet codebase currently supports using either a HopeRF RFM22B or a HopeRF RFM98W radio module as the FSK modulator. The RFM22B is now obsolete, so the RFM98W option is probably better.
UpuTronics sells a suitable RFM98W Raspberry Pi shield, with shield sizes suitable for a RPi2 Model A, and a Pi Zero/W.
In both cases, the shield must be modified with the addition of a single wire, connecting the DIO2 pin (GPIO2 on the RFM98W) to the TXD pin (pin 8) on the Raspberry Pi's header. We use this wire to modulate the RFM98W in 'direct asynchronous' 2-FSK mode.
The above image shows how this can be implemented on one of the UpuTronics shields. A length of re-work wire is used to join the two pins, and is held down with silicone.
Adafruit also sell a suitable shield which is known to work with Wenet. Make sure you buy the "LoRa RFM96W 433 MHz" version. This board also has easier to solder pads for connecting the RPi TX line to the DIO2 input on the module. Note that this board uses SPI CE1, which will need to be configured later.
See the following diagram for details on what has to be connected on the board for Wenet operation:
The Wenet code is intended to be used with a PiCam. We recommend the v2 and HQ cameras.
The newer PiCam v3 is known to drift in focus with temperature, and auto-focus is a bit temperamental (still some autofocus optimisation work to be done).
The Wenet transmitter code can optionally get payload position information from a uBlox GPS module (accessed via USB-Serial), and overlay the position on the downlinked image. This must be a uBlox module, as we use uBlox protocol to ensure the module is in airborne mode.
USB-connected uBlox GPS units are available fairly cheaply on eBay, under the name 'VK-172 G-mouse'. These have a uBlox 7 chipset (or at least a very good clone of one...) and have been tested up to 37km altitude. They appear as an ACM serial device, and later on in the setup process a udev rule is added to provide a symlink to the serial port at /dev/ublox.
Mount them away from everything else in your payload box (especially the camera cables!) to avoid GPS lock issues due to RFI.
Install the required dependencies from apt-get using:
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install git build-essential vim python3-dev python3-numpy python3-picamera2 python3-crcmod python3-spidev python3-pip python3-serial python3-rpi.gpio imagemagick gsfonts --no-install-recommends
We need fsphil's 'slow-scan digital video' compression utility available on the system. From the home directory, run:
git clone https://github.com/fsphil/ssdv.git
cd ssdv
make
sudo make install
Run:
cd
git clone https://github.com/projecthorus/wenet.git
sudo cp ~/wenet/tx/99-usb-serial.rules /etc/udev/rules.d/
In turn, this:
- Grabs a copy of the Wenet git repository
- Copies udev rules to be able to easily access a uBlox GPS unit at /dev/ublox
Finally, we need to compile the LDPC Encoding library:
cd ~/wenet/tx/
gcc -fPIC -shared -o ldpc_enc.so ldpc_enc.c
Run sudo raspi-config
, and under Interfacing options, enable:
- SPI
- Serial (When prompted, set 'Enable Login Shell' to NO, and 'Serial Port Hardware Enabled' to YES.)
Edit /boot/config.txt
(e.g. sudo nano /boot/config.txt
and add the following lines at the end as required.
Note that on Bookworm this file is now /boot/firmware/config.txt
For Pi Zero W, Pi 3 and other RPis with bluetooth, we need to add:
dtoverlay=pi3-disable-bt
This makes sure that we have access to the 'good' UART peripheral on the RPI, not the very limited Mini-UART.
We may also need to under-clock the CPU to avoid Oops - undefined instruction: 0 [#1] ARM
errors due to overheating:
arm_freq=700
If using a PiCam v3, it's highly recommended to adjust the camera link frequency to move its harmonics away from the GPS L1 frequency. To do this, look for the line camera_auto_detect=1
and comment it out. Then add the following line at the bottom of the file:
dtoverlay=imx708,link-frequency=447000000
Reboot for these changes to take effect.
If required, the attached GPS unit can be used to synchronise the system clock, via NTPd's Shared Memory Interface.
To use this, we need to grab the ntpdshm python library from pip, and also install the NTPD server:
sudo apt-get install ntp
sudo pip3 install ntpdshm
The NTP config file (/etc/ntpsec/ntp.conf
) then need to be edited, and the following lines added at the end of the file:
server 127.127.28.2 minpoll 4 maxpoll 4
fudge 127.127.28.2 time1 0.09 flag1 1 refid PYTH stratum 2
Restart NTPD using sudo systemctl restart ntp
This section assumes you have a Wenet Receiver available.
Before testing with a camera, is is useful to transmit some test images to check the FSK modulator is working. The test_images
directory contains a set of test images that you can transmit. Run:
cd ~/wenet/test_images
python3 compress_test_images.py
This will produce SSDV-compressed versions of the JPEG images, and may take a few minutes to run (depending on the RPi board in use).
Now, we need to start up the radio module:
cd ~/wenet/tx
python3 tx_test_images.py --rfm98w 0 --frequency <freq>
Replace <freq>
with a frequency in MHz that you are licensed to use. Note that the transmitted signal is over 300 kHz wide, so is in breach of the ISM regulations in most countries. Here in Australia, we run our Wenet payloads on 443.500 MHz, under an Advanced amateur radio licence, though it's possible to run this with even a Foundation level license.
Depending on your LoRa shield, your module might be using a different chip-select line than the default (CE0). To select the other chip-select line, you can change the 0
to a 1
in the command above (e.g. --rfm98w 1
. Note that you will also need to change this in any startup scripts you might use later.
The test images will now start transmitting.
Hopefully images will start appearing on your Wenet receiver! If you're not seeing any modulation, or the images seem to be overly corrupted (lots of missing packets), then you might not be be using the correct UART, and you need to double check those dtoverlay settings.
To check that the RPi can communicate with an attached uBlox GPS unit, run:
cd ~/wenet/tx
python3 ublox.py /dev/ublox
A large amount of JSON objects should be written to the terminal, containing the various GPS parameters (latitude, longitude, time, etc)
If you set up NTPD earlier, you can add --ntp
before /dev/ublox
, and then in a different terminal run ntpq -p
. You should see a SHM(2)
entry in the list of NTP peers. A *
next to the SSH(2) entry indicates that this source is being used as the primary time source.
We can start up a basic version of the image transmission script to check communication with the camera and general transmissions are OK.
cd ~/wenet/tx
sudo python3 tx_picamera2_gps.py --rfm98w 0 --frequency <freq> YOURCALL
(It's unfortunately easier to run these scripts as sudo from now on, as some of them need to set system time.)
Debug information on the scripts current actions will be written to the terminal. Images should be captured, re-sized, and transmitted via the FSK modulator. To exit, Ctrl-C (might need to do this a few times.. sometimes things get stuck!)
You can get a 'live' video stream from your camera over a network by using the raspivid
utility, which can be started with:
libcamera-vid -t 0 -l -o tcp://0.0.0.0:3333 --width 1920 --height 1080
Access the stream by opening VideoLan Player (VLC) and opening a network address of: tcp/h264://your.pi.ip.address:3333
If you're worried about Raspbian locking up, you can setup a hardware watchdog. Some information on this is available here: https://diode.io/raspberry%20pi/running-forever-with-the-raspberry-pi-hardware-watchdog-20202/
The tx_picamera2_gps.py
Python script will automatically capture images and GPS data, overlay GPS position information at the top of the image, and transmit images. Note that this needs to be run as root, as it will try and write into NTPD shared memory by default to set the system time, or as a fallback, will just use timedatectl
to set the system time on first GPS lock.
The start_tx.sh
script in ~/wenet
is designed to be started up by systemd on boot, and will enable and configure the radio module, then start tx_picamera2_gps.py
. Edit this file and adjust the MYCALL and TXFREQ parameters as necessary, and any other changes as needed as described in the script.
The systemd service file ( wenet_tx.service
) shouldn't need any changes if you are running as the 'pi' user. If you're running as a different user, you will probably need to change the paths (/home/pi/wenet) in the .service file.
Install the systemd service file using:
sudo cp wenet_tx.service /etc/systemd/system/
Test it using:
sudo systemctl start wenet_tx
... which will start up the wenet transmitter, and start capturing and sending images. Confirm you can receive this using a local Wenet receiver.
You can look at the systemd log output by running:
sudo journalctl -f -u wenet_tx
The Wenet transmit process will also by default write any log output to /home/pi/wenet/tx/debug.log
(this output mirrors the text messages which are also transmitted through the Wenet downlink). You can follow this log by running:
tail -f /home/pi/wenet/tx/debug.log
2024-07-21T05:25:29.238885,TXing Text Message #238: PiCam Debug: Capturing Image 1 of 5
2024-07-21T05:25:30.371565,TXing Text Message #239: PiCam Debug: Capturing Image 2 of 5
2024-07-21T05:25:31.473176,TXing Text Message #240: PiCam Debug: Capturing Image 3 of 5
2024-07-21T05:25:32.777074,TXing Text Message #241: PiCam Debug: Capturing Image 4 of 5
2024-07-21T05:25:33.903736,TXing Text Message #242: PiCam Debug: Capturing Image 5 of 5
2024-07-21T05:25:35.170286,TXing Text Message #243: PiCam Debug: Choosing Best Image.
2024-07-21T05:25:35.190281,TXing Text Message #244: PiCam Debug: Copying image to storage with filename ./tx_images//20240721-042529Z_picam.jpg
2024-07-21T05:25:35.370014,TXing Text Message #245: PiCam Debug: Running Image Post-Processing
2024-07-21T05:25:35.376563,TXing Text Message #246: Adding overlays to image.
... many more lines
To start the wenet_tx service on boot, run:
sudo systemctl enable wenet_tx
Note that it will take ~30-40 seconds after boot for transmissions to start.
If for whatever reason you need to stop the transmitter processes, you can run:
sudo systemctl stop wenet_tx
Some further configuration may be required depending on your payload setup. The main things you may want to change are the capture & transmit resolutions, and whether horizontal/vertical flip is used (depends on your camera orientation).
Sometimes we see a Kernel Oops when running convert. This seems to be a kernel corruption issue related to overheating. The advice seems to be to lower the CPU clock frequency to 700 MHz (arm_freq=700
) for better stability, or alternatively over-volt the CPU (over_voltage=2
).
Message from syslogd@wenetdev at Sep 15 06:12:24 ...
kernel:[18610.048006] Internal error: Oops - undefined instruction: 0 [#2] ARM
Message from syslogd@wenetdev at Sep 15 06:12:24 ...
kernel:[18610.049324] Process convert (pid: 4973, stack limit = 0x8a854088)
Message from syslogd@wenetdev at Sep 15 06:12:24 ...
kernel:[18610.049358] Stack: (0xdcafdec8 to 0xdcafe000)
... more messages here
dmesg shows:
[18610.048006] Internal error: Oops - undefined instruction: 0 [#2] ARM
[18610.048121] Modules linked in: dw9807_vcm imx708 spidev brcmfmac vc4 brcmutil sha256_generic libsha256 8021q garp stp llc snd_soc_hdmi_codec drm_display_helper cec cfg80211 drm_dma_helper drm_kms_helper cdc_acm snd_soc_core snd_compress i2c_mux_pinctrl i2c_mux snd_pcm_dmaengine syscopyarea sysfillrect sysimgblt fb_sys_fops bcm2835_codec(C) bcm2835_unicam raspberrypi_hwmon bcm2835_isp(C) v4l2_dv_timings bcm2835_v4l2(C) v4l2_mem2mem rfkill v4l2_fwnode bcm2835_mmal_vchiq(C) videobuf2_vmalloc v4l2_async videobuf2_dma_contig videobuf2_memops videobuf2_v4l2 videobuf2_common snd_bcm2835(C) videodev snd_pcm i2c_bcm2835 spi_bcm2835 snd_timer snd mc vc_sm_cma(C) uio_pdrv_genirq uio fixed drm fuse drm_panel_orientation_quirks backlight ip_tables x_tables ipv6
[18610.048554] CPU: 0 PID: 4973 Comm: convert Tainted: G D C 6.1.21+ #1642
[18610.048592] Hardware name: BCM2835
[18610.048613] PC is at linux_banner+0xc7a78/0x1dd784
[18610.048676] LR is at handle_mm_fault+0x67c/0xd94
[18610.048742] pc : [<c0a0a1f4>] lr : [<c01ce4f8>] psr: a0000113
[18610.048768] sp : dcafdec8 ip : c001cf7c fp : cb9223c8
[18610.048790] r10: 00000000 r9 : dcafdfb0 r8 : c0c2f02c
[18610.048812] r7 : 00000000 r6 : 00000000 r5 : ae7d4000 r4 : 00000000
[18610.048835] r3 : 00000a53 r2 : c7301040 r1 : 00000000 r0 : c3b8df50
[18610.048859] Flags: NzCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment user
[18610.048889] Control: 00c5387d Table: 07434008 DAC: 00000055
[18610.048912] Register r0 information: non-slab/vmalloc memory
[18610.048946] Register r1 information: NULL pointer
[18610.048973] Register r2 information: slab task_struct start c7301040 pointer offset 0
[18610.049025] Register r3 information: non-paged memory
[18610.049052] Register r4 information: NULL pointer
[18610.049077] Register r5 information: non-paged memory
[18610.049104] Register r6 information: NULL pointer
[18610.049129] Register r7 information: NULL pointer
[18610.049154] Register r8 information: non-slab/vmalloc memory
[18610.049180] Register r9 information: 2-page vmalloc region starting at 0xdcafc000 allocated at kernel_clone+0xac/0x31c
[18610.049243] Register r10 information: NULL pointer
[18610.049270] Register r11 information: non-slab/vmalloc memory
[18610.049298] Register r12 information: non-slab/vmalloc memory
[18610.049324] Process convert (pid: 4973, stack limit = 0x8a854088)
[18610.049358] Stack: (0xdcafdec8 to 0xdcafe000)
[18610.049389] dec0: c2da8540 c2da81c0 dcafdf2c c08c6378 c0c3b420 079e234f
[18610.049425] dee0: ae7d4000 cb9223c8 ffffffff c2ec0828 00000cc0 000ae7d4 ae7d4000 ae7d4000
[18610.049460] df00: 00000a55 c7436b98 c7436b98 00000000 00000000 00000000 c3b8d750 c2da8570
[18610.049495] df20: 00000000 52b0e49f 00000817 dcafdfb0 c2da8540 ae7d4004 00000817 00000255
[18610.049530] df40: c2ec0828 00000002 c2da8570 c08cd358 00000006 dcafdf54 dcafdf54 c2da8540
[18610.049564] df60: 01920000 c0c34bfc 00000817 c08cd220 ae7d4004 dcafdfb0 00000000 be9adb20
[18610.049599] df80: 00000003 c00189fc ffffffff c7301040 00c5387d c0009080 b3d9a4e0 80000010
[18610.049634] dfa0: ffffffff c7301040 00c5387d c0008f94 00000000 01980ca3 00004747 0197fa9a
[18610.049668] dfc0: ae7d4010 019416e0 000000f3 00000000 00003600 00000000 be9adb20 00000003
[18610.049702] dfe0: abacadab be9ab1d8 b63d99d8 b3d9a4e0 80000010 ffffffff 00000000 00000000
[18610.049745] handle_mm_fault from do_page_fault+0x138/0x3a8
[18610.049829] do_page_fault from do_DataAbort+0x40/0xb4
[18610.049890] do_DataAbort from __dabt_usr+0x54/0x60
[18610.049935] Exception stack(0xdcafdfb0 to 0xdcafdff8)
[18610.049966] dfa0: 00000000 01980ca3 00004747 0197fa9a
[18610.050002] dfc0: ae7d4010 019416e0 000000f3 00000000 00003600 00000000 be9adb20 00000003
[18610.050036] dfe0: abacadab be9ab1d8 b63d99d8 b3d9a4e0 80000010 ffffffff
[18610.050069] Code: 73c5cb76 68737213 70f86db3 5fe469a4 (f6c517fa)
[18610.050098] ---[ end trace 0000000000000000 ]---
[18610.050120] note: convert[4973] exited with irqs disabled
Using a PiCam v3, autofocus, a ublox 7 series USB GPS, and a RFM98W running 17 dBm output power. Also connected via Wifi.
Pi Zero W 2:
- Idle: 5V, avg 200mA
- Transmitting: 5V, avg load 500mA, peaking 700ma
20 min transmit time energy: 5V, 147 mAh start CPU temp: 40 stop CPU temp: 55 avg image encode time is 0.56s 32 complete images received. Radio Temp: 35.0, CPU Temp: 54.2, CPU Speed: 700, Load Avg: 0.96, 0.88, 0.65,
Pi Zero W:
- Idle: 5V, avg 200mA
- Transmitting: 5V, 430mA avg, peaking 570mA Radio Temp: 14.0, CPU Temp: 48.7, CPU Speed: 700, Load Avg: 3.11, 2.07, 1.06 (weird radio temp report, don't trust this) Noting considerably longer time between packets, lots of dead time with no images sent.
20 min transmit time energy: 5V, 133 mAh start CPU temp: 42.2 stop CPU temp: 52-53 avg image encode time is 4.3s 6 complete images received.