Raspberry Pi 3 WiFi FPV Drone Bridge
I recently got a cheap WiFi FPV drone. Specifically the Visuo XS809HW. I can’t legally use it past line of site in the U.S., but I thought it’d be cool to take a shot at boosting the WiFi range. Initially I installed an external antenna which on its own will probably take the little thing out of my line of site, but I really wanted to take it a step further.
There are a couple cheap WiFi repeaters that can be used with pretty good results and I did buy one of them, but I really wanted to get it repeating from my 1000mw alfa with a nice 9dbi antenna to really be able to drive it out. On top of that I wanted to be able to easily take pcaps of the traffic so I can maybe work on reversing the protocols to get FPV and control native on the Pi.
Well I got it working with mixed results, but be warned, what follows isn’t exactly kosher networking. It’s not something I’d advise implementing on a real network, or for that matter, on a drone you’re not willing to see crash and burn.
The control latency is pretty good, but the FPV is pretty lossy with a full 1-2 second lag. In the future I’m likely to try a DDWRT repeater, and I’m considering working an angle to get my rtl8187 supported on LineageOS on my Pi via a custom kernel build or chrooted nix so I can run the XSW UFO app natively with the high power card and high gain antenna. Thats for a later day though, so lets begin with what we’ve got now.
Everything beginning with “pi#” is to be run on the Pi’s shell. Boxes following “CONFIG:” are inside a config file.
Starting with a fresh install of Raspbian Stretch lite install all updates and the requisite softwares. I use vim so if you like another editor then use that. Unless it’s emacs then you can just go suck an egg. 😛 If you’re not a nix nerd then you should probably use the nano editor instead of vim.
pi# sudo apt update && sudo apt full-upgrade pi# sudo apt install vim dnsmasq hostapd parprouted avahi-daemon
Generate network interface names based on their mac addresses. This way even if one wireless card is brought up before the other during boot the config files wont need to be changed because the cards swapped the wlan0 and wlan1 names.
pi# sudo rm /etc/systemd/network/99-default.link pi# sudo vim /etc/systemd/network/99-default.link
CONFIG:
[Link] NamePolicy=kernel database onboard slot path mac MACAddressPolicy=persistent
Reboot the Pi.
pi# sudo reboot
After the device reboots ensure both of your WiFi devices are plugged in and run.
pi# ifconfig
You should see something similar to the following picture. The device names beginning with wlx are what you want to take note of. These are the names with which we will be addressing the WiFi cards in the following config files. If you’re unsure which card is which then just unplug one of them and run ifconfig again. The one that is still plugged in shows up. For the rest of this tutorial I will refer to the wired NIC as enx0 the card connecting to the drone as wlx0 and the card broadcasting the local network as wlx1, but you will need to use your device names.
Edit your /etc/network/interfaces file to reflect the following. I just delete everything in there and use the following config. If your drone broadcasts a secured network then see this link and make changes as appropriate. Adafruit WiFi Connection
pi# sudo vim /etc/network/interfaces
CONFIG:
auto lo iface lo inet loopback auto enx0 iface enx0 inet dhcp auto wlx0 allow-hotplug wlx0 iface wlx0 inet dhcp wireless-essid Your-Drones-essid-Here post-up parprouted wlx1 wlx0 post-up ip addr add $(/sbin/ip addr show wlx0 | perl -wne 'm|^\s+inet (.*)/| && print $1')/32 dev wlx1 post-down pkill -9 parprouted post-down sudo ip addr flush dev wlx0 post-down sudo ip addr flush dev wlx1 auto wlx1 allow-hotplug wlx1 iface wlx1 inet manual
Set some iptables rules to set up NAT and allow multicast and broadcast forwarding. If someone who knows iptables a bit better can double check this I’d be grateful.
pi# sudo vim /etc/iptables.ipv4.nat
CONFIG:
*filter :INPUT ACCEPT [5:388] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [3:392] -A FORWARD -m pkttype --pkt-type multicast -j ACCEPT -A FORWARD -m pkttype --pkt-type broadcast -j ACCEPT -A FORWARD -i wlx1 -o wlx0 -j ACCEPT -A FORWARD -i wlx0 -o wlx1 -j ACCEPT COMMIT *nat :PREROUTING ACCEPT [0:0] :INPUT ACCEPT [0:0] :OUTPUT ACCEPT [1:160] :POSTROUTING ACCEPT [1:160] -A POSTROUTING -o wlx1 -j MASQUERADE COMMIT
Set up the dnsmasq.conf for the dhcp server. This bit is not exactly kosher. We’re starting a second dhcp server on the same subnet. This makes me cringe, but its listening on a different interface, there should never be more than a couple hosts on this machine at any time, and the ip range is well away from where the drone’s ip lease range starts. If someone out there can get dhcp-helper working reliably then that would be a much better solution.
pi# sudo vim /etc/dnsmasq.conf
CONFIG:
interface=wlx1 listen-address=192.168.0.2 bind-interfaces server=192.168.0.1 domain-needed bogus-priv dhcp-range=192.168.0.100,192.168.0.150,4h
Edit rc.local so we start dnsmasq on boot and load in our iptables rules. Add the following lines just above the line “exit 0”
pi# sudo vim /etc/rc.local
CONFIG:
iptables-restore < /etc/iptables.ipv4.nat service dnsmasq start
Now we will enable ipv4 forwarding. Go into the sysctl.conf file, find and uncomment or add the following line to the file.
pi# sudo vim /etc/sysctl.conf
CONFIG:
net.ipv4.ip_forward=1
Next we will set up hostapd to manage the local repeated WiFi access point. I’m boring, but you can change the values below to make your access point something more fun.
pi# sudo vim /etc/hostapd/hostapd.conf
CONFIG:
interface=wlx1 driver=nl80211 hw_mode=g channel=6 ieee80211n=1 wmm_enabled=1 ht_capab=[HT40][SHORT-GI-20][DSSS_CCK-40] macaddr_acl=0 ignore_broadcast_ssid=0 auth_algs=1 wpa=2 wpa_key_mgmt=WPA-PSK rsn_pairwise=CCMP ssid=PiBridge wpa_passphrase=PassPhrase
Now we need to make sure that this hostapd file is actually getting loaded when hostapd starts. Modify the following /defaults/ file to match this.
pi# sudo vim /etc/defaults/hostapd
CONFIG:
DAEMON_CONF="/etc/hostapd/hostapd.conf"
Now we’re going to set up the avahi daemon. We need to enable mDNS relaying here. Do so by uncommenting the following line and ensuring it mirrors this.
pi# sudo vim /etc/avahi/avahi-daemon.conf
CONFIG:
enable-reflector=yes
Next make sure you’re in your /home/ and create a little script to reconnect your Pi to your drone whenever you inevitably change the battery. Then make it executable.
pi# cd ~ pi# vim ~/DroneConn.sh
CONFIG:
#!/usr/bin/env bash sudo ifdown wlx0 sleep 2 sudo ifup wlx0
pi# sudo chmod +x DroneConn.sh
Finally disable unwanted services, enable the services you want to run at boot, reboot everything, and cross your fingers. I find that some times things fall over, but if I’ve got the drone on to hand out an I.P. to wlx0 then the Pi boots fine.
pi# sudo systemctl disable dhcpcd.service pi# sudo systemctl enable hostapd.service pi# sudo systemctl enable dnsmasq.service pi# sudo reboot
Finally I want to shout out to the resources I used to piece this together.
Surfer Tim on the RasPi forums
This pimylifeup.com guide
The Debian Wiki
This Adafruit Tutorial
Questions, Comments, Suggestions? Let me know. I’m open to all of it.