This weeks Monday post is a guest post written by Wolfgang Hoenig from University of Southern California.
What’s better than a single Crazyflie? A swarm of them! Our research group at the University of Southern California is the Automatic Coordination of Teams (ACT lab), and we research collaborative problem-solving with multiple robots. The Crazyflie is a great platform for research because of its openness and extensibility; additionally, the size allows us to test algorithms on a swarm of robots even in space-limited indoor environments.
After obtaining 6 Crazyflie 2.0 quadcopters and 1 Crazyflie 1.0 for our lab, we started looking into how to fly them at the same time — a basic requirement for any swarm experiments. The official Bitcraze GUI can only connect to a single Crazyflie at a time, although the underlying library comes with basic MultiFlie support. In particular, there is an URI (Uniform Resource Identifier), which has the following format if you connect using the Crazyradio: “radio://<radioIndex>/<channel>/<datarate>”. Here, radioIndex is a number starting from 0 for each attached Crazyradio, the channel is a number between 0 and 125 describing the frequency, and datarate is either 250K, 1M, or 2M. The obvious solution is to just buy one Crazyradio per Crazyflie and use separate radio indices in the URI. To avoid any form of interference, different channels need to be chosen as well. This approach has two drawbacks:
- The number of Crazyradios increases pretty fast, and using 7 radios for 7 Crazyflies definitely becomes unwieldy.
- The 2.4 GHz band becomes occupied – finding enough free frequency bands might not be easy if there are many other networks, such as Wifi or BlueTooth, around.
Bitcraze addressed the first issue a long time ago, by allowing to use a single radio for multiple Crazyflies. This approach uses PC-sided timeslicing: The radio sends a packet to the first flie and waits for an acknowledgment. Afterwards it switches the channel to the next one, and so on. The higher level requests are stored in a queue in Python, with a separate thread for each radio working on the queue. The code lived in its own branch and wasn’t updated for a while, but merging this branch with the master branch was fairly easy. There were a bunch of race conditions in the code, but most of them are hopefully fixed in my branch.
The second issue can only be solved by extending the URI itself by another unique number.
Luckily, the underlying communication protocol (Enhanced ShockBurst) by Nordic Semiconductor does have a notion of addresses. The address can be up to 5 bytes long and was simply set to 0xE7E7E7E7E7 for each Crazyflie. Making this number configurable is easy, but touches many different places in the code. It was implemented specifically for the Crazyflie 2.0, so the following discusses how it works:
- NRF-Firmware: This firmware runs on the NRF51, the chip which manages the power and integrates the radio. The address can be set in here, but where should we get the value from? I simply mimicked the code for setting the channel, as this was already a feature of the firmware.
In this case, the data comes from the syslink interface, which is a simple serial connection between the NRF51 and the STM32, the second microcontroller which runs the control algorithm.
- STM32-Firmware: This firmware has access to an EEPROM, which is able to store configuration data permanently, even during power loss. That EEPROM currently stores trim values for roll and pitch, channel, and datarate. Adding another field for the address was easy — Bitcraze even already had a version field and checksum which improves the behavior if the firmware is updated.
- Python Client: The Python client required three changes:
- Adding another configuration option field to allow a 5 byte device address. I basically copied the code for handling the channel again, plus did some additional UI work to allow a user to input hexadecimal numbers.
- Updating the URI to “radio://<radioIndex>/<channel>/<datarate>/<address>”, where address is a 5-Byte hexadecimal number. For compatibility, the following URIs are equivalent: “radio://0/80/250K” and “radio://0/80/250K/0xE7E7E7E7E7”. This allows all existing code to work exactly like before.
- Adding an input field in the connect dialog to select an address. Scanning over all possible addresses isn’t feasible: There are 2^40 different possibilities!
What does this mean in practice? That it’s now possible to control 6 Crazyflies just with 3 radios.
All these changes are already part of the official repositories; however, you’ll need the multi_radio branch to use multiple flies per radio.
And there’s even more to look forward to: An improved firmware of the Crazyradio could greatly improve the performance of the timeslicing and thus allow us to control more flies with fewer radios. Luckily, Bitcraze has already started working on it.
If you’re a researcher and use ROS, you can use our ROS driver to create your own CrazySwarm. It supports Crazyflie 1.0, Crazyflie 2.0, and the Multi-Radio and Multi-Addressing described above. It even comes with a controller to use with a motion capture system!
Have fun flieing!
Wolfgang Hoenig
PhD Student
Automatic Coordination of Teams Laboratory
University of Southern California