To receive notifications about scheduled maintenance, please subscribe to the mailing-list gitlab-operations@sympa.ethz.ch. You can subscribe to the mailing-list at https://sympa.ethz.ch

Commit 04e96bb6 authored by beuchatp's avatar beuchatp

Upgrade the crazyradio cflib to release 0.1.10 (13 Mar 2020) from the...

Upgrade the crazyradio cflib to release 0.1.10 (13 Mar 2020) from the crazyflie-lib-python repository on the bitcraze github
parent 1904ec99
Contribution guide
==================
👍🎉 Thanks a lot for considering contributing 🎉👍
We welcome and encourage contribution. There is many way to contribute: you can
write bug report, contribute code or documentation.
You can also go to the [bitcraze forum](https://forum.bitcraze.io) and help others.
## Reporting issues
When reporting issues the more information you can supply the better.
Since the lib runs on many different OSes, can connect to multiple versions of the Crazyflie and you could use our official releases or clone directly from Git, it can be hard to figure out what's happening.
- **Information about the environment:**
- What OS are your running on
- What version of Python are you using
- If relevant, what version of the Crazyflie firmware are you using
- **How to reproduce the issue:** Step-by-step guide on how the issue can be reproduced (or at least how you reproduce it).
Include everything you think might be useful, the more information the better.
## Improvements request and proposal
We and the community are continuously working to improve the lib.
Feel free to make an issue to request a new functionality.
## Contributing code/Pull-Request
We welcome code contribution, this can be done by starting a pull-request.
If the change is big, typically if the change span to more than one file, consider starting an issue first to discuss the improvement.
This will makes it much easier to make the change fit well into the lib.
There is some basic requirement for us to merge a pull request:
- Describe the change
- Refer to any issues it effects
- Separate one pull request per functionality: if you start writing "and" in the feature description consider if it could be separated in two pull requests.
- The pull request must pass the automated test (see test section bellow)
In your code:
- Don't include name, date or information about the change in the code. That's what Git is for.
- CamelCase classes, but not functions and variables
- Private variables and functions should start with _
- 4 spaces indentation
- When catching exceptions try to make it as specific as possible, it makes it harder for bugs to hide
- Short variable and function names are OK if the scope is small
- The code should pass flake8
### Run test
In order to run the tests you can run:
```
python tools/build/build
python3 tools/build/build
```
......@@ -45,7 +45,7 @@ from std_msgs.msg import Int32
from dfall_pkg.msg import ControlCommand
from dfall_pkg.msg import IntWithHeader
from dfall_pkg.msg import FlyingVehicleState
from dfall_pkg.msg import GyroMeasurements
#from dfall_pkg.msg import GyroMeasurements
# Import dfall_pkg services
from dfall_pkg.srv import IntIntService
......@@ -287,9 +287,9 @@ class CrazyRadioClient:
cfStateEstimate.pitch = -data["stateEstimateZ.pitch"] / 1000.0
cfStateEstimate.yaw = data["stateEstimateZ.yaw"] / 1000.0
# > (roll,pitch,yaw) anglular rates (direct from gryo)
cfStateEstimate.rollRate = data["stateEstimateZ.rateRoll"] / 1000.0
cfStateEstimate.pitchRate = -data["stateEstimateZ.ratePitch"] / 1000.0
cfStateEstimate.yawRate = data["stateEstimateZ.rateYaw"] / 1000.0
#cfStateEstimate.rollRate = data["stateEstimateZ.rateRoll"] / 1000.0
#cfStateEstimate.pitchRate = -data["stateEstimateZ.ratePitch"] / 1000.0
#cfStateEstimate.yawRate = data["stateEstimateZ.rateYaw"] / 1000.0
# Print out one value for DEBUGGING
#print "[CRAZY RADIO] received (z,vz) = ( %6.3f , %6.3f )" %( cfStateEstimate.z , cfStateEstimate.vz )
......@@ -310,23 +310,23 @@ class CrazyRadioClient:
# Initialise the variable for the gyroscope data
gyroMeasurements = GyroMeasurements()
# # Initialise the variable for the gyroscope data
# gyroMeasurements = GyroMeasurements()
# Retrieve the values from the data packet received
# > (roll,pitch,yaw) anglular rates (direct from gryo)
gyroMeasurements.rollrate = data["stateEstimateZ.rateRoll"] / 1000.0
gyroMeasurements.pitchrate = -data["stateEstimateZ.ratePitch"] / 1000.0
gyroMeasurements.yawrate = data["stateEstimateZ.rateYaw"] / 1000.0
# # Retrieve the values from the data packet received
# # > (roll,pitch,yaw) anglular rates (direct from gryo)
# gyroMeasurements.rollrate = data["stateEstimateZ.rateRoll"] / 1000.0
# gyroMeasurements.pitchrate = -data["stateEstimateZ.ratePitch"] / 1000.0
# gyroMeasurements.yawrate = data["stateEstimateZ.rateYaw"] / 1000.0
# Fill in the name
gyroMeasurements.vehicleName = self.crazyflie_name
# # Fill in the name
# gyroMeasurements.vehicleName = self.crazyflie_name
# Print out one value for DEBUGGING
#print "[CRAZY RADIO] gyro (r,p,y) = ( %6.3f , %6.3f , %6.3f )" %( gyroMeasurements.rollrate*RAD_TO_DEG , gyroMeasurements.pitchrate*RAD_TO_DEG , gyroMeasurements.yawrate*RAD_TO_DEG )
# # Print out one value for DEBUGGING
# #print "[CRAZY RADIO] gyro (r,p,y) = ( %6.3f , %6.3f , %6.3f )" %( gyroMeasurements.rollrate*RAD_TO_DEG , gyroMeasurements.pitchrate*RAD_TO_DEG , gyroMeasurements.yawrate*RAD_TO_DEG )
# Publish the gyroscope measurements
cfgyroMeasurements_pub.publish(gyroMeasurements)
# # Publish the gyroscope measurements
# cfgyroMeasurements_pub.publish(gyroMeasurements)
......@@ -337,20 +337,38 @@ class CrazyRadioClient:
def _start_logging(self):
# NOTE: that logging can only be started when
# connected to a Crazyflie is becuse "add_config(...)"
# function check that the variables requested are
# available in the onboard TOC (table of contents).
# A "LOGGING GROUP" FOR THE BATTERY VOLTAGE:
# Initialise a log config object
self.logconf_battery = LogConfig("LoggingBattery", period_in_ms=battery_polling_period)
# Add the varaibles to be logged
self.logconf_battery.add_variable("pm.vbat", "float");
# Add the log config to the crazyflie object
self._cf.log.add_config(self.logconf_battery)
if self.logconf_battery.valid:
#
# Try to add the log config to the crazyflie object
try:
self._cf.log.add_config(self.logconf_battery)
# Add the callback for received data
self.logconf_battery.data_received_cb.add_callback(self._data_received_battery_callback)
# Add the callback for errors
self.logconf_battery.error_cb.add_callback(self._logging_error)
print "[CRAZY RADIO] The log config for the battery voltage is valid"
else:
print "[CRAZY RADIO] The log config for the battery voltage is invalid"
# Check the log config is valid
if self.logconf_battery.valid:
# Start the logging
self.logconf_battery.start()
rospy.loginfo("[CRAZY RADIO] Started the log config for the battery voltage")
else:
rospy.loginfo("[CRAZY RADIO] The log config for the battery voltage is invalid, hence logging has not been started.")
# Handle "key error" exceptions:
except KeyError as e:
rospy.logerr("[CRAZY RADIO] For the battery voltage, the following error occurred while trying to add the log config: %s" % str(e) )
# Handle "attribution error" exceptions:
except AttributeError:
rospy.logerr("[CRAZY RADIO] The battery voltage log config has a bad configuration.")
# A "LOGGING GROUP" FOR THE STATE ESTIMATE:
......@@ -374,26 +392,30 @@ class CrazyRadioClient:
self.logconf_stateEstimate.add_variable("stateEstimateZ.pitch", "int16_t");
self.logconf_stateEstimate.add_variable("stateEstimateZ.yaw", "int16_t");
# > (roll,pitch,yaw) anglular rates (direct from gryo)
self.logconf_stateEstimate.add_variable("stateEstimateZ.rateRoll", "int16_t");
self.logconf_stateEstimate.add_variable("stateEstimateZ.ratePitch", "int16_t");
self.logconf_stateEstimate.add_variable("stateEstimateZ.rateYaw", "int16_t");
# Add the log config to the crazyflie object
self._cf.log.add_config(self.logconf_stateEstimate)
if self.logconf_stateEstimate.valid:
#self.logconf_stateEstimate.add_variable("stateEstimateZ.rateRoll", "int16_t");
#self.logconf_stateEstimate.add_variable("stateEstimateZ.ratePitch", "int16_t");
#self.logconf_stateEstimate.add_variable("stateEstimateZ.rateYaw", "int16_t");
#
# Try to add the log config to the crazyflie object
try:
self._cf.log.add_config(self.logconf_stateEstimate)
# Add the callback for received data
self.logconf_stateEstimate.data_received_cb.add_callback(self._data_received_stateEstimate_callback)
# Add the callback for errors
self.logconf_stateEstimate.error_cb.add_callback(self._logging_error)
print "[CRAZY RADIO] The log config for the state estimate is valid"
else:
print "[CRAZY RADIO] The log config for the state estimate is invalid"
# START THE LOGGING FOR ALL THE "LOGGING GROUPS" ADDED
# > For the battery voltage
self.logconf_battery.start()
print "[CRAZY RADIO] Started the log config for the battery voltage"
# > For the state estimate
self.logconf_stateEstimate.start()
print "[CRAZY RADIO] Started the log config for the state estimate"
# Check the log config is valid
if self.logconf_stateEstimate.valid:
# Start the logging
self.logconf_stateEstimate.start()
rospy.loginfo("[CRAZY RADIO] Started the log config for the state estimate")
else:
rospy.loginfo("[CRAZY RADIO] The log config for the state estimate is invalid, hence logging has not been started.")
# Handle "key error" exceptions:
except KeyError as e:
rospy.logerr("[CRAZY RADIO] For the state estimate, the following error occurred while trying to add the log config: %s" % str(e) )
# Handle "attribution error" exceptions:
except AttributeError:
rospy.logerr("[CRAZY RADIO] The state estimate log config has a bad configuration.")
......@@ -605,7 +627,7 @@ class CrazyRadioClient:
):
# Call the CrazyRadio function that sets the
# paramter for reseting the onboard estimate
self._cf.param.set_value("kalman.resetEstimation", "1")
self._cf.param.set_value("kalman.resetEstimation", 1)
# Inform the user
#print "[CRAZY RADIO] reqested the Crazyflie to reset the onboard estimate"
......
......@@ -13,26 +13,37 @@ For more info see our [wiki](http://wiki.bitcraze.se/ "Bitcraze Wiki").
* [Fork the cflib](https://help.github.com/articles/fork-a-repo/)
* [Clone the cflib](https://help.github.com/articles/cloning-a-repository/), `git clone git@github.com:YOUR-USERNAME/crazyflie-lib-python.git`
* [Install the cflib in editable mode](http://pip-python3.readthedocs.org/en/latest/reference/pip_install.html?highlight=editable#editable-installs), `pip install -e path/to/cflib`
* [Uninstall the cflib](http://pip-python3.readthedocs.org/en/latest/reference/pip_uninstall.html), `pip uninstall cflib`
Note: If you are developing for the [cfclient][cfclient] you must use python3.
* [Uninstall the cflib if you don't want it any more](http://pip-python3.readthedocs.org/en/latest/reference/pip_uninstall.html), `pip uninstall cflib`
Note: If you are developing for the [cfclient][cfclient] you must use python3. On Ubuntu (16.04, 18.08) use `pip3` instead of `pip`.
### Linux, OSX, Windows
* Build a [virtualenv (local python environment)](https://virtualenv.pypa.io/en/latest/) with package dependencies
* `pip install virtualenv`
* `virtualenv venv`
* `source venv/bin/activate`
* `pip install -r requirements.txt`
The following should be executed in the root of the crazyflie-lib-python file tree.
#### Virtualenv
This section contains a very short description of how to use [virtualenv (local python environment)](https://virtualenv.pypa.io/en/latest/)
with package dependencies. If you don't want to use virualenv and don't mind installing cflib dependencies system-wide
you can skip this section.
* Install virtualenv: `pip install virtualenv`
* create an environment: `virtualenv venv`
* Activate the environment: `source venv/bin/activate`
* Connect the crazyflie and run an example: `python -m examples.basiclog`
* Deactivate the virtualenv if you activated it `deactivate`
Note: For systems that support [make](https://www.gnu.org/software/make/manual/html_node/Simple-Makefile.html), the first four steps can be replaced with `make venv`
Note: The first three steps can be skipped if you don't mind installing cflib dependencies system-wide.
* To deactivate the virtualenv when you are done using it `deactivate`
Note: For systems that support [make](https://www.gnu.org/software/make/manual/html_node/Simple-Makefile.html), you can use `make venv` to
create an environment, activate it and install dependencies.
#### Install cflib dependencies
Install dependencies required by the lib: `pip install -r requirements.txt`
# Testing
To verify the installation, connect the crazyflie and run an example: `python examples/basiclog`
## Testing
### With docker and the toolbelt
For information and installation of the
......@@ -45,9 +56,12 @@ Note: Docker and the toolbelt is an optional way of running tests and reduces th
work needed to maintain your python environmet.
### Native python on Linux, OSX, Windows
* [Tox](http://tox.readthedocs.org/en/latest/) is used for native testing: `pip install tox`
[Tox](http://tox.readthedocs.org/en/latest/) is used for native testing: `pip install tox`
* If test fails after installing tox with `pip install tox`, installing with `sudo apt-get install tox`result a successful test run
* Test package in python2.7 `TOXENV=py27 tox`
* Test package in python3.4 `TOXENV=py34 tox`
* Test package in python3.6 `TOXENV=py36 tox`
Note: You must have the specific python versions on your machine or tests will fail. (ie. without specifying the TOXENV, `tox` runs tests for python2.7, 3.3, 3.4 and would require all python versions to be installed on the machine.)
......@@ -62,13 +76,18 @@ The following steps make it possible to use the USB Radio without being root.
```
sudo groupadd plugdev
sudo usermod -a -G plugdev <username>
sudo usermod -a -G plugdev $USER
```
You will need to log out and log in again in order to be a member of the plugdev group.
Create a file named ```/etc/udev/rules.d/99-crazyradio.rules``` and add the
following:
```
# Crazyradio (normal operation)
SUBSYSTEM=="usb", ATTRS{idVendor}=="1915", ATTRS{idProduct}=="7777", MODE="0664", GROUP="plugdev"
# Bootloader
SUBSYSTEM=="usb", ATTRS{idVendor}=="1915", ATTRS{idProduct}=="0101", MODE="0664", GROUP="plugdev"
```
To connect Crazyflie 2.0 via usb, create a file name ```/etc/udev/rules.d/99-crazyflie.rules``` and add the following:
......@@ -76,6 +95,12 @@ To connect Crazyflie 2.0 via usb, create a file name ```/etc/udev/rules.d/99-cra
SUBSYSTEM=="usb", ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE="0664", GROUP="plugdev"
```
You can reload the udev-rules using the following:
```
sudo udevadm control --reload-rules
sudo udevadm trigger
```
[cfclient]: https://www.github.com/bitcraze/crazyflie-clients-python
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# import roslib; roslib.load_manifest('dfall_pkg')
# import rospy
# from dfall_pkg.msg import ControlCommand
# from std_msgs.msg import Int32
# General import
import time, sys
import struct
import logging
# import rosbag
# from rospkg import RosPack
from std_msgs.msg import Float32
# from std_msgs.msg import String
# Add library
#sys.path.append("lib")
# CrazyFlie client imports
import cflib
from cflib.crazyflie import Crazyflie
from cflib.crtp.crtpstack import CRTPPacket, CRTPPort
import cflib.drivers.crazyradio
# Logging import(*
from cflib.crazyflie.log import LogConfig
# Logging settings
logging.basicConfig(level=logging.ERROR)
# Types:
CF_COMMAND_TYPE_MOTORS = 6
CF_COMMAND_TYPE_RATE = 7
CF_COMMAND_TYPE_ANGLE = 8
CONTROLLER_MOTOR = 2
CONTROLLER_ANGLE = 1
CONTROLLER_RATE = 0
RAD_TO_DEG = 57.296
# CrazyRadio states:
CONNECTED = 0
CONNECTING = 1
DISCONNECTED = 2
# Commands coming
CMD_RECONNECT = 0
CMD_DISCONNECT = 1
# rp = RosPack()
# record_file = rp.get_path('dfall_pkg') + '/LoggingOnboard.bag'
# rospy.loginfo('afdsasdfasdfsadfasdfasdfasdfasdfasdfasdf')
# rospy.loginfo(record_file)
# bag = rosbag.Bag(record_file, 'w')
class CrazyRadioClient:
"""
CrazyRadio client that recieves the commands from the controller and
sends them in a CRTP package to the crazyflie with the specified
address.
"""
def __init__(self):
# Setpoints to be sent to the CrazyFlie
self.roll = 0.0
self.pitch = 0.0
self.yaw = 0.0
self.motor1cmd = 0.0
self.motor2cmd = 0.0
self.motor3cmd = 0.0
self.motor4cmd = 0.0
self._status = DISCONNECTED
self.link_uri = ""
# self.status_pub = rospy.Publisher(node_name + '/CrazyRadioStatus', Int32, queue_size=1)
# self.FlyingAgentClient_command_pub = rospy.Publisher('FlyingAgentClient/Command', Int32, queue_size=1)
time.sleep(1.0)
# Initialize the CrazyFlie and add callbacks
self._init_cf()
# Connect to the Crazyflie
self.connect()
def _init_cf(self):
self._cf = Crazyflie()
# Add callbacks that get executed depending on the connection _status.
self._cf.connected.add_callback(self._connected)
self._cf.disconnected.add_callback(self._disconnected)
self._cf.connection_failed.add_callback(self._connection_failed)
self._cf.connection_lost.add_callback(self._connection_lost)
def get_status(self):
return self._status
def update_link_uri(self):
self.link_uri = "radio://0/79/2M"
def connect(self):
# update link from ros params
self.update_link_uri()
print "Connecting to %s" % self.link_uri
self._cf.open_link(self.link_uri)
def disconnect(self):
print "Motors OFF"
self._send_to_commander(0, 0, 0, 0, 0, 0, 0, 0, CONTROLLER_MOTOR)
print "Disconnecting from %s" % self.link_uri
self._cf.close_link()
def _data_received_callback(self, timestamp, data, logconf):
#print "log of stabilizer and battery: [%d][%s]: %s" % (timestamp, logconf.name, data)
batteryVolt = Float32()
stabilizerYaw = Float32()
stabilizerPitch = Float32()
stabilizerRoll = Float32()
batteryVolt.data = data["pm.vbat"]
stabilizerYaw.data = data["stabilizer.yaw"]
stabilizerPitch.data = data["stabilizer.pitch"]
def _logging_error(self, logconf, msg):
print "Error when logging %s" % logconf.name
# def _init_logging(self):
def _start_logging(self):
self.logconf = LogConfig("LoggingTest", 100) # second variable is freq in ms
self.logconf.add_variable("stabilizer.roll", "float");
self.logconf.add_variable("stabilizer.pitch", "float");
self.logconf.add_variable("stabilizer.yaw", "float");
self.logconf.add_variable("pm.vbat", "float");
self._cf.log.add_config(self.logconf)
if self.logconf.valid:
self.logconf.data_received_cb.add_callback(self._data_received_callback)
self.logconf.error_cb.add_callback(self._logging_error)
print "logconf valid"
else:
print "logconf invalid"
self.logconf.start()
print "logconf start"
def _connected(self, link_uri):
"""
This callback is executed as soon as the connection to the
quadrotor is established.
"""
# cf_client._send_to_commander(15000, 15000, 15000, 15000);
# cf_client._send_to_commander_rate(1000, 0, 1000, 0, 1, 1, 1)
cf_client._send_to_commander_angle(1000, 0, 1000, 0, 1, 1, 1)
print "sent command to commander"
# Config for Logging
self._start_logging()
def _connection_failed(self, link_uri, msg):
"""Callback when connection initial connection fails (i.e no Crazyflie
at the specified address)"""
rospy.logerr("Connection to %s failed: %s" % (link_uri, msg))
def _connection_lost(self, link_uri, msg):
"""Callback when disconnected after a connection has been made (i.e
Crazyflie moves out of range)"""
rospy.logerr("Connection to %s lost: %s" % (link_uri, msg))
def _disconnected(self, link_uri):
"""Callback when the Crazyflie is disconnected (called in all cases)"""
self.logconf.stop()
rospy.loginfo("logconf stopped")
self.logconf.delete()
rospy.loginfo("logconf deleted")
def _send_to_commander_motor(self, cmd1, cmd2, cmd3, cmd4):
pk = CRTPPacket()
pk.port = CRTPPort.COMMANDER_GENERIC
pk.data = struct.pack('<BHHHH', CF_COMMAND_TYPE_MOTORS, cmd1, cmd2, cmd3, cmd4)
self._cf.send_packet(pk)
def _send_to_commander_rate(self, cmd1, cmd2, cmd3, cmd4, roll_rate, pitch_rate, yaw_rate):
pk = CRTPPacket()
pk.port = CRTPPort.COMMANDER_GENERIC
pk.data = struct.pack('<BHHHHfff', CF_COMMAND_TYPE_RATE, cmd1, cmd2, cmd3, cmd4, roll_rate, pitch_rate, yaw_rate)
self._cf.send_packet(pk)
def _send_to_commander_angle(self, cmd1, cmd2, cmd3, cmd4, roll, pitch, yaw):
pk = CRTPPacket()
pk.port = CRTPPort.COMMANDER_GENERIC
pk.data = struct.pack('<BHHHHfff', CF_COMMAND_TYPE_ANGLE, cmd1, cmd2, cmd3, cmd4, roll, pitch, yaw)
self._cf.send_packet(pk)
if __name__ == '__main__':
# global node_name
# node_name = "CrazyRadio"
# rospy.init_node(node_name, anonymous=True)
# Initialize the low-level drivers (don't list the debug drivers)
cflib.crtp.init_drivers(enable_debug_driver=False)
#wait until address parameter is set by FlyingAgentClient
# while not rospy.has_param("~crazyflieAddress"):
# time.sleep(0.05)
#use this following two lines to connect without data from CentralManager
# radio_address = "radio://0/72/2M"
# rospy.loginfo("manual address loaded")
# global cfbattery_pub
# cfbattery_pub = rospy.Publisher(node_name + '/CFBattery', Float32, queue_size=10)
global cf_client
cf_client = CrazyRadioClient()
# rospy.Subscriber("FlyingAgentClient/CrazyRadioCommand", Int32, cf_client.crazyRadioCommandCallback) # allows commands from scripts
# time.sleep(1.0)
# rospy.Subscriber("FlyingAgentClient/ControlCommand", ControlCommand, controlCommandCallback)
# rospy.spin()
# rospy.loginfo("Turning off crazyflie")
#wait for client to send its commands
# time.sleep(1.0)
# bag.close()
# rospy.loginfo("bag closed")
# cf_client._cf.close_link()
# rospy.loginfo("Link closed")
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# || ____ _ __
# +------+ / __ )(_) /_______________ _____ ___
# | 0xBC | / __ / / __/ ___/ ___/ __ `/_ / / _ \
# +------+ / /_/ / / /_/ /__/ / / /_/ / / /_/ __/
# || || /_____/_/\__/\___/_/ \__,_/ /___/\___/
#
# Copyright (C) 2011-2013 Bitcraze AB
#
# Crazyflie Nano Quadcopter Client
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301, USA.
"""
The Crazyflie Micro Quadcopter library API used to communicate with the
Crazyflie Micro Quadcopter via a communication link.
The API takes care of scanning, opening and closing the communication link
as well as sending/receiving data from the Crazyflie.
A link is described using an URI of the following format:
<interface>://<interface defined data>.
See each link for the data that can be included in the URI for that interface.
The two main uses-cases are scanning for Crazyflies available on a
communication link and opening a communication link to a Crazyflie.
Example of scanning for available Crazyflies on all communication links:
cflib.crtp.init_drivers()
available = cflib.crtp.scan_interfaces()
for i in available:
print "Found Crazyflie on URI [%s] with comment [%s]"
% (available[0], available[1])
Example of connecting to a Crazyflie with know URI (radio dongle 0 and
radio channel 125):
cf = Crazyflie()
cf.open_link("radio://0/125")
...
cf.close_link()
"""