ArduPilot 电机失效测试 Lua 脚本(motor_failure_test)完全指南
【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot
导读
本指南围绕 ArduPilot 仓库中 motor_failure_test.md 与其配套脚本 motor_failure_test.lua 展开,讲解如何在 ArduCopter 与 ArduPlane(QuadPlane/VTOL)上通过一个 RC 开关在飞行中人为停止指定电机,用于验证多旋翼/垂起飞行器在单电机或多电机失效时的飞行控制表现。读完本文,你将掌握该脚本的安装启用方式、MOT_STOP_BITMASK位掩码的精确配置方法、开关触发逻辑,以及脚本底层基于 100Hz 调度与 PWM 覆盖超时机制的安全设计原理。
脚本是什么:在真实飞行中模拟电机失效
motor_failure_test是一段完整的 Lua Applet,其目标非常明确——在飞行过程中真正停止一个或多个电机,模拟真实电机失效场景。相比在地面静态测试电机的启停,飞行中的电机失效测试能直接检验飞控的姿态/位置控制余量、混控器的容错能力以及整机在推力缺失下的表现。
根据 motor_failure_test.md 的说明,该脚本的适用机型与前提条件如下:
- Copter(ArduCopter)与 QuadPlane(仅 VTOL 模式);
- 八电机及以上(如 X8、八轴)的机型:在单个电机失效时应能轻松保持飞行;
- 六轴(Hexa)机型:在推力充足的前提下同样可以应对单个电机失效;
- 四轴等电机数更少的机型不具备足够的容错能力,不建议使用本脚本进行失效测试。
安装与启用:三步加载脚本
根据 libraries/AP_Scripting/applets/README.md 的说明,所有 Applet 都是"开箱即用"的完整脚本,无需用户编辑脚本内部任何代码,只需完成以下三步:
- 拷贝脚本文件:将 motor_failure_test.lua 复制到飞控 SD 卡(或内部存储)的
APM/scripts目录下; - 启用脚本引擎:将
SCR_ENABLE参数设为1,并确保当前飞控硬件具备运行 Lua 脚本的能力; - 重启飞控:让脚本管理器扫描并加载
APM/scripts目录下的脚本。
脚本加载成功后,它会在参数系统中动态注册新参数MOT_STOP_BITMASK(详见下文"参数解析"),这正是原文档所说"该参数由脚本添加、只有脚本加载到 SD 卡后才会出现"的原因。
配置参数详解
MOT_STOP_BITMASK:指定要停止的电机
脚本通过param:add_table机制动态注册参数。在 motor_failure_test.lua 中可以看到:
-- add new param MOT_STOP_BITMASK local PARAM_TABLE_KEY = 75 assert(param:add_table(PARAM_TABLE_KEY, "MOT_", 1), "could not add param table") assert(param:add_param(PARAM_TABLE_KEY, 1, "STOP_BITMASK", 0), "could not add param")参数表键值(PARAM_TABLE_KEY)为 75,前缀为MOT_,最终注册出的完整参数名为MOT_STOP_BITMASK,默认值为0。param:add_table/param:add_param是 ArduPilot Lua 绑定中的标准参数注册接口,在 BattEstimate.lua 等多个 Applet 中都有相同用法。
MOT_STOP_BITMASK是一个按位编码(bitmask)的电机编号掩码,其语义如下:
| 参数值 | 二进制表示 | 被停止的电机 |
|---|---|---|
| 0 | 000000000000 | 不停止任何电机(默认,全部正常运行) |
| 1 | 000000000001 | 电机 1(Motor1) |
| 2 | 000000000010 | 电机 2(Motor2) |
| 3 | 000000000011 | 电机 1 和 电机 2 |
| 4 | 000000000100 | 电机 3 |
| 8 | 000000001000 | 电机 4 |
| 任意组合 | 各位累加 | 对应位置的电机全部停止 |
即:值 1 停止电机 1,值 2 停止电机 2,值 3 同时停止电机 1 和 2,依此类推。该参数支持的最高电机编号为12——脚本在 motor_failure_test.lua 中只遍历了1..12共 12 个电机位。
RC 开关:触发失效的"扳机"
失效触发由一个RC 通道辅助开关(RC switch option 300,即 Scripting1)控制:
- 开关低(位置 LOW):所有电机正常运行;
- 开关高(位置 HIGH):按
MOT_STOP_BITMASK指定的电机被停止。
脚本在启动时通过 Lua 绑定rc:find_channel_for_option(300)查找被配置为 option 300 的 RC 通道(motor_failure_test.lua),找不到时会直接断言报错退出。底层实现位于 RC_Channel.cpp:RC_Channels::find_channel_for_option会遍历全部 RC 通道,返回option参数值等于 300 的那一路。
开关位置判断依赖 RC_Channel.cpp 中的get_aux_switch_pos()逻辑:RC PWM 低于触发阈值(AUX_PWM_TRIGGER_LOW)判为 LOW,高于阈值(AUX_PWM_TRIGGER_HIGH)判为 HIGH,中间为 MIDDLE。脚本仅对 HIGH(位置值 2)响应,因此请将开关拨到高位来触发电机停止。
配置方法:在地面站(如 Mission Planner / QGC)中,将某个 2 段或 3 段开关对应的 RC 通道功能(RCn_OPTION)设为300(Scripting1),并确认开关在高位/低位的 PWM 落在触发阈值之外。
停止电机的 PWM 基准:PWM_MIN 的作用
脚本停止电机的方式,是把目标电机通道的 PWM 输出强制覆盖为电机最低 PWM(PWM_MIN)。它在脚本加载时读取该值(motor_failure_test.lua):
-- read spin min param, we set motors to this PWM to stop them local pwm_min if quadplane then pwm_min = assert(param:get("Q_M_PWM_MIN"),"Lua: Could not read Q_M_PWM_MIN") else pwm_min = assert(param:get("MOT_PWM_MIN"),"Lua: Could not read MOT_PWM_MIN") end- Copter:读取
MOT_PWM_MIN,该参数定义在 AP_MotorsMulticopter.cpp,默认值1000(单位 PWM/微秒),取值范围0~2000,含义是"永远不会输出到电机的最低 PWM 值"; - QuadPlane:读取
Q_M_PWM_MIN(QuadPlane 的电机最低 PWM 参数)。
将电机 PWM 拉低到 PWM_MIN 即等效于让该电机停转(电调收到最低信号不再驱动电机旋转)。
源码级工作原理:从位掩码到 PWM 输出的完整链路
1. 电机编号 → 输出功能 → 输出通道的映射
每次MOT_STOP_BITMASK发生变化时,脚本会执行update_stop_motors()重建需要停止的通道列表(motor_failure_test.lua)。映射规则在源码中清晰可见:
for i = 1, 12 do if ((1 << (i-1)) & new_bitmask) ~= 0 then -- convert motor number to output function number local output_function if i <= 8 then output_function = i+32 else output_function = i+81-8 end ...- 电机 1~8:输出功能号 = 电机号 + 32,即33~40,对应 SRV_Channel 枚举中的
Motor1~Motor8(见 SRV_Channel.cpp 中33:Motor1 ... 40:Motor8的枚举定义); - 电机 9~12:输出功能号 = 电机号 + 81 - 8,即82~85,对应
Motor9~Motor12(见 SRV_Channel.cpp 中82:Motor9 ... 85:Motor12)。
随后通过SRV_Channels:find_channel(output_function)将该输出功能映射到具体的伺服/输出通道号,存入stop_motor_chan表。若某个功能号当前没有对应通道(未配置),则该电机会被跳过,不会报错。
2. 100Hz 主循环与 15ms 覆盖超时
脚本的主循环update()(motor_failure_test.lua)以100Hz(每 10ms 一次)的节奏被重新调度:
function update() update_stop_motors(stop_motor_bitmask:get()) if switch:get_aux_switch_pos() == 2 then for i = 1, #stop_motor_chan do -- override for 15ms, called every 10ms -- using timeout means if the script dies the timeout will expire and all motors will come back -- we cant leave the vehicle in a un-flyable state SRV_Channels:set_output_pwm_chan_timeout(stop_motor_chan[i],pwm_min,15) end end return update, 10 -- reschedule at 100hz end return update() -- run immediately before starting to reschedule当开关位于高位(get_aux_switch_pos() == 2)时,对每个待停止通道调用 Lua 绑定SRV_Channels:set_output_pwm_chan_timeout(chan, pwm, timeout_ms)(绑定声明见 docs.lua),把该通道 PWM 覆盖为pwm_min,超时时间设为 15ms。
3. 安全机制:脚本崩溃自动恢复
这是该脚本最值得关注的设计:每次 PWM 覆盖的超时(15ms)短于循环周期(10ms)。只要脚本正常运行,10ms 一次的重新覆盖会让停止状态持续保持;而一旦脚本因任何原因停止运行(崩溃、被禁用、被删除),15ms 后超时自动到期,所有被覆盖的电机通道会自动恢复为正常输出,全部电机重新运转。
正如源码注释所强调的:
"using timeout means if the script dies the timeout will expire and all motors will come back — we can't leave the vehicle in an un-flyable state"
即脚本通过超时机制保证:任何异常情况下飞行器都不会被"永久锁死"在部分电机停转的不可飞状态,从而把测试风险控制在一个安全边界内。
实战使用建议与注意事项
- 测试前提:仅在电机数满足容错条件(八轴及以上,或推力充足的六轴)的机型上使用本脚本;开始前请务必在地面确认
MOT_STOP_BITMASK的目标电机编号与实物电机一致,避免停错电机造成失控。 - 安全高度与空域:飞行中电机失效测试应在足够高度、开阔空域进行,并随时准备通过开关低位恢复所有电机。
- 开关状态确认:确认 option 300 所在通道的开关高低位判断正确,避免拨动方向相反导致测试意外触发。
- 参数动态注册:
MOT_STOP_BITMASK仅在脚本成功加载后才出现于参数列表,若地面站中看不到该参数,请检查SCR_ENABLE=1、脚本路径是否为APM/scripts/motor_failure_test.lua。 - 故障日志记录:测试过程中可结合飞控的故障保护与日志分析,观察电机失效后飞控的姿态保持能力与混控补偿效果。
延伸阅读
- 脚本主文件:motor_failure_test.lua
- 官方说明文档:motor_failure_test.md
- Applet 通用安装说明:libraries/AP_Scripting/applets/README.md
- 底层实现:RC_Channel.cpp(开关查找与位置判断)、AP_MotorsMulticopter.cpp(
MOT_PWM_MIN定义)、SRV_Channel.cpp(输出功能号枚举)、docs.lua(Lua API 绑定)
【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考