从选型到上天:用PX4开发一个新机型的完整实操记录
(正文开始)
搞无人机开发的人,迟早会撞上这样一个问题:手上有一台多旋翼、固定翼、倾转旋翼或者完全自定义的机架,想要跑PX4固件,但PX4默认支持的机型列表里没有它。这时候你就得自己动手,把PX4“调教”成能对付你手上这堆电机和舵机的固件。
这篇文章想聊的正是这件事:如何在PX4里开发一个全新的机型。我会从PX4如何理解“机型”开始讲起,然后讲清楚要改哪些文件、怎么写混控器、怎么配参数,最后再讲讲仿真验证和实测避坑。内容面向准备做飞控开发、有基础但是没真正从头配过新机型的开发者,也欢迎想搞明白PX4内部逻辑的爱好者来读。整个过程不需要你改动PX4的核心算法代码,属于“配置驱动”的开发方式,但足够应付绝大多数新机型的适配需求。
我自己在这条路上踩过不少坑,所以这篇文章更像是一份折腾记录,而不是官方文档的复读。官方文档能告诉你要做什么,但往往不告诉你为什么,更不会告诉你哪些地方容易翻车。这部分,我来补。
1. 先搞清楚PX4是怎么理解“机型”的
1.1 从核心架构说起:PX4眼中一台无人机是什么样
在动手之前,得先建立整体概念。PX4不是“一个程序”,它更像是一套模块化系统:姿态估计、状态估计、位置控制、姿态控制、混控输出、传感器驱动、导航等等模块相互独立,通过uORB消息总线通信。
这套架构里,与你“新机型”开发关系最大的,不是控制算法本身,而是“控制算法与物理机架之间的桥梁”——混控器(Mixer)。控制算法计算的是“我想要多大的俯仰力矩、横滚力矩、偏航力矩和总推力”,混控器则负责把这三个力矩加一个推力,翻译成每一个电机/舵机各自的PWM值或转速指令。
所以PX4对新机型的适配,核心工作集中在两处:一是告诉飞控“当前是什么类型的机架”,二是告诉混控器“你这个机架有多少个执行器,每个执行器在几何上如何贡献力矩和推力”。
1.2 新机型的开发到底要改哪些东西
明确了上面这个架构,开发新机型的任务清单就很清晰了:
- 添加机架定义(Airframe),包括机架ID、机型名称、对应的启动脚本。
- 写混控器文件,描述电机/舵机的几何布局、方向、倾斜角。
- 配置启动脚本,设置机架类型、默认参数、混控器文件路径。
- 设置传感器安装方向参数,告诉飞控传感器板相对于机架的旋转关系。
- 校准与验证,包括加速度计、陀螺仪、水平姿态、遥控器、电调行程。
- 仿真或实机测试,根据飞行表现迭代参数。
说句实话,第一步往往是“抄作业”——从PX4已有的机型里找一个最接近你的构型的,然后改。这比从零手写要高效得多。我自己第一次搞的时候,就是把一个标准X四旋翼的配置复制了一份,然后一刀一刀改成自己那个奇形怪状的六轴。
2. 开发前准备:环境、工具和基本概念
2.1 工具链与环境准备
开发新机型并不需要非常特殊的工具,你需要的只是能编译PX4固件的环境。PX4现在主推Ubuntu系统上的工具链。如果你用Windows,建议装个虚拟机或者用WSL2,原生Windows下编译PX4我试过,体验实在是一般,碰到的坑比解决问题的时间还多。macOS也能编译,但同样属于“能跑但基本靠折腾”的状态。
整个环境准备的核心步骤是:装好依赖工具链,克隆PX4源码,然后跑一次标准的固件编译,确认环境没问题。我个人的建议是先把PX4的官方文档里的“编译PX4固件”那一节完整照着走一遍。这个过程中最常出的问题集中在:Python依赖版本冲突、git子模块拉取失败、CMake缺少组件。如果你只是要改机型配置,甚至都不需要动太多源码,所以环境这块别追求太新太特别的发行版,Ubuntu LTS版本是最稳的选择。
2.2 理解构建系统和启动脚本
PX4的固件构建系统是基于CMake的。以多旋翼为例,最终生成的固件会把ROMFS目录里的内容打包进去。对于机型配置来说,有三个目录要特别关注:
ROMFS/px4fmu_common/init.d/:里面主要是各种启动脚本框架,比如rcS主启动脚本。ROMFS/px4fmu_common/init.d/airframes/:真正的机架定义脚本全在这里,按机架类型分文件。ROMFS/px4fmu_common/mixers/:混控器文件目录。
PX4启动时,rcS会根据当前设置的SYS_AUTOSTART参数找到对应的机架定义脚本,然后执行它。这个脚本里会干几件事:设置MAV_TYPE(机架类型)、设置具体的机架参数、加载混控器文件、启动相应的传感器和姿态估计模块等。
这里有一个很多人一开始会忽略的点:SYS_AUTOSTART这个参数的值,不是随便写的,它是PX4内部的一张“机型表”里的索引。如果你要在QGC(地面站)的“机架列表”里看到一个真正有名字的新机型,你需要在固件源码里把这个机架注册到机型表里。机型表的位置在src/modules/airframe_selector相关代码里,这部分涉及源码修改,但对于大多数开发测试来说,直接用“自定义机架”其实就可以了。
2.3 参考一个现有机型怎么起步
最合理的开发路线,是找参考机架来改。比如你想做一个六旋翼的Y型布局,可以先找一个已经存在的标准六旋翼配置。PX4源码里有不少现成的参考,多机型的配置文件都在相应的init.d/airframes子目录里,只要去找就能发现归属关系。
查阅官方机架支持列表也是好办法,但那个列表更新可能略慢于源码。以我的经验,直接去源码目录里翻是最准确的。找到参考机架后,把对应的启动脚本、混控器文件复制出来,放在旁边,对照着改。还有一个技巧:QGC里如果选了某个机架,它会显示该机架的配置类型ID和参数名。通过QGC可以反查配置对应关系,对确认“我改的东西到底生效没有”很有帮助。
3. 在代码里添加一个新机型
3.1 混控器文件怎么写——先看透格式再说
这是新机型开发最核心的一步。混控器文件描述的是“执行器与飞控输出之间的映射关系”。PX4的混控器文件以.mix结尾,放在ROMFS/px4fmu_common/mixers/目录下。
先看一个最简单的多旋翼混控器长什么样。以四旋翼X型为例,混控器内容本质上是组合了多个“旋翼控制组”。每个旋翼的混控规则由这样一段来定义:
R: 4x 100这行的意思是有4个输入、缩放值为100%。接下来是每个输入对应的具体参数格式。每个旋翼条目一般长得像这样:
M: 2 O: -10000 10000 10000 0 S: 0 3 0 10000 1 0 -10000 0 S: 0 3 1 10000 1 0 -10000 0第一行M: 2表示这是一个有两个输入的混控器。第二行O:是输出范围设置。接下来的两行S:定义了每个输入如何参与混控:输入来自哪个通道组、哪个轴,如何缩放和偏移。
说实话,手写这个格式非常折磨。我最初接触时看得一头雾水,后来逐渐明白:PX4在编译时通过px4-mixers工具或者运行时的混控器加载逻辑解析这些文本。多旋翼的混控器文件通常不需要你手算每个系数,因为PX4提供了一套生成机制——你在机架定义脚本里写好电机几何布局,系统能调用脚本自动生成对应的混控器内容。
实际操作中,更常见的做法是:把现成四旋翼的混控文件复制出来,稍微修改电机数量和正反桨标记。关键是要搞懂S:行里这几个数字的含义。
拿四旋翼举例子。首先四个输出分别对应四个电机,每个电机的混控系数由R:下面的多行S:和M:结构定义。四旋翼X布局里,每个电机需要同时接收来自“横滚”、“俯仰”、“偏航”、“油门”这四个通道的指令。所以混控器文件里每个输出会包含多个S:行,每一个对应一个输入轴。
S:行的具体含义是:第一个数字是输入组编号,第二个是该组内的通道序号,第三个是缩放轴选择,后面是缩放系数和偏移值。举个例子,横滚通道在姿态控制组里通常是3 0,油门是3 2。这四个轴通过各自的比例系数组合到同一个输出,就完成了电机指令的混控。正反桨的区别通过偏航通道的系数正负号来体现:顺时针电机偏航系数为负,逆时针为正,这是为了让差动力矩方向一致。
对于正常的四旋翼、六旋翼、八旋翼,你根本不需要手工算每个系数,用PX4内置的混控器生成工具最靠谱。你在机架定义脚本里写的MIXER变量,比如MIXER quad_x,会直接在固件启动时加载对应混控器文件。要真正理解格式,最好的办法是拿一个quad_x.main.mix文件,对着NuttShell里mixer show命令的输出来看,比对着文档猜要直观得多。
3.2 混控矩阵计算的思路:从几何到系数
如果你做的是标准对称布局,直接用现成混控器就行。但如果机架布局有非对称、电机有倾斜角、或者你要做倾转旋翼这类特殊机型,就必须理解背后的力学关系,自己计算混控矩阵。
混控矩阵的本质是解一个线性方程组:已知期望的三个力矩和一个推力,求每个电机的力输出。假设你有N个电机,每个电机的位置向量是(r_i),产生的力方向是(n_i)。那么每个电机对机体的力矩贡献是(r_i×n_i·F_i),推力贡献是(n_i·F_i)。把这些贡献写成矩阵形式,就是一个4行N列的矩阵。混控器要做的事,就是把这个矩阵求逆(或最小二乘伪逆),把“期望力矩+推力”映射成“电机指令”。
有了这个概念,你就明白为什么电机臂长、倾斜角、转向会出现在混控矩阵中,也知道非对称布局不能用标准混控器的原因——它的几何不满足矩阵的对称性假设。手算的时候我建议直接用Python/SciPy或者MATLAB来做:先建几何模型,算矩阵,求伪逆,然后直接生成S:行格式。这比自己拍脑袋填系数要靠谱一个数量级。
3.3 启动脚本怎么配
启动脚本是机架定义的核心文件。它决定了飞控上电后以什么模式启动、加载哪个混控器、配置哪些传感器参数。
脚本第一行一般是#!/bin/sh,接下来按顺序执行一系列PX4 shell命令。一个典型多旋翼启动脚本会包含类似这样的内容:
#!/bin/sh set -e . airframes/config_frames/quad_x其实更常见的是直接以#开头设置一些shell变量:
#! /bin/sh set -e . /etc/init.d/rcS然后设置机架类型、混控器、传感器方向:
param set MAV_TYPE 2 param set SENS_BOARD_ROT 0 set MIXER quad_x param set PWM_MAIN_DISARM 1000 param set PWM_MAIN_MIN 1075 param set PWM_MAIN_MAX 1900MAV_TYPE 2对应MAVLink里的多旋翼类型。SENS_BOARD_ROT 0表示传感器板水平安装,这是大多数情况。MIXER指定混控器文件名,注意这里不需要带.main.mix后缀和路径,系统会在mixers/目录里自动找。
执行set MIXER quad_x,系统会在启动过程中加载混控器。这个脚本里还可以加一些机型相关的默认PID参数,比如穿越机通常会把默认姿态增益调高,拍照平台更看重平滑性。如果新机型有特殊传感器方向,还可以在这里param set相关参数,以后每次启动自动生效。
启动脚本本身并不难写,但内容顺序有讲究。我建议把参数设置放在前面,混控器设置放在中间,后段交给rcS做通用启动。如果你中途改乱了,最坏情况下飞控会启动到一半就停。别问我是怎么知道的。
3.4 传感器安装方向设置:躲不开的矩阵
飞控板装在机架上的方向不一定和机架坐标系一致。常见的情况是飞控板朝前装、朝后装、侧着装,或者斜着45度装。PX4解决这个问题靠的是SENS_BOARD_ROT这一组参数,它们描述了“传感器板坐标系相对于机架坐标系的旋转”。
PX4的ROT值有预设的枚举表,比如ROTATION_NONE是0,ROTATION_YAW_90是2,数字在一个头文件里列着。你可以直接用param set SENS_BOARD_ROT 2这类方式设置,但前提是你知道传感器板怎么转。这里最容易犯的错误是把机架转了当成传感器转了,方向搞反。
我的建议是:能水平安装就水平安装,能正向安装就正向安装,别给自己找麻烦。只有安装空间真的受限时才去配置这个旋转矩阵,而且务必用PX4自带的boardrotation.py脚本生成对应的参数值,别再靠猜。
4. 参数配置与传感器校准
4.1 机架参数与QGC校准流程
机型代码改完了,固件重新刷进去,地面上就该收尾了。在QGC里需要完成一系列校准:遥控器校准、加速度计校准、陀螺仪校准、水平水平校准、电调校准。这些都是QGC自带的标准流程,每一步的界面引导都很清晰,照着做就行。但有几个细节值得单独提醒。
首先是加速度计校准。如果你传感器板安装方向设置了非零的角度,校准过程需要按照QGC界面上那个机体图案摆放无人机。这个图案不是摆设——飞控要通过它知道你当前处于什么姿态来记录传感器偏置。
其次是水平校准。在校准加速度计之后,会把当前姿态作为水平基准。所以做这一步时,飞机必须放在绝对水平的平面上。有一点容易被忽略:此时电池和负载最好已经装好,因为重心和重量分布会影响最终的姿态悬停效果,尽管水平校准本身只校准姿态偏移,严格来说和负载关系没那么大,但是为了后续飞行的一致性,我习惯在接近实际起飞重量的状态下做。
最后是电调校准。这一步只对PWM电调有意义,DShot或CAN总线协议的电调一般不需要。校准的关键点是断开螺旋桨,必须断开,这是我见过事故率最高的一个环节。电调校准的耗时取决于设备数量,全流程大概就是“上电-听到提示音-设置最大-设置最小-完成”。
4.2 电机测试与安装方向检查
校准完成后,第一件事不是解锁起飞,而是先做电机测试。QGC的电机测试界面支持单独驱动某一个电机输出,这个功能极其重要。
在电机测试之前,你至少要对新机型做一次静态的电机方向检查。步骤是这样的:先把螺旋桨装上(只装一个电机的桨,或者全部装但用胶带固定住机身),然后通过QGC驱动单个电机,观察风的方向是否和预期一致。
这里我强烈建议养成“自检表”的习惯:
- 每个电机编号是否和混控器里的输出通道对应正确?
- 电机旋转方向是否正确?有无反转?
- 螺旋桨是否装反?正反桨是否对位正确?
- 每个电机在姿态指令下的出力方向是否与姿态修正方向一致?
最后这一点测试起来要小心。一种安全做法是:解锁但保持油门最低,然后通过遥控器手动给定横滚、俯仰、偏航摇杆量,观察对应电机转速增减是否符合逻辑。比如横滚右倾指令,右侧电机应该提速,左侧电机应该降速。这种检查必须在非常谨慎的状态下进行,最好有第二个人在旁边随时准备拔电池。
4.3 预解锁检查清单
在正式起飞前,再列一份预解锁检查清单,每一条都是真金白银换来的教训:
- 螺旋桨锁紧、方向正确。
- 电池电压充足,电调信号线和电源线连接牢固。
- 遥控器模式正确(PWM、SBUS、CRSF等已绑定且输出正常)。
- GPS(如果使用)已搜到足够卫星数,定位精度达标。
- 罗盘校准完成且附近无强磁场干扰源。
- 加速度计和陀螺仪零偏稳定,无连续跳变。
- QGC里参数与混控器已正确加载,预解锁检查项全部通过。
预解锁检查并不复杂,但每一条都有对应的真实事故记录。我见过不止一次GPS没定位就解锁起飞然后飞机疯跑的案例。也别嫌麻烦,这几十秒的自检比报修便宜太多了。
5. 仿真验证:先别急着上真机
5.1 命令行仿真与Gazebo
如果开发的是标准多旋翼,在刷真机之前,完全可以在软件仿真环境里做一轮验证。PX4官方推荐的仿真路线是Gazebo。理论上你只需要把机架定义加进PX4固件,然后启动仿真环境,PX4就会加载你的混控器和参数飞起来。
问题是Gazebo的构型和物理模型,和你真实机架并不能完全一致,除非你有精力和经验把模型调得很好。所以仿真阶段的定位是“验证代码逻辑与参数基本正确”,不是“验证真实飞行手感”。
实际开发中有个非常实用的技巧:即使不建三维模型,也可以跑所谓的“纯软件在环”模式。这其实是PX4的px4 sitl命令行仿真,比Gazebo轻量得多,适合快速试探参数和启动脚本行为。你可以在命令行里设置机型参数、启动飞控,然后通过MAVLink与地面站通信。它不会为你提供视觉环境,但对排查“启动脚本有没有报错”、“混控是否加载成功”来说足够了。
5.2 HITL硬件在环测试
比纯仿真更进一步的是HITL。这时候飞控是真实硬件,但传感器数据由仿真器通过串口或USB伪造输入。这种方式能验证真机上的固件配置是否正确、传感器驱动能否初始化,以及整体系统的启动链路是否顺畅。
HITL比SITL更接近真实状态,但对环境的配置要求也高一些。如果你只是要验证一个配置文件,SITL通常就够用了;如果你怀疑是飞控板本身的问题或者驱动问题,再上HITL不迟。
5.3 仿真能帮你发现哪些问题
我自己的项目在仿真阶段发现过三次有价值的问题:混控器编号不匹配导致某个电机完全不转、启动脚本里参数顺序错误导致传感器初始化失败、机架ID写错导致QGC不认识这个机型。这些如果不仿真验证,直接上真机,虽然不一定会炸机,但排查起来绝对比仿真里看日志要痛苦得多。
仿真时顺手看飞控的uORB话题数据是非常有效的排查手段。比如用listener sensor_combined看传感器数据流、用listener vehicle_attitude看姿态估计输出、用listener actuator_controls看控制指令。有这些数据支撑,很多问题都能快速定位到具体模块,而不是在一堆现象里瞎猜。
6. 常见问题与排查技巧实录
6.1 启动脚本和混控器常见错误
开发新机型最常见的报错,一个是“Unable to load mixer”,另一个是“Parameter does not exist”。前者通常是混控器文件名拼写错误或文件路径不对,后者是启动脚本里用了错误的参数名。
我排查这类问题时的一个习惯是:先在NuttShell里手动跑一遍命令。不要依赖开机自动加载,而是进入飞控的shell,手动执行mixer load quad_x或者param set ...。手动跑能回显错误信息,方便定位问题。
常见的混控器加载问题还有一个隐蔽来源:你自定义的混控器文件是放在源码目录里,但旧固件还在工作。刷入新固件前一定要确认编译时把新文件打进去了,不然你改了文件,飞控里跑的还是旧内容。检查方法很简单,刷新固件后去NuttShell里执行ls /etc/mixers/,看看文件在不在,时间戳对不对。
6.2 电机转向和混控方向搞反了怎么办
这个坑几乎是每个自己装过机的新手都会踩的。现象:解锁后给一点油门,飞机往一侧翻;推俯仰摇杆,飞机往反方向低头。
处理思路很简单:先检查电机旋转方向,再检查螺旋桨正反桨安装位置;都没问题的话,调混控器里的符号。
具体操作时,在QGC电机测试界面单独测每个电机的转向,看和混控器定义是否一致。如果只是某个电机的转向反了,最直接的办法是调整电调的三根电机线(任意两根对调),不要改混控器参数——因为混控器模型假设的是“该电机的旋向是某个方向”,如果实际反了,物理世界和数学模型就不一致,后面飞行姿态一定会出问题。
真正需要改混控器符号的是这种情况:模型里定义的电机旋向和实际物理方向都正确,但坐标系定义有误解。比如你做的Y3布局,中间电机负责俯仰但混控器里写成了偏航,这时候就要纠正混控器矩阵系数,而不是调电机线。
6.3 第一次解锁试飞的要点与PID调参入门
机型能稳住,才算真正开发完成。第一次试飞强烈建议在室外空旷草坪上进行,周围没有人和障碍物。解锁后小油门,让飞机刚刚能离地,就立即收油降落。这个过程只验证一件事:飞机有没有明显的反向翻转趋势。如果没有,再慢慢增加悬停时间。
悬停中如果发现飞机缓慢往某个方向漂,排除传感器校准问题之后,一般靠遥控器微调,或者重新做水平校准。如果飞机低频振荡(呼吸感地上下或左右晃动),通常是姿态增益太高。如果飞机感觉“软绵绵”的,操控反应迟钝,则说明增益偏低。
PX4的姿态控制参数主要在MC_ROLL_P、MC_PITCH_P、MC_YAW_P以及对应的MC_ROLL_RATE_P、MC_ROLL_RATE_I等参数上。新手调参时一个非常有效的策略是:只动比例项,从默认值逐步下调或上调,一次只改一个轴,改完就试飞。千万不要同时动多个参数,那样你永远不知道是哪一个改动起了作用。
我调参的整体心得可以概括成一句话:先飞稳,再飞准,最后飞快。姿态环稳定是基础,位置控制再慢慢跟上。如果姿态环都不稳定,后面谈再多导航控制都没有意义。
6.4 几条真金白银的避坑经验
再分享几条纯粹来自实操的经验。
第一,所有自定义配置文件务必备份在原码之外的独立目录里,并用版本管理。我用过最傻的方法就是在PX4源码里直接改完,然后升级固件时全部被覆盖。后来养成的习惯是单独维护一份patch或者独立配置文件,编译时通过自定义构建配置把它组装进去。
第二,混控器文件的修改往往要求刷固件才生效。飞控上运行的是打包在固件里的文件系统,你改完源码以为改完了,但没重新编译刷机,那等于没改。我见过有人在QGC里找了半天混控器设置按钮,其实QGC根本不提供这样的界面。一切以源码编译为准,搞清楚这个模型能帮你省下大量时间。
第三,进程通信问题:有些参数在飞行中是实时生效的,有些需要重启飞控。遇到参数改了没生效,先看看这个参数是不是需要重启。这类信息在参数元数据里会标,QGC也会提示。
第四,不要一开始就在一个巨大而复杂的机架上做开发。我见过很多开发者试图一次搞定一台八轴倾转旋翼机,最后卡在混控矩阵上一个半月无法推进。我的建议是先用一个小巧的、已验证过的标准机架跑通“改配置-编译-刷机-校准-试飞”全流程,再逐步往你的目标机型上加复杂度。每做一步改动就验证一步,比憋大招稳健得多。
第五,日志永远是最好的老师。PX4的ULog里记录了飞机几乎所有的内部状态:传感器原始数据、姿态估计、控制指令、电机输出、模式切换等等。试飞不顺利时,把ulog文件导入日志分析工具,一次任务的飞行数据可以解释绝大多数异常现象。很多问题如果只靠肉眼观察和遥控器上的抖动,往往会得出错误结论,而数据不会说谎。
最后的几句实话
回头来看,用PX4开发新机型这件事,表面上是个技术过程,其实更像一场“系统思维”的磨炼。你逼着自己同时理解控制原理、执行器物理、传感器方向、构建系统和调试流程,任何一个环节出问题,飞机都不会给你好脸色看。
就我个人而言,到现在都还保留着“小步快跑”的配置习惯:新机型的第一次编译通过、第一次解锁、第一次离地、第一次全自主飞行,每个里程碑之间绝不跳过验证步骤。这个习惯让我避免了至少三次险些炸机的事故。我希望看到这篇文章的你,也能建立起同样的耐心。
最后再分享一个小的实用技巧:如果你用的是QGC,在“分析”界面里可以同时监视vehicle_attitude和actuator_controls两个话题,手动晃动飞机,观察控制输出是否有对应变化。这个小技巧能让你在起飞前就发现传感器方向装错或者控制方向反了的问题,省下一堆炸机的钱。祝你开发的新机型一次离地就稳如老狗。