ArduPilot不写C也能加飞行逻辑?Lua脚本引擎上手实录
2026/9/11 15:20:56 网站建设 项目流程

ArduPilot不写C也能加飞行逻辑?Lua脚本引擎上手实录

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

你的飞机需要"到特定高度自动悬停拍照",但官方固件没这个功能。改C源码重刷固件至少折腾一天,其实不需要——ArduPilot 内置了 Lua 脚本引擎,把脚本丢进 SD 卡就能跑。这篇实测笔记带你把 ArduPilot Lua 脚本系统从参数配置到三个真实场景完整跑通,覆盖无人机自定义飞行指令最常见的开发需求。

它能做什么 🚀

  • 在飞控内跑定时循环逻辑,读传感器、改参数、向地面站推数据(遥测监控、低电量报警)
  • 切换飞行模式、设置目标位置与速度、触发起飞降落(自动化任务、特殊机动)
  • 通过串口、CAN 与外挂设备对话(接新传感器、云台、LED 屏)
  • 自建SCR_前缀参数表,在地面站直接调脚本行为(带可调参数的飞行逻辑)

实测下来,这套机制的价值在于:飞控脚本开发不用动一行 C 代码,脚本改完重传文件即可,迭代速度完全不在一个量级。

跑起来之前,先搞清这些 🔧

硬件前提只有一条:flash 大于 1MB 的板子,构建时会自动启用脚本支持(见 AP_Scripting 的 README)。运行时再把SCR_ENABLE设为 1 并重启。脚本存放位置:真机是 SD 卡APM/scripts/目录,SITL 是工作目录下的scripts/,开机自动加载所有.lua文件。

核心参数都在SCR_命名空间下,定义见 脚本引擎源码,最常用的 6 个:

参数名作用默认值注意事项
SCR_ENABLE启用 Lua 脚本(1=启用)0修改后必须重启
SCR_HEAP_SIZE脚本可用堆内存43/100/200KB 按板级修改后必须重启,小内存板别乱调
SCR_VM_I_COUNT单次迭代允许的虚拟机指令数上限10000超了会被判定耗时过长,是防死循环的看门狗
SCR_DEBUG_OPTS调试位掩码(内存/耗时报告等)0bit1 开启运行期内存与耗时消息
SCR_LD_CHECKSUM已加载脚本的校验和-1(不校验)配错校验和直接禁止解锁,防脚本被篡改
SCR_THD_PRIORITY脚本线程优先级0(Normal)官方明确警告:调高可能影响飞控稳定性

ArKV6S 这类板子 flash 超过 1MB,构建脚本支持是默认行为,无需额外配置。

环境搭建压缩成 4 步:

  1. git clone https://gitcode.com/GitHub_Trending/ar/ardupilot && cd ardupilot
  2. Tools/environment_install/install-prereqs-ubuntu.sh -y装依赖(脚本路径见 环境依赖安装脚本)
  3. ./waf configure --board=CubeBlack && ./waf plane构建,脚本支持自动包含
  4. 不想刷机就先 SITL:Tools/autotest/sim_vehicle.py -v ArduCopter,脚本放进工作目录scripts/

脚本若要挂外挂设备,第一步是查板子的引脚图确认哪路串口空闲,ACNS-CM4Pilot 的 pinout 就是典型样例。

三个真实场景跑通自定义指令 ⚡

仓库里现成的 130+ 个示例在 示例脚本库,下面挑三个不同难度的场景拆。

基础:Circle 模式恒定地速

场景:飞手用拨轮随时调整 Circle 模式半径,半径一变地速就变,你需要"速度恒定、半径随便改"。

思路:写一个定时循环,检查飞机已解锁、在飞、处于 Circle 模式(Copter 模式号 7)后才生效;每次读当前圈半径,用速度 / 周长 × 360反算角速度写回去。对应copter-circle-speed.lua

local speed = Parameter("CSPD_SPEED") function update() if not arming:is_armed() or vehicle:get_mode() ~= 7 then return update, 1000 end local radius = vehicle:get_circle_radius() vehicle:set_circle_rate(360 * (speed:get() / (radius * math.pi * 2))) return update, 100 end return update()

坑点提示:循环的"心跳"是return update, 毫秒数,忘了这行脚本只执行一次就永远停摆——这是新手最高频的错误。

Aeromind 6X 这类 H7 级飞控的脚本堆默认在 100~200KB 档,写复杂逻辑前先看一眼自己的堆余量。

进阶:状态机实现"前后往返"自动任务

场景:起飞→前飞 10 米→原路返回→落地,全程无人接管,是飞控脚本开发里最典型的自动化任务。

思路:用一个本地stage变量搭状态机,每个阶段只做一件事,且只在动作接口返回true时才进入下一阶段——vehicle:set_mode()vehicle:start_takeoff()这些接口都带布尔返回,天然适合做"动作完成确认"。对应copter_pingpong.lua的骨架:

if stage == 0 then if vehicle:set_mode(copter_guided_mode_num) then stage = stage + 1 end elseif stage == 1 then if vehicle:start_takeoff(takeoff_alt) then stage = stage + 1 end elseif stage == 5 then vehicle:set_mode(copter_land_mode_num) end return update, 100

坑点提示:示例里的模式号 4(Guided)、9(Land)是 Copter 专属,固定翼、Rover、Sub 的模式表各不相同,照抄模式号换机型必摔,写脚本前先对一遍自己机型的模式号。

边界:脚本崩溃、死循环与内存保护

场景:脚本里藏个逻辑错误,飞在天上怎么自保?这里要分清两层保护:Lua 层的错误捕获,和引擎层的资源限制。

思路:Lua 层用pcall包住业务逻辑,出错就通过gcs:send_text把错误甩给地面站(仓库里有现成的protected_call.lua可参考);引擎层则是前面参数表的三道闸——SCR_VM_I_COUNT掐死单次迭代的计算量,SCR_HEAP_SIZE封顶内存,SCR_LD_CHECKSUM在解锁前就拦住被篡改的脚本:

function update() local ok, err = pcall(work) if not ok then gcs:send_text(0, "script error: " .. tostring(err)) end return update, 500 end return update()

坑点提示pcall只接得住 Lua 运行期错误,接不住引擎层因指令数超限或堆耗尽而终止脚本——长脚本调试时把SCR_DEBUG_OPTS的 bit1 打开,盯着运行期内存与耗时消息才是对的姿势。

容易踩的坑 + 下一步

先列 4 个实测高频错误:

  • 循环不转了update结尾忘了return update, ms,补上即可
  • 飞控变卡SCR_THD_PRIORITY调太高抢了飞控循环的 CPU,退回 0,确实需要实时性再逐项审脚本
  • 参数改了没生效SCR_ENABLESCR_HEAP_SIZESCR_THD_PRIORITY都标了 RebootRequired,改完必须重启
  • 换机型脚本跑飞:跨机型照抄模式号,先查模式表再动手

下一步建议:

  1. 通读 官方示例脚本库,按你机型的目录前缀(copter-/plane-/rover-/sub)挑相近场景改
  2. 写代码时把 脚本绑定接口文档 配进 Lua 语言服务器,能直接获得接口补全和参数提示
  3. 接口行为拿不准时,回 脚本引擎源码 对一遍参数注释,比论坛猜得快

飞控逻辑的边界不该由固件版本决定——先把最简单的simple_loop.lua在 SITL 里跑起来,剩下的都是量的积累。

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询