crazyflie-CRTP 协议
概述
本文主要分析 CRTP 协议的结构,对该协议结构的理解,有助于后续的数据扩展和对软件架构的理解。为了和 Crazyflie 通信,Crazyflie 飞控中提出一种高层次的协议叫做 CRTP (Crazy RealTime Protocol
)。这种简单的协议使用一些可以收发数据的双向目标端口,但是大都时候通信由主机发起。

物理载体
当前 CRTP 同时支持 Crazyradio 和 USB (只针对 Crazyflie 2.0) 模式。
物理载体 | 支持的飞控 |
---|---|
Crazyradio (PA) | Crazyflie 1.0/2.0 |
USB | Crazyflie 2.0 |
协议头
每个数据包拥有 1 字节的数据头和 31 字节有效数据载荷,数据头布局如下:
1 | 7 6 5 4 3 2 1 0 |
其中:
- Port: 用来区别与消息相关的功能和任务
- Link: 为以后使用预留
- Channel: 用来识别子任务和子功能
端口分配
当前端口分配如下:
端口 | 目标 | 用途 |
---|---|---|
0 | Console | 读取使用 consoleprintf 打印到 Crazyflie 控制台上的控制台信息 |
2 | Parameters | 获取或设置 Crazyflie 参数.Crazyflie 源码中宏定义参数 |
3 | Commander | 发送控制 滚转 / 俯仰 / 偏航 / 油门调节的设置点 |
4 | Memory access | 访问类似于单线或 I2C 总线的非易失性存储器 (只支持 Crazyflie 2.0) |
5 | Data logging | 设置包含需要在特殊周期发回 Crazyflie 的变量的日记块. |
6 | Localization | 与定位相关的数据包 |
7 | Generic Setpoint | 允许发送设置点和控制模式 |
13 | Platform | 用于其它平台控制,例如调试和关机 |
14 | Client-side debugging | 调试界面并只存在于 Crazyflie Python API,Crazyflie 飞控本身不具备 |
15 | Link layer | 用于控制和询问通信连接 |
Console 端口说明
该端口作为一种文本控制台方式,可以使用 consoleprintf 函数从 Crazyflie 飞控端到主机端打印文本信息。
通信协议
1 | Answer (Crazyflie to host): |
如果任何如下条件满足,飞行器端的缓存区的内容将被发送:
- 输出缓存区满 (31 字节)
- 一个 "新行" 字符已经被发送 (或
- 已发出刷新命令
代码分析
参考源文件 console.c,函数调用关系如下:
consoleInit 函数说明
该函数用于初始化相关变量,并创建二值型信号量 synch 用于任务间,任务和中断间同步。
流程图

consoleTest 函数说明
该函数返回初始化结果,初始化成功即测试通过。
consolePuts 函数说明
该函数用于发送字符串。
流程图
该函数主要通过调用 consolePutchar 函数,实现字符串的发送。
consolePutchar 函数说明
该函数用于发送单字节字符。
参考 module/interface/console.h 文件,通过 utils/src/eprintf.c 文件中的 eprintf 函数,将 consolePutchar 函数映射到通用打印函数,使用宏定义 consolePrintf 表示。其中 VA_ARGS 是可变参数宏。
1 | #define consolePrintf(FMT, ...) eprintf(consolePutchar, FMT, ## __VA_ARGS__) |
在 utils/interface/debug.h 文件中
1 | #define DEBUG_PRINT(fmt, ...) consolePrintf(DEBUG_FMT(fmt), ##__VA_ARGS__) |
使用 DEBUG_PRINT 宏定义映射 consolePrintf 函数,通过无线模块或者 USB 接口发送,并在控制台显示。
流程图
consolePutcharFromISR 函数说明
该函数用于在中断中运行,进行字符的发送工作。
流程图
consoleSendMessage 函数说明
该函数用于将消息缓存区的的数据 messageToPrint,通过 CRTP 函数发送出去。
addBufferFullMarker
该函数用于当发送队列快满时,在队列缓存区最后加上缓存区满的标志 (
findMarkerStart 函数说明
该函数用于查找标志的起始位置。
consoleFlush 函数说明
该函数用于发送清空缓存区的内容。
Parameters 端口说明
参数系统使得飞行器的所有可获得和可设置参数可访问。飞行器拥有一个可修改得参数表,在这个表中,每个参数都和一个 ID 和一个组名相关联。三个 ID 用于访问 TOC,参数如下:
TOC 访问
这些信息允许访问参数表的内容。信息的第一个字节是信息 ID,信息 ID 定义如下:
命令 | 数值 | 注解 |
---|---|---|
CMD_GET_ITEM | 0 | 原始版本,获取 TOC 元素 |
CMD_GET_INFO | 1 | 原始版本,获取 CRC 信息 |
CMD_GET_ITEM_V2 | 2 | V2 版本,获取 TOC 元素 |
CMD_GET_INFO_V2 | 3 | V2 版本,获取 CRC 信息 |
上游数据 ID 和命令单独发送,下游数据包拥有如下形式:
1 | Bytes 1 1 1 空终止字符串 |
参数被 PC 端有序请求直到最后。当达到最后参数时,ID 为 0' 最后的 TOC 元素 ',复位命令允许复位 TOC 指针,因此下一个发送 TOC 元素将会是第一个。“获取 TOC CRC” 命令也会返回参数数量。
CRC32 是飞行器 TOC 的哈希值。旨在 PC 应用程序中实现 TOC 的缓存以避免每次飞行器连接后获取完整的 TOC。
参数类型用一个字节描述如下:
类型码 | c 语言类型 | Python 解包 |
---|---|---|
0x08 | uint8_t | '<B ' |
0x09 | uint16_t | '<H' |
0x0A | uint32_t | '<L' |
0x0B | uint64_t | '<Q' |
0x00 | int8_t | '<b' |
0x01 | int16_t | '<h' |
0x02 | int32_t | '<i' |
0x03 | int64_t | '<q' |
0x05 | FP16 | '' |
0x06 | float | '<f' |
0x07 | double | '<d' |
参数读取
PC 客户端请求内容如下:
字节 | 请求字段 | 内容 |
---|---|---|
0 | ID | 需要读取参数的 ID |
Crazyflie 飞控端应答内容如下:
字节 | 应答字段 | 内容 |
---|---|---|
0 | ID | 参数 ID 值 |
1- ... | 数值 | 参数值。TOC 中描述了大小和形式 |
参数读取请求是在通道 1 上的一个简单包,Crazyflie 飞控应答相应的参数值。
参数写入
PC 客户端请求写入内容如下:
字节 | 请求字段 | 内容 |
---|---|---|
0 | ID | 需要写入的参数 ID 值 |
1- ... | value | 写入值,大小和形式在 TOC 中有描述 |
Crazyflie 飞控端应答内容如下:
字节 | 应答字段 | 内容 |
---|---|---|
0 | ID | 参数 ID |
1- ... | 数值 | 参数值,大小和形式在 TOC 中有描述 |
写入请求是一个通道 2 上的简单包。Crazyflie 飞控发回参数值作为应答。
其它命令
如下其它命令被使用:
命令内容 | |
---|---|
0x00 | 按名称设置 |
按名称设置
请求内容
字节 | 请求字段 | 内容 |
---|---|---|
0 | 按名称设置 | 0x00 |
1~ n | 组 | 组名 |
n ~ (n+1) | NULL | 0 |
(n+1) ~ (n+m+1) | 名称 | 参数名称 |
(n+m+1)~(n+m+2) | NULL | 0 |
(n+m+2)~(n+m+3) | 类型 | 参数类型 |
(n+m+3) ~ ... | 数值 | 参数数值,大小和形式由类型描述 |
应答内容
字节 | 应答字段 | 内容 |
---|---|---|
0 | 按名称设置 | 0x00 |
1~ n | 组 | 组名 |
n ~ (n+1) | NULL | 0 |
(n+1) ~ (n+m+1) | 名称 | 参数名称 |
(n+m+2) | NULL | 0 |
(n+m+3) | 错误 | 如果参数被成功写入返回 0. 其它编码 |
组名和参数名称是 ASCII 字符串的形式,对应的大小分别为 n 和 m。
Commander 端口说明
命令端口被用来发送从 PC 客户端到 Crazyflie 飞控的控制指令,用来调节滚转、俯仰、偏航和油门等控制信号。随着通信链的建立这些数据包能被发送出去,并且直到下一包数据接收到之前该数值都是有效的。
通信协议
1 | +-------+-------+-------+-------+ |
名称 | 字节 | 大小 | 类型 | 注释 |
---|---|---|---|---|
滚转角 | 0-3 | 4 | float | 滚转设置点 |
俯仰角 | 4-7 | 4 | float | 俯仰设置点 |
偏航角 | 8-11 | 4 | float | 偏航设置点 |
油门 | 12-13 | 2 | uint16_t | 油门设置点 |
Memory access 端口说明
存储器访问对 Crazyflie Nano Quadcopter无用,当前只在 Crazyflie 2.0 中应用。使用存储器访问给出如下可能性:
获得哪些存储单元可用的信息;
读取 / 写入 / 擦除 存储器;
当前如下存储器被支持:
Crazyflie 2.0 的板载 EEPROM;
Crazyflie 2.0 扩展板上的单线存储器;
有更多的信息关于 EEPROM 如何构建和单总线存储器如何工作和构建可用。
逻辑流程图
对于客户端获取信息和读写存储器是可选择的,但是 Crazyflie Python 客户端总是在连接状态下载关于存储器的信息。
通信协议
存储器端口使用 3 个不同的通道:
端口 | 通道 | 功能 |
---|---|---|
4 | 0 | 获取关于存储器数量和类型的信息并同时擦除 |
4 | 1 | 读取存储器 |
4 | 2 | 写入存储器 |
通道 0:信息 / 设置
这个通道被用来获取存在的存储器数量、关于存储器的信息和大规模擦除内存的可能性。每个包的第一个字节是命令类型:
命令内容 | 命令 | 操作 |
---|---|---|
1 | GET_NBR_OF_MEMS | 获取存储器的数量 |
2 | GET_MEM_INFO | 获取关于存储器的信息 |
3 | SET_MEM_ERASE | 块擦除存储器 |
GET_NBR_OF_MEMS
这个被用来获取存在的存储器数量。
- 请求从 PC 主机到 Crazyflie 飞控:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | 获取存储器数量 | 0x01 | 1 | 命令字节 |
- 响应从 Crazyflie 飞控到 PC 主机:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | 获取存储器数量 | 0x01 | 1 | 命令字节 |
1 | 存储器数量 | 1 | (所有类型) 存在存储器数量 |
例如当 Crazyflie 飞控上存在三个存储器时:
1 | Host-to-Crazyflie: <port/chan> 0x01 |
GET_MEM_INFO
该命令被用来获取存储器的 ID 信息。存储器的 ID 是顺序的,并且从 0 到 1,其数值小于从 GET_NUMBER_OF_MEMS 返回的存储器数量。
- 请求从 PC 主机到 Crazyflie 飞控:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | 获取存储器信息 | 0x02 | 1 | 命令字节 |
1 | 存储器 ID | 1 | 存储器 ID (0 <= id < 存储器数量) |
- 如果 id 有效,应答从 Crazyflie 飞控到 PC 主机如下:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | GET_MEM_INFO | 0x02 | 1 | 命令字节 |
1 | MEM_ID | 1 | 存储器 ID | |
2 | MEM_TYPE | 1 | 存储器类型 (详见如下) | |
3 | MEM_SIZE | 4 | 存储器的字节数 | |
7 | MEM_ADDR | 8 | 存储器地址 (只对单总线存储器有效) |
关于 MEM_ID 字段如下:
ID | 数值 | 注解 |
---|---|---|
EEPROM_ID | 0x00 | 关于 |
LEDMEM_ID | 0x01 | LED 环存储器 ID |
LOCO_ID | 0x02 | 本地位置节点 ID |
TRAJ_ID | 0x03 | 轨迹 ID |
LOCO2_ID | 0x04 | 本地位置节点 2 的 ID |
LH_ID | 0x05 | 灯塔基站的 ID |
TESTER_ID | 0x06 | 存储器测试 ID |
USD_ID | 0x07 | 待确认 |
OW_FIRST_ID | 0x08 | 第一个单总线存储器 ID |
关于 MEM_TYPE 字段如下:
类型 | 数值 | 注解 |
---|---|---|
MEM_TYPE_EEPROM | 0x00 | 电可擦除存储器 |
MEM_TYPE_OW | 0x01 | 单总线存储器 |
MEM_TYPE_LED12 | 0x10 | LED 环 |
MEM_TYPE_LOCO | 0x11 | 本地位置节点 |
MEM_TYPE_TRAJ | 0x12 | 轨迹 |
MEM_TYPE_LOCO2 | 0x13 | 本地位置节点 2 |
MEM_TYPE_LH | 0x14 | 灯塔基站 |
MEM_TYPE_TESTER | 0x15 | 存储器测试 |
MEM_TYPE_USD | 0x16 | 待确认 |
- 如果 id 无效,应答从 Crazyflie 飞控到 PC 主机如下:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | GET_MEM_INFO | 0x02 | 1 | 字节命令 |
1 | MEM_ID | 1 | 存储器 id |
例如对于单总线存储器的请求内容如下:
MEM_ID=1, MEM_SIZE=112bytes, MEM_ADDR=0x1234567890ABCDEF
1 | Host-to-Crazyflie: <port/chan> 0x02 0x01 |
例如请求的存储器索引信息无效时:
1 | Host-to-Crazyflie: <port/chan> 0x01 0x10 |
SET_MEM_ERASE (代码中无描述)
该命令被用来块擦除给定的 id 存储器。存储器的 id 是顺序的,并且从 0 到 1,其数值小于从 GET_NUMBER_OF_MEMS 返回的存储器数量。
- 请求从 PC 主机到 Crazyflie 飞控:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | SET_MEM_ERASE | 0x03 | 1 | 命令字节 |
1 | MEM_ID | 1 | 存储器 ID (0 <= id < 存储器数量) |
- 应答从 Crazyflie 飞控到 PC 主机:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | SET_MEM_ERASE | 0x03 | 1 | 命令字节 |
1 | MEM_ID | 1 | 存储器 id | |
2 | STATUS | 1 | 命令状态 (详见如下) |
例如请求块擦除 MEM_ID=2 的存储器
1 | Host-to-Crazyflie: <port/chan> 0x03 0x02 |
通道 1:存储器读取
这个通道只被用来读取存储器,因此信息不包含任何命令字节。
- 请求从 PC 主机到 Crazyflie 飞控:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | MEM_ID | 1 | 存储器 id (0 <= id < 存储器数量) | |
1 | MEM_ADDR | 4 | 要读取的首字节地址 | |
5 | LEN | 1 | 要被读取的字节数量 |
- 如果存储器的 ID 有效且地址和长度读取有效,则应答从 Crazyflie 飞控到 PC 主机如下:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | MEM_ID | 1 | 存储器 id (0 <= id < 存储器数量) | |
1 | MEM_ADDR | 4 | 要读取的首字节地址 | |
5 | STATUS | 1 | 请求状态 (详见如下) | |
6 | DATA | 1 .. 24? | 要读取的数据 (只有 MEM_ID/MEM_ADDR/LEN 有效时) |
例如从 MEM_ID=0x01 MEM_ADDR=0x0A 读取 LEN=0x0F 字节数据:
1 | Host-to-Crazyflie: <port/chan> 0x01 0x0A 0x00 0x00 0x00 0x0F |
通道 2:存储器写入
该通道只被用来写入存储器,因此消息中不好含任何命令字节。
- 请求从 PC 主机到 Crazyflie 飞控:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | MEM_ID | 1 | 存储器 id (0 <= id < 存储器数量) | |
1 | MEM_ADDR | 4 | 要写入的首字节地址 | |
5 | DATA | 1 .. 24? | 要写入的数据 |
- 如果存储器的 ID 有效并且地址和长度被写入有效,应答从 Crazyflie 飞控到 PC 主机:
字节 | 字段 | 数值 | 长度 | 注解 |
---|---|---|---|---|
0 | MEM_ID | 1 | 存储器 id (0 <= id < 存储器数量) | |
1 | MEM_ADDR | 4 | 要写入的首字节地址 | |
5 | STATUS | 1 | 请求状态 |
DataLog 端口说明
log 端口分为三个通道:
端口 | 通道 | 功能 |
---|---|---|
5 | 0 | 访问内容表:用于读取出 TOC |
5 | 1 | 日志控制操作:用于添加 / 删除 / 开始 / 暂停 log 块 |
5 | 2 | 日志数据操作:用于从 Crazyflie 飞控端到 PC 客户端发送 log 数据 |
访问内容表 (Table of content access)
这个通道用来下载包含所有可记录变量和变量类型的内容表。每组信息的第一个字节对应于命令,所有这个通道的通信都被客户端初始化,并且所有来自飞行器的应答都包含同样的命令字节。
TOC 命令字 | 命令 | 操作 |
---|---|---|
0 | CMD_GET_ITEM | 原始版本:从 TOC 中获取元素 |
1 | CMD_GET_INFO | 原始版本:获取 TOC 和 LOG 子系统的信息 |
2 | CMD_GET_ITEM_V2 | V2 版本:从 TOC 中获取元素 |
3 | CMD_GET_INFO_V2 | V2 版本:获取 TOC 和 LOG 子系统的信息 |
Get TOC item
CMD_GET_ITEM 命令允许从飞行器上检索日志变量名、组名和变量类型。该命令旨在从 0 到 LOG_LEN 的所有 ID 中被请求。
1 | Request (PC to Copter): |
下表说明 PC 端请求内容如下:
字节 | 请求字段 | 内容 |
---|---|---|
0 | GET_ITEM | 数值 0 作为 GET_ITEM 操作 |
1 | ID | 被检索元素的 ID,变量数量从 0 到 LOG_LEN |
下表说明 Crazyflie 飞控端的应答响应内容:
字节 | 应答字段 | 内容 |
---|---|---|
0 | GET_ITEM | 数值 0 用于 GET_ITEM 操作 |
1 | ID | 返回元素的 ID |
2 | Type | 元素的变量类型,详见变量类型列表 |
3-... | Group | 包含元素组名可变的空终止字符串 |
... | Name | 包含元素变量名可变的空终止字符串 |
如果请求的 ID 高于 (TOC_LEN-1),则元素类型、元素组名和元素变量名不被发送。
Get Info
当连接到飞行器时,首先要请求 Get Info 命令。该操作能够知道变量数量、日志实施的限制和日志变量的指纹。
原始版本的请求和应答流程如下:
1 | Request (PC to Copter): |
下表详述 PC 端的请求内容:
字节 | 请求字段 | 内容 |
---|---|---|
0 | GET_INFO | 数值 1 用于 GET_INFO 操作 |
下表详述 crazyflie 飞控应答内容:
字节 | 应答字段 | 内容 |
---|---|---|
0 | GET_INFO | 数值 1 用于 GET_INFO 操作 |
1 | LOG_LEN | 包含在日志表中的元素的数量 |
2 | LOG_CRC | 在日志 TOC 存储区内容数值的 CRC 值,这是飞行器版本的指纹 |
6 | LOG_MAX_PACKET | 飞行器的最大日志包数量,可以在飞行器中编程 |
7 | LOG_MAX_OPS | 飞行器中的可编程操作的最大数量,该操作是一种日志变量检索程序 |
Log control
日志控制通道允许安装、激活、失效和移除日志包。就像访问 TOC 通道第一个字节代表的命令,日志控制同样有如下命令:
控制命令字节 | 命令 | 操作 |
---|---|---|
0 | CREATE_BLOCK | 创建一个新的日志块 |
1 | APPEND_BLOCK | 在存在的日志块上追加变量 |
2 | DELETE_BLOCK | 删除一个日志块 |
3 | START_BLOCK | 启用日志块传输 |
4 | STOP_BLOCK | 停止日志块传输 |
5 | RESET | 删除所有的日志块 |
6 | CREATE_BLOCK_V2 | V2 版本:创建一个新的日志块 |
7 | APPEND_BLOCK_V2 | V2 版本:在存在的日志块上追加变量 |
Create block
1 | Request (PC to Copter): |
返回状态参考 <errno.h> 文件内容。
Append variable to block
1 | Request (PC to Copter): |
返回状态参考 <errno.h> 文件内容。
Delelte block
1 | Request (PC to Copter): |
通过请求的 LOG_BLOCK_ID,查找相关节点,并删除链表中的该节点。
Start block
通过启动相应的定时器实现日志的发送,并设置相应的周期时间。
1 | Request (PC to Copter): |
Stop block
通过停止相应的定时器来停止日志数据的发送。
1 | Request (PC to Copter): |
Reset
停止所有日志块的发送、删除所有日志块的内容,释放所有日志块的空间。
1 | Request (PC to Copter): |
CREATE BLOCK V2
V2 版本的日志块创建。
1 | Request (PC to Copter): |
APPEND BLOCK V2
V2 版本的追加日志内容。
1 | Request (PC to Copter): |
Log data
日志数据通道用于飞行器在可编程速率下发送日志块数据。
详细的请求内容如下:
1 | Answer (Copter to PC): |
字节 | 应答字段 | 内容 |
---|---|---|
0 | BLOCK_ID | 日志块的 ID |
1 | TIME_STAMP | 时标以 ms 形式,从飞行器启动起算起,并以 3 字节的小端整形表示 |
4-... | Log variable values | 日志包的数据值以小端形式表述 |
Localization 端口说明
该端口组有一系列定位相关的数据包,主要如下几个通道:
端口 | 通道 | 命名 | |
---|---|---|---|
6 | 0 | External Position | 外部位置 |
6 | 1 | Generic localization | 通用定位 |
6 | 2 | External Position Packet | 外部位置数据包 |
External Position
该数据包被用来发送由外部系统获取的 Crazyflie 位置信息。主要用该数据包发送由运动捕获系统获取的位置信息,并通过扩展卡尔曼滤波,允许 Crazyflie 计算位置估计并控制其状态。
数据包形式如下:
1 | struct CrtpExtPosition |
Generic Localization
该通道用于定位子系统有用的主机数据包,该数据包被创建用来服务于自身位置系统数据包,但可以被用作对更多通用系统像 GPS NMEA 编码或二进制数据流。数据包格式如下:
字节 | 数值 | 注解 |
---|---|---|
0 | PACKET_TYPE | |
1-... | Payload | 数据包的有效载荷,数据形式由包类型确定 |
关于 PACKET_TYPE 定义:
包类型 | 数值 | 含义 |
---|---|---|
RANGE_STREAM_FLOAT | 0 | 待确认 |
RANGE_STREAM_FP16 | 1 | 待确认 |
LPS_SHORT_LPP_PACKET | 2 | LPS 发送 LPP 数据包 |
EMERGENCY_STOP | 3 | 紧急停止 |
EMERGENCY_STOP_WATCHDOG | 4 | 接收超时触发紧急停止 |
COMM_GNSS_NMEA | 6 | 待确认 |
COMM_GNSS_PROPRIETARY | 7 | 待确认 |
EXT_POSE | 8 | 外部位置信息包 |
EXT_POSE_PACKED | 9 | 外部位置信息压缩包 |
LPS:Loco Positioning System
LPP:Loco Positioning Protocol
LPP Short packet tunnel
该数据用于发送 LPP 短包到本地位置系统,有效数据以 LPP Short Packet的形式发送给系统。
Emergency stop
当收到时,稳定循环系统被设置到紧急停止模式,该模式下停止所有电机。直到飞控状态复位,否则稳定循环模式一直保持在紧急停止状态。
EMERGENCY_STOP_WATCHDOG
飞控启动时超时紧急停止处于失效状态,当第一个数据包接收开始,超时 1s 就会使能超时紧急停止。该数据包至少每秒被 Crazyflie 发送和接收一次,否则稳定循环系统就会被设置进入紧急停止状态且所有电机停转。
EXT_POSE
外部系统的位置信息,详细结构如下:
字节 | 字段 | 类型 | 含义 |
---|---|---|---|
0 | EXT_POSE | byte | 外部位置 信息包 |
1 - 4 | x | float | x 轴坐标信息 |
5 - 8 | y | float | y 轴坐标信息 |
9 - 12 | z | float | z 轴坐标信息 |
13 - 16 | qx | float | 四元素姿态信息:方位信息的 x 轴分量 |
17 - 20 | qy | float | 四元素姿态信息:方位信息的 y 轴分量 |
21 - 24 | qz | float | 四元素姿态信息:方位信息的 z 轴分量 |
25 - 28 | qw | float | 四元素姿态信息:矢量大小系数 |
EXT_POSE_PACKED
外部位置系统的数据通过该数据包形式进行压缩发送,节省通道带宽,详细包形式如下:
字节 | 字段 | 类型 | 系数 | 含义 |
---|---|---|---|---|
0 | EXT_POSE_PACKED | byte | 外部位置信息压缩包 | |
1 | id | uint8 | Crazyflie 飞控地址的最后 8bit | |
2 - 3 | x | int16 | 0.001 | x 轴坐标信息 |
4 - 5 | y | int16 | 0.001 | y 轴坐标信息 |
6 - 7 | z | int16 | 0.001 | z 轴坐标信息 |
8 - 11 | quaternion | uint32_t | 压缩格式的四元素 (压缩算法详见 quatcompress.h) | |
... | 另一同样包形式的元素 |
每个 CRTP 数据包可以达到两个外部位置信息元素。
Generic Setpoint 端口说明
该端口允许发送设定点到飞行器平台。其理念在于能够为每个不同的用例定义设定点数据的包格式。因此这是一个拥有一个通道和一个主要包形式的通用端口。
端口 | 通道 | 命名 |
---|---|---|
7 | 0 | 通用设定点 |
通用设定点包的形式如下:
字节 | 数值 | 注解 |
---|---|---|
0 | ID | 设定点数据包类型的 ID 值 |
1 - ... | Payload | 数据形式由数据包类型确定 |
详细的包类型如下:
ID | Type |
---|---|
0 | stop |
1 | Velocity World |
2 | Z Distance |
3 | CPPM Emulation |
4 | Altitude Hold |
5 | Hover |
6 | Full State |
7 | Position |
Stop
这个设定点无有效负载,用于停止电机和失效控制循环。需要在 Crazyflie 飞控着陆的情况下发送。
Velocity World
世界坐标系中的速度设定点伴随着偏航角速度。适用于在本地位置系统的遥控模式。
有效载荷数据的形式如下:
1 | struct velocityPacket_s { |
Z Distance
设置 Crazyflie 飞控绝对高度和俯仰 / 滚转角度,数据有效载荷形似如下:
1 | struct zDistancePacket_s { |
CPPM Emulation
CRTP 数据包拥有一个 CPPM(Crazyflie Pulse Position Modulation
) 仿真通道,该通道数据范围 1000-2000,其中间值为 1500,支持原始的 RPYT(Roll Pitch Yaw Thrust
) 通道,再加上高达 MAX_AUX_RC_CHANNELS 数量的辅组通道。辅组通道是可选的,并且除非给定通道被实际使用,发射器没必要传输所有的数据 (numAuxChannels 是设定依据)。
有效数据载荷形式:
1 | #define MAX_AUX_RC_CHANNELS 10 |
Altitude Hold
设置 Crazyflie 飞控的垂直速度和滚转 / 俯仰角度。
数据有效载荷形式如下:
1 | struct altHoldPacket_s { |
Hover
设置 Crazyflie 飞控绝对高度和在刚体坐标系下的速度。
数据有效载荷形似如下:
1 | struct hoverPacket_s { |
Full State
设置所有的控制状态。其数据有效载荷形式如下:
1 | struct fullStatePacket_s { |
Position
设置绝对位置和方向,其数据有效载荷形式如下:
1 | struct positionPacket_s { |
连接步骤
CRTP 被设计为无状态模式,所以不需要握手过程。任何命令可以在任何时候被发送,但是对于一些日记 / 参数 / 存储 命令,为了主机客户端能够发送正确的信息,内容表 (TOC) 需要被下载。为了能够使用所有的功能,在连接的情况下,执行 Python API 将会下载 参数 / 日记 / 存储 TOC 。