4. DroneCAN消息与数据类型
在 DroneCAN 网络中,节点之间交换的不是“裸字节”,而是有明确语义的消息。每条消息都由一个唯一的消息 ID 标识,其内部字段按照固定的数据类型和顺序排列,最终被序列化成紧凑的二进制帧。理解消息结构、数据类型、数组、联合体、常量与类型签名,是编写自定义 DroneCAN 设备固件、生成 DSDL 定义以及排查通信问题的前提。
一、消息结构:从 DSDL 到二进制帧
DroneCAN 使用 DSDL(DroneCAN Specification Description Language)描述消息。一个 DSDL 文件通常包含消息名称、字段列表、常量定义以及可选的类型签名。编译工具链(如 dronecan_dsdlc)会把 DSDL 编译成 C/C++ 头文件,生成序列化与反序列化函数。
消息在传输时遵循“字段顺序即编码顺序”的原则:先声明的字段先编码,且每个字段按自身类型占用固定或可变字节数。接收方必须使用完全相同的 DSDL 定义才能正确解析,否则会出现字段错位、数值异常甚至节点掉线。
二、数据类型:基础类型与取值范围
DroneCAN 的基础数据类型分为整型、浮点型和布尔型。整型又分为有符号与无符号,并支持 8/16/32/64 位宽度。浮点型支持 16 位半精度和 32 位单精度。布尔型在编码时通常占 1 位,但为了对齐方便,实际实现中常按 1 字节处理。
| 类型 | 位宽 | 取值范围/说明 | 典型用途 |
|---|---|---|---|
| uint8 / int8 | 8 | 0~255 / -128~127 | 状态码、小范围计数 |
| uint16 / int16 | 16 | 0~65535 / -32768~32767 | PWM、温度、电压 |
| uint32 / int32 | 32 | 0~4294967295 / -2147483648~2147483647 | 时间戳、计数器 |
| uint64 / int64 | 64 | 大范围整数 | 高精度时间、唯一 ID |
| float16 | 16 | 半精度浮点 | 节省带宽的物理量 |
| float32 | 32 | 单精度浮点 | 姿态、位置、速度 |
| bool | 1 | true / false | 使能标志、状态位 |
选择类型时,应优先考虑“够用且不溢出”。例如电池电压用 uint16 表示毫伏即可覆盖 0~65.535V,没必要用 float32;而姿态四元数必须用 float32,否则精度不足会导致控制抖动。
三、数组与联合体:表达重复与多选一
数组用于表达同一类型的一组数据。DroneCAN 支持固定长度数组和可变长度数组。固定长度数组在编码时直接连续排列;可变长度数组会先编码一个长度字段,再编码实际元素。数组元素可以是基础类型,也可以是嵌套消息类型。
# 固定长度数组示例
float32[3] gyro_xyz
uint8[16] node_id_list
# 可变长度数组示例
float32[<=8] temperatures
uint8[<=255] payload
联合体(union)用于表达“多个字段中同一时刻只有一个有效”的场景。在 DSDL 中,联合体通常通过标签字段加多个可选字段实现。接收方先读取标签,再根据标签决定后续解析哪个字段。联合体在 DroneCAN 中不如数组常见,但在某些配置消息或诊断消息中会出现。
<=8),否则编译工具无法确定缓冲区大小,可能导致栈溢出或传输失败。
四、常量与类型签名:保证语义一致
常量用于在 DSDL 中定义固定值,例如枚举、模式选择、状态码。常量不参与序列化,但会出现在生成的头文件中,供应用程序直接引用。常见写法如下:
uint8 MODE_IDLE = 0
uint8 MODE_ARMED = 1
uint8 MODE_FAILSAFE = 2
uint8 mode
类型签名(type signature)是 DroneCAN 保证消息兼容性的关键机制。它由 DSDL 编译器根据消息的字段名、类型、顺序和常量计算出一个 64 位哈希值。当两个节点使用不同版本的 DSDL 通信时,类型签名不一致会导致消息被丢弃或节点拒绝通信。因此,修改消息定义后必须重新编译并同步更新所有相关节点。
五、案例与排障:一次“字段错位”的复盘
某团队在调试电池管理节点时,飞控端收到的电压值始终为 0,而电流值却异常巨大。排查发现:电池节点固件使用的 DSDL 中,voltage 字段为 uint16,而飞控端使用的旧版 DSDL 中该字段为 float32。由于类型签名不一致,飞控端本应丢弃该消息,但测试时关闭了签名校验,导致按错误类型解析,出现字段错位。
正确的做法是:修改 DSDL 后重新编译,确保所有节点的类型签名一致;在 CI 流程中加入 DSDL 编译检查;对关键消息保留版本号或使用新的消息 ID,避免直接修改已发布消息的字段类型。
六、方法流程:定义一条自定义消息
- 确定消息用途与消息 ID,避免与现有标准消息冲突。
- 在 DSDL 文件中声明字段,选择合适的数据类型与数组长度。
- 如需枚举或模式选择,使用常量定义,不要硬编码魔法数字。
- 运行
dronecan_dsdlc生成头文件,检查类型签名。 - 在节点固件中调用生成的编码/解码函数,完成收发。
- 使用
dronecan_gui_tool或总线抓包工具验证字段值与签名。
掌握消息结构、数据类型、数组、联合体、常量与类型签名,就能在 DroneCAN 网络中定义出既紧凑又可靠的通信接口,为后续设备开发打下坚实基础。