仿真、测试、调试与安全回滚¶
飞控测试不是“刷进去能启动,再试飞看看”。正确顺序是先用低成本、可重复、不会产生动力的环境排除问题,再逐级增加真实硬件和物理风险。

六层验证¶
1. 静态检查¶
检查:
- 编译警告;
- 格式和代码规范;
- 静态分析;
- 未定义行为;
- 越界和空指针;
- 单位和类型;
- 未使用或不可达代码;
- 依赖和许可证变化。
静态检查不能证明运行时正确,但能用较低成本排除一类缺陷。
2. 主机端单元测试¶
适合验证:
- 数学函数;
- 协议解析;
- 参数范围和迁移;
- 滤波器;
- 坐标变换;
- 控制器边界;
- 故障状态机。
测试应覆盖正常值、边界值、无效值、溢出、非数值和状态切换。
3. 软件在环¶
软件在环(SITL,Software In The Loop)让飞控逻辑在主机系统上与仿真模型交互,适合:
- 自动任务;
- 模式切换;
- 参数行为;
- 失联和传感器故障;
- 回归场景;
- 批量自动化。
软件在环通常不会真实复现处理器时序、总线电气、电源、缓存和全部驱动行为。
4. 硬件在环¶
硬件在环(HITL,Hardware In The Loop)或硬件环仿真让真实飞控硬件运行固件,由仿真器提供传感器或环境反馈。
它可以增加对真实处理器、调度、输入输出和部分驱动的覆盖,但测试能力取决于具体注入边界。只把姿态数据发给飞控,不代表已经验证真实IMU总线。
5. 拆桨台架¶
在真实接线和供电条件下验证:
- 启动和恢复;
- 传感器方向;
- 接收机和失联;
- 电压、电流和温度;
- 电机编号和方向;
- 输出范围;
- 日志完整性;
- 看门狗和故障上报。
必须拆除螺旋桨。软件界面中的“电机测试”按钮不会消除物理风险。
6. 受控飞行¶
只验证前五层无法覆盖的空气动力、振动、真实链路和整机行为。需要:
- 合法、隔离且有足够缓冲区的场地;
- 明确测试卡;
- 受控飞行包线;
- 观察员和中止条件;
- 基线与修改版对照;
- 完整日志;
- 每次只增加有限风险。
软件在环和硬件在环不能互相替代¶
| 能力 | SITL | HITL | 拆桨台架 | 受控飞行 |
|---|---|---|---|---|
| 算法逻辑 | 强 | 强 | 中 | 强 |
| 自动化回归 | 强 | 中 | 弱 | 弱 |
| 真实处理器时序 | 弱 | 强 | 强 | 强 |
| 真实传感器总线 | 通常无 | 取决于注入边界 | 强 | 强 |
| 电源和接线 | 无 | 部分 | 强 | 强 |
| 空气动力和振动 | 模型 | 模型 | 无 | 强 |
| 人身和财产风险 | 低 | 低至中 | 中 | 高 |
表中的“强”表示相对覆盖能力,不代表单次测试已经充分。
PX4 v1.17.0的可执行测试路线¶
以下命令在已经完成可执行基线构建后运行:
| 目标 | 命令或操作 | 通过标准 | 失败后 |
|---|---|---|---|
| 工作区完整 | git status --short |
只有本次预期修改 | 停止并识别额外差异 |
| 文本差异 | git diff --check |
无空白错误,退出码0 | 修正后重跑 |
| 主机测试 | make tests |
全部测试结束且退出码0 | 保留第一个失败用例和日志 |
| 启动SITL | make px4_sitl sihsim_quadx |
出现pxh>且无启动错误 |
保留完整构建与启动输出 |
| 核对版本 | ver all |
报告与固定基线一致 | 停止,检查目录和构建缓存 |
| 运行示例 | hello start |
出现hello、五次Doing work...和goodbye |
检查构建注册与源码差异 |
| 读取主题 | listener vehicle_acceleration 5 |
返回5个带时间戳样本 | 检查仿真、主题名称和发布者 |
| 退出 | shutdown |
进程正常退出 | 记录卡死位置 |
make tests验证主机测试集合,不能代替SITL;SITL使用主机调度,不能据此声明目标微控制器满足实时期限。
构建或SITL异常时的固定检查¶
先把证据放在源码目录之外,避免污染git status:
EVIDENCE_DIR="../px4-evidence/$(date +%Y%m%d-%H%M%S)"
mkdir -p "$EVIDENCE_DIR"
pwd | tee "$EVIDENCE_DIR/pwd.txt"
git rev-parse --show-toplevel | tee "$EVIDENCE_DIR/root.txt"
git rev-parse HEAD | tee "$EVIDENCE_DIR/head.txt"
git status --short | tee "$EVIDENCE_DIR/status.txt"
git submodule status --recursive | \
tee "$EVIDENCE_DIR/submodules.txt"
捕获测试输出和真实退出码:
set -o pipefail
make tests 2>&1 | tee "$EVIDENCE_DIR/make-tests.log"
TEST_STATUS=${PIPESTATUS[0]}
printf 'tests_exit=%s\n' "$TEST_STATUS" | \
tee "$EVIDENCE_DIR/make-tests.exit"
先查看第一条失败,而不是只看最后一屏:
rg -ni -m 20 \
"error|failed|failure|traceback|ninja: build stopped|no such file" \
"$EVIDENCE_DIR/make-tests.log"
如果没有匹配结果,直接查看日志开头和结尾:
如果修改后的SITL仍显示旧文字,依次确认:
pwd
git rev-parse HEAD
git status --short
rg -n "learning-build: read-only diagnostic v1" \
src/examples/hello/hello_main.cpp
只有在保存日志、确认源码差异后,才隔离明确的SITL构建目录:
BUILD_DIR="build/px4_sitl_default"
test -f "$BUILD_DIR/CMakeCache.txt" || exit 1
mv "$BUILD_DIR" \
"$EVIDENCE_DIR/px4_sitl_default.failed"
git submodule update --init --recursive
make px4_sitl sihsim_quadx
这样既强制重新生成该目标,又保留旧构建供比较。PX4的distclean会反初始化子模块并清理部分忽略文件,不应在包含开发数据的工作副本中作为普通排障步骤;也不得使用git clean -fdx或手工删除不明目录替代。重新构建后问题仍存在时,回到日志中的第一条错误,不继续叠加修改。
故障注入怎么开始¶
在SITL控制台先执行:
只使用该固定版本帮助中实际列出的命令和组件。每个故障场景先写出:
若帮助中没有对应注入能力,应编写测试替身或使用更高一层测试环境,不要把“没有观察到故障”解释为测试通过。
故障注入¶
至少考虑:
- 传感器停止更新;
- 时间戳跳变或样本延迟;
- 总线超时和错误;
- GNSS丢失或跳点;
- 磁力计不一致;
- 遥控链路丢失;
- 数据链中断;
- 电池低电压;
- 参数损坏;
- 存储写入失败;
- CPU过载;
- 执行器饱和或失效;
- 系统重启。
故障注入必须定义预期检测时间、状态转换、输出动作、日志证据和恢复条件。
调试证据的优先级¶
推荐顺序:
- 可重复步骤;
- 版本和配置;
- 状态与错误码;
- 时间戳日志;
- 任务和资源统计;
- 断言与崩溃转储;
- 调试器断点和内存检查;
- 示波器或逻辑分析仪;
- 受控故障注入。
大量打印不是可靠的第一选择。它可能改变时序、填满缓冲区并掩盖原问题。
使用调试器¶
GNU调试器(GDB,GNU Debugger)配合SWD或联合测试行动小组接口(JTAG,Joint Test Action Group)可用于:
- 停止在异常位置;
- 查看调用栈;
- 检查寄存器和内存;
- 设置断点和观察点;
- 解析硬故障;
- 下载或恢复固件。
在实时控制任务中暂停处理器会冻结输出和看门狗状态。连接真实动力系统时不得随意断点调试。
建立恢复路径¶
通用恢复步骤无法替代具体板卡文档,因为恢复按键、USB标识、引导加载程序、闪存地址和调试接头都可能不同。刷写前必须把下表填写为可执行值:
| 项目 | 必须记录 |
|---|---|
| 正常上传 | 完整命令、端口、成功输出 |
| 进入引导模式 | 按键、跳线、上电顺序或命令 |
| 设备识别 | USB标识、串口名称或调试探针 |
| 应用镜像 | 文件、目标、提交和SHA-256 |
| 引导镜像 | 官方文件、版本和适用板卡 |
| SWD/JTAG | 接头针脚、电压、工具和配置 |
| 擦写地址 | 仅使用目标板官方内存布局 |
| 参数恢复 | 备份文件、版本和导入验证 |
| 成功标志 | 启动信息、版本、传感器和通信 |
| 停止条件 | 身份不符、供电异常或校验失败 |
例如,只有在真实硬件已确认属于px4_fmu-v5_default目标时,正常上传命令才可以写为:
官方示例的成功输出包括Erase、Program、Verify达到100%,随后Rebooting。若设备不能进入现有引导加载程序,就必须改用该板卡官方恢复说明和正确SWD接线;不能猜测闪存地址,也不能把FMUv5命令套到相似板卡。
恢复流程必须实际演练。只保存一个文件名而没有对应版本、地址和操作步骤,不算恢复方案。
测试卡模板¶
| 字段 | 内容 |
|---|---|
| 目标 | 本次只验证什么 |
| 基线 | 固件、提交、参数和硬件 |
| 改动 | 补丁或配置差异 |
| 环境 | 仿真模型、台架或场地 |
| 前置条件 | 拆桨、限流、区域和人员 |
| 步骤 | 可重复操作 |
| 期望结果 | 数值范围、状态和时限 |
| 中止条件 | 何时立即停止 |
| 证据 | 日志、波形、录像和校验值 |
| 恢复 | 回到已验证基线的方法 |
发布门禁¶
- 所有新增代码经过评审;
- 基线和修改版测试使用相同场景;
- 自动测试可重复运行;
- 时序、闪存、内存和日志开销在预算内;
- 参数和消息兼容性已验证;
- 失效与恢复路径有证据;
- 板级目标和硬件版本明确;
- 没有跳过的高风险未知项;
- 受控飞行没有超出预先批准的包线;
- 发布产物、源码和测试记录能够对应。
检查理解¶
- 软件在环为什么不能证明真实总线和电源正确?
- 硬件在环的覆盖范围为什么取决于注入边界?
- 大量打印为什么可能改变原始故障?
- 调试器断点为什么不能在带真实动力的系统中随意使用?
- 什么条件满足后才算具有可执行的恢复路径?