news 2026/9/11 3:23:13

ArduPilot Lua 脚本系统完整指南:不改固件为飞控加装自定义能力

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ArduPilot Lua 脚本系统完整指南:不改固件为飞控加装自定义能力

ArduPilot Lua 脚本系统完整指南:不改固件为飞控加装自定义能力

【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot

ArduPilot 内置的 Lua 脚本引擎允许你在飞控上直接运行 .lua 脚本:读传感器、覆盖舵机、响应任务指令,全程不需要重新编译固件。本文基于源码仓库里的 AP_Scripting 模块拆解三件事:引擎如何加载和调度脚本、一套 SCR_ 参数怎么配、如何在 SITL 里跑通第一个脚本并处理生产环境的坑。读完后你能独立完成"写脚本 → 本地验证 → 上车部署"的完整闭环。

引擎解剖:一个线程、一座沙箱、一个熔断器 🚀

很多人以为脚本和飞控主循环抢 CPU,实际 ArduPilot 的做法是把脚本关进一个独立空间。初始化时,AP_Scripting/核心模块 会创建一个名为 "Scripting" 的专用线程(默认栈 17KB),所有 .lua 脚本共享这一个线程轮流执行。

隔离由三层机制保证,理解它们之后调参就不玄学了:

  • 独立堆:脚本拥有单独的 Lua 堆,大小按平台分级——小容量平台 43KB,MEM_CLASS_500 档 100KB,MEM_CLASS_1000 及以上(含 SITL/Linux)200KB,与飞控主程序内存互不侵占
  • 协作式调度:脚本"函数 + 毫秒延迟"的返回值决定下次执行时间,调度器按时间先后排列所有脚本,谁也不阻塞谁
  • 指令计数熔断:Lua 虚拟机挂了 MASKCOUNT 钩子,累计执行指令数超过SCR_VM_I_COUNT(默认 10000)立即抛出 "Exceeded CPU time",防止死循环脚本烧掉整块飞控

注意:熔断器保护的是 CPU,不是安全。一个脚本用死循环烧死自己后,调度器会清理资源并每秒检查一次是否需要重启,期间其他脚本照常运行。

加载机制:两个目录与一组 SCR_ 参数 🔧

脚本从哪来、以什么条件运行,全部由参数和目录约定控制。上电后引擎扫描两个位置:SD 卡的/APM/scripts/目录和编译进固件的 ROMFS 内置目录,SCR_DIR_DISABLE可按位屏蔽(bit 0=ROMFS,bit 1=APM/scripts)。SITL 环境下脚本直接放在仓库工作目录的scripts/文件夹即可。

核心参数一览,全部以 SCR_ 为前缀,可在 Mission Planner 等地面站直接修改:

  • SCR_ENABLE:总开关,1 启用 Lua 脚本,0 禁用,修改后需重启飞控
  • SCR_HEAP_SIZE:脚本堆大小,1KB 到 1MB,默认值按平台分级,改完需重启
  • SCR_VM_I_COUNT:单脚本指令熔断阈值,范围 1000~1000000,默认 10000
  • SCR_THD_PRIORITY:脚本线程优先级,0(Normal)到 8(Boost),默认 Normal,即低于 IO、存储、主循环等所有系统线程
  • SCR_LD_CHECKSUM / SCR_RUN_CHECKSUM:已加载/正在运行的脚本 CRC32 校验和,不匹配则拒绝解锁,-1 表示不检查
  • SCR_DEBUG_OPTS:位掩码调试选项,bit 1 输出运行时内存与耗时,bit 3 将运行统计写入 dataflash
  • SCR_USER1~USER6:六个 float 用户参数,脚本内可读,适合把"半径""阈值"这类调试点外提

参数配完,下一步是让引擎真正转起来。

跑通第一个脚本:SITL 四步法

不用真机也能完整走一遍流程,SITL 下脚本放在仓库工作目录的scripts/子文件夹:

  1. 启动仿真(脚本支持在闪存大于 1MB 的板型上自动启用):
Tools/autotest/sim_vehicle.py -v ArduPlane
  1. 在地面站或 MAVProxy 中开启脚本引擎并重启:
param set SCR_ENABLE 1 reboot
  1. 把你的 .lua 文件放入scripts/目录,重启后自动加载
  2. 地面站控制台看到 "Scripting: restarted" 且无 Lua 报错即成功

仓库自带的 README 示例是个好起点——它展示了最小可用的"周期性函数"写法,也解释了返回值机制:

function update() local pos, home = ahrs:get_location(), ahrs:get_home() if pos and home then local d = math.min(pos:get_distance(home), 1000) SRV_Channels:set_output_pwm(96, 1000 + d) end return update, 1000 -- 1 秒后再跑一次 end return update, 1000

末尾的return update, 1000就是协作调度的钩子:返回的函数会被按延迟重新排队。输出写到通道 96(SCRIPTING_3),这是专门留给脚本的保留通道,不会干扰真实舵机——验证脚本行为时这是个安全的观察出口。

图:运行 ArduPilot Lua 脚本的飞控,真实硬件上脚本存放于 SD 卡 /APM/scripts 目录

跑通之后,值得看看这个引擎到底开放了哪些手脚。

API 全景:脚本能碰什么

Lua 侧的绑定由 lua_bindings/C 函数绑定层 生成,按用途可以分四类记:

  • 状态读取ahrs:get_location()battery:voltage()esc/motors转速与温度
  • 控制输出SRV_Channels:set_output_pwm()写保留通道、vehicle:change_mode()切模式、RC 通道覆盖
  • 任务集成mission:queue_item()动态追加任务点;注册mission:scripting_cmd_handler后,任务里的 NAV_SCRIPT 指令(cmd 18)执行时,飞控会把参数推给脚本处理——这是"任务规划调脚本"的正式通道,而不是轮询
  • 硬件直连:I2C 设备、CAN 传感器、独立串行口(SCR_SDEV_EN)、网络 socket,等于把飞控当成一块可编程 IO 扩展板

任务指令的例子值得看,它展示了脚本如何被动响应而非主动轮询:

local function on_scripting_cmd(p1, p2, p3, p4) gcs:send_text(0, "NAV_SCRIPT received, p1=" .. p1) end mission:scripting_cmd_handler(on_scripting_cmd)

注册后任务中执行 NAV_SCRIPT 指令时,p1 为整数参数、p2~p4 为 float 参数,回调被调度器统一触发,不会和主控制循环抢时间片。

图:ArduPilot 飞控接线示意,脚本可通过串口、I2C、CAN 等接口直接驱动扩展硬件

能碰的东西越多,越要懂得怎么把它管好。

生产环境调优与避坑

先说最常踩的三个坑:

  • 内存不足:控制台报 "Insufficient memory loading" 时,加大SCR_HEAP_SIZE(改完重启)。堆是独立沙箱,加到 100KB 也不会挤占导航滤波的内存
  • CPU 超限:报 "Exceeded CPU time" 说明单轮逻辑太重,正确做法是拆分逻辑、拉大调度间隔;直接调大 SCR_VM_I_COUNT 只是掩盖问题
  • 优先级误区SCR_THD_PRIORITY默认 Normal 是刻意压低,让脚本永远排在系统线程之后。参数注释里明确警告:提到 MAIN/BOOST 档前必须逐个审计所有脚本,因为所有脚本共享同一优先级,一个脚本失控会连坐全部

另外两个容易被忽略的运维能力:

  1. 热重启:地面站发送 MAVLink 的 SCRIPTING_CMD(STOP / STOP_AND_RESTART)即可停掉或重建整个脚本环境,不用断电重启飞控,调试迭代时非常顺手
  2. 校验和锁机:脚本更新后,置SCR_DEBUG_OPTSbit 5 可把当前脚本 CRC 存进 SCR_LD_CHECKSUM / SCR_RUN_CHECKSUM。之后只要有人误删或改动了脚本文件,飞控拒绝解锁——对多机车队和科研外场作业来说这是必要的保险

沙箱能防脚本写坏内存,防不了脚本用高频 PWM 输出写坏机械结构。任何直接输出到真实通道的脚本,务必先在 SITL 或地面台架上验证极限行为。

小结与延伸资源

本文覆盖了 AP_Scripting 的完整机制链路:独立线程沙箱与指令熔断、SCR_ 参数体系、SITL 验证流程、四类 API 表面,以及校验和与热重启这类生产手段。边界同样清楚:脚本运行在低优先级线程里,适合 IO、逻辑、数据处理类扩展,不适合替代主控制环;涉及解锁安全和机械输出的部分,校验和与地面测试不能省。

延伸入口:

  • 示例脚本库:libraries/AP_Scripting/examples/,60 多个按场景分类的现成脚本(CAN 读写、电池监测、电机矩阵、翻车保护等)
  • 模块说明:libraries/AP_Scripting/README.md,编译开关与最小脚本速览
  • 内置 Lua 模块:libraries/AP_Scripting/modules/,MAVLink 消息封装、NMEA2000 等开箱即用的扩展

【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 3:23:04

ZLUDA终极指南:在非NVIDIA显卡上运行未经修改的CUDA程序

ZLUDA终极指南:在非NVIDIA显卡上运行未经修改的CUDA程序 【免费下载链接】ZLUDA CUDA on non-NVIDIA GPUs 项目地址: https://gitcode.com/GitHub_Trending/zl/ZLUDA 手里有CUDA程序,机器上却只有一张非NVIDIA显卡?ZLUDA让你在非NVIDI…

作者头像 李华
网站建设 2026/9/11 3:22:56

Python开源贡献实战:从Fork到PR合并的完整指南

用Python给开源项目提PR,真的没有想象中那么难。两年前我连GitHub的Fork按钮都不敢点,后来靠着给一个小型数据处理库修文档、补测试用例,一步步走到了现在能独立提交功能模块。这篇文章把从零到合并PR的完整链路梳理了一遍,包括怎…

作者头像 李华
网站建设 2026/9/11 3:22:37

朴素贝叶斯算法原理与应用实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 3:19:07

长期记忆系统设计:从存储到认知接口的工程实践

1. 为什么“长期记忆”不是加个数据库就完事了?“长期记忆系统的设计与实现”——看到这个标题,很多人第一反应是:不就是把用户说过的话存进MySQL或者MongoDB里,再做个模糊搜索吗?我去年也这么想。当时接手一个客服对话…

作者头像 李华
网站建设 2026/9/11 3:17:12

ML-For-Beginners NLP 课程:用 TextBlob 实现机器翻译与情感分析

ML-For-Beginners NLP 课程:用 TextBlob 实现机器翻译与情感分析 【免费下载链接】ML-For-Beginners 12 weeks, 26 lessons, 52 quizzes, classic Machine Learning for all 项目地址: https://gitcode.com/GitHub_Trending/ml/ML-For-Beginners 导读 本篇文…

作者头像 李华
网站建设 2026/9/11 3:15:34

Python+PyMuPDF批量删除PDF水印:文本、图片、矢量一次搞定

收到一份PDF,打开一看,每一页右下角都压着“内部资料请勿外传”的半透明水印,想打印出来开会,又不想让人看到这个“内部”字样;想直接发给合作方,又怕显得很不专业。手动删?几十页文件一页一页去…

作者头像 李华