4. DroneCAN报文结构
DroneCAN 建立在 CAN 2.0B 扩展帧之上,所有通信都封装在 29 位标识符的扩展帧里。理解 DroneCAN 报文结构,核心是抓住三件事:帧类型决定这条报文是广播、服务请求还是服务响应;消息 ID 决定这条报文承载的是哪个数据类型;传输层决定超过 8 字节的数据如何分片与重组。这三者共同构成了 DroneCAN 的寻址与传输模型。
一、帧类型:四种通信语义
DroneCAN 用 29 位 ID 的最高几位区分帧类型,常见有四类:
- Message 广播帧:节点周期性地向总线广播自身状态或测量值,例如
uavcan.protocol.NodeStatus、uavcan.equipment.ahrs.Solution。广播帧没有确认机制,接收方按需订阅。 - Service 请求帧:一个节点向另一个节点发起服务调用,例如参数读取、固件升级、节点重启。请求帧携带源节点 ID 和目标节点 ID。
- Service 响应帧:目标节点对请求的应答,响应帧的 ID 与请求帧一一对应,通过传输层中的传输 ID 匹配。
- Anonymous 匿名帧:节点尚未获得节点 ID 时使用,典型场景是动态节点 ID 分配中的
Allocation请求。匿名帧没有源节点 ID,因此不能用于需要确认的服务。
帧类型不是靠 CAN 数据场里的某个字节区分,而是编码在 29 位 ID 的位段中。这意味着接收方在仲裁阶段就能识别报文语义,无需先解析数据场。
二、消息 ID 分配:数据类型编号
消息 ID 是 DroneCAN 对“数据类型”的全局编号,而不是节点编号。每个数据类型在编译期由 DSDL 定义生成一个固定的 16 位消息 ID,例如:
uavcan.protocol.NodeStatus -> 消息ID 341
uavcan.protocol.GetNodeInfo -> 消息ID 1
uavcan.protocol.param.GetSet -> 消息ID 11
uavcan.equipment.ahrs.Solution -> 消息ID 1001
uavcan.equipment.esc.RawCommand -> 消息ID 1030
消息 ID 的分配遵循“标准数据类型集中管理、厂商自定义类型分段使用”的原则。标准类型由 UAVCAN/DroneCAN 规范统一分配,厂商自定义类型通常使用高位段,避免与标准类型冲突。消息 ID 相同但帧类型不同的报文,在总线上可以共存,因为帧类型位段不同。
关键区分:节点 ID 标识“谁在说话”,消息 ID 标识“说的是什么”。同一个节点可以发送多种消息 ID,同一种消息 ID 也可以由多个节点发送。接收方通常按“消息 ID + 源节点 ID”组合来区分数据来源。
三、传输层:单帧与多帧
CAN 数据场最多 8 字节,而 DroneCAN 的许多数据类型远超 8 字节,因此传输层负责分片与重组。传输层有两种模式:
- 单帧传输:数据长度不超过 7 字节时,直接放在一帧中,首字节为传输层头部,剩余为有效载荷。
- 多帧传输:数据超过 7 字节时,拆分为起始帧、中间帧和结束帧。起始帧携带总长度和 CRC,中间帧按序携带数据,结束帧完成校验。
传输层头部中包含 传输 ID(Transfer ID),用于区分同一消息 ID 的多次传输,防止重复帧被误认为新数据。接收方按传输 ID 递增顺序重组,若发现丢帧则丢弃整条传输并等待下一次完整传输。
单帧: [传输层头 1B][数据 0..7B]
多帧: [起始帧: 头+总长+CRC][中间帧: 头+数据][结束帧: 头+数据+CRC]
调试时如果看到某条消息频繁出现“重组失败”或“CRC 错误”,优先检查总线负载率和线缆质量。多帧传输对丢帧非常敏感,高负载下更容易暴露物理层问题。
四、节点 ID 与动态分配
节点 ID 是 7 位整数,取值范围 1~127,0 保留给匿名帧。节点 ID 在总线内必须唯一,否则会出现地址冲突。DroneCAN 支持两种分配方式:
- 静态分配:通过参数或编译配置为每个节点固定节点 ID,适合节点数量固定、角色明确的机载系统。
- 动态分配:节点上电后先以匿名帧发送
Allocation请求,总线上的分配器(通常是飞控)根据当前占用情况返回一个空闲节点 ID。节点获得 ID 后,再以正常帧参与通信。
动态分配的核心流程是:节点发送匿名 Allocation 请求 → 分配器检查 ID 占用表 → 返回唯一 ID → 节点确认并切换到该 ID。若节点在超时时间内未收到响应,会重试或进入安全状态。
五、案例与场景:多节点上电分配
假设一架四旋翼上电,飞控作为分配器,四个电调节点同时上电。每个电调先以匿名帧发送 Allocation 请求,飞控按到达顺序依次分配 ID 10、11、12、13。分配完成后,电调开始周期广播 uavcan.equipment.esc.Status,飞控按“消息 ID + 源节点 ID”区分四个电调的状态。若某个电调未收到分配响应,它会重试;若总线出现两个相同 ID,飞控会检测到冲突并触发重新分配或告警。
六、常见误区与复盘
| 误区 | 正确理解 |
|---|---|
| 把消息 ID 当成节点地址 | 消息 ID 标识数据类型,节点 ID 才标识发送方 |
| 认为所有报文都是单帧 | 超过 7 字节的数据必须走多帧传输层 |
| 动态分配后不检查冲突 | 节点 ID 必须唯一,冲突会导致通信异常 |
| 忽略传输 ID 的作用 | 传输 ID 用于区分同一消息 ID 的多次传输,防止重复帧误判 |
动态分配虽然方便,但依赖分配器在线。如果飞控未启动或分配器失效,新节点可能一直无法获得节点 ID。对安全性要求高的场景,建议关键节点使用静态 ID,动态分配仅用于可插拔的外设节点。
掌握帧类型、消息 ID、传输层和节点 ID 四者关系后,再看 DroneCAN 的 DSDL 定义和总线日志,就能快速判断一条报文“是谁发的、发的是什么、是否需要重组、目标是谁”。这是后续学习参数服务、固件升级和总线诊断的基础。