User Tools

Site Tools


projects:crazyflie:pc_utils:pylib

This is an old revision of the document!


The Crazyflie Python API

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 this library and the API that it implements. For more specific details look at the Python Doc in the code.

Structure of the library

TODO

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).

    cflib.crtp.initDrivers()
    available = cflib.crtp.scanInterfaces()
    for a in available:
        print "Interface with URI [%s] found and name/comment [%s]" % (a[0], a[1])

Opening and closing a communication link is doing by using the Crazyflie object:

    crazyflie = Crazyflie()
    crazyflie.openLink(radio://0/10/250K)
    # Do stuff
    crazyflie.closeLink()

Sending control commands

Currently all the communication is either parameters, logging or control commands. The special case of control commands is minimize latency since it's a faster way than using parameters.

To send a new control set-point use the following:

    roll    = 0.0
    pitch   = 0.0
    yawrate = 0
    thrust  = 0
    crazyflie.commander.sendControlSetpoint(roll, pitch, yawrate, thrust)

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.

Parameter setting is done using:

    parameterName = "group.name"
    parameterValue = 3
    crazyflie.param.setParamValue(parameterName, parameterValue)

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 callbacks.

    crazyflie.param.addParamUpdateCallback("group.name", paramUpdateCallback)
 
    def paramUpdateCallback(name, value):
        print "%s has value %d" % (name, value)

Logging

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 framework. They 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 but 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:

#include "param.h"
 
bool ledFreeze = false;
 
PARAM_GROUP_START(led)
PARAM_ADD(PARAM_UINT8, freeze, &ledFreeze)
PARAM_GROUP_STOP(led)

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:

# crazyflie is an instance of the Crazyflie class that has been instantiated and connected
    crazyflie.param.setParamValue("led.freeze", True)

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:

    crazyflie = Crazyflie()
    crazyflie.param.addParamUpdateCallback("led.freeze", paramUpdateCallback)
 
    def paramUpdateCallback(name, value):
        print "%s has value %s" % (name, value) # This will in our example print: led.freeze has value True

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:

#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)

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:

    # 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"])
projects/crazyflie/pc_utils/pylib.1360605569.txt.gz · Last modified: 2015-07-15 16:30 (external edit)