news 2026/9/13 23:15:29

飞控二次开发入门:外挂树莓派与自定义模块两条路径详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
飞控二次开发入门:外挂树莓派与自定义模块两条路径详解

一个从大学就开始折腾航模、后来搞了几年无人机开发的人,我见过太多同学拿到 Pixhawk 之后做的第一件事,就是把 PX4 源码从 GitHub 上 clone 下来,然后盯着src/modules目录发呆两小时,最后默默删掉仓库,关掉电脑。

飞控二次开发,真不是这么玩的。

这个领域确实容易让人迷失方向:网上一搜“飞控二次开发”,出来的不是源码仓库就是晦涩难懂的论文;再点开几个视频,发现大家都在玩树莓派、移植视觉、跑自主飞行,好像每个人都已经搭好了完整的无人机系统。但实际上,飞控二次开发是有清晰路径的,而且它比其他工业软件(比如 Creo、NX、QGIS 那些二次开发)要直观得多——因为你能立刻看到飞机在天上飞。

这篇文章我想把飞控二次开发的两条主流路径一次讲透:一条是外挂树莓派,不碰飞控内部逻辑,靠串口通信在外围做文章;另一条是自定义模块,直接住进飞控固件里,改的是控制算法和任务逻辑。适合刚准备入门的航模爱好者、无人机开发者、以及想把 ROS 和飞控结合起来的同学参考。

1. 为什么劝你别一上来就啃源码

先说说我的观点:源码不是不能啃,而要等跑通流程之后再啃。

很多新手以为二次开发 = 读源码 + 改源码。这个想法在飞控领域尤其容易翻车,原因是飞控的代码复杂度远高于普通应用软件。以 PX4 为例,它包含传感器驱动、状态估计(EKF)、姿态控制、位置控制、导航任务、通信协议、安全机制等一大堆子系统,整个仓库几十万行 C/C++ 代码,实际编译出来的固件还依赖实时操作系统(NuttX)。别说读懂,想找到“改哪一行能起效”都是个技术活。

还有一个更现实的问题:源码改了,你怎么验证?

飞控不像普通的软件,改坏了重新装一个就能继续。它跑在 4~6 个旋翼上面,任何逻辑错误都可能导致炸机。如果你连飞控和地面站的通信都还没打通,连机载日志都不会看,就直接去改 SIM 模式的源码,出了问题你根本不知道是自己写错了还是系统本来就那样。

所以我一直建议初学者把二次开发分成两个阶段:

  • 第一阶段:不改飞控内部,通过对外接口(串口、MAVLink 协议、MAVSDK)控制它。
  • 第二阶段:对系统有一定理解之后,再进入源码层,写自定义模块。

这两个阶段不是对立的,而是递进的。很多人担心“外挂树莓派”是不是太低级,其实完全不是。你看工业界真正落地的无人机方案,绝大多数都是“飞控+机载电脑”架构:树莓派、Jetson 或者香橙派作为上位机,飞控作为执行单元。真正做到源码级别的二次开发,反而集中在飞控厂商和极少数算法团队。

2. 飞控二次开发的完整路径地图

在进入具体操作之前,先梳理一下飞控二次开发的四个层级,这样你就能明白自己现在站在哪里,下一步该往哪走。

2.1 四个开发层级,对应不同能力要求

  • 第一层:参数级。通过地面站改 PID、改飞行模式、调电调和遥控器曲线。这是最基础的一层,几乎每个人都经历过。
  • 第二层:外设级。给飞控接 GPS、数传、摄像头云台、光流传感器、LED 灯带。这需要懂一些硬件接线和串口配置,但不需要动飞控内部逻辑。
  • 第三层:外挂计算单元(机载电脑)。通过树莓派、Jetson 等外部计算设备连接飞控。这是目前应用最广、投资回报最高的一种二次开发方式,也是本文第一条路径的重点。
  • 第四层:源码与自定义模块。直接修改或新增飞控固件中的模块,比如自定义控制律、传感器融合算法、特殊任务逻辑。这是本文第二条路径的重点。

很多人一上来就把目标定在第四层,忽略了前三层的积累。这就像新司机非要学漂移,连油门刹车都没踩熟,结果可想而知。

2.2 两条主线:外挂树莓派 vs 自定义模块

一句话总结这两条路线的区别:外挂树莓派是在飞控外面加一个“外脑”,自定义模块是给飞控本身“换脑”。

外挂树莓派的好处非常明显:开发语言用 Python,生态极其丰富,图像处理、机器学习、ROS 库都能直接用;写错了代码不会影响飞控稳定性,最坏结果就是树莓派重启一下;调试起来也方便,连个屏幕看输出、SSH 上去跑脚本都行。它的缺点是高频率、高实时性的任务做不了,毕竟串口通信本身有延迟,而且飞控和树莓派是两套独立的系统,协同工作会有一定的架构复杂度。

自定义模块则完全不同。它是把代码编译进飞控固件,直接跑在 STM32 等单片机芯片上,实时性有硬件级保证。比如你想实现一个新的滤波算法、一条自定义的飞行任务,或者想在姿态控制里加一个补偿项,这些绕开飞控内部是做不到的。但代价是开发门槛高:需要懂 C/C++、懂嵌入式编译、懂 uORB 消息机制,还要承担刷固件失败导致飞控变砖的风险。

我个人给你的建议是:如果你过去的工作重心在应用层,比如视觉避障、航线规划、物流配送、电力巡检,优先走外挂树莓派路线;如果你对飞控本身感兴趣,想深入系统内部,那自定义模块这条路早晚要过。

3. 路径一:外挂树莓派,用 Python 给飞控加外挂

这是我认为最容易跑通、也最容易被忽视的一条路。它的本质很简单:树莓派通过串口和飞控通信,飞控把姿态、位置、电压等状态告诉树莓派,树莓派再根据你的逻辑发出控制指令。

拿一套常见的穿越机配置举例:LQRC APEX 小胡子 5 寸机架 + SpeedyBee F405 飞控 + 55A 电调,这是很多玩家跑视觉穿越机的标配。F405 飞控从型号上就能看出来用的是 STM32F405 芯片,算力有限,跑不了复杂的视觉算法,但它可以稳定地执行姿态控制。你在它上面挂一个树莓派,树莓派负责把摄像头画面算得出哪里有障碍物,再把“该往左躲”的决策通过串口告诉飞控,飞控负责真正把飞机飞过去。这就是“外挂”的核心价值:各干各的擅长的事。

3.1 硬件接线:一根杜邦线解决通信连接

树莓派和飞控之间的通信,最简单可靠的方式是 UART 异步串口。树莓派 4B 或 5 的 GPIO 排针上,14 脚是 TXD、15 脚是 RXD,把这两个脚接到飞控的 TELEM 串口上,再连通地线,就完成了物理连接。

注意三个坑:

  • 发射接接收,接收接发射。树莓派的 TXD 要接飞控的 RX,树莓派的 RXD 要接飞控的 TX。很多第一次接线的人栽在这里。
  • 一定要共地。树莓派的 GND 和飞控的 GND 要连在一起,否则串口数据会出现乱码。
  • 飞控串口电平一般是 3.3V,树莓派的 GPIO 也是 3.3V,可以直连。如果飞控板子比较老,要注意确认电平是否兼容,不匹配就需要电平转换模块。

接好线之后,在树莓派端查一下端口名,通常是/dev/ttyAMA0/dev/serial0。如果用的是树莓派 4B/5,默认硬件串口可能被蓝牙占用,需要做一步处理,后面会细说。

3.2 飞控端串口配置,别漏掉这两个关键项

硬件接好了,飞控还得告诉它“老子的这个串口要用来跟树莓派说话”。

以 PX4 飞控为例,连接 QGroundControl 后,进入参数设置界面,找到MAV_1_CONFIG,把它设置为你接线的那个串口编号(比如 TELEM2)。然后设置MAV_1_BAUD为 57600。两个参数都要改,只改一个飞控不会正常输出 MAVLink 数据。

如果是 ArduPilot 固件,对应的是SERIAL2_PROTOCOL=2SERIAL2_BAUD=57。参数名略有差异,但逻辑一模一样:启用串口、指定协议、设置波特率。

如果你用的是 Betaflight 穿越机飞控,情况稍有不同。Betaflight 默认用 MSP 协议和外部设备通信,在 CLI 里输入resource查看可用 UART,然后用serial 1 0 115200 57600 0 115200这种命令把串口配置成 MSP 模式。树莓派端再配合msp相关的 Python 库来读取姿态。这一块略显折腾,但原理上还是串口通信那点事。

3.3 树莓派端装好环境:pymavlink 是主角

树莓派端的工作,本质上是把 MAVLink 协议用起来。

MAVLink 是 Pixhawk 项目组制定的无人机通信协议,它定义了飞控和地面站、机载电脑之间通信的消息格式。好消息是你不需要手写协议解析,Python 生态里已经有现成的库:pymavlinkdronekit

在树莓派上执行:

sudo apt update sudo apt install python3-pip sudo usermod -a -G dialout $USER pip3 install pymavlink pyserial

usermod那一步是把当前用户加入dialout组,否则你很可能遇到串口权限不够的问题。改完组之后需要重新登录或者重启树莓派。

如果 pip 安装速度慢,可以把 pip 源换成国内镜像,比如清华源或阿里云源,具体做法是编辑~/.pip/pip.conf。这个属于基础操作,就不展开了。

3.4 实战:读取姿态数据,先让数据动起来

环境装完之后,第一件事不是急着写控制逻辑,而是先确认树莓派能收到飞控的数据。

我这里给一个最小可用的读取代码:

from pymavlink import mavutil # 串口设备名和波特率要和飞控端配置一致 master = mavutil.mavlink_connection('/dev/ttyAMA0', baud=57600) # 等待飞控心跳包 master.wait_heartbeat() print("心跳连接成功,飞控已上线") while True: msg = master.recv_match(type='ATTITUDE', blocking=True) if msg: print(f"roll: {msg.roll:.2f} pitch: {msg.pitch:.2f} yaw: {msg.yaw:.2f}")

运行之后,如果串口线和飞控参数都配置正确,你会看到终端里不断滚出当前的姿态角数据。手动晃动一下飞控,数值会跟着变化。看到这个画面,说明“外挂”这条路已经打通了一半。

如果你手边有树莓派官方摄像头 OV5647,还可以同时把画面推上来自主的视觉任务:树莓派计算视野里的目标位置,再把偏差换算成控制指令发给飞控。很多视觉避障和循迹飞行的原型就是这么搭出来的。

3.5 实战:从树莓派发送控制指令

读数据只是第一步,真正的二次开发是要让树莓派作为“大脑”去指挥飞控。

这里以一个常见的解锁并起飞动作为例:

import time from pymavlink import mavutil master = mavutil.mavlink_connection('/dev/ttyAMA0', baud=57600) master.wait_heartbeat() # 切换飞控模式到 GUIDED(引导模式) mode = 'GUIDED' mode_id = master.mode_mapping()[mode] master.set_mode(mode_id) master.arm_disarm(True) time.sleep(2) # 发送起飞指令,目标高度 10 米 master.mav.command_long_send( master.target_system, master.target_component, mavutil.mavlink.MAV_CMD_NAV_TAKEOFF, 0, 0, 0, 0, 0, 0, 0, 10 )

如果你想做更细粒度的航点控制,比如让飞机飞到指定的经纬度和高度,可以发送SET_POSITION_TARGET_GLOBAL_INT消息。这类消息的参数比较多,建议去查 pymavlink 的官方文档,这里不展开详细字段了。

提示:在室内测试时一定要绑好机架或者去掉桨叶,相信我,每个人在第一次跑通控制脚本时都会手忙脚乱。

关于代码里没有解释清楚的协议细节,我补充一个经验:MAVLink 消息分为请求和命令两类,很多新手只记得发命令,却忘了检查飞控是否真的执行了。调试阶段建议把recv_match打印出来,看飞控返没返回COMMAND_ACK,只有收到 ACK 才代表命令真正被接受。

另外,如果你的飞控是 Betaflight 系统的,上面这套 MAVLink 代码不适用,记得找 MSP 协议的库。

4. 路径二:自定义模块,真正住进飞控内部

外挂树莓派玩熟之后,你会发现有些事在外部做不了:比如你想给飞控加一个“检测到剧烈震动时自动降低油门响应”的功能,或者你想实现一种飞控本身没有的飞行模式。这时候就需要进入自定义模块的世界了。

这条路径以 PX4 为例来讲,因为 PX4 的模块化设计在开源飞控里是最清晰的,非常适合学习。

4.1 先用仿真跑起来:开发环境搭建

自定义模块开发的第一步,不是买硬件,而是把仿真环境跑起来。

PX4 官方支持 Gazebo 仿真。在你的开发机(不需要是树莓派)上执行:

git clone --recursive https://github.com/PX4/PX4-Autopilot.git cd PX4-Autopilot make px4_sitl gazebo

第一次编译会下载工具链和依赖库,时间根据网络情况从十几分钟到一个小时不等。如果卡在下载环节,优先检查网络,并考虑使用国内镜像源加速。

仿真环境启动后,你会看到一个虚拟的无人机在 Gazebo 里出现,这个时候你就可以在不炸机的前提下,随便折腾代码,重启模拟器就恢复了。我个人强烈建议:自定义模块开发的前期,所有测试都在仿真中进行,等逻辑稳定后再刷到真机上。

4.2 摸清模块长什么样:uORB 通信模型

PX4 内部模块之间不直接调用函数,而是通过一个叫 uORB 的消息总线进行通信。每个模块要么订阅(subscribe)自己关心的话题,要么发布(publish)自己产出的数据。

举个例子:姿态估计模块计算完飞机姿态后,会发布vehicle_attitude话题。姿态控制模块订阅这个话题,拿到姿态数据后计算控制量,再发布给电机驱动模块。整个过程像一个公开的布告栏:任何人可以把信息贴上去,任何人也可以来读。

理解这个模型,是自定义模块开发的关键。你不需要关心别人怎么实现的,只需要知道你需要的消息在哪个话题上,以及它包含什么字段。常用的话题包括:

  • vehicle_attitude:姿态四元数
  • vehicle_local_position:本地位置和速度
  • sensor_combined:传感器原始数据
  • battery_status:电池电压和剩余电量

4.3 写一个自定义模块需要准备什么

一个最基本的 PX4 自定义模块,通常包含三个部分:模块入口程序、CMakeLists.txt 编译配置文件、启动脚本。

模块入口程序的简化示意:

#include <px4_platform_common/px4_config.h> #include <px4_platform_common/tasks.h> #include <uORB/uORB.h> #include <uORB/topics/vehicle_attitude.h> extern "C" __EXPORT int my_hello_main(int argc, char *argv[]); int my_hello_main(int argc, char *argv[]) { int sub = orb_subscribe(ORB_ID(vehicle_attitude)); struct vehicle_attitude_s att{}; while (true) { orb_copy(ORB_ID(vehicle_attitude), sub, &att); PX4_INFO("roll: %f pitch: %f", (double)att.roll, (double)att.pitch); px4_usleep(100000); } return 0; }

CMakeLists.txt 里声明模块:

px4_add_module( MODULE modules__my_hello MAIN my_hello STACK_MAIN 2000 SRCS my_hello.cpp DEPENDS )

这段代码的作用是订阅姿态话题,然后每 100 毫秒打印一次滚转和俯仰角。虽然是简化版,但它体现了自定义模块的核心结构:入口函数、订阅、在循环里处理数据。

正式的 PX4 模块会基于ModuleBase类编写,支持start/stop/status等命令行指令,方便在 PX4 控制台里动态管理。这里不展开写完整类框架,你到对应版本的src/examples目录里找一个 hello 模块参考即可。

4.4 编译部署流程与版本注意点

模块代码写好后,把它放到src/modules/my_hello/目录下,然后执行:

make px4_fmu-v5

编译完成后会生成固件文件。刷固件可以用 QGroundControl 的地面站界面选择“自定义固件”手动刷入,也可以用编译环境直接上传。注意:你编出来的固件必须和飞控板型号匹配,比如 SpeedyBee F405 就不能刷 px4_fmu-v5 这种针对 Pixhawk 4 的固件。刷错固件轻则飞控不启动,重则变砖。

启动自定义模块这一步也容易踩坑。不同 PX4 版本里启动脚本的位置不一样,有的在ROMFS/px4fmu_common/init.d/,有的在ROMFS/px4fmu_common/init.d-posix/,还有的可能在板级配置目录里。最靠谱的做法是参照你当前版本中其他模块的注册方式,照着抄一遍。

注意:PX4 的版本更新速度很快,跨版本之间的模块 API、编译系统、启动脚本目录都有变动。网上搜到的教程大概率是旧版本的,遇到编译报错先检查版本兼容性。

5. 两条路径怎么选?我给出一个参考决策表

很多人在群里问“我有树莓派,要不要再买一块 Pixhawk”、“我该学 Python 还是学 C++ 做飞控二次开发”。这种问题其实没有标准答案,但可以从实际需求倒推。

判断维度外挂树莓派自定义模块
你擅长的语言Python、ROSC/C++、嵌入式
改动的位置飞控外部逻辑飞控固件内部
实时性要求一般,串口有延迟高,直接进调度器
典型应用视觉避障、航线规划、环境感知自定义控制律、传感器融合、故障检测
故障代价树莓派重启即可飞控失灵,可能需要重新刷固件
上手时间顺利的话半天跑通 demo保守估计需要一周以上
硬件需求额外一台树莓派/机载电脑一块支持对应固件的飞控板

说实话,这两条路径并不互斥,反而是配合使用的。我有一个很典型的经历:最开始我用树莓派给飞控写了一个“电量低于 20% 自动返航”的外挂脚本,跑得很欢乐。后来发现串口链路偶尔抽风,如果树莓派死机了,整个返航逻辑也跟着失效。之后我把同样的逻辑下沉为飞控内部的一个自定义模块,虽然开发周期长了不少,但可靠性高多了。

所以我的建议是:先走通外挂路线,把任务逻辑、控制指令的来龙去脉搞清楚,等你的需求对实时性、可靠性提出更高要求时,再考虑把它迁移成自定义模块。

6. 常见问题与排查技巧实录

做飞控二次开发,遇到的问题五花八门,但真正卡住绝大多数人的就那几个。我把这些年踩过的坑整理成一张速查表:

现象可能原因排查思路
树莓派收不到飞控心跳接线错误、未配置串口参数、波特率不一致先检查 TX/RX 是否交叉,再检查飞控端MAV_1_CONFIGMAV_1_BAUD,最后确认波特率是否匹配
串口打开提示 Permission denied当前用户不在 dialout 组执行sudo usermod -a -G dialout $USER,重新登录后生效
树莓派串口数据乱码未共地、波特率错误确认 GND 是否连通,树莓派和飞控波特率设为一致
树莓派 4B 串口没有输出硬件串口被蓝牙占用/boot/config.txt中增加dtoverlay=disable-bt,然后重启
刷固件后飞控无反应固件和板子型号不匹配确认你使用的固件目标和你飞控的主控芯片一致
仿真启动后画面卡顿Gazebo 资源占用高降低仿真分辨率,关掉其他大型软件
树莓派突然重启供电不足树莓派 4B 对 5V 电流要求高,不要只靠飞控的 BEC 供电,用独立电源模块

这里重点展开几个容易忽略的细节:

第一个是树莓派 4B 的串口问题。树莓派 4B 的硬件 UART 默认分配给了蓝牙模块,如果不在/boot/config.txt里加上dtoverlay=disable-bt,你用/dev/ttyAMA0收到的数据可能全是噪音。树莓派 5 的默认状态又不太一样,拿到新板子先查一下当前系统的串口映射情况再动手。

第二个是供电问题。SpeedyBee F405 这类穿越机飞控的 BEC 主要是给接收机、图传供电的,电流余量不会太大。树莓派 4B 满载时可以吃到 3A 的电流,直接从飞控取电非常危险,轻则树莓派重启,重则把飞控的电调供电部分烧掉。我的做法是给树莓派单独配一个 5V/5A 的 BEC,或者直接用独立的充电宝供电,跟动力系统彻底隔离。

第三个是 GPS 场景。很多人把树莓派 3B+ 接了 GPS 模块做定位,但忘了 GPS 模块和飞控之间可能存在频率冲突,导致搜星很慢。树莓派端的 GPS 和飞控端的 GPS 最好错开安装位置,避免互相干扰。

第四个是摄像头权限问题。树莓派接 OV5647 摄像头后,如果运行 OpenCV 提示无法打开设备,多半是没启用摄像头接口,或者当前用户没有 video 组权限。在树莓派终端执行sudo raspistill -o test.jpg,如果这个都出不了图,就说明摄像头驱动层面有问题,别急着调代码。

7. 一点个人经验:先跑通,再深入

做飞控二次开发这几年,我最大的体会是:这个领域不缺少资料,缺少的是循序渐进的节奏感。

很多人在第一个星期就试图搞清楚 PX4 所有模块的源码,结果被 EKF、卡尔曼滤波、控制分配这些名词劝退。而如果你换一个思路,先让树莓派和飞控对上话,再用 MAVLink 下发指令,亲眼看到飞机按照你的命令行进动作,这种正反馈会激发你持续深入的动力。等到外挂逻辑写得顺手了,你对飞控工作方式的理解已经足够支撑你去读源码、写模块了。

还有一个实用技巧想分享:无论走哪条路,都要养成看日志的习惯。外挂树莓派阶段,把你脚本里的关键变量都记录到文件里;自定义模块阶段,善用 PX4 的日志系统和logger模块。真机飞行前几天,在仿真环境里反复测试你写的所有边缘场景。我认识不少开发者,就是靠着一份详尽的日志,在一次炸机之后定位到了飞控内部一个极其隐蔽的时序问题。

飞控二次开发这条路并不难,难的是别在一开始就用错方法。从外挂树莓派开始,让 Python 成为你探索天空的入口;等你想往深了走,再一头扎进源码,那时你看到的将不是一个陌生的代码海洋,而是一套你已经熟悉其行为的系统,正在等待你用代码给它注入新的灵魂。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 23:14:41

扫码模块二次开发实战:USB/TTL/RS232接口深度解析

1. 这不是“能不能做”的问题&#xff0c;而是“怎么做得稳、改得透、用得久”的实战指南扫码模块支持二次开发吗&#xff1f;——这个问题每天在产线调试现场、设备集成商办公室、嵌入式开发工位上被问几十次。但真正卡住工程师的&#xff0c;从来不是“支不支持”&#xff0c…

作者头像 李华
网站建设 2026/9/13 23:14:35

【Linux 系统管理】

Linux 系统管理1. 查看系统信息1.1 查看系统架构1.2 查看 CPU 信息2. ps 查看进程3. kill 杀死进程4. top 实时监控5. free 查看内存6. 磁盘管理6.1 mount / umount&#xff1a;设备文件挂载 / 卸载6.2 df&#xff1a;查看所有已挂载磁盘的使用情况6.3 du&#xff1a;统计查看目…

作者头像 李华
网站建设 2026/9/13 23:06:39

自带降重+降 AI 率功能!2026这3款降AI率软件太省心了!

谁还在为AI生成论文的AI率太高发愁&#xff1f;明明用AI省了时间&#xff0c;结果查重时AIGC率超标&#xff0c;直接被老师打回重写&#xff0c;熬夜改到崩溃真的太窒息了&#xff01;最近被问最多的就是“有没有可以自动降AI率的论文生成工具”&#xff0c;作为过来人&#xf…

作者头像 李华
网站建设 2026/9/13 23:04:31

MMC实时仿真三大核心坑:求解器、事件时序与内存映射

1. 项目概述&#xff1a;为什么MMC实时仿真不是“把模型拖进Simulink跑起来”那么简单做MMC&#xff08;模块化多电平换流器&#xff09;的实时仿真&#xff0c;我前后踩过三个真正让人半夜改代码、反复重启电脑、对着示波器抓头发的大坑——不是模型搭错了&#xff0c;不是参数…

作者头像 李华
网站建设 2026/9/13 23:03:36

新手程序员轻松掌握Prompt工程,让大模型成为你的得力助手

本文深入解析了Prompt工程的本质&#xff0c;强调清晰定义任务边界、上下文、输出协议和验收方法的重要性。文章详细介绍了如何构建有效的Prompt&#xff0c;包括角色设定、任务描述、上下文提供、格式约束、示例展示等关键要素。此外&#xff0c;还探讨了Few-shot示例的应用、…

作者头像 李华