User Tools

Site Tools


projects:crazyflie:pc_utils:pylib

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
projects:crazyflie:pc_utils:pylib [2013-05-05 23:19]
danielsamuels
projects:crazyflie:pc_utils:pylib [2021-06-24 16:58] (current)
kimberly
Line 1: Line 1:
-====== The Crazyflie Python API ====== +<WRAP center round important 60%> 
-In order to easily use and control the Crazyflie there's an library made in Python that gives high-level functions and hides the details. This page contains generic information about how to use this library and the API that it implements. +This page has deprecated and will be archivedPlease go to [[https://www.bitcraze.io/]]
- +</WRAP
-If you are interested in more details look in the PyDoc in the code or: +This topic has been moved [[doc:crazyflie:api:python:index|here]].
-  * Communication protocol for [[projects:crazyflie:comm_protocol:log | logging]] or [[projects:crazyflie:comm_protocol:param | parameters]] +
-  * Firmware implementation of the [[projects:crazyflie:firmware:log | logging]] or [[projects:crazyflie:firmware:param | parameters]] +
- +
-===== Structure of the library ===== +
-**TODO** +
- +
-===== Connection- and link-callbacks ===== +
-The library uses callbacks for asynchronous events such as when the connection is dropped or when new logging data arrives. Here's a list of linkstatus callbacks: +
-    * //connectionInitiated// - Called when a request has been made to the library to establish a connection +
-    * //connectSetupFinished// - Called when the connection has been established and the log/param TOC has been downloaded +
-    * //disconnected// - Called when the connection has been closed (both when requested and not requested to close) +
-    * //connectionLost// - Called when the connection has been closed (without being requested to be closed) +
-    * //connectionFailed// - Called if the connection fails when it is being established (between the request and connection setup finished) +
-    * //linkQuality// - Called periodically to report link status. This is done at the discretion of the link drivers +
- +
-To register for callbacks the following is used: +
-<code python> +
-    crazyflie = Crazyflie() +
-    crazyflie.linkQuality.addCallback(linkQualityCallback) +
-</code> +
- +
-There are more callbacks than this available in the Crazyflie but these are the ones most useful. +
- +
-===== Uniform Resource Identifier (URI) ===== +
-All communication links are identified using an URI build up of the following: %%InterfaceType://InterfaceId/InterfaceChannel/InterfaceSpeed%% +
- +
-Currently only //radio// and //debug// interfaces are used but there's ideas for more like //udp//, //serial//, //usb//, etc...Here are some examples: +
-  * %%radio://0/10/250K (Radio interface, USB dongle number 0, radio channel 10 and radio speed 250 Kbit/s)%% +
-  * %%debug://0/1 (Debug interface, id 0, channel 1)%% +
- +
-===== Variable and parameter names ===== +
-All names of parameters and loggable variables use the same structure: //group.name// +
- +
-There's a limit of 28 chars in total **(?)** and here are some examples: +
-  * stabalizer.roll +
-  * system.battery +
- +
-===== Finding a Crazyflie and connecting =====  +
-The first thing to do is to find a Crazyflie quadcopter that we can connect to. This is done by queuing the library that will scan all the available interfaces (currently the debug and radio interface). +
-<code python+
-    cflib.crtp.init_drivers() +
-    available = cflib.crtp.scan_interfaces() +
-    for i in available: +
-        print "Interface with URI [%s] found and name/comment [%s]" % (i[0], i[1]) +
-</code> +
- +
-Opening and closing a communication link is doing by using the Crazyflie object: +
-<code python> +
-    crazyflie = Crazyflie() +
-    crazyflie.open_link("radio://0/10/250K"+
-    # Do stuff +
-    crazyflie.close_link() +
-</code> +
-===== Sending control commands ===== +
-Currently all the communication is either parameters, logging or control commands. The special case of control commands is to minimize latency since it's a faster way than using parameters. +
- +
-To send a new control set-point use the following: +
-<code python> +
-    roll    = 0.0 +
-    pitch   = 0.0 +
-    yawrate = 0 +
-    thrust  = 0 +
-    crazyflie.commander.send_setpoint(roll, pitch, yawrate, thrust) +
-</code> +
- +
-Thrust is an integer value ranging from 10001 (next to no power) to 60000 (full power). Sending a command makes it apply for 2 seconds, after which the firmware will cut out the power. Depending on where the Crazyflie is, this can be a Bad Thing! With this in mind, you need to try and maintain a thrust level, with a tick being sent at least once every 2 seconds. Ideally you should be sending one tick every 0.01 seconds, for 100 commands a second. This has a nice added benefit of allowing for very precise control. +
-===== Parameters ===== +
-The parameter framework is used to read and set parameters. This functionality should be used when: +
-  * The parameter is not changed by the Crazyflie but by the client +
-  * The parameter is not read periodically +
-If this is not the case then the logging framework should be used instead. +
- +
-To set a parameter you have to the connected to the Crazyflie. A parameter is set using: +
-<code python> +
-    parameterName = "group.name" +
-    parameterValue = 3 +
-    crazyflie.param.setParamValue(parameterName, parameterValue) +
-</code> +
- +
-The parameter reading is done using callbacks. When the connection is established to the Crazyflie all the parameters are read. When a parameter is updated from the client (using the code above) the parameter will be requested again by the library and this will trigger the callbacksParameter callbacks can be added at any time (you don't have to be connected to a Crazyflie). +
-<code python> +
-    crazyflie.param.addParamUpdateCallback("group.name", paramUpdateCallback) +
- +
-    def paramUpdateCallback(name, value): +
-        print "%s has value %d" % (name, value) +
-</code> +
- +
-A callback can also be removed using: +
-<code python> +
-crazyflie.param.addParamUpdateCallback("group.name", paramUpdateCallback) +
-</code> +
- +
-===== Logging ===== +
-The logging framework is used to enable the "automatic" sending of variable values at specified intervals to the clientThis functionality should be used when: +
-  * The variable is changed by the Crazyflie and not by the client +
-  * The variable is updated at high rate and you want to read the value periodically +
-If this is not the case then the parameter framework should be used instead. +
- +
-To create a logging configuration the following can be used: +
-<code python> +
-    periodInMilliSeconds = 10 +
-    logconf = LogConfig("Logging", periodInMilliSeconds) +
-    logconf.addVariable(LogVariable("group1.name1", "float")) +
-    logconf.addVariable(LogVariable("group1.name2", "uint8_t")) +
-    logconf.addVariable(LogVariable("group2.name1", "int16_t")) +
-</code> +
- +
-The datatype should match what has been configured in the Crazyflie firmware. The valid datatypes are: +
-  * float +
-  * uint8_t and int8_t +
-  * uint16_t and int16_t +
-  * uint32_t and int32_t +
-  * FP16 (this is a fixed point version of floating point) +
- +
-The logging cannot be started until your are connected to a Crazyflie: +
-<code python> +
-    # Callback called when the connection is established to the Crazyflie +
-    def connected(linkURI): +
-        logpacket = crazyflie.log.newLogPacket(logconf) +
- +
-        if (logpacket != None): +
-            logpacket.dataReceived.addCallback(dataCallback) +
-            logpacket.startLogging() +
-        else: +
-            print "One or more of the variables in the configuration was not found in log TOC. No logging will be possible." +
- +
-    def dataCallback(data): +
-        # Print all the keys and values for them +
-        for k in data.keys(): +
-            print "Key: %s=%s" % (k, str(data[k])) +
-</code> +
- +
- +
-====== Logging and parameter examples ====== +
-Below are the two examples described in the video <insert link to video here when done> that shows the parameter and logging frameworkThey have been re-written to fit outside the QT context so they do not match the video 1:1 but they show the same concept. +
- +
-Remember that if you use the callbacks for parameters and logging together with QT and the callbacks manipulate objects in the UI then they have to be wrapped using signals. Otherwise you will en up with timing issues that will (at some point) crash the application since UI objects should only be updated with the same thread that draws the objects. +
- +
-===== Adding a parameter ===== +
-In this example we will add a parameter that will be used to "freeze" the LED update function. This isn't very useful but it shows how to use parameters :-) +
- +
-First of all we need to add the parameter to the firmware, this is done by using the macros PARAM_GROUP_START, PARAM_ADD and PARAM_GROUP_STOP. In //crazyflie-firmware/drivers/src/led.c// we insert the following to add a parameter: +
-<code c> +
-#include "param.h" +
- +
-bool ledFreeze = false; +
- +
-PARAM_GROUP_START(led) +
-PARAM_ADD(PARAM_UINT8, freeze, &ledFreeze) +
-PARAM_GROUP_STOP(led) +
-</code> +
- +
-This will add a parameter in the TOC named //led.freeze// of the type uint8_t. +
- +
-Now we should use this parameter on the client side. This can either be done by reading or writing the parameter. First we add the code to write the parameter: +
-<code python> +
-# crazyflie is an instance of the Crazyflie class that has been instantiated and connected +
-    crazyflie.param.setParamValue("led.freeze", True) +
-</code> +
- +
-The parameter-framework relies on the fact that the parameters are changed from the client or that the client polls the value of parameters. If you are interested in logging changes that the Crazyflie does itself then the logging-framework is better. If you are interested in reading a parameter this should be done using a callback that will be called from the framework when the value for the parameter is updated. This happens in two cases: +
-  * When the Crazyflie has connected values for all the parameters in the TOC are fetched +
-  * When the client changes a value for a parameter the new value will be sent back from the Crazyflie +
- +
-To register for a callback and to implement the callback the following is used: +
-<code python> +
-    crazyflie = Crazyflie() +
-    crazyflie.param.addParamUpdateCallback("led.freeze", paramUpdateCallback) +
- +
-    def paramUpdateCallback(name, value): +
-        print "%s has value %s" % (name, value) # This will in our example printled.freeze has value True +
-</code> +
- +
-===== Adding loggable variables ===== +
-In this example we will add logging for the raw gyro values read from the sensor. +
- +
-First of all we add the variables to the logging TOC by using the macros LOG_GROUP_START, LOG_ADD and LOG_GROUP_STOP. In our example we edit the file //crazyflie-firmware/modules/src/stabalizer.c//: +
-<code c> +
-#include "log.h" +
-// The raw gyro values are stored in the gyro struct +
-LOG_GROUP_START(gyro) +
-LOG_ADD(LOG_FLOAT, x, &gyro.x) +
-LOG_ADD(LOG_FLOAT, y, &gyro.y) +
-LOG_ADD(LOG_FLOAT, z, &gyro.z) +
-LOG_GROUP_STOP(gyro) +
-</code> +
- +
-This will add the variables //gyro.x//, //gyro.y// and //gyro.z// to the logging TOC as floats. +
- +
-On the client side we now add the log configuration, start the logging and then a callback will be called every 10 ms when data arrives from the Crazyflie: +
-<code python+
-    # Callback called when the connection is established to the Crazyflie +
-    def connected(linkURI): +
-        gyroconf = LogConfig("Gyro", 10) +
-        gyroconf.addVariable(LogVariable("gyro.x", "float")) +
-        gyroconf.addVariable(LogVariable("gyro.y", "float")) +
-        gyroconf.addVariable(LogVariable("gyro.z", "float")) +
- +
-        # crazyflie is an instance of the Crazyflie class that has been instantiated and connected +
-        gyrolog = crazyflie.log.newLogPacket(gyroconf) +
- +
-        if (gyrolog != None): +
-            gyrolog.dataReceived.addCallback(gyroData) +
-            gyrolog.startLogging() +
-        else: +
-            print "gyro.x/y/z not found in log TOC" +
- +
-    def gyroData(data): +
-        print "Gyrodata: x=%.2f, y=%.2f, z=%.2f" % (data["gyro.x"], data["gyro.y"], data["gyro.z"]) +
- +
-</code> +
- +
-====== Simple code example ====== +
-As a starter guide, this application connects to the Crazyflie, turns on the motors and then asks the user to set the thrust level. +
- +
-<code python> +
-import time +
-from threading import Thread +
- +
-import cflib.crtp +
-from cflib.crazyflie import Crazyflie +
- +
- +
-class Main: +
- +
-    # Initial values, you can use these to set trim etc. +
-    roll = 0.0 +
-    pitch = 0.0 +
-    yawrate = 0 +
-    thrust = 10001 +
- +
-    def __init__(self): +
-        self.crazyflie = Crazyflie() +
-        cflib.crtp.init_drivers() +
- +
-        # You may need to update this value if your Crazyradio uses a different frequency. +
-        self.crazyflie.open_link("radio://0/10/250K"+
- +
-        self.crazyflie.connectSetupFinished.add_callback(self.connectSetupFinished) +
- +
-    def connectSetupFinished(self, linkURI): +
-        # Keep the commands alive so the firmware kill-switch doesn't kick in. +
-        Thread(target=self.pulse_command).start() +
- +
-        while 1: +
-            self.thrust = int(raw_input("Set thrust (10001-60000):")) +
- +
-            if self.thrust == 0: +
-                self.crazyflie.close_link() +
-                break +
-            elif self.thrust <= 10000: +
-                self.thrust = 10001 +
-            elif self.thrust > 60000: +
-                self.thrust = 60000 +
- +
-    def pulse_command(self): +
-        self.crazyflie.commander.send_setpoint(self.roll, self.pitch, self.yawrate, self.thrust) +
-        time.sleep(0.1) +
- +
-        # ..and go again! +
-        self.pulse_command() +
- +
-Main() +
-</code>+
projects/crazyflie/pc_utils/pylib.1367788757.txt.gz · Last modified: 2015-07-15 16:30 (external edit)