很多人第一次玩无人机,手里同时捏着两块板子:一块 Pixhawk 飞控,一块树莓派。Pixhawk 负责飞行控制,树莓派拿来跑高级功能,但真到接线的时候,不少人卡在“树莓派到底怎么和飞控说话”这一步。我最早也在这个问题上折腾了一整个周末,后来搞明白其实核心就一件事:让两者通过 MAVLink 协议在串口上建立连接。这篇文章就是把树莓派连接 Pixhawk 的完整流程拆开讲一遍,从硬件选型、系统配置到实际接线、数据验证,再到后面跑 MAVROS、做数传中继,所有环节我都会按自己踩过的坑来写。不管你用 USB 还是 GPIO 串口,看完之后应该都能自己把链路调通。
1. 整体设计与思路拆解
1.1 为什么要在飞控旁边放一台树莓派
Pixhawk 这类飞控,说白了是一个实时控制器。它跑的是 PX4 或 ArduPilot 固件,负责姿态解算、位置估计、电机控制这些对实时性要求极高的工作。但它的 CPU 和内存都很有限,跑不了 Linux,也装不了 OpenCV、深度学习模型这类东西。而树莓派是一台完整的 Linux 小电脑,算力比飞控高一个量级,还能接摄像头、接 Wi-Fi、跑 ROS。把树莓派和飞控组合起来,就成了无人机开发圈里最常见的伴机电脑方案,官方叫 companion computer。
这个组合能做的事很多。最典型的是机载视觉:摄像头接在树莓派上,跑目标检测或者避障算法,再把计算结果通过 MAVLink 发给飞控,让飞控去执行。其次是通信中继:树莓派连上 Wi-Fi 或 4G,地面站通过局域网或公网连到树莓派,就相当于给飞控加了一条网络数传。哪怕你只是想在飞行过程中多存一份日志,或者在飞控不方便插线的时候远程改参数,树莓派都能接得上。
在选型上,树莓派 4B 是目前性价比最稳的选择,4GB 版本足够跑 MAVROS 加简单的视觉程序;树莓派 5 性能更强,但散热和功耗要额外照顾;如果只是做伴机电脑、不想太重,Zero 2W 也能胜任,只是 GPIO 排针需要自己焊。飞控这边,Pixhawk 4、Pixhawk 6C、Cube 系列都支持标准的 MAVLink 串口和 USB,选型时重点看有没有引出 TELEM 接口,别买那种阉割版飞控板。
1.2 三种连接方式怎么选
树莓派和 Pixhawk 之间的物理连接,我实际试过的主要有三种:USB、UART(飞控上的 TELEM 口)、SPI。SPI 一般是 Pixhawk 6X 这类新板子给高速外设准备的,配置相对复杂,普通玩家用得少。真正日常用到的就是 USB 和 UART,两者各有各的适用场景。
| 连接方式 | 优点 | 缺点 | 适合场景 |
|---|---|---|---|
| USB | 即插即用,驱动简单,不用改飞控参数 | 线重、接口松动风险、占用 USB 口 | 桌面调试、开发验证 |
| UART(TELEM) | 连接稳定,适合装机后长期使用,重量轻 | 需要改树莓派串口配置和飞控参数 | 机载部署、飞行使用 |
| SPI/其他 | 带宽高、延迟低 | 配置复杂,板子兼容性不一 | 高速外设、特殊项目 |
我的建议是:第一次调通先用 USB,因为 USB 是插上就能用,先把 MAVLink 数据链路跑起来,确认整个流程没问题了,再换成 UART 做最终装机。这个顺序能帮你把“线没接对”和“软件配置不对”两类问题分开排查,少走很多弯路。另外要注意,USB 连接虽然方便,但在多旋翼上长时间飞行时不推荐,因为 USB 头容易在振动中松脱,一旦松了通信就断了。
1.3 通信协议先搞明白:MAVLink 是什么
不管是 USB 还是 UART,树莓派和飞控之间“说话”用的都是同一个协议:MAVLink。它是一套轻量的消息协议,飞行数据、姿态、GPS 坐标、遥控指令、参数读写,全都封装成一条条消息在线路上传输。飞控每隔一定时间会主动往外发一个心跳包,告诉对端“我还活着”,这也是我们判断链路通了没有的最直观标志。
你不需要把 MAVLink 的每个字段都背下来,但心里要有个数:树莓派上的所有工具,不管是 MAVProxy、MAVROS 还是 QGroundControl,本质上都是在收发 MAVLink 消息。链路通不通,就看能不能收到心跳;功能做不成,大概率也能从消息流里看出来是哪条消息没对上。理解了这一层,后面所有操作都会变得顺理成章。
2. 准备工作与软件环境
2.1 树莓派系统安装
连接之前,先把树莓派的系统准备好。我用的镜像一直是 Raspberry Pi OS 64 位版本,可以用官方 Raspberry Pi Imager 烧录。烧录完成后,首次开机前建议在 Imager 里就把 SSH 打开、设置好 Wi-Fi 和用户名密码,这样你就不需要外接显示器和键盘,直接通过 SSH 进树莓派操作,后面全程命令行就行。
系统启动后,先用sudo apt update && sudo apt upgrade把系统更新一遍,再装几个后面一定会用到的包:python3-pip、git、screen。如果你的网络环境访问官方源慢,就顺手换个国内镜像源,操作按你的发行版版本改/etc/apt/sources.list和对应的 sources.list.d 文件即可。这里提醒一句,树莓派 5 和树莓派 4 的系统源路径略有差别,别直接复制别人的配置文件,看清楚版本再动手。
树莓派的用户名建议设置得简单点,后面连接飞控和定义串口权限都会用到。我个人习惯默认的pi用户,因为很多现有教程、脚本和 systemd 服务都默认写pi的路径,如果你改成别的用户名,可能会遇到一些莫名其妙找不到目录的问题。
2.2 打开 GPIO 串口,并处理端口权限
这是整个教程里最容易踩坑的一步。树莓派的 GPIO 14 和 GPIO 15 引脚是板载 UART,但默认情况下,树莓派系统并没有把这对引脚作为普通串口暴露出来,尤其是树莓派 3B/4B 这一代,板载 UART 默认被蓝牙占用,GPIO 上的串口状态很混乱。为了让飞控能接在 GPIO 上,你需要手动开启串口,并把蓝牙占用的那个 PL011 UART 释放出来。
具体操作是编辑/boot/config.txt(树莓派 5 上是/boot/firmware/config.txt),在文件末尾加两行:
enable_uart=1 dtoverlay=disable-bt第一行让 GPIO 上的 UART 生效,第二行把 PL011 UART 从蓝牙手上拿回来给 GPIO 用。保存后重启,再用ls -l /dev/serial*检查,正常情况下你会看到/dev/serial0这个符号链接,它指向真正的串口设备。拿不准用哪个设备名的时候,用/dev/serial0准没错。
串口设备默认权限是 root 用户,普通用户直接访问会报 Permission denied。把当前用户加进 dialout 组:
sudo usermod -a -G dialout $USER然后注销重新登录,或者干脆重启一次,权限就生效了。这里一个小细节:如果系统里还有蓝牙相关的服务,disable-bt 之后可以顺手执行sudo systemctl disable hciuart,避免它反复抢占串口资源。还有一点,树莓派默认把启动日志输出到串口,如果不去掉内核参数里的console=serial0,115200,系统启动日志会一直霸占这个串口,MAVLink 数据就没法正常收发,这一步在后面排查乱码时特别重要。
2.3 飞控端该准备的参数
飞控端不用动硬件,但要确认两件事:固件版本,以及对应的串口参数。如果你用的是 USB 连接,大多数固件根本不用改参数,插上就能通信。但如果你打算用 UART(TELEM 口),就需要在飞控上把对应串口配置成 MAVLink 模式。
以 ArduPilot 固件为例,TELEM2 口一般是 SERIAL2 端口,对应的参数是SERIAL2_PROTOCOL,把它设为 2(表示 MAVLink2);波特率参数SERIAL2_BAUD设为 57,表示 57600。固件不同参数名会有差异,比如 PX4 里一般是SER_TEL2_BAUD这类名字。改完参数后,一定要重启飞控让它生效,然后在 QGroundControl 里重新连接,确认参数确实被写进去了。
出门右转,第一次接触飞控的读者可能对“刷固件”也不熟。刷固件的方式很简单:先把飞控用 USB 连到电脑,打开 QGroundControl,它会自动识别飞控型号和当前固件,在 Firmware 页面选择 PX4 或 ArduPilot 对应的固件版本,点烧录即可。刷完固件之后再进参数页面去改刚才说的串口参数,顺序不要反。
另外一个最容易忽略的点:Pixhawk 的 TELEM 口引脚定义。虽然大部分飞控的 TELEM2 都兼容标准 JST-GH 6 针接口,排列是 TX、RX、VCC、GND、CTS、RTS,但不同品牌会做调整。接线之前先把你的飞控说明书翻出来,看清楚哪个是 TX、哪个是 RX,千万别想当然,接反了串口一点都不工作。
3. 连接实操:两种方式都给你走一遍
3.1 先用 USB 把链路打通
如果你手头有 Pixhawk 和树莓派都在桌面上,第一步别纠结 GPIO,直接找一根能传数据的 USB 线,把飞控和树莓派连起来。树莓派上电后,飞控也会通过 USB 取电启动。这时候在树莓派终端里跑:
lsusb应该能看到飞控对应的厂商 ID。然后再看:
ls /dev/ttyACM*正常情况会列出/dev/ttyACM0,这就是 Pixhawk 通过 USB 枚举出来的串口设备。如果设备名没出现,先检查 USB 线是不是只能充电不能传数据的线,这个问题我遇到不下三次。别小看这一点,很多人的飞控在地面站里能连,插到树莓派上就不识别,最后发现是用的充电线。
树莓派上要跟飞控对话,最顺手的是 MAVProxy。安装很简单:
pip3 install --user mavproxy然后启动连接:
mavproxy.py --master=/dev/ttyACM0 --baudrate 115200启动后如果看到MAV>提示符,并且终端里持续滚动 logged、heartbeat 这类信息,说明链路已经通了。你可以输入status查看飞控发来的消息统计,看看有没有收到 HEARTBEAT、GPS_RAW_INT、ATTITUDE 这些核心消息。这一条链路通了,后面接什么都好说。
3.2 换成 UART:GPIO 直连飞控
USB 验证没问题后,开始做正式装机用的 UART 连接。接线原则很简单:树莓派的 TX 接飞控的 RX,树莓派的 RX 接飞控的 TX,然后 GND 和 GND 必须连在一起,也就是所谓的共地。简单说就是交叉接,别同名单连。
树莓派 40pin 排针上,GPIO14 是 TXD,GPIO15 是 RXD,GND 随便选一个,比如 pin6。飞控端用 TELEM2 口,多数标准接口定义如下:
| 引脚 | 信号 |
|---|---|
| 1 | TX |
| 2 | RX |
| 3 | VCC(5V) |
| 4 | GND |
| 5 | CTS |
| 6 | RTS |
实际接线只用 TX、RX、GND 三根。树莓派 GPIO14(TX)接到飞控 TELEM2 的 RX 引脚,树莓派 GPIO15(RX)接到飞控 TELEM2 的 TX 引脚,两边 GND 相连。至于 VCC 那根线,一般不建议接——树莓派和飞控各自供电,VCC 接了反而可能造成电源冲突,用共地来保证电平基准一致就够了。
这里再强调一次电平问题:树莓派 GPIO 是 3.3V TTL 电平,Pixhawk 的 TELEM 口同样是 3.3V 逻辑,所以可以直接互连,不需要电平转换模块。但千万别把飞控的电源输出直接怼到树莓派 5V 引脚上,虽然都是 5V,但两边电源没有隔离,负载变化时容易互相干扰。
接好线后,树莓派上访问的串口设备是/dev/serial0。先快速验证一下有没有数据,用 Python 串口库简单读一下:
python3 -m serial.tools.miniterm /dev/serial0 57600如果屏幕上出现各种乱码一样的二进制内容,其实是好信号,说明飞控在源源不断地往这个串口发 MAVLink 数据。乱码只是因为你直接看了原始二进制。真正的调试还是用 MAVProxy 更舒服:
mavproxy.py --master=/dev/serial0 --baudrate 57600看到心跳输出,UART 链路就正式完工了。
3.3 如何判断链路质量好坏
链路通了只是第一步,判断链路好不好同样重要。在 MAVProxy 里输入status,重点看 heartbeat 的计数是不是持续增长;再输入show arming或者观察遥控器通道值有没有更新,能更清楚地看到数据流的连续性。
如果只是桌面短距离测试,UART 一般很稳。真正装机以后,电机运转会产生电磁干扰,串口线尽量用双绞线或者屏蔽线,并且远离电调、电机线。线束长度超过 20 厘米时,更要留意信号完整性,必要时把波特率从 57600 降到 38400,以换取更强的抗干扰能力。这个经验是我在四轴机架上吃过亏之后总结出来的,千万别觉得波特率越高越好,稳定才是第一位的。
4. 进阶:让树莓派真正干起活来
4.1 跑 MAVROS,把飞控接进 ROS
树莓派连接飞控的核心目的是做更复杂的任务,而 ROS 是这一圈子里绕不开的框架。以 ROS 1 Noetic 为例,装 MAVROS 之后,一条命令就能把串口数据转成 ROS topic:
sudo apt install ros-noetic-mavros ros-noetic-mavros-extras roslaunch mavros px4.launch fcu_url:=serial:///dev/serial0:57600USB 连接时把fcu_url改成:
fcu_url:=serial:///dev/ttyACM0:115200启动后,rostopic echo /mavros/state能看到飞控的连接状态,/mavros/imu/data能看到 IMU 数据。到这一步,飞控和树莓派之间的数据通路就完整地接进了 ROS 生态,后面你想做视觉避障、自主航点,都是在这个基础上加功能。
如果你是 ArduPilot 固件,启动文件要用apm.launch而不是px4.launch,两者对消息命名空间的处理有些差异。另外,MAVROS 启动时会自动做飞控和机载电脑的时间同步,如果启动日志里出现 time sync 失败的告警,多半是串口波特率或者设备节点没配对,回 3.2 节重新检查一遍连线。
4.2 把树莓派当成网络数传中继
另一个很实用的玩法,是把树莓派变成飞控的地面站中转。飞控本身带的数传模块距离有限,但树莓派如果连着 Wi-Fi,就能把 MAVLink 数据包转发到局域网内的任何设备上,地面站软件不用再插 USB 线。
MAVProxy 启动时就支持转发:
mavproxy.py --master=/dev/serial0 --baudrate 57600 --out=udp:192.168.1.100:14550其中192.168.1.100改成你的地面站电脑 IP。QGroundControl 里添加一个 UDP 连接,监听 14550 端口,就能远程看到飞控的所有数据。这个方法在调试机架、试飞不太方便插线时特别有用,等于给飞控加了一条 Wi-Fi 数传。
如果要做多路转发,比如一边给 QGC 用,一边给 ROS 节点用,MAVProxy 的--out可以写多个,也可以直接用mavlink-router这种更现代的工具。mavlink-router 的配置文件里把 Endpoint 分别指向 UDP、TCP 和串口,一个进程统一管理,比开好几个 MAVProxy 窗口干净得多。
4.3 从数据链路到机载大脑
如果你已经走到这一步,树莓派就从简单的数据透传工具升级成了真正的伴机电脑。我在实际项目里,最常用的是在树莓派上跑一个 Python 脚本,订阅 MAVLink 的 GPS 和姿态消息,结合摄像头图像做简单的目标跟随;稍微复杂一点的,会直接用 MAVSDK 写几行 Python 代码控制飞机执行航线。
MAVSDK 的用法非常直观。装好之后,几行代码就能读飞控状态:
import asyncio from mavsdk import System async def run(): drone = System() await drone.connect(system_address="serial:///dev/serial0:57600") async for state in drone.core.connection_state(): print("连接状态:", state) asyncio.run(run())这个例子比 MAVROS 轻量很多,适合快速验证链路,也适合写一些小工具。不过它不像 MAVROS 那样直接集成 TF、坐标系转换这些机器人中间件,所以做完整自主系统时,大部分人还是回到 ROS 生态。我的建议是,简单任务用 MAVSDK,复杂系统用 MAVROS,两个都装也不冲突。
刚开始不要一上来就冲视觉和自主飞行,给自己定一个递进目标:先做到树莓派能实时读到飞控姿态,再做能通过树莓派发送指令,最后再加根据外部输入自动改航线。每一步都验证链路可靠,再往下一步走,这个节奏能让你少掉很多头发。
5. 常见问题与排查技巧实录
5.1 飞控插上 USB,树莓派里看不到设备
最常见的三个原因:USB 线是充电线;系统没有用最新镜像导致缺少 CDC 驱动,Raspberry Pi OS 一般不会;或者设备名不是 ttyACM 而是别的。先用lsusb确认飞控有没有被识别,再看dmesg | tail的内核日志,里面会直接告诉你设备被识别成了什么。
如果确认是设备节点名不同,比如/dev/ttyUSB0,问题不大,把后续所有命令里的设备名替换掉就行。另外要注意,树莓派上如果同时插了多个串口设备,ttyACM0 的编号可能漂移,建议用 udev 规则给 Pixhawk 做一个固定别名,网上有现成规则,配置一次能省掉后面不少麻烦。
5.2 串口有数据但 MAVProxy 一堆报错
如果 MAVProxy 启动后反复出现 link error 或者 parse error,先查波特率是否一致。飞控端 SERIAL2_BAUD=57 代表 57600,树莓派端就要用--baudrate 57600,两边差一位都不行。还有一个隐蔽坑:串口设备被系统 console 占用了。如果/boot/config.txt里存在console=serial0,115200这类内核参数,必须把它去掉,不然树莓派系统启动日志会一直在串口上跑,直接跟 MAVLink 数据打架。
检查 console 参数的方法很简单,执行cat /proc/cmdline,如果输出里带着console=serial0或者console=ttyAMA0,就是在占用串口。把/boot/config.txt或/boot/cmdline.txt里对应内容删掉,重启再试。
5.3 接上 UART 后飞控没反应、不启动
先检查接线是不是 RX 和 TX 接反了,这个问题概率最高。其次确认 GND 有没有接,没有共地的话,电平基准都不一致,数据根本没法解调。最后看飞控的 TELEM 口是不是被其他外设占用了——比如某些飞控的 TELEM2 同时接数传模块,串口上同时挂着两个设备,也会导致通信异常。
还有一个小坑是飞控端波特率参数没生效。ArduPilot 的参数改动有些必须重启飞控才生效,有些人改完直接在 QGC 里点断开,参数确实保存了,但飞控还在旧参数下运行,这时候树莓派怎么连都连不上。所以改完参数一定要整机断电重启,不是软重启,是断电再上电。
5.4 飞控在测试中不断重启
这是我见过的最危险的坑。树莓派和飞控同时由一个 5V BEC 供电,电机功率一上来,电压被拉低,飞控就重启了。解决办法是分开供电:飞控用独立的 BEC 供电,树莓派用独立的 5V 电源,两者只通过信号线共地。不要为了少一根线把两个电源并在一起,这不是偷懒的地方。
如果你实在只有一个电源,就必须加一个大电容或者用带足够余量的 BEC。很多 30A 以上的电调内置 BEC 输出标称 5V 3A,看起来够用,但低速堵转或者舵机猛打的时候瞬时电流可以拉到很大,飞控对这种电压跌落非常敏感。树莓派也有同样问题,它比飞控更挑电,电压稍微低一点就直接重启或者 SD 卡报错。
5.5 最终排查速查表
| 现象 | 大概率原因 | 处理方向 |
|---|---|---|
| /dev/ttyACM0 不存在 | USB 线、驱动 | 换数据线,查 dmesg |
| serial0 不存在 | 串口没开启 | 检查 config.txt |
| MAVProxy 报错 | 波特率不一致 | 两端参数核对 |
| 有数据但解析不出 | 系统 console 占用 | 去掉 console=serial0 |
| 飞控重启 | 供电不足 | 独立供电 |
| 通信时好时坏 | 线材干扰或接触不良 | 换屏蔽线、重新压线 |
| 有连接但无法解锁 | 飞控预解锁检查不通过 | 看 QGC 报错信息,逐个排除 |
如果你已经照着上面这些步骤走完,应该能在树莓派上看到飞控的心跳数据了。我个人在实际操作中的体会是,树莓派连接 Pixhawk 这件事,真正的难点从来不是哪条命令记不住,而是从不稳定的链路里找出问题所在。所以第一次动手,别着急往机架上装,先在桌面上把 USB 链路、UART 链路都调通,再考虑往真机上搬。
最后再分享一个小技巧:装机之后,给树莓派和飞控之间留一点间距,别叠得太紧。飞控上的 IMU 对震动和磁场敏感,树莓派的 SD 卡读写、风扇电机会带来额外干扰,两者靠得太近容易让飞控解锁时报警。分开布置,再加一层减震泡沫,能省掉很多后续排查时间。这个方案还能怎么扩展?等你跑通 MAVLink,就可以继续加数传模块、加摄像头、接 ROS,一步步把它做成真正的机载大脑。