Wifibroadcast is a project aimed at the live transmission of HD video (and other) data using wifi radios. One prominent use case is to transmit camera images for a first person view (FPV) of remote controlled aircrafts.
In contrast to a normal wifi connection wifibroadcast tries to mimic the advantageous properties of an analog link (like graceful signal degradation, unidirectional data flow, no association between devices).
Wifibroadcast puts the wifi cards into monitor mode. This mode allows to send and receive arbitrary packets without association. Additionally, it is also possible to receive erroneous frames (where the checksum does not match). This way a true unidirectional connection is established which mimics the advantageous properties of an analog link.
Wifibroadcast is included in the latest EMLID Raspberry Pi beta image for NAVIO+ and NAVIO2, which is great because now one may use one RPi’s untapped processing power to get video from the camera and transmit it on the fly, while running Ardupilot or PX4 on the same unit.
Enabling and disabling WBC can be done via ssh as demonstrated in the docs, but this quickly gets frustrating when in the field. Instead, it would be much simpler to be able to control video transmission via a spare RC switch on the Radio Transmitter. With Ardupilot running and PyMavlink it is easy to write a Python script that controls WBC. The folks at EMLID have introduced WBC as a
systemd service, thus interfacing with
systemctl from python is enough to do the job. According to this Stackoverflow question, there is an easy way to interface with systemd, using the DBus API, and this is what we will be using. Below are the steps I used to achieve this.
First, we need to configure Ardupilot to output telemetry locally via UDP:
Ardupilot -A -C
This will enable us to communicate with Ardupilot easily from within the RPi. Then, we are going to need to have the PyMAVLink library installed. This library enables a Python script to send and receive MAVLink messages. You can install PyMAVLink using pip as follows:
pip install pymavlink
As a next step comes the actual script that listen for RC related MAV messages and runs our shell commands:
import os, signal, time, dbus, argparse
from pymavlink import mavutil
video_enabled = False
sysbus = dbus.SystemBus()
self.systemd1 = self.sysbus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1')
manager = dbus.Interface(self.systemd1, 'org.freedesktop.systemd1.Manager')
parser = argparse.ArgumentParser(description='Simple example how to interact with RC channels.')
parser.add_argument('--connect', help="vehicle connection target string.")
parser.add_argument("--rate", default=4, type=int, help="requested stream rate")
args = parser.parse_args()
connection_string = args.connect
print("\nConnecting to vehicle on: %s" % connection_string)
# create a mavlink serial instance
master = mavutil.mavlink_connection(connection_string)
# wait for the heartbeat msg to find the system ID
print("Sending all stream request for rate %u" % args.rate)
for i in range(0, 3):
mavutil.mavlink.MAV_DATA_STREAM_ALL, args.rate, 1)
'''wait for a heartbeat so we know the target system IDs'''
print("Waiting for APM heartbeat")
print("Heartbeat from APM (system %u component %u)" % (m.target_system, m.target_system))
'''process mav data'''
msg = m.recv_match(type=['RC_CHANNELS'], blocking=True)
if not msg:
if msg.get_type() == "BAD_DATA":
value = msg.chan8_raw # channel 8. Change this to your liking
if value > 1500 and video_enabled == False:
video_enabled = True
print "Starting Video Stream"
elif value <= 1500 and video_enabled == True:
video_enabled = False
print "Stopping Video Stream"
if __name__ == "__main__":
The script is configured to listen to RC channel 8, so if you need to listen to a different chennel, you’ll need to change that. Also, the threshold for detecting a value change is 1500, which is somewhere around the middle of a servo value. Again, change this if required.
Finally, we will need to let the OS know that we want the script to run at startup. While we may do this easily by altering
/etc/rc.local, a cleaner alternative is to introduce a new service. This is easily done by creating a new file with extension
/lib/systemd/system/ . I chose to name it “wbcrcs”, for Wifibroadcast RC Switch1:
sudo nano /lib/systemd/system/wbcrcs.service
And add the following:
Description=WBC RC Switch
Finally, you’ll need to enable the service:
sudo systemctl daemon-reload
sudo systemctl enable wbcrcs.service
Reboot the Pi and your custom service should run :
sudo systemctl daemon-reload
In this post we implemented a simple way to enable and disable Wifibroadcast video transmission through the use of an RC Switch. If successfully configured, our script will run as a service, and be available at boot time. This is convenient to allow configuration through WiFi and later on switching on video transmission when in the field.
Why not Dronekit?
There was a post sometime back in the EMLID forums where George Staroselskiy had demonstrated the same type of control using Dronekit. But using Dronekit alone raised the CPU usage on a RPi2 to around 20%. With the MAVLink-based solution presented in this post, the CPU usage floats around 2%. Still too much for a simple RC switch listener, but acceptable.