做飞控的人应该都有这种体会:纯仿真跑得飞起,一上真机就怂了。电机响应快慢、机架刚度、螺旋桨软硬、电压跌落、传感器噪声这些在纯软件仿真里全被“理想化”之后,控制算法很难看出真实水平。而直接上真机调试,炸一次就是几千块的成本,时间上更拖不起。硬件在环仿真(HIL)正好是夹在中间的过渡带——把真实的PX4飞控硬件放进回路里,其余环境全部用Simulink虚拟出来。这篇文章我会围绕“Simulink + PX4”这套组合,把你搭建HIL仿真时需要理解的概念、准备的环境、踩过的坑和可复现的步骤一次讲清楚。无论你是刚开始折腾PX4开发环境,还是已经在Ubuntu下自己编译过固件,这篇都能帮你把仿真精度往上提一个档次。
1. 为什么需要HIL:先搞清楚仿真里的“环”是什么
1.1 从纯仿真到硬件在环的递进关系
很多时候我们所说的“仿真”其实指三件完全不同的事:模型在环(MIL)、软件在环(SIL)和硬件在环(HIL)。MIL阶段,控制器和被控对象全在Simulink里,你验证的是算法本身逻辑对不对;SIL阶段,把控制器代码从模型生成出来,但依然运行在PC上,验证的是代码生成有没有引入错误;到了HIL阶段,控制器代码烧进真实的飞控板,由飞控板去驱动整个闭环。
这套递进关系里,HIL最大的价值是让“跑代码的硬件”提前进场。飞控板的CPU负载、浮点精度、中断响应、总线通信、内存限制,这些在纯软件环境里根本模拟不出来。举个我实际见过的例子:一个在Simulink里仿真稳定到不行的姿态控制器,烧到某块飞控板上却出现高频抖动,原因是板子上的传感器数据读取频率被中断优先级挤掉了,导致的时延变化在纯电脑仿真里完全不存在。
用HIL能帮你把这类问题在上真机之前暴露出来,而且所有实验都是可重复、可回放的。这比真机试飞最大的优势在于:你可以在同一架“虚拟飞机”上反复测试不同参数,不会出现“上次飞的时候风大”这种玄学干扰。
1.2 HIL到底环住了哪些环节
在PX4语境下,我们常说的硬件在环仿真,实际的“环”是这样的:真实飞控板(比如Pixhawk系列)读取来自虚拟环境的传感器数据,姿态解算、控制律计算都在真实板子上完成,计算出来的执行器指令再通过MAVLink协议返回给虚拟环境,虚拟环境更新飞行器状态,再循环往复。
这个过程里,真正被“环住”的是飞控板的全部嵌入式软硬件,而飞行动力学、传感器物理特性、外界环境则全部由仿真环境替代。用Simulink来搭建这个“被替代”的部分,好处是你对模型的控制能力极强:风场你说了算,传感器噪声你说了算,机架参数你说了算,因为所有物理量都在Simulink模型里。
还有一条很容易被忽略的环:控制律模型从Simulink生成代码并集成到PX4固件之后,HIL实际上也验证了这条代码链路。也就是说,HIL既能验证“PX4原版固件+第三方虚拟环境”这套组合,也能验证“你的Simulink控制器+自制固件”这套组合。后面第三部分我会专门展开这两种用法。
1.3 纯软件仿真和HIL的关键差异
很多初学者问我:既然Gazebo和jMAVSim已经能做仿真,为什么还要折腾Simulink HIL?其实两者目的不同。Gazebo偏重环境交互和多机协同,适合做感知层面的验证;而Simulink偏重控制算法和系统级建模,适合把复杂动力学和控制器放在一个平台下联合调试。
另一个关键差异在物理模型的自由度。Simulink里你可以轻易把六自由度刚体方程、电机电调动态、气流干扰、弹性机架模型全部构建出来,而且可以随时在Simulink外部模式下在线改参数。这种模型层面的透明度和操控性,是Gazebo那种“现成机体模型”给不了的。
此外,如果你做的是多旋翼之外的机型,比如固定翼、倾转旋翼,或者带吊挂载荷的无人机,Simulink里建模的自由度会让你少走很多弯路。
2. 准备工作:Ubuntu下搭建PX4开发环境与Simulink工具箱
2.1 Ubuntu里的PX4开发环境到底要装什么
现在大家普遍用Ubuntu 20.04或22.04来做PX4开发。无论做SITL还是HITL,几个基础依赖是跑不掉的:git、cmake、ninja-build、gcc-arm-none-eabi交叉编译链,以及Python相关的依赖工具。PX4官方文档推荐用一串脚本来安装工具链,但我在实际使用中遇到过网络源不稳定导致安装失败的情况,所以更建议分步骤安装,这样每装一步都能确认是否成功。
装完工具链之后,建议先执行一次编译验证环境是否干净:make px4_fmu-v5_default。注意这个命令会拉取PX4的全部上游依赖,包括子模块和NuttX工具链,第一次会比较慢。如果这一步能顺利编译通过生成固件,你的开发环境基本就合格了。
如果你打算做SITL,还要额外装jMAVSim或Gazebo的依赖。HITL则并不需要跑SITL固件,但仿真器经常是同一条命令启动,所以我一般都会把SITL环境也配好,这样可以在纯软件层面先调通通信逻辑,再切换到HITL时问题会更少。
2.2 Simulink端需要哪些工具箱
Simulink侧需要的核心工具箱主要有四个:Simulink本身、Embedded Coder、Stateflow(如果你要做状态机逻辑)和Simulink Coder。如果要做FMU导出,还要安装FMU Builder支持包;要跟PX4的MAVLink打通,通常会用到Simulink自带的MAVLink通信库,或者直接通过串口/UDP的Send-Receive模块收发MAVLink字节流。
还有一个MathWorks官方提供的“Simulink Support Package for PX4 Autopilots”支持包,它能直接生成PX4模块代码并集成到固件里。不过要注意一点:这个支持包对PX4固件版本和飞控硬件有对应关系,版本不匹配时编译会报很奇怪的错误。我自己的习惯是,优先用自定义MAVLink收发模型来打通HIL链路,因为这种方式对固件版本不敏感,通用性更强。
2.3 硬件准备:飞控选型、供电与接线检查
做HITL时硬件本身要求不高,常用的Pixhawk 4、Pixhawk 6C、CUAV v5+这类板子都可以。需要注意的点是:HITL模式下飞控通常通过USB连接电脑,所以USB线质量很重要,最好选带磁环的短数据线,避免仿真过程中掉线。
还有一个很关键但容易被忽略的接线问题:很多飞控板在HITL模式下是不需要接电调信号线的,但一定要给飞控正常供电。可以是USB供电,也可以是独立的5V BEC供电。部分飞控在只接USB、不接其他传感器时会出现电压监测告警,一般不影响HITL,但如果告警太频繁建议外接一个5V供电,省得干扰调试心态。
接线完成后,建议先用QGroundControl连接飞控,确认能看到实时姿态数据、能正常刷写固件,再做下一步。这步如果出问题,后面HIL调试再折腾通信就没意义了。
3. Simulink与PX4联合的几种方案选型
3.1 方案一:Simulink模型生成代码,集成进PX4固件
这是很多做控制算法的人首先想到的路线:在Simulink里设计好姿态控制器或位置控制器,用Embedded Coder生成C/C++代码,然后作为自定义模块编译进PX4固件。这样做的好处是控制律完全由自己定义,不受PX4默认控制器结构的限制。
实现方式上有两条子路线。一条是使用MathWorks的PX4支持包,它会自动生成符合PX4模块结构的代码;另一条是自己按PX4的模块规范写一个自定义uORB消息驱动,再把Simulink生成的代码嵌进去。我个人的经验是:后者虽然前期工程量大,但可控性最高,调试时你能随时查看中间变量,遇到奇怪问题不会被支持包的封装层挡住。
这条路线配合HIL的意义在于:固件编译好后,可以先用HIL验证控制律在真实硬件上的表现,再决定要不要上真机。相当于把控制算法的验证周期从“写完就试飞”变成了“写完先在虚拟环境跑上百个起降”。
3.2 方案二:Simulink作为虚拟被控对象,与PX4飞控构建HIL闭环
这是我最推荐的一种HIL实现方式,也是本文实操部分重点讲的方向。思路很简单:Simulink里搭建飞机六自由度动力学模型,模型内部的“传感器仿真”模块生成加速度计、陀螺仪、磁力计、气压计数据,通过HIL MAVLink消息发给真实PX4飞控板;飞控板跑完姿态估计和控制律后,把执行器指令通过MAVLink发回Simulink,Simulink再驱动动力学模型更新状态,循环往复。
用Simulink搭被控对象模型的优势在于:传感器噪声、延迟、故障注入都能自由控制。比如你想看飞控在GPS丢星瞬间的表现,直接在那个信号上插入一个自定义中断即可,这在真实环境中很难复现,但在Simulink里只是一根信号线的事情。
3.3 方案三:FMU/FMI联合仿真,先做软件在环
如果你的目的不是HIL而是先验证算法,那FMU/FMI路线更轻量。你可以在Simulink里把控制器或被控对象模型导出成一个FMU(Functional Mock-up Unit),然后让PX4 SITL或其他仿真软件加载这个FMU,形成跨工具联合仿真。
FMU的价值在于解耦:无论对方用什么仿真工具,只要支持FMI标准,就能加载你的模型。之前我用这种方式把Simulink的电机模型导出给另一个团队做电气系统仿真,对方不需要安装MATLAB,照样能跑我们的模型。不过FMU在PX4生态里目前更多用于SITL阶段的验证,真正要上真实飞控板对时序有严格要求的场合,还是要走代码生成或者直接MAVLink通信的路线。
3.4 方案四:Simulink外部模式在线调参与数据监视
在HIL调试过程中,你往往需要实时看到Simulink模型里的中间状态,还要能在线调整参数。Simulink的外部模式(External Mode)就是干这个事的。它可以让运行在真实飞控上的代码通过通信链路实时反馈信号到Simulink,并允许你在Simulink界面里直接改动参数。
有人会误以为外部模式就是HIL,其实两者可以独立使用,也可以组合使用。更常见的做法是:HIL把飞控板纳入回路,外部模式把Simulink模型与真实飞控通信的通道“实时打开”,这样你在调试窗口里能看到仿真机模型的风速、推力、角速度反馈,而不是只看到飞控发出的MAVLink遥测。这种透明感,对排查控制律发散问题帮助特别大。
4. 完整实操:Simulink + PX4硬件在环一步步落地
4.1 从QGroundControl启动HITL模式
我以Pixhawk 4 + 自定义Simulink模型做HIL为例,给你走一遍完整流程。第一步是打开QGroundControl,把飞控通过USB连上电脑,在“模拟”设置页面(不同版本QGC位置略有差异,一般在“应用设置”或“总览”菜单里找)把仿真模式从SITL切到HITL。这里有一个版本差异:新版QGC会把HITL入口放到“载具设置”的“模拟”标签下,找不到就搜索“Simulation”或“HIL”。
切换后,QGC会提示你选择仿真器类型。选jMAVSim也行,但既然我们用Simulink搭被控对象模型,仿真器其实由Simulink替代,所以这里的关键不是选哪个仿真器,而是让QGC进入HITL通信等待状态。接着在Ubuntu终端启动PX4提供的仿真桥接环境,不同固件版本的启动命令会有差异,常用的是make px4_sitl jmavsim或者直接运行./Tools/simulation/jmavsim/run_jmavsim.sh。启动后你会看到仿真窗口在等待HITL数据。
4.2 Simulink模型里实现HIL的MAVLink收发
接下来就是核心部分:Simulink模型里需要完成两件事,一是实现六自由度动力学模型,二是实现MAVLink的HIL消息解析与打包。为了简化,你可以先不写完整的MAVLink协议栈,而是直接用字节收发模块,因为你只需要处理几条HIL消息:HIL_SENSOR(仿真传感器数据)、HIL_ACTUATOR_CONTROLS(执行器指令)和HIL_STATE_QUATERNION(飞控状态反馈)。
用Simulink实现时,我建议用UDP Receive和UDP Send模块来收发,因为QGC和PX4的HIL接口默认监听的是UDP端口。飞控通过USB传给电脑的数据,由QGC转成UDP包给仿真器,这条链路在HITL下已经存在,你的Simulink模型只需要接入对应端口即可。
在模型内部,从HIL_ACTUATOR_CONTROLS消息解析出四路电机指令后,进入动力学模型计算加速度和角速度,再把积分出的姿态用欧拉角或四元数表示,送入HIL_SENSOR消息生成模块。需要注意:HIL_SENSOR里的加速度计和陀螺仪数据需要加上噪声和偏置,否则飞控的姿态估计太“干净”,当你之后切到真实传感器时会遇到性能断崖。
4.3 关键参数设置与数据流核对
通信打通后,你会发现Simulink模型和QGC之间会有频率不匹配的问题。PX4的HITL消息一般要求仿真器以250Hz或更高频率发送HIL_SENSOR,而你的Simulink模型如果步长设定不合适,就会出现数据饥饿或者数据堆积。建议把Simulink求解器设置成固定步长,步长取0.004s,对应250Hz,这样跟飞控的姿态解算频率刚好匹配。
另外要注意坐标系的统一。Simulink动力学模型里的坐标系和飞控体坐标系必须一致。之前我犯过一个低级错误:模型里把Z轴方向定义反了,结果HIL一启动飞控直接判定“坠落”,紧急停机。排查了半天才发现是坐标系符号问题,这种问题最坑,因为模型看起来完全正常,逻辑上找不到错。
链路核对建议按这个顺序做:先用QGC看HITL是否收到仿真数据,再在Simulink里看收到的执行器指令是否随遥控器或Pixhawk的自动模式变化,最后再怀疑动力学模型内部的坐标系和参数问题。
4.4 从Simulink控制器集成到PX4固件的HIL验证
如果你走的是Simulink控制器集成固件这条路线,流程又有不同:先在Simulink里做好控制器模型,用Embedded Coder生成代码,然后通过PX4模块方式或支持包方式把代码嵌入固件,重新编译出带自定义控制器的固件,烧录到飞控板。
烧录后,回到HITL环境,你会面对一个很有价值的情况——飞控板的姿态环是你自定义的,而位置环可能还是PX4默认的,两者能否协同工作,正好通过HIL来验证。我在这个环节遇到过编译器优化导致浮点运算结果与仿真不一致的问题,后来通过对比HIL日志里实际算出的控制量与Simulink模型内部同一节点的输出,才发现差异来源。这个对比建议你用PX4的日志文件或QGC的飞行数据记录来做,不要只靠肉眼观察飞机姿态变化。
4.5 Simulink外部模式与HIL组合调试
强烈建议你在HIL运行时把Simulink的外部模式一并打开。具体做法是在模型里把动力学模型的几个关键输出(比如电机转速、机体加速度、姿态角)用信号监视模块引出,然后在Simulink工具栏里选择外部模式并点击运行。
打开外部模式后,每次修改风场强度或传感器噪声参数,几乎即时生效,而不需要重新编译模型。这种实时调参体验,在实际调试HIL时堪称“作弊器”。我曾经在验证一个抗风控制器时,在外部模式里把阵风从3米/秒逐步加到12米/秒,一边加一边观察姿态角变化,整个过程半小时不到就找到参数边界。要是走传统编译-烧录-试飞流程,至少要两天。
5. 常见问题与排查技巧实录
5.1 飞控连不上QGC,HITL无法启动
这是步骤0的问题,通常跟USB线、驱动和端口占用有关。先确认系统能否识别到飞控的USB设备,Linux下用lsusb看设备列表,能看到对应的设备ID就说明硬件连接正常。然后检查串口是否被ModemManager之类服务抢占,很多Linux发行版默认会自动打开串口调试功能,导致QGC连不上飞控,解决方案是把飞控串口加到ModemManager的禁用列表里。
如果这些都没问题,但QGC还是连不上,建议换一个USB口,并排除扩展坞环节。做HITL调试时飞控的数据量很大,扩展坞的供电不足会造成USB设备反复复位。
5.2 HIL模式下飞控姿态数据飘移或跳变
飞控在HITL模式下接收的是仿真传感器数据,如果Simulink发过来的传感器噪声过大,或者数据帧率不稳定,姿态估计结果就会飘。可以先在Simulink模型里把传感器噪声设成零,看姿态是否稳定,如果稳定,说明问题出在传感器仿真参数上,再逐步把噪声加回来。还有一个常见原因:HIL_SENSOR里的磁场强度数据没按地理坐标系设置,导致飞控的磁力计数据与实际航向不符,表现出来就是偏航角缓慢漂移。
5.3 Simulink收不到执行器指令
注意HIL_ACTUATOR_CONTROLS消息由飞控发给仿真器,而不是仿真器主动拉取。如果你的模型收不到,先检查飞控是否真的运行在HITL状态,可以在QGC里看飞控是否有仿真相关的状态提示。其次检查UDP端口和IP绑定是否正确,尤其是Simulink模型作为UDP接收方时,要绑定到QGC实际发送数据的目标端口上。
还有一个坑:部分PX4固件版本需要在启动参数里显式启用HIL功能,否则即使QGC显示HITL模式,飞控也不发送执行器指令。这种情况检查启动日志里有没有类似“HITL enabled”的提示,没有的话需要在启动参数里补上对应配置。
5.4 Simulink代码生成后PX4固件编译失败
代码生成相关错误通常分两类:一类是Simulink模型中有不支持的模块或数据类型,一类是生成代码与PX4编译器版本不兼容。第一类解决办法比较直接,检查报错信息里指出的模块,换成支持嵌入式代码生成的等价模块即可。第二类比较麻烦,需要确认你用的Embedded Coder版本支持你当前的目标芯片,比如STM32F7系列需要对应的ARM Cortex-M7支持包。
我做过的项目中,最容易踩的坑是模型里用了一个模拟仿真专用的高级模块,生成代码时报“不支持代码生成”,其实功能上完全可以被基础模块替代,换模块后问题迎刃而解。
5.5 仿真时间不同步导致控制发散
HIL真正的难点不是通信,而是时间同步。Simulink模型以250Hz频率发传感器数据,飞控也在跑自己的控制循环,两边如果不同步,累积的相位延迟会让控制量出现明显延迟,表现为系统持续振荡。
排查方法很简单:在飞控日志里看HIL_SENSOR时间戳和飞控内部时间戳的延迟,如果延迟波动超过5毫秒,就要检查仿真环境是否有负载导致数据发送抖动。我建议在模型里用一个实时时钟模块来驱动数据发送,而不是依赖Simulink求解器的仿真步数。仿真时间卡在某个步长时,可以用外部模式在线调整,效果立竿见影。
关于HIL后续扩展的一些想法
最后再分享一点体会:HIL这套环境一旦搭好,能玩的花样其实很多,不只是验证控制器。你可以在Simulink侧加入执行器故障模型,模拟某个电机在起飞过程中突然失效,观察PX4能否通过混控器重新分配推力;也可以加入GPS中断,测试飞控的降落应急逻辑;还能跟Carsim这类车辆动力学软件搞“机-车联合场景”,让无人机在虚拟车辆上方跟踪移动目标。这些实验在真机环境下要么代价极高,要么根本不可复现,但在Simulink + PX4的HIL平台里,都是可以反复操作的日常实验。
我在实际使用中的另一个心得是:把HIL平台当成“虚拟风洞”和“数字孪生测试床”,而不是仅仅当做一个验证工具。每次调试前先在Simulink里把飞行场景、故障注入、传感器参数统一配置好,记录归档,这样每次实验都有对照、有回放。坚持这种工作流,一段时间后你会发现自己对PX4固件、控制律和硬件关系的理解会比单纯刷机试飞来得扎实得多。