14 Crtp Protocol Library - Cflib

一、cflib

cflib是一个基于CRTP协议的通信协议包,基于python开发,通过调用函数接口与Crazyflie实现通信.ESPlane完整移植了Crazyflie的CRTP协议,因此也能使用该软件包进行开发.

二、cflib安装过程&&解决依赖问题

cflib安装过程&&解决依赖问题

1. Fork the cflib
2. Clone the cflib, git clone git@github.com:YOUR-USERNAME/crazyflie-lib-python.git
3. Install the cflib in editable mode, pip install -e path/to/cflib

Note: If you are developing for the [cfclient]you must use python3. On Ubuntu (16.04, 18.08) use pip3 instead of pip.

cflib卸载过程

1. Uninstall the cflib if you don’t want it any more, pip uninstall cflib

三、cflib库设计架构

该库依赖事件回调函数机制.函数调用后会立即返回,当事件发生后,会调用回调函数.该库不包含任何可保持应用程序运行的线程或锁.Functions like open_link will return immediately, and the callback connected will be called when the link is opened.

  • Callbacks

    所有的回调函数使用Caller 类,包含了以下方法

    add_callback(cb)
        """ Register cb as a new callback. Will not register duplicates. """

    remove_callback(cb)
        """ Un-register cb from the callbacks """

    call(*args)
        """ Call the callbacks registered with the arguments args """

四、修改底层接口

设计上支持 radio,udp, serial, usb,等多种底层接口对接上层crtp协议,目前只有原生的radio通信方式功能比较完善,其他方式需要修改xxxxdriver.py文件.上层应用程序通过在连接函数中输入不同的URI来选择底层接口.ESPlane项目使用WiFi通信,因此修改了udpdriver.py与硬件对接.

InterfaceType://InterfaceId/InterfaceChannel/InterfaceSpeed//统一格式:
//使用Radio interface, USB dongle number 0, radio channel 10 and radio speed 250 Kbit/s: 
radio://0/10/250K
udp://192.168.4.1//使用UDP协议

五、cflib中变量的命名规则

  1. 所有的param变量和log变量遵守同一个命名结构:group.name

  2. 名字总长度不能超过28个字符

六、一般工作流程

1. 初始化drivers,搜索所有可以使用的底层接口

init_drivers(enable_debug_driver=False)
       """ Search for and initialize link drivers. If enable_debug_driver is True then the DebugDriver will also be used."""

2. 设置回调函数

    # Called on disconnect, no matter the reason
    disconnected = Caller()
    # Called on unintentional disconnect only
    connection_lost = Caller()
    # Called when the first packet in a new link is received
    link_established = Caller()
    # Called when the user requests a connection
    connection_requested = Caller()
    # Called when the link is established and the TOCs (that are not cached)
    # have been downloaded
    connected = Caller()
    # Called if establishing of the link fails (i.e times out)
    connection_failed = Caller()
    # Called for every packet received
    packet_received = Caller()
    # Called for every packet sent
    packet_sent = Caller()
    # Called when the link driver updates the link quality measurement
    link_quality_updated = Caller()

注册回调函数:

    crazyflie = Crazyflie()
    crazyflie.connected.add_callback(crazyflie_connected)

3. 查找和链接Crazyflie

查找能够被链接上的Crazyflie:

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

使用Crazyflie对象打开和关闭通信链接

    crazyflie = Crazyflie()
    crazyflie.connected.add_callback(crazyflie_connected)
    crazyflie.open_link("udp://192.168.4.1")
    crazyflie.close_link()

4. 发送控制命令

    roll    = 0.0  //deg,目标偏角
    pitch   = 0.0  //deg,目标偏角
    yawrate = 0  //角速度
    thrust  = 0  //from 10001 (next to no power) to 60000 (full power) 发送间隔必须小于500ms,否者飞机将去使能,最理想状态10ms发送一次
    crazyflie.commander.send_setpoint(roll, pitch, yawrate, thrust)
    send_setpoint(roll, pitch, yaw, thrust):
        """
        Send a new control set-point for roll/pitch/yaw/thust to the copter

        The arguments roll/pitch/yaw/trust is the new set-points that should
        be sent to the copter
        """

七、Parameters系统设计

param库用于读取和设置固件运行时参数,跟log不一样的是,这里被用来操作固件中不经常改动的参数.该库并不连续的更新获取到的param值,当每次修改参数时,固件会返回更新过的值.

使用过程:

  1. 注册参数更新时的回调函数 parameter updated callbacks

  2. 链接ESPlane,获取parameter Table of content (TOC)

  3. 请求更新所有参数

  4. library收到更新值依次调用注册过的回调函数

  5. 修改参数,参数将被发送到固件

    param_name = "group.name"
    param_value = 3
    crazyflie.param.set_value(param_name, param_value)
  1. 每次修改参数后,注册在当前参数的回调函数将会被调用

    crazyflie.param.add_update_callback(group="group", name="name", param_updated_callback)

    def param_updated_callback(name, value):
        print "%s has value %d" % (name, value)
    add_update_callback(group, name=None, cb=None)
        """
        Add a callback for a specific parameter name or group. If not name is specified then
        all parameters in the group will trigger the callback. This callback will be executed
        when a new value is read from the Crazyflie.
        """

    request_param_update(complete_name)
        """ Request an update of the value for the supplied parameter. """

    set_value(complete_name, value)
        """ Set the value for the supplied parameter. """

八、logging系统设计

该库支持实时logging程序中的变量.可以创建多个logblock(或称为logconf),每个block包含一组变量和logging频率.一旦该logblock被发送到固件,固件将按照配置的频率自动发回数据.

使用过程:

1.链接ESPlane,获取Table of content (TOC)

2.配置一个logblock,设置block包含的变量和获取周期

    logconf = LogConfig(name="Logging", period_in_ms=100)
    logconf.add_variable("group1.name1", "float")
    logconf.add_variable("group1.name2", "uint8_t")
    logconf.add_variable("group2.name1", "int16_t")

3.在检查配置是否有效之后,为应用程序中的数据设置回调并启动日志监视

    # Callback called when the connection is established to the Crazyflie
    def connected(link_uri):
        crazyflie.log.add_config(logconf)

        if logconf.valid:
            logconf.data_received_cb.add_callback(data_received_callback)
            logconf.error_cb.add_callback(logging_error)
            logconf.start()
        else:
            print "One or more of the variables in the configuration was not found in log TOC. No logging will be possible."

    def data_received_callback(timestamp, data, logconf):
        print "[%d][%s]: %s" % (timestamp, logconf.name, data)

    def logging_error(logconf, msg):
        print "Error when logging %s" % logconf.name

4.固件按照指定的获取周期向上位机发送参数数据

注意事项

  1. crtp协议数据包最大为32bytes,也就意味着log block中变量个数不能太多

  2. 发送周期最小10ms

API LogConfig

    # Called when new logging data arrives
    data_received_cb = Caller()
    # Called when there's an error
    error_cb = Caller()
    # Called when the log configuration is confirmed to be started
    started_cb = Caller()
    # Called when the log configuration is confirmed to be added
    added_cb = Caller()

    add_variable(name, fetch_as=None)
        """Add a new variable to the configuration.

        name - Complete name of the variable in the form group.name
        fetch_as - String representation of the type the variable should be
                   fetched as (i.e uint8_t, float, FP16, etc)

        If no fetch_as type is supplied, then the stored as type will be used
        (i.e the type of the fetched variable is the same as it's stored in the
        Crazyflie)."""

    start()
        """Start the logging for this entry"""

    stop()
        """Stop the logging for this entry"""

    delete()
        """Delete this entry in the Crazyflie"""

API Crazyflie add_config(logconf) """Add a log configuration to the logging framework.

    When doing this the contents of the log configuration will be validated
    and listeners for new log configurations will be notified. When
    validating the configuration the variables are checked against the TOC
    to see that they actually exist. If they don't then the configuration
    cannot be used. Since a valid TOC is required, a Crazyflie has to be
    connected when calling this method, otherwise it will fail."""

最后更新于