ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

给 ArduPilot 加自定义逻辑:一个 .lua 文件跑通飞控二次开发

2026/9/11 19:06:50 拓冰建站 浏览量
给 ArduPilot 加自定义逻辑:一个 .lua 文件跑通飞控二次开发 给 ArduPilot 加自定义逻辑一个 .lua 文件跑通飞控二次开发【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilotArduPilot 的固件功能强大但总有改不动的时候想提前 30 秒低电压告警、想给日志加一列自己算的字段、想让任务里某个航点触发一段专属逻辑——这些需求去翻 C 源码改固件成本太高。ArduPilot 的 Lua 脚本引擎就是为此设计的往 SD 卡里丢一个.lua文件飞控启动时自动加载脚本通过 ahrs、gcs、voltage_sensor 这些内置对象直接读写飞控状态不用碰一行 C。本文带你从脚本跑起来到看懂底层怎么调度的再到真实场景用法和那些我踩过、你也可能踩的坑。适合刚接触 ArduPilot 二次开发或者受够了要加个功能就得重刷固件的开发者。30 秒把脚本跑起来 先看前置条件两条就够飞控的 flash 得超过 1MBF7/H7 这一档基本都满足AEROFOX-H7、CubeBlack 这类都行脚本会自动在固件里编译进来不用你改任何宏如果你手上没板子SITL 模拟器天然带脚本支持可以直接开干。启用步骤极简把参数SCR_ENABLE设为 1重启飞控。系统会自动创建脚本目录——实机上在 SD 卡的/APM/scripts/SITL 里是工作目录下的scripts/文件夹。往这个目录里丢一个.lua文件重启后它就活了。下面这个脚本跑通你就入门了全文就这几个 API记住返回 function 延迟毫秒这个节奏就行local function update() gcs:send_text(5, Hello from ArduPilot Lua) return update, 5000 -- 5 秒后再调我一次 end return update, 1000 -- 脚本加载 1 秒后第一次执行几个关键参数平时基本不动遇到对应症状再来改参数默认值什么时候碰它SCR_ENABLE0首次启用时设 1改完必须重启SCR_HEAP_SIZE43KB / 100KB / 200KB按内存档位自动给大脚本 OOM 就加它SCR_VM_I_COUNT10000单次回调的 VM 指令上限脚本被Exceeded CPU time干掉时相关SCR_THD_PRIORITYNormal脚本线程优先级想抢资源再调默认值就是安全的SCR_DEBUG_OPTS0按位开关比如第 1 位打开内存/耗时运行日志底层是怎么转的 ⚙️数据流一句话讲清启动后 AP_Scripting::init() 创建一个低优先级的独立线程脚本在这个线程里跑和主控制回路不抢 CPU然后 lua_scripts 扫一遍脚本目录把每个.lua文件读进一个独立沙箱环境脚本之间互相看不到变量也碰不到危险 API。之后就是回调-调度循环每个脚本执行完用返回值告诉调度器几毫秒后再叫我调度器按next_run_ms维护一个有序链表到点就取一个脚本跑。CPU 方面有个看门狗每执行SCR_VM_I_COUNT条 VM 指令触发一次 hook超时直接抛 Exceeded CPU time 并把该脚本移除——所以你在 Lua 里写死循环飞控不会跟着卡死只是你的脚本会被杀掉。脚本够得着什么看 bindings 生成的绑定层ahrs 拿姿态位置、voltage_sensor 拿电池、gcs 发消息、vehicle 改参数都是对固件 C 接口的封装。也就是说Lua 不是外挂它和固件跑在同一颗 MCU 上只是隔着一层受控的桥。三个真实场景告警、遥测、任务联动 场景一低电压提前告警。默认 failsafe 的电压阈值是死的但你常想在触发保护之前先通知地面站电压开始不对劲了。思路低频轮询voltage_sensor:get_voltage(0)低于自己设的线比如 10.5V就发 GCS 文本严重的直接切模式。回调间隔 1 秒足够别用 10ms——电池电压不会一毫秒变一次local function monitor() local v voltage_sensor:get_voltage(0) if v and v 10.5 then gcs:send_text(0, Low batt: .. v .. V) end return monitor, 1000 end return monitor, 1000这种阈值告警 自定义动作的模式可以套任何传感器温度、空速、地形高度都一样换个 API 就行。场景二把算过的数据送到地面站或日志。有人要往遥测里塞自定义字段比如自己算的电机温度均值、航向积分漂移有人要把传感器原始帧解析后记进 DataFlash。这里推荐先看仓库里现成的 frsky_battery.lua 和 logging.lua前者演示怎么把数据打包进 CRSF 遥测的自定义包后者演示log对象怎么写自定义日志消息。套路都是同一个——低频回调里算好通过绑定 API 发出去一次别算太多。场景三任务指令联动脚本。上面两个场景脚本都是常驻轮询还有另一种玩法脚本平时不做事等任务mission里的 scripting 指令来触发。机制是固件收到任务指令后把它推进一个队列handle_mission_command脚本通过 mission 模块拉取并处理。落地效果就是航线里某个航点打电话给你的脚本脚本执行完自定义逻辑比如换参数组、起降吊舱、切拍摄参数再继续飞任务。仓库的 applets 目录 里有一批这种半成品——param-lockdown、advance-wp、copter-deadreckon-home这类读一个现成的比自己从零写快十倍。翻车现场与自救指南 启动后 GCS 报 Unable to allocate memory。症状是脚本线程直接没起来。方向SCR_HEAP_SIZE太小或者你一次性堆了十几个脚本。把堆从 43KB 提到 100KB改完重启实在不行先砍脚本数量——堆是固定预分配的不是弹性内存。某脚本突然消失日志报 Exceeded CPU time。就是单次回调干太多活了死循环、大数组、或者 10ms 频率回调里塞了复杂计算。方向查这个脚本里最重的那段逻辑把回调间隔拉长实在需要算的拆成多次回调分步算。日志报 did not return a function 或 did not return a delay。回调里 return 的格式不对——必须是函数引用 数字毫秒两个值少一个这个脚本就被永久移除不会重试。这是新手最高频的翻车点对着开头那个最小脚本抄格式就对了。脚本明明放进去了就是不加载。三连查文件是不是.lua结尾点开头隐藏文件不扫目录对不对实机/APM/scripts/SITL 是工作目录下scripts/SD 卡格式是不是飞控认的。用SCR_DEBUG_OPTS打开第 0 位加载失败时会有明确提示而不是静默。解锁arming被拦报错带 Scripting: ... 字样。前起检查会把脚本的最后一条错误原样报出来——脚本加载失败会直接阻止解锁这是保护机制不是 bug。方向先按上面方法修好脚本错误另外如果你启过SCR_LD_CHECKSUM/SCR_RUN_CHECKSUM校验和换过脚本没更新校验和参数也会拦解锁。接下来去哪 想系统学按这个顺序翻AP_Scripting/README.md 讲构建侧怎么启用examples 目录 是 API 用法大全按文件名搜你要的能力ahrs-*、mission-*、can_*applets 目录 是可移植场景包每个都带一份.md说明想读实现入口就是 lua_scripts.cpp 的run_next_script两百行看懂整个调度循环。现在就动手把开头那个 7 行的 hello world 丢进 SITL 的scripts/目录SCR_ENABLE设 1 跑一遍模拟器看到 Hello from ArduPilot Lua 出现在消息框里这条路径你就走通了。【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考