1. 无人机通信协议全景
1.1 三个关键词:MAVLink、PPM、SBUS 到底在无人机里扮演什么角色
刚开始玩无人机的时候,最容易懵的事情不是怎么飞,而是看不懂飞控背后的那堆线。一堆杜邦线、排针、接收机、数传模块,每个接口旁边还标着看不懂的英文缩写:RX、TX、SBUS、PPM、TELEM...如果你把某个插头插错位置,飞控可能毫无反应,甚至直接冒烟。
这其实就是通信协议的锅。无人机内部各个模块之间要说话,PPM、SBUS、MAVLink 就是它们各自的语言体系。PPM 和 SBUS 负责把遥控器的手柄操作转成飞控能读懂的通道数据,MAVLink 则负责飞控和地面站、机载电脑之间传递状态信息和任务指令。要真正理解无人机,这三条协议绕不开。
先抛结论:PPM 和 SBUS 都属于遥控链路层面的输入协议,解决的是"遥控器怎么把操作意图传给飞控";MAVLink 属于遥测和任务链路层面的通信协议,解决的是"飞控怎么把状态告诉地面站、地面站怎么把航点下发到飞控"。两者层级不同,但经常出现在同一台无人机上,所以大家容易混在一起。这篇文章就把它们逐个拆开讲清楚。
1.2 遥控链路与数传链路,两条逻辑线不要混
在深入协议之前,先理清一条逻辑线:一架无人机里,数据的流动路径其实可以分为两条主流。
第一条是遥控链路,从遥控器发射机到接收机,再到飞控。你要打杆、切模式、解锁、返航,这些操作都走这条路。PPM 和 SBUS 就是这条路线上飞控和接收机之间的通信方式。老式遥控器还经常用 PWM,一根信号线对应一个通道,通道多了就得拉一捆线;PPM 和 SBUS 则用一根信号线传所有通道。
第二条是数传链路,从飞控到地面站软件(Mission Planner、QGroundControl 等)或者机载电脑(树莓派、NVIDIA Jetson 之类)。你在地面站上看到的高度、速度、电池电压、卫星数,都是通过这条路传上来的;你在电脑上规划一系列航点,也需要走这条路下发。MAVLink 就是这条链路上最常见的语言。
这两条线有时候会交汇,比如某些接收机支持遥测回传,能把接收信号强度通过遥控链路反向发回遥控器;再比如 ArduPilot 允许你把遥控通道值记录进日志,方便回放分析。但概念上,先把这两条逻辑分开,后面看协议就不会乱。
2. MAVLink 深度解析
2.1 MAVLink 的诞生与设计思路
MAVLink 全称 Micro Air Vehicle Link,最早由 Lorenz Meier 在 2009 年为了 PX4 项目设计。后来 ArduPilot 也开始采用,逐渐成了开源飞控领域的事实标准。
为什么要专门设计一个协议,而不是直接用现成的 TCP/IP 或者简单的串口字符串?因为无人机通信有自己独特的约束:带宽有限、链路可能丢包、消息要求低延迟、还要支持不同厂商设备互操作。MAVLink 的设计目标就是"轻量、可靠、可扩展"。
MAVLink 有两种主要版本,MAVLink 1 和 MAVLink 2。MAVLink 2 在 1 的基础上增加了消息签名、扩展帧头、更大的载荷上限,是目前推荐使用的版本。ArduPilot 从 4.x 系列开始全面支持 MAVLink 2,默认也是按 MAVLink 2 输出。
MAVLink 的本质是一种二进制串行协议,数据按固定格式打包成"帧",通过串口、UDP、TCP 等载体传输。它不关心底层物理链路是 USB 线、数传电台还是局域网,只要你有一个能传字节的通道,就能跑 MAVLink。
2.2 MAVLink 消息帧结构与解析流程
MAVLink 的帧结构有点像快递包裹,每一层都有固定字段,收件人拿到包裹先验视再拆包。一个标准的 MAVLink 2 帧长这样:
- 帧起始标志(STX):固定值 0xFD,表示这是 MAVLink 2 消息。MAVLink 1 是 0xFE,看到第一个字节基本就能区分版本。
- 帧长度(LEN):表示后面载荷区域的字节数。
- 不兼容标志(INC_FLAGS)和兼容标志(CMP_FLAGS):用来做签名、扩展等特性开关。
- 序列号(SEQ):消息序号,用于检测丢包。
- 系统 ID(SYS ID):区分同一链路上的不同飞行器或地面站。
- 组件 ID(COMP ID):区分同一系统内的不同组件,比如飞控是 1,摄像头是 100。
- 消息 ID(MSG ID):告诉接收方这条消息是心跳、姿态、航点还是别的什么。
- 载荷(PAYLOAD):实际的消息内容,比如姿态消息里就是横滚角、俯仰角、偏航角。
- 校验和(CRC):从协议里提取出来的 16 位 CRC,用于完整性校验。
- 签名(SIGNATURE):可选字段,MAVLink 2 里如果开启签名,会额外多出 13 个字节,防止消息被伪造或篡改。
解析流程其实不复杂。接收端拿到串口字节流后,先等一个 0xFD,然后读取长度字段,再按长度读完整的帧,最后做 CRC 校验。校验通过就把载荷交给对应的消息解析器。
很多刚开始接触的人看到 CRC 会问:串口通信本身有奇偶校验,为什么还要在协议层再算一次?因为串口校验只保证字节在物理传输过程中没有被干扰,不能保证发端和收端使用的是同一套帧格式。MAVLink 的 CRC 里还混入了消息的"指纹信息",如果收发两端的消息定义不一致,CRC 就对不上,就能及时发现问题。这个设计在飞控固件升级后特别有用,端和端定义不匹配时会立刻体现出来。
2.3 常用 MAVLink 消息盘点
MAVLink 目前定义了上百种消息,日常开发真正高频用到的其实就那么几个。
HEARTBEAT(心跳)是所有 MAVLink 系统的基础。飞控会定时(默认 1 秒)向外广播心跳消息,告诉地面站"我还在线,我的类型是 ArduPilot,当前飞行模式是什么"。地面站如果连续一段时间没收到心跳,就会提示连接断开。
GPS_RAW_INT(GPS 原始信息)携带经纬度、海拔、地面速度、卫星数、定位类型。地面站画地图轨迹靠的就是它。
ATTITUDE(姿态)携带四元数和欧拉角。如果你看地面站的姿态仪表盘在动,那就是 ATTITUDE 消息在工作。
GLOBAL_POSITION_INT 是经过滤波后的全局位置估计,包含经纬度、相对高度、绝对高度和三维速度。相比 GPS_RAW_INT,这个值更平滑,更适合任务逻辑使用。
SYS_STATUS(系统状态)包含电池电压、电流、剩余电量、传感器健康位。很多地面站的电池显示就依赖这条消息。
任务相关的消息有 MISSION_ITEM_INT、MISSION_COUNT、MISSION_REQUEST_INT 等。地面站下发航点的时候,会先发一个 MISSION_COUNT 告诉飞控下面要传多少个航点,然后飞控逐个发送 MISSION_ITEM_INT 请求,地面站再逐条把航点发过去。整个过程有一个明确的握手流程,保证每个航点都送达,传完后还要 MISSION_ACK 确认。
高频发送的消息一般有速率控制。ArduPilot 里 SR0_EXTRA、SR1_POSITION 等参数就是干这个的。合理设置消息传输速率,能有效避免链路带宽被无用的消息占满。
2.4 MAVLink 的应用场景和哪种场景不该用
MAVLink 最常见的应用是飞控与地面站之间的通信,但它的应用边界远不止于此。
机载电脑通过串口或 USB 连接飞控,用 MAVLink 读取实时状态、发送指令,这是无人机自动驾驶最常见的架构。开源生态里非常成熟的 MAVSDK 就是面向机载电脑的 MAVLink 开发库,支持 Python、C++、Swift 等多种语言。
编队飞行也是 MAVLink 的重要场景。多台无人机通过数传组网,共享位置和速度信息,配合规划算法实现编队。MAVLink 默认的广播模式天然支持这种拓扑:同一链路上一台飞控广播的消息,其他飞控也都能收到。
不过 MAVLink 并非万能。它的设计目标是飞行控制相关的高频小数据包,不适合传大文件。很多新手尝试用 MAVLink 传图片,结果发现带宽几乎被榨干,还耽误正常遥测,这就是用错了场景。图像和视频应该走独立链路,比如 WiFi 图传或者 HDMI 采集卡,MAVLink 只负责元数据和指令。
3. PPM 工作原理与适用场景
3.1 PPM 信号到底是怎么编码的
PPM 全称 Pulse Position Modulation,脉冲位置调制。它的核心思想是:把所有通道的油门、方向、开关状态按顺序塞进一个固定周期的信号里,用"高电平保持的时间长度"来表示每个通道的数值。
具体来说,一个完整的 PPM 帧大约 20 到 25 毫秒,帧的起始由一个比较宽的同步脉冲标记出来。同步脉冲之后,是一连串窄脉冲,两个窄脉冲之间的时间间隔代表一个通道的值。每个通道值范围通常是 1000 到 2000 微秒,对应 PWM 输入的最小到最大。如果某个通道值是 1500 微秒,就说明这个通道处于中立位置。
举个例子,8 通道的 PPM 信号大概是这样的结构:
- 同步脉冲(约 300 微秒高电平)
- 通道 0 的间隔时间(比如 1200 微秒)
- 窄脉冲(约 300 微秒高电平)
- 通道 1 的间隔时间(比如 1500 微秒)
- 窄脉冲
- 依次类推,直到第 8 个通道
- 帧之间的空白时间填充到 20 毫秒周期
接收机输出的 PPM 信号本质上是把原本独立的 PWM 通道信号串行化。原来 8 通道需要 8 根信号线,现在只需要 1 根信号线,代价是对时序的要求更高。任何一段电平跳变抖动,都可能被解码器解读成错误的通道值。
很多飞控的输入端有 PPM 编码器电路,直接把接收机输出的 PPM 信号解码成各通道的 PWM 值。Pixhawk 系列飞控通常要求把接收机信号线接到 RC_IN 接口。ArduPilot 在参数里设置 RC_PROTOCOLS 为 0 时,会同时自动检测 PPM 和 SBUS 输入。
3.2 用示波器看一段真实 PPM 信号
如果你手头有示波器或者逻辑分析仪,强烈建议实际抓一段 PPM 信号看看。我最初就是用逻辑分析仪看了 PPM 波形之后,才对"脉冲位置调制"有了直观的理解。
把接收机的 PPM 输出接上逻辑分析仪,设置采样率不低于 1 MHz,手动拨动遥控器油门杆,你能看到清晰的波形:一个宽的同步脉冲后面跟着一串均匀分布的窄脉冲。通道值变化时,对应的间隔会变大或变小。整个过程肉眼很难看出差异,必须借助处理器的时间捕获功能测量。
在代码层面,PPM 解码通常用输入捕获中断。MCU 捕获到每次上升沿或下降沿的时间戳,时间差就是电平持续时间,再根据帧周期和通道间隔来划分通道。如果你要自己写 PPM 解码器,重点关注的不是高电平本身,而是两个上升沿之间的时间间隔。这是新手最容易搞反的地方:以为通道值等于脉冲宽度,其实是等于脉冲间隔。
3.3 PPM 的局限性:延迟、精度和协议天花板
PPM 最大的问题是精度和延迟。
精度方面,PPM 的一个通道间隔通常解析到 1 微秒量级,这在 1000 到 2000 微秒的量程里,理论精度大约千分之一。实际中因为帧周期固定,通道间隔受到上一通道和下一通道抖动的影响,精度会更差一些。对于油门、方向这类通道,这个精度完全够用,但如果你用遥控通道去做云台微调或者特殊控制模式,精度不足的问题会暴露出来。
延迟方面,因为所有通道是串行传输的,最后一个通道必须等前面所有通道都"说"完之后才能轮到自己。8 通道 PPM 信号,最后一个通道的更新周期约等于一个完整帧周期,也就是 20 毫秒左右。相比之下,SBUS 全通道串行传输的帧周期是 14 毫秒,延迟更小。
还有一个天花板:PPM 的通道数上限受帧周期限制。标准 20 毫秒周期最多塞 8 到 10 个通道。如果你要 12 通道甚至 16 通道遥控,PPM 就撑不住了。这也解释了为什么现代遥控协议逐渐往 SBUS、CRSF 这类数字协议迁移。
顺便说一句,PPM 是模拟时代的产物,但它并没有完全退役。很多入门级接收机和开源飞控仍然支持 PPM 输入,因为简单、稳定、兼容性好。对于只飞 4 通道、6 通道固定翼或多旋翼的玩家,PPM 依然是够用的方案。
3.4 PPM 适合用在什么场景
基于上面的特性,PPM 的适用场景比较明确。
一是入门级搭建。新手第一次焊飞控、接接收机的时候,PPM 接线最简单,通常只要一根信号线加一根地线,接收机只要有 PPM 输出就够。出错概率低,排查也直观。
二是备用通道少的小型机架。比如 250 级别以下的穿越机,如果你不需要太多通道,用 PPM 可以减少一根线,机身更清爽。
三是对延迟不敏感的飞行器。慢速固定翼、FPV 巡航、测绘无人机,对打杆延迟的敏感度远低于穿越机。这种场景下 PPM 的延迟感知并不明显。
如果你的目标是高速穿越机或竞速机,建议跳过 PPM,直接上 SBUS 或 CRSF。延迟和帧率差距在高速飞行中会直接影响手感。
4. SBUS 深度解析
4.1 SBUS 的信号格式与数据帧结构
SBUS 是由 Futaba 推出的一种串行总线协议,如今已经被大量第三方接收机、飞控、舵机支持,成了遥控链路里事实上的数字标准。
SBUS 底层走的是 UART 串口,波特率固定 100000,8 位数据位、偶校验、2 位停止位。注意这个波特率不是常规的 9600、115200,而是 100000,这导致它不能直接接到普通串口工具上解析,需要专门的硬件或软件适配。
SBUS 数据帧长度固定 25 字节,其中 22 字节是通道数据,每 11 位一个通道,一共 16 个通道。11 位的分辨率意味着通道值范围是 0 到 2047,比 PPM 的精度高了不少。实际飞控通常会把 0 到 2047 映射成 1000 到 2000 的 PWM 值范围,通道 1 到 16 的数据按小端字节序连续存放。
除了通道数据,SBUS 帧里还包含标志位和尾字节。标志位用于指示信号丢失、舵机帧失败等状态;尾字节固定是 0x00。帧之间有一个明显的空闲间隔,接收端根据这个间隔来同步帧边界。
SBUS 信号还有一个坑:逻辑电平是反相的。Futaba 在设计时把信号发出来的时候就是反相的,很多飞控的 SBUS 输入接口内部有反相电路,但如果你买的是那种廉价接收机转接板,可能需要自己加一级反相器。这一点我在后面的"常见问题"里再详细展开。
4.2 用数据视角看 SBUS 与 PPM 的差异
如果只看最终效果,SBUS 和 PPM 都是把遥控器通道数据传给飞控,但数据组织方式截然不同。
PPM 是模拟时序信号:每个通道的数值体现在脉冲间隔里,解码需要精确的定时测量;SBUS 是数字信号:每个通道的数值体现在二进制数据里,解码只需要正确读取字节然后拼位。打个比方,PPM 像摩尔斯电码,靠长短间隔表达信息;SBUS 像普通文本文件,按格式读取即可。
数据率方面,SBUS 的 16 通道同时传输,帧周期 14 毫秒(实际约 7 毫秒高电平 + 7 毫秒低电平,最大 14 毫秒),对应约 70 Hz 的刷新率。这比 20 毫秒周期的 PPM 有优势,而且通道数更多、分辨率更高,所以现代高端遥控器普遍支持 SBUS 输出。
ArduPilot 里对 SBUS 的处理是把串口接收到的字节流按 SBUS 帧结构解析,然后再转成 RC 通道值。如果你接的是 SBUS 信号,注意接收机接飞控的线要接到 RC_IN,而不是普通串口。很多飞控的 SBUS 输入口和 PPM 输入口是同一个物理接口,固件自动识别协议类型,但硬件上需要有反相电路。
4.3 SBUS 的优势和局限
优势第一条就是通道数和精度。16 通道对绝大多数无人机绰绰有余,11 位分辨率也能满足精细操作需求。
优势第二条是延迟更低。数字协议不需要像 PPM 那样等待帧周期全部走完,数据打包后一次性传输,处理效率更高。对于穿越机选手来说,SBUS 比 PPM 延迟低是一种可感知的改善。
局限方面,SBUS 最大的问题是兼容性。它毕竟是 Futaba 制定的私有协议,虽然被广泛支持,但在细节上各厂商实现并不完全一致。部分廉价接收机输出的 SBUS 信号时序不稳定,偶发丢帧;部分飞控对 SBUS 的反相处理不够好,导致信号无法识别。
另一个局限是 SBUS 能传输的信息种类有限。它只是单向遥控通道数据,不支持回传。如果你需要接收机把 RSSI(接收信号强度)等参数回传给飞控甚至地面站,得找支持相应回传协议的接收机,或者另外走一条遥测链路。这一点和 MAVLink 的丰富消息体系形成鲜明对比。
4.4 SBUS 的适用场景
SBUS 几乎覆盖了 PPM 的全部场景,而且更优秀。所以如果条件允许,建议优先用 SBUS。
穿越机和竞速机是 SBUS 的最大受益者。低延迟、高刷新率让打杆反馈更跟手,这也是穿越机玩家普遍追求数字协议的原因。
大型多旋翼和固定翼也是 SBUS 的主场。你可能有 8 通道甚至 12 通道的需求,比如控制起落架、云台、投掷器、相机触发等,SBUS 可以轻松满足。
还有一个实用场景是飞控调参。当你需要在地面站里观察遥控器各通道的输入是否正常时,SBUS 提供更准确的数值,映射后的通道值稳定,很少出现 PPM 那种跳变。
5. 三者对比:怎么选怎么用
5.1 一张表看懂 MAVLink、PPM、SBUS
| 对比维度 | MAVLink | PPM | SBUS |
|---|---|---|---|
| 通信层级 | 遥测/任务链路 | 遥控输入链路 | 遥控输入链路 |
| 信号类型 | 二进制串行数据包 | 模拟时序脉冲 | 数字串行数据 |
| 传输内容 | 状态、指令、航点、参数等 | 1-10 通道的遥控值 | 1-16 通道的遥控值 |
| 典型波特率/帧率 | 57600/115200 等,取决于链路 | 每帧 20-25ms | 每帧 14ms,100000 波特率 |
| 通道分辨率 | 不适用(消息字段) | 约 1us 间隔 | 11 位(0-2047) |
| 是否需要专门硬件 | 串口/TTL/数传模块 | 输入捕获引脚 | UART + 反相电路 |
| 双向通信 | 支持(飞控与地面站双向) | 不支持(单向) | 不支持(单向) |
| 可扩展性 | 消息可以自定义 | 受帧长限制 | 固定结构,不可扩展 |
| 适用场景 | 地面站交互、自动驾驶、编队 | 入门机、低通道数 | 穿越机、多通道高端机 |
这张表建议大家存下来。选型的时候先问一句:这条链路上要传什么?如果是遥控操作指令,在 PPM 和 SBUS 之间二选一;如果是飞控与电脑之间的状态和任务,那考虑 MAVLink。
5.2 从硬件层面看信号线应该怎么接
硬件接线是新手最容易困惑的地方。
PPM 接收机通常有 CH1 到 CH8 的引脚,其中 CH1 或标注为 PPM 的输出引脚输出合并后的 PPM 信号。把该引脚接到飞控的 RC IN 信号脚即可。
SBUS 接收机一般有一个专门的 SBUS 引脚,如果没有,有的接收机允许你在编程设置里把某个通道改成 SBUS 输出。把 SBUS 引脚接到飞控的 SBUS/RX 输入脚,注意部分飞控还需要一根反向信号线。很多现代飞控都集成了 SBUS 反相电路,直接接就行;老飞控或者自制的转接板上,可能需要三极管反相电路。
MAVLink 走的是数传串口。Pixhawk 系列飞控上有 TELEM1、TELEM2 接口,每一个都是四针:TX、RX、VCC、GND。接数传模块时,飞控的 TX 接数传的 RX,飞控的 RX 接数传的 TX,VCC 和 GND 对应接好。如果你用的是机载电脑,可以直接用 USB 线连飞控的 USB 口,或者通过 UART 转接板连接。
5.3 从软件层面看三种协议的配合
一台完成了的无人机,软件层面往往是三种协议同时在工作。
飞控启动后,接收机通过 PPM 或 SBUS 输入遥控信号,经过协处理器或主控解码后,映射到 RC 通道值(RC Channel)。ArduPilot 把通道 1-4 默认映射为 Roll、Pitch、Throttle、Yaw,通道 5 以上是模式开关和辅助开关。地面上你在 Mission Planner 的 RC 界面看到的值,就是经过映射后的结果。
与此同时,飞控通过 MAVLink 持续向外广播心跳和状态消息。地面站收到后,把飞控模式和传感器状态显示在界面里。你在地面站上点"写航点",地面站就把航点数据用 MAVLink 消息发送给飞控,飞控存储到参数和任务列表里。飞行时,飞控根据 MAVLink 下发的任务和当前姿态解算控制输出,同时继续通过遥控链路接收手动打杆指令。
三者的配合核心是:遥控链路和数传链路是独立的两套通路,飞控是它们的交汇点。如果你想做更高级的开发,比如在机载电脑上写 Python 脚本控制飞行,实际上是在和 MAVLink 打交道,而不是直接干涉 PPM/SBUS。
6. 实战:用 Python 通过 MAVLink 给 ArduPilot 发航点
6.1 环境准备与连接方式
这一节我们进入实操。假设你手里有一台 ArduPilot 飞控(Pixhawk 系列或同类),目标是通过 USB 或数传连接电脑,用 Python 代码向飞控下发一组航点。
推荐用 pymavlink 这个 Python 库。它是 MAVLink 官方生态的 Python 实现,安装很简单:
pip install pymavlink连接方式有两种。USB 直连时,Linux 下一般识别为 /dev/ttyACM0,Windows 下是 COM3 之类;数传模块连接时,通常是一个串口设备。确定设备路径后,用 pymavlink 建立连接:
from pymavlink import mavutil # USB 直连时波特率通常 115200,数传则按数传模块的波特率设置 master = mavutil.mavlink_connection('/dev/ttyACM0', baud=115200) # 等待飞控心跳,确认通信链路正常 master.wait_heartbeat() print("收到心跳,飞控在线")如果这一步卡住了,先检查设备路径是否正确、串口是否被占用、波特率是否匹配。常见的坑是插着 Mission Planner 占用了串口,导致 Python 无法打开。
6.2 发送航点的完整代码
ArduPilot 的航点上传遵循一个明确的消息握手流程:先发 MISSION_COUNT 声明航点数量,然后逐个处理飞控返回的 MISSION_REQUEST_INT 请求,每个请求对应一个航点索引,我们用 MISSION_ITEM_INT 把对应航点发送过去,最后飞控返回 MISSION_ACK。
下面是一份可以直接跑通的示例代码,往飞控上传两个航点:
import time from pymavlink import mavutil master = mavutil.mavlink_connection('/dev/ttyACM0', baud=115200) master.wait_heartbeat() # 清除当前任务,避免旧航点干扰 master.mav.mission_clear_all_send(master.target_system, master.target_component) # 等待清除确认 ack = master.recv_match(type=['MISSION_ACK'], blocking=True) print(f"清除任务结果: {ack}") # 定义航点列表:(纬度, 经度, 相对高度) waypoints = [ (31.123456, 121.654321, 20.0), (31.123457, 121.654322, 25.0), ] # 发送航点数量 master.mav.mission_count_send(master.target_system, master.target_component, len(waypoints), 0) # 逐个响应飞控的请求 sent = 0 while sent < len(waypoints): msg = master.recv_match(type=['MISSION_REQUEST_INT', 'MISSION_REQUEST'], blocking=True) seq = msg.seq lat, lon, alt = waypoints[seq] master.mav.mission_item_int_send( master.target_system, master.target_component, seq, # 航点序号 mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT, # 坐标系:全局相对高度 mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, # 命令类型:普通航点 0, 0, # 是否继续自动航点、是否从当前点开始 0, 0, 0, # 参数1-3:停留时间、半径、通过半径 int(lat * 1e7), # 纬度,单位 1e-7 度 int(lon * 1e7), # 经度 float(alt), # 高度 0, 0, # 相机相关参数,不需要就置 0 mavutil.mavlink.MAVLINK_TYPE_MISSION_ITEM_INT ) sent += 1 # 等待最终确认 ack = master.recv_match(type=['MISSION_ACK'], blocking=True) print(f"航点上传结果: {ack}")这段代码有几点需要解释。
纬度、经度用 int 类型,单位是 1e-7 度,所以要把浮点数乘以 1e7 再取整。如果你直接填浮点数,飞控会解析错误。
坐标系用了 MAV_FRAME_GLOBAL_RELATIVE_ALT,意思是经纬度取全局真实坐标,高度取相对于起飞点的海拔。这是大多数无人机任务的默认选择,因为不需要知道绝对海拔,也不用担心气压计漂移。
参数 1、2、3 的含义随命令类型变化。对 NAV_WAYPOINT 来说,参数 1 是停留时间(秒),参数 2 是到达半径(米),参数 3 是通过半径(米)。常用的设置是参数 2 设为 0.2 到 0.5 米,表示飞机到距离航点中心这么多米就算到达。
航点上传成功后,你可以用下面代码切到 AUTO 模式,让飞控执行任务:
# 切换飞行模式 mode_id = master.mode_mapping().get('AUTO') if mode_id is None: print("未知模式") else: master.set_mode_apm(mode_id)注意 ArduPilot 默认要求解锁后才能自动起飞执行任务。如果你只是测试航点上传,不需要解锁,上传成功后在地面站里也能看到任务列表被更新。
6.3 自定义 MAVLink 消息的实现思路
热词里提到"MAVLink 自定义消息",这里展开讲一下。MAVLink 2 之所以比 MAVLink 1 强大,除了签名和扩展性之外,一个关键点是支持在 XML 中定义自己的消息,然后生成对应的编解码代码。
pymavlink 支持自定义消息。步骤是:
- 在某个目录里新建一个 XML 文件,比如 my_messages.xml,里面用 MAVLink 的 XML 语法定义消息名、ID、字段。
- 用 mavgen.py 脚本生成 Python 代码。
- 把生成的代码放进项目里,import 后就能使用自定义消息。
例如定义一个简单的调试消息:
<mavlink> <messages> <message id="150" name="MY_DEBUG"> <description>Custom debug message</description> <field type="float" name="value">A float value</field> <field type="uint16_t" name="index">Index number</field> </message> </messages> </mavlink>生成代码后,发送方调用 my_debug_send 发送,接收方在 mavlink 回调里捕获 MY_DEBUG 消息即可。
不过要提醒一句:自定义消息只适合两端都是你控制的设备。如果一端是标准地面站或标准 MAVLink 库,对方不会解析你的自定义消息,可能会报警或忽略。实际项目中,我一般建议优先用标准消息里已有的字段,或者用 DEBUG_VECT、STATUSTEXT 这类通用消息来传递调试信息。只有确实没有标准方案时,才考虑自定义消息。
7. 常见问题与排查技巧
7.1 遥控器没反应,飞控收不到通道输入
这是新手最高频的问题。接好线、通电、对频成功,但打杆没反应。
排查顺序建议按下面来:
- 打开 Mission Planner 的 Radio Calibration 页面,观察通道值是否随打杆变化。如果通道值不动,说明接收机和飞控之间的链路没通。
- 确认接线是否正确。很多飞控的 RC_IN 接口是有方向性的,信号线、电源线、地线的引脚定义别接反。
- 如果信号线接了但没反应,检查接收机是否真的输出了 PPM 或 SBUS。有的接收机出厂默认 PWM 输出,需要进接收机设置里改协议。
- 检查飞控的 RC_PROTOCOLS 参数。ArduPilot 里 RC_PROTOCOLS=0 表示自动检测,有些自定义固件里默认值可能不同,需要改成 0 或指定协议。
- 确认固件版本。老版本固件对 SBUS 反相的支持可能不完善,更新固件后重试。
7.2 SBUS 信号接反或接收失效
SBUS 最经典的坑就是反相。我把話放这里:几乎每个从 PPM 转 SBUS 的玩家都踩过这个坑。
当你把 SBUS 接收机接到飞控,发现飞控死活不识别通道值时,第一反应应该是检查信号反相。最简单的方法是用逻辑分析仪抓一下 SBUS 引脚的电平。正常 SBUS 信号在空闲时是低电平;如果抓到的空闲电平是高电平,说明信号是反相的。
解决方式有三种:
- 购买支持自动反相的接收机或飞控。现在主流的 Pixhawk 飞控大多内置反相电路,不需要额外处理。
- 自己做一个反相电路。用一个 NPN 三极管就能实现,网上有现成电路图。
- 用飞控内部参数处理。部分飞控固件里的 RC_PROTOCOLS 或 SERIAL_OPTIONS 参数有"Signal Inverted"选项,调节后可能解决。
另外注意:有些飞控的 SBUS 输入引脚和 UART 引脚复用,如果你在参数里把对应的串口设为其他功能,SBUS 输入可能会失效。
7.3 MAVLink 通信丢包或连不上地面站
MAVLink 连接不上的原因五花八门,最常见的有三个。
串口被占用。Mission Planner 或其他地面站程序占用着串口,你再开 Python 或者第二个地面站,肯定连不上。解决办法是关闭其他程序,或者用不同的 USB 口。
波特率不匹配。飞控端 TELEM1 默认波特率一般是 57600,USB 口默认 115200。如果你用数传模块连接,数传模块空中波特率为 57600,地面端也要配成 57600。曾经有个朋友把数传模块的地面端波特率设置成 115200,连接上但数据全是乱码,排查了好久才发现是波特率问题。
线路接触不良或数传模块供电不足。数传模块虽然有 VCC 和 GND 接线,但个别质量差的 USB 转串口线供电能力弱,导致数传模块无线重连。这种问题表现很诡异:心跳偶尔能收到,但很快断开。建议用独立供电的 USB Hub,或者换一根质量好的数据线。
7.4 协议转换模块怎么选
硬件的世界里,还有一种常见需求是把一种协议转成另一种。比如某些飞控只有 PPM 输入,而你的遥控器接收机只支持 SBUS 输出;或者你想用地面站通过 MAVLink 控制一个只支持模拟遥控输入的飞控。
如果只是 PPM 和 SBUS 互转,市面上有专门的小模块,比如"PPM to SBUS 转换器"或者"SBUS to PPM 转换器"。选这种模块时要看清楚输入输出逻辑电平是否匹配、是否支持反相、通道数上限是多少。便宜的模块可能只转了信号,没有做反相处理,接上去还是不行。
如果是 MAVLink 和其他协议的转换,就有意思了。很多开源项目比如 MAVProxy、QGroundControl 本身就支持多种 MAVLink 传输端点,用一根 USB 线连接飞控和电脑,不需要额外模块。如果你需要在物理层把 MAVLink 转成串口透传,基本就是一个 UART 转 TTL 模块,没有协议上的魔法。
8. 最后分享几个实操心得
写到这里,我把这几年和这三类协议打交道的体会一并说透,希望能帮你少走弯路。
第一个心得:信号完整性的优先级远高于协议本身。不管是 PPM、SBUS 还是 MAVLink,信号线一定要用短线、屏蔽线或者双绞线,并且避开电调和大电流线。无人机上电调产生的电磁干扰非常强,我曾经在一个四轴上把接收机信号线和电调线平行走,结果 SBUS 信号在地上站上表现为间歇性丢通道,重新布线后才恢复正常。别小看这种问题,排查起来非常费时间。
第二个心得:动手前先做地面测试。拿到一套新飞控、新接收机,不要直接上桨,先接好所有线,进入 Mission Planner 或 QGroundControl 检查通道映射、模式切换是否正常,再用文字指令或者模拟器验证 MAVLink 通信。我见过不少飞友在装好机后首次试飞,因为通道方向反了直接翻机。地面测试花 10 分钟,能避免炸机的损失。
第三个心得:尽量用较新版本的 MAVLink 和固件。ArduPilot 从 4.1 开始默认使用 MAVLink 2,对自定义消息、签名、扩展字段的支持都更好。如果你还在用老固件,建议升级到 4.1 以上,很多莫名其妙的兼容性问题会在升级后消失。
第四个心得:对数传链路带宽做一点规划。MAVLink 默认的 SRx 参数设置的是每秒发送几条消息,如果你同时连接地面站和机载电脑,两个消费端会共享链路带宽。有时候地面站显示卡顿,不是硬件问题,而是因为 SR0_EXTRA 里配置了太多不必要的高频消息。按需关闭一些消息,你会发现链路稳定很多。
第五个心得:不要把 SBUS 和 CRSF 搞混。同样是数字串行协议,SBUS 是 100000 波特率、偶校验、2 停止位、11 位通道;CRSF 是 420000 波特率、8N1、每个通道 16 位,还支持双向通信。穿越机圈子里现在 CRSF 越来越流行,因为它延迟更低,还能回传遥控器和接收机状态。如果你买的是 ExpressLRS 接收机,默认输出通常是 CRSF,不是 SBUS。接错后飞控不识别,是玩穿越机最容易犯的错之一。
如果你能把 MAVLink、PPM、SBUS 这三条线彻底理解透,无人机在你的眼里就不再是一堆线和参数,而是一套可以灵活组合、按需定制的完整系统。希望这篇长文能帮你把最基础、也最关键的一环打结实。