第3章:软件在环测试(SIL)——让飞控代码先飞一会儿

说实话,很多刚入行的朋友容易犯一个错误:代码写完就直接往真机上跑。我当年也干过这事,结果嘛……嗯,炸鸡了。从那以后,我养成了一个习惯——先做SIL,再谈真机

软件在环测试,说白了就是把飞控代码放到仿真环境里跑。你想想看,不用螺旋桨、不用电池、不用担心中午炸机,多好。今天我就带你走一遍SIL的完整流程。

3.1 SIL环境搭建——你的第一个虚拟试飞场

搭建SIL环境,核心就三样东西:飞控模型仿真器通信桥梁。我个人习惯用这套组合:

组件 推荐工具 作用
飞控固件 PX4 / ArduPilot 你要测试的代码本体
仿真器 Gazebo / jMAVSim 模拟物理世界和传感器
通信层 MAVSDK / ROS 2 让飞控和仿真器对话

安装步骤其实不复杂,但有几个坑我得提醒你:

我曾经踩过的坑: 版本不匹配!PX4 v1.13 和 Gazebo 9 搭配没问题,但换成 Gazebo 11 就各种报错。建议先查官方兼容性矩阵,再动手装。

具体安装命令(以Ubuntu 20.04为例):

# 安装PX4依赖
sudo apt update
sudo apt install git zip cmake build-essential genromfs ninja-build exiftool -y

# 克隆PX4源码
git clone https://github.com/PX4/PX4-Autopilot.git --recursive
cd PX4-Autopilot

# 编译并启动SIL仿真
make px4_sitl gazebo

看到控制台输出 INFO [commander] Ready for takeoff!,恭喜你,环境搭好了。

3.2 飞控模型与仿真器配置——让虚拟飞机听话

环境跑起来只是第一步。真正的挑战在于模型配置。你想想看,如果仿真里的飞机和真机参数对不上,那测试结果就是废纸。

我一般会关注这几个关键参数:

  • 气动参数:升力系数、阻力系数、力矩系数
  • 传感器噪声:IMU的零偏、GPS的精度、磁力计的干扰
  • 执行器延迟:电机响应时间、舵机行程

举个例子,在Gazebo里调整四旋翼的模型文件:

<!-- 修改 ~/PX4-Autopilot/Tools/sitl_gazebo/models/iris/iris.sdf -->
<model name="iris">
  <link name="base_link">
    <inertial>
      <mass>1.5</mass>  <!-- 实际重量1.5kg -->
      <inertia>
        <ixx>0.029</ixx>
        <iyy>0.029</iyy>
        <izz>0.055</izz>
      </inertia>
    </inertial>
  </link>
</model>
我的小技巧: 把真机的CAD模型导出的惯性参数直接填进去。这样仿真出来的响应曲线,和真机实测的吻合度能到90%以上。

3.3 自动化测试脚本编写——解放双手的关键

手动跑SIL?一次两次还行,跑100次你手就废了。所以自动化脚本是必须的。我习惯用Python写测试脚本,配合MAVSDK控制飞控。

一个典型的自动化测试脚本长这样:

#!/usr/bin/env python3
import asyncio
from mavsdk import System

async def run_mission():
    drone = System()
    await drone.connect(system_address="udp://:14540")
    
    print("等待飞控就绪...")
    async for state in drone.core.connection_state():
        if state.is_connected:
            print("已连接!")
            break
    
    # 上传航线任务
    mission_items = [
        MissionItem(47.398, 8.545, 10, 10, True, float('nan'), float('nan'), 
                    MissionItem.CameraAction.NONE, float('nan'), float('nan'), 
                    float('nan'), float('nan'), float('nan')),
        # ... 更多航点
    ]
    
    await drone.mission.upload_mission(mission_items)
    await drone.mission.start_mission()
    
    # 监控飞行状态
    async for position in drone.telemetry.position():
        print(f"高度: {position.relative_altitude_m:.2f}m")
        if position.relative_altitude_m < 0.5:
            print("降落完成")
            break

if __name__ == "__main__":
    asyncio.run(run_mission())
核心要点: 脚本里一定要加超时机制和异常处理。我曾经有一次脚本没加超时,仿真跑了整整一夜,第二天发现飞机早就撞地了,但脚本还在傻等。

3.4 测试用例设计——覆盖比完美更重要

测试用例怎么设计?我的原则是:先覆盖,再优化。别想着一次写出完美的用例,先保证该测的都测了。

我一般把测试用例分成这几类:

  1. 功能测试:起飞、悬停、航线飞行、降落
  2. 边界测试:最大速度、最大高度、最小电量
  3. 故障注入:GPS丢失、电机失效、传感器漂移
  4. 回归测试:每次代码提交后跑一遍

举个例子,GPS丢失的测试用例:

测试编号:TC-FAIL-001
测试名称:GPS信号丢失后自动切换为惯性导航
前置条件:飞机处于悬停状态,GPS信号正常
测试步骤:
  1. 在仿真中关闭GPS输出
  2. 观察飞控状态切换
  3. 等待30秒后恢复GPS
  4. 检查位置误差
预期结果:
  - 飞控应在2秒内切换到惯性导航模式
  - 恢复GPS后位置误差小于5米
实际结果:(测试后填写)
结论:通过/失败
注意: 故障注入测试一定要做恢复测试。我见过太多案例,故障注入后系统能扛住,但恢复时直接崩了。说白了,能进能退才是真本事。

3.5 知识体系总览

下面这张图,是我自己整理的SIL测试知识体系。你照着这个框架走,基本不会漏掉关键环节:

软件在环测试(SIL)知识体系 环境搭建 模型与仿真器 测试脚本与用例 PX4/ArduPilot + Gazebo MAVSDK/ROS 2通信层 版本兼容性检查 气动参数配置 传感器噪声建模 执行器延迟仿真 Python自动化脚本 功能/边界/故障测试 回归测试与报告 可靠的飞控代码 → 真机测试

你看,整个SIL测试其实就围绕这三块展开。环境搭好了,模型配准了,脚本和用例到位了,剩下的就是让代码在仿真里反复跑、反复验证。

最后说一句: SIL测试不是走过场。我见过太多团队,SIL跑一遍就急着上真机,结果真机出问题又回来改代码。其实SIL阶段多花一天,真机阶段能省一周。这笔账,你算算看。

公众号:蓝海资料掘金营,微信deep3321