3、故障注入基础:概念、分类与注入方法
各位同学好,我是老张。今天咱们聊聊故障注入。
说实话,我刚开始做飞控测试那会儿,觉得这玩意儿挺玄乎的。不就是让系统出点错吗?后来真在项目里栽了跟头,才明白——故障注入不是搞破坏,而是帮我们提前发现系统的软肋。
3.1 故障注入的概念
故障注入,说白了就是故意给系统制造麻烦。我们主动往飞控系统里塞一些异常情况,然后观察它怎么反应。
为什么要这么做?你想想看,飞机在天上飞,什么情况都可能遇到——传感器突然坏了、通信链路断了、CPU死机了。如果等到真出事了才发现系统扛不住,那代价可就大了。
核心思想:故障注入 = 主动制造异常 → 观察系统行为 → 评估容错能力 → 改进设计
我在做某型无人机飞控时,就遇到过这么个事。地面测试一切正常,结果第一次试飞,GPS信号突然丢失,飞机直接失控了。后来一查,原来是飞控软件里对GPS失效的处理逻辑有bug。如果当时做了故障注入测试,这个问题早就能发现。
3.2 故障的分类
故障的类型很多,我习惯把它们分成三大类:硬件故障、软件故障、通信故障。
3.2.1 硬件故障
硬件故障是最直观的。传感器坏了、执行器卡住了、电源掉电了,这些都是硬件层面的问题。
| 故障类型 | 典型例子 | 影响 |
|---|---|---|
| 传感器故障 | IMU输出漂移、GPS无信号 | 姿态估计错误 |
| 执行器故障 | 舵机卡死、电机停转 | 控制失效 |
| 电源故障 | 电压跌落、瞬间掉电 | 系统复位 |
| 内存故障 | 位翻转、数据损坏 | 程序跑飞 |
嗯,这里要注意一点:硬件故障不一定是完全失效。比如IMU的零偏慢慢漂移,这种渐进式故障其实更难检测。
3.2.2 软件故障
软件故障就更有意思了。代码里藏着各种坑——数组越界、死循环、任务优先级反转……
我曾经遇到过一个问题:飞控程序跑着跑着突然不响应了。查了两天才发现,是一个定时器中断服务函数里调用了printf,导致中断嵌套把栈给撑爆了。这种软件故障,你不做注入测试,光靠代码审查很难发现。
我的经验:软件故障注入最常用的手段是修改内存数据、篡改函数返回值、模拟任务超时。说白了就是让软件以为某些条件成立了,实际上并没有。
3.2.3 通信故障
通信故障在飞控系统里特别常见。毕竟飞机上有那么多传感器、执行器,还有地面站,数据链路一旦出问题,后果很严重。
- 丢包:数据包在传输过程中丢失了
- 延迟:数据包到达时间比预期晚
- 乱序:数据包到达的顺序和发送时不一样
- 数据损坏:数据包内容被篡改
- 链路中断:完全失去连接
我记得有一次做无人机编队测试,两架飞机之间的通信链路偶尔会中断几毫秒。就这么几毫秒,编队队形就乱了。后来我们在通信协议里加了心跳机制和超时重传,才算解决。
3.3 注入方法
知道了故障类型,接下来就是怎么把故障注入进去。常用的方法有三种:修改参数、模拟信号、篡改数据包。
3.3.1 修改参数
这是最直接的方法。在飞控软件运行过程中,直接修改某个参数的值。
// 示例:注入IMU零偏故障
// 正常情况下的IMU数据
float gyro_x = read_gyro_x();
// 注入故障:在gyro_x上叠加一个偏置
float fault_bias = 0.05; // 0.05 rad/s 的偏置
gyro_x += fault_bias;
// 将故障数据送入姿态解算模块
attitude_estimate(gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z);
这种方法的好处是简单,不需要额外硬件。但要注意,修改参数时要确保不会引发系统崩溃——我们是要测试容错能力,不是要搞破坏。
3.3.2 模拟信号
模拟信号注入需要硬件支持。比如用信号发生器给传感器接口注入一个错误的电压信号,或者用电阻网络模拟传感器输出。
我当年做某型飞控的硬件在环测试时,就用过这种方法。把IMU的SPI接口断开,接上一个FPGA板子,让它模拟IMU输出各种异常数据——比如输出全零、输出饱和值、输出随机噪声。
警告:模拟信号注入一定要做好隔离!我曾经有一次不小心把信号发生器的输出接到了飞控板的电源上,结果烧了一块板子。嗯,从那以后我每次接线都要反复检查三遍。
3.3.3 篡改数据包
这种方法主要针对通信链路。在数据包传输过程中,截获并修改数据包的内容。
// 示例:篡改GPS数据包
// 假设我们截获了一个GPS NMEA数据包
char gps_packet[] = "$GPGGA,123519,4807.038,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47";
// 篡改经纬度数据
// 把纬度从 4807.038 改成 4807.500
char tampered_packet[] = "$GPGGA,123519,4807.500,N,01131.000,E,1,08,0.9,545.4,M,46.9,M,,*47";
// 将篡改后的数据包发送给飞控
send_to_fc(tampered_packet);
这种方法特别适合测试飞控对数据完整性的校验能力。如果飞控没有做CRC校验或者校验逻辑有漏洞,篡改的数据包就会被当成有效数据使用,后果可想而知。
3.4 知识体系总览
下面这张图是我自己画的,把故障注入的核心逻辑串起来了。大家可以对照着看,心里有个整体框架。
3.5 避坑指南
最后,分享几个我踩过的坑,希望能帮大家少走弯路。
避坑1:故障注入不是一次性的事。我见过很多团队,只在开发后期做一次故障注入测试,然后就觉得万事大吉了。其实应该在每个迭代周期都做,特别是修改了关键模块之后。
避坑2:注入的故障要贴近真实场景。别搞那些现实中根本不会出现的故障。比如你非要测试飞控在-200°C下的表现,那纯属浪费时间。
避坑3:做好故障注入的日志记录。我曾经有一次做了几十次注入测试,结果忘了记录每次注入的参数和结果,最后分析时一头雾水。现在我的习惯是,每次注入前先写日志,注入后再写结果,形成完整的测试报告。
好了,关于故障注入的基础知识就讲到这里。记住一句话:故障注入不是目的,提升系统的健壮性才是。
公众号:蓝海资料掘金营,微信deep3321