2. MAVLink协议栈架构:物理层、数据链路层、网络层、传输层在MAVLink中的体现
很多刚接触MAVLink的朋友会问我:「这玩意儿到底算哪一层的协议?」说实话,我第一次看MAVLink的代码时也有这个困惑。它不像TCP/IP那样层次分明,但仔细拆解后你会发现,MAVLink确实在四个层面上都有自己的实现逻辑。只不过,它把很多工作揉进了数据链路层和传输层里。
我个人习惯把MAVLink的协议栈想象成一个「轻量级的通信骨架」。它不需要像OSI七层模型那样面面俱到,但该有的东西一个不少。下面我带你一层一层剥开来看。
核心观点: MAVLink的协议栈是「按需裁剪」的。物理层完全交给硬件,数据链路层是MAVLink的主战场,网络层只在UDP模式下存在,传输层则靠消息ID和确认机制来保证可靠性。
2.1 物理层:MAVLink不关心,但你不能不管
MAVLink本身不定义物理层。它只规定「数据以字节流的形式在链路上传输」。至于这个字节流走的是串口、USB虚拟串口、WiFi UDP还是蓝牙RFCOMM,MAVLink一概不管。
我在项目中遇到过最典型的场景:飞控通过UART与数传电台连接,电台走433MHz或915MHz频段。这时候物理层就是UART+无线电。后来换成了4G模块,物理层变成了PPP over LTE。MAVLink代码一行没改,照样跑。
我的建议: 选物理层时重点关注两个指标——波特率和误码率。串口场景下,115200 bps是起步,我现在习惯用57600甚至921600。误码率高的链路(比如远距离数传),一定要在数据链路层开CRC校验,MAVLink 2.0默认就开着。
常见的物理层载体包括:
- UART/串口:最经典,飞控与数传、地面站之间的主力通道
- USB:地面站直连飞控,走CDC ACM虚拟串口
- WiFi UDP:高带宽场景,比如机载计算机与地面站之间的视频+数据混合链路
- 蓝牙/BLE:手机地面站与小型无人机之间的短距连接
- 以太网:集群无人机的地面骨干网络
2.2 数据链路层:MAVLink的「主战场」
这一层是MAVLink最核心的部分。说白了,它定义了「一帧数据长什么样」。你打开任何一段MAVLink的抓包日志,看到的十六进制数据就是按照这个帧结构排列的。
MAVLink 2.0的帧结构如下:
| 偏移 | 名称 | 长度(字节) | 说明 |
|---|---|---|---|
| 0 | STX | 1 | 帧起始标志,MAVLink 2.0 固定为 0xFD |
| 1 | LEN | 1 | 有效载荷长度(0-255) |
| 2 | INC_FLAGS | 1 | 不兼容标志位(如签名启用) |
| 3 | CMP_FLAGS | 1 | 兼容标志位 |
| 4 | SEQ | 1 | 序列号,用于丢包检测 |
| 5 | SYS | 1 | 系统ID(发送方) |
| 6 | COMP | 1 | 组件ID(发送方) |
| 7-9 | MSG | 3 | 消息ID(低24位) |
| 10..10+LEN-1 | PAYLOAD | LEN | 有效载荷数据 |
| 10+LEN | CK | 2 | CRC16校验(包含整个帧头+载荷) |
| 10+LEN+2 | SIG | 13 | 可选签名(启用INC_FLAGS位时存在) |
你看这个结构,每个字段都有明确职责。STX是帧头,告诉接收方「新的一帧开始了」。SEQ序列号是我个人觉得最实用的设计——接收方只要检查SEQ是否连续,就能知道中间有没有丢包。
我曾经踩过的坑: 早期用MAVLink 1.0时,STX是0xFE,MSG ID只有1字节(最多255种消息)。后来MAVLink 2.0把STX改成0xFD,MSG ID扩展到3字节。如果你在同一个链路上混用1.0和2.0的设备,接收方会解析错帧。我当年调试时花了整整两天才发现是版本混用的问题。切记:同一链路上所有设备的MAVLink主版本必须一致。
2.3 网络层:系统ID + 组件ID = 逻辑寻址
MAVLink的网络层非常轻量。它没有IP地址,没有路由表,只靠两个ID来定位通信节点:
- 系统ID(System ID):标识一个独立的无人机系统。比如一架飞机是一个系统,地面站是另一个系统。
- 组件ID(Component ID):标识系统内的一个功能模块。比如飞控是1号组件,GPS是2号组件,相机是3号组件。
你想想看,一个地面站同时控制三架无人机,每架无人机上又有飞控、GPS、云台三个组件。这时候通信怎么寻址?
很简单:地面站发送一条消息,目标系统ID=2,目标组件ID=1,这条消息就只被2号飞机的飞控接收。其他飞机和组件看到ID不匹配,直接丢弃。
关键点: MAVLink的网络层是「广播+过滤」模式。所有设备共享同一个物理信道,但每个设备只处理与自己系统ID和组件ID匹配的消息。这种设计在串口总线上特别高效——不需要路由协议,不需要ARP,零开销。
不过要注意,MAVLink的网络层只在多系统场景下才真正发挥作用。如果你只是飞控直连地面站,系统ID固定为1和255,组件ID固定为1,网络层基本是透明的。
2.4 传输层:消息ID + 确认 + 重传
传输层是MAVLink里最容易被忽视的一层。很多人以为MAVLink只是「发个消息就完事了」,其实它有一套完整的传输保障机制。
传输层的核心要素有三个:
- 消息ID(MSG ID):每个消息类型有唯一的24位ID。比如HEARTBEAT是0,SYS_STATUS是1,GPS_RAW_INT是24。接收方根据MSG ID就知道该用哪个结构体来解析PAYLOAD。
- 确认机制(ACK/NACK):MAVLink定义了COMMAND_ACK等消息,用于确认命令是否被正确执行。不是所有消息都需要确认,但关键指令(比如解锁、起飞、航点上传)必须有ACK。
- 重传策略:MAVLink协议本身不强制重传,但上层协议(比如Mission Protocol、Command Protocol)会定义超时重传逻辑。我习惯在发送关键指令后启动一个500ms的定时器,没收到ACK就重发,最多重试3次。
我的经验: 在丢包率高的链路上(比如远距离数传),建议把HEARTBEAT的发送间隔从1秒缩短到0.5秒。这样接收方可以更快地检测到链路中断。但别太短——我见过有人设成50ms,结果整个信道被心跳包塞满,正常数据反而发不出去了。
另外,MAVLink 2.0还支持消息分片(Fragmentation)。当一条消息的PAYLOAD超过255字节时,发送方会自动拆成多个帧,接收方再重组。这个功能在传输大尺寸的日志文件或参数列表时特别有用。
2.5 四层架构的协同工作
说了这么多,你可能觉得四层是各自独立的。其实在实际运行中,它们紧密配合。我画个流程图你就明白了:
你看这个流程,从应用层调用打包函数开始,一路向下经过传输层、网络层、数据链路层,最后通过物理层发出去。接收方收到后,从物理层往上反向解析,每一层做自己的事。
我个人觉得,理解这个四层架构最大的价值在于:当你遇到通信问题时,能快速定位是哪一层出了故障。
- 如果完全收不到数据,先查物理层——串口线松了?波特率配错了?
- 如果能收到但解析乱码,查数据链路层——CRC校验失败?帧头不对?
- 如果能解析但消息没反应,查网络层——系统ID和组件ID配对了没?
- 如果能收到但命令没执行,查传输层——ACK超时了?重传次数用完了?
总结一下: MAVLink的四层架构虽然不像TCP/IP那样严格分层,但每一层都有明确的职责边界。物理层交给硬件,数据链路层负责帧封装和校验,网络层负责逻辑寻址,传输层负责消息标识和可靠性保障。你在实际开发中,只要把这四层的分工理清楚,遇到问题就能像剥洋葱一样一层一层排查。