I was using my Gumstix Verdex to control an iRobot Create with the ever handy Element Sticky board when I encountered a serious problem. The network setup around here has a ton of access points with the same SSID. When you move throughout the network, most sane wireless hardware does what is called a “handover.” The wireless adapter detects that the signal to the current access point is weak, and then scans and reassociates with a stronger AP. The process isn’t always seamless, but it happens. Apparently, the Marvell 88W8385 (the wireless module used by the Verdex) has no such support in its driver/hardware. So as the Create trundles along, the wifi signal just keeps getting weaker, until it starts dropping out. As another wonderful feature of the driver, when the wifi signal has dropped out, the module refuses to execute any commands. That’s right, you can’t even ifdown wlan0 to reset/reassociate the stupid thing. If you try, you get a helpful: NETDEV WATCHDOG: wlan0: transmit timed out.
What’s a roboticist to do? Well, obviously, create a software hack that forces the gumstix to reassociate when its signal strength to the current AP gets low!
At first, this seemed to be a little tricky, as it is kind of a pain to deal with the parsing minutia necessary to figure out which access point is the best. Luckily, Gumstix/OpenEmbedded has a solution, in the form of wpa_supplicant. This little daemon is designed to allow connections to WPA-enabled networks, which is not useful, except for a nifty little hidden feature: it automatically re-associates with the best AP if the hardware “happens” to do a scan. Well, we can force that using iwlist wlan0 scan!
So, the solution is twofold:
- Write a background script that measures RSSI and runs iwlist when signal gets weak.
- Configure wlan0 to use wpa_supplicant on the Verdex.
The first part isn’t too bad. We need to write a script that loops, checking the RSSI of the current AP, and starts scanning only when the RSSI gets low. Using copious amounts of text hackery, I wrote the following script to do exactly that:
#!/bin/sh
echo STARTING SCAN-O-MATIC
while [ 1 ]
do
RSSI=`iwconfig wlan0 | grep Signal | awk '{print $4}' | cut -d ":" -f 2`
if [ ${RSSI} -lt "-60" ]
then
iwlist wlan0 scan > /dev/null
sleep 5
else
sleep 2
fi
done
For convenience later on, I saved this script as /etc/wpa_supplicant/scan.sh. With that done, the next step isn’t too tricky either. wpa_supplicant ships with the gumstix-basic-image, so as long as you are using that, you probably already have wpa_supplicant. To get it to run with wireless (wlan0), you just have to change a couple of config settings. Create the file /etc/wpa_supplicant.conf. This file will contain the configurations for the networks you want wpa_supplicant to try to join. Since I only have one network, mine looks like this:
ap_scan=1
fast_reauth=1
network={
ssid="FOOBAR"
key_mgmt=NONE
}
If you have weirder settings, just look up the docs for wpa_supplicant. Note the ap_scan=1. I think that is important for ensuring that wpa_supplicant will reassociate networks when you scan. Next, we just have to tell the Gumstix that we want to use this stuff when we activate wlan0. So, we put the following into /etc/network/interfaces:
auto wlan0
iface wlan0 inet dhcp
pre-up wpa_supplicant -Dmarvell -iwlan0 -c/etc/wpa_supplicant.conf -Bw
up /etc/wpa_supplicant/scan.sh &
down ps | grep scan.sh | grep -v grep | xargs kill `awk '{print $1}'`
down killall wpa_supplicant
This should look very similar to the WPA example that gumstix provides. However, you can see that we also start our scanning script in the background, and kill it when the interface goes down. Make sure you comment out any other iface block for wlan0, as having multiple definitions will screw things up.
Now, just reup the interface and voila, wpa_supplicant will come up and associate to the best access point. If the RSSI drops below our threshold (-60dB in the above), then our scan script will run, and wpa_supplicant will use the results to associate to a better access point. It seems to work fine for running around pretty dense wireless network areas, with about a 3 second delay every time it actually tries to switch networks. So have fun and let your robots run free!