ArduPilot 四旋翼混合机(Quadplane)自动包裹投放:plane_package_place 脚本配置、任务规划与源码原理详解
【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot
ArduPilot 的plane_package_place脚本为四旋翼混合机(Quadplane)实现了完整的自动包裹投放(Package Place)功能:飞机在 AUTO 模式下飞抵投放点,垂直下降到测距仪设定的高度,悬停稳定后自动触发投放舵机,再爬升回原高度继续执行后续任务。本文将基于官方文档 plane_package_place.md 与同名 Lua 脚本 plane_package_place.lua 的完整源码,讲解脚本安装启用、PKG_*参数配置、PAYLOAD_PLACE任务航点规划、两种投放模式(空中投放 / 着陆后投放),并深入底层 C++ 实现,揭示任务命令处理、中止投放判定与着陆中止(abort landing)的完整调用链,帮助你直接在自己的 Quadplane 上部署一套可用的自动投递方案。
脚本概述:为 Quadplane 补齐"精准投放"能力
ArduPilot 固件本身已支持MAV_CMD_NAV_PAYLOAD_PLACE(航点 ID 94)任务命令,但其核心行为等同于一次 VTOL 着陆——到达后落地、结束命令。而真实的物流投递、搜救物资投放场景通常要求"低空悬停投放后自行爬升继续任务",这正是 plane_package_place.lua 要解决的问题。
该脚本运行在 AP_Scripting(Lua)环境中,通过监听当前导航命令是否为NAV_VTOL_PAYLOAD_PLACE来接管整个投放流程,并借助固件原生接口实现四件事:
- 在垂直下降阶段根据测距仪(rangefinder)高度精确触发投放舵机;
- 投放前悬停一段时间,让飞机进入稳定悬停状态,保证投放精度;
- 投放后继续悬停片刻,确保包裹干净脱离;
- 调用
quadplane:abort_landing()中止着陆、爬升回初始高度并继续任务。
从源码看,脚本通过mission:get_current_nav_id()判断当前航点(plane_package_place.lua),与固件侧将MAV_CMD_NAV_PAYLOAD_PLACE视为 VTOL 着陆命令的处理方式(见 ArduPlane/commands_logic.cpp)完全对应,因此脚本对固件版本要求低,纯 Lua 层即可实现全部逻辑,无需改动固件。
安装与启用:三步让脚本生效
官方文档要求在 microSD 卡的APM/scripts目录安装脚本(或编译进固件 ROMFS),然后开启脚本系统并重启:
- 将 plane_package_place.lua 复制到飞控 microSD 卡的
APM/scripts目录(文件名保持plane_package_place.lua不变),或按 ArduPilot 构建流程将该 applet 编译进固件的 ROMFS; - 设置
SCR_ENABLE=1启用脚本系统; - 重启飞控,使脚本加载生效。
脚本加载成功后会通过 GCS 发送提示信息Loaded package place script(plane_package_place.lua),可在地面站消息窗口确认。此外,脚本还自带故障保护:protected_wrapper()使用pcall包裹update(),一旦执行出错不会导致脚本整体退出,而是显示Internal Error: ...并将重试间隔临时拉长到 1 秒,避免错误刷屏(plane_package_place.lua)。
前提提示:脚本仅在固件编译时启用了
AP_SCRIPTING_ENABLED(即 HAL 脚本支持)的版本上可用,主流标准固件默认满足。
参数详解:PKG_* 四件套
脚本启动时通过param:add_table(9, "PKG_", 5)注册了一张独立的参数表(plane_package_place.lua),所有参数以PKG_为前缀,重启后即可在地面站看到。完整参数如下:
| 参数 | 默认值 | 类型 | 含义 |
|---|---|---|---|
PKG_ENABLE | 0 | 布尔 | 总开关,设为 1 启用脚本 |
PKG_RELEASE_FUNC | 94 | 整数 | 投放舵机对应的SERVOn_FUNCTION功能号 |
PKG_RELEASE_HGT | 10 | 浮点(米) | 触发投放的测距仪高度,0 表示着陆后再投放 |
PKG_RELEASE_HOLD | 1 | 浮点(秒) | 投放前后的悬停保持时间 |
PKG_ENABLE:总开关
必须设置为1脚本才会生效。源码在脚本加载阶段和每次update()中都会检查该值(plane_package_place.lua、plane_package_place.lua),为 0 时脚本直接空转,不执行任何投放逻辑。脚本即使已加载,也可以通过随时改回 0 的方式临时禁用投放。
PKG_RELEASE_FUNC:投放舵机功能号
该参数指明哪个伺服功能号用于包裹释放。官方推荐保持默认值 94,并把实际舵机的SERVOn_FUNCTION也设为 94。功能号 94 对应Script1(脚本输出通道 1),在 SRV_Channel.h 中定义为k_scripting1 = 94,其地面站枚举说明见 SRV_Channel.cpp。
脚本加载后会立即对该通道执行两行初始化(plane_package_place.lua):
SRV_Channels:set_range(PKG_RELEASE_FUNC:get(), 1000) SRV_Channels:set_output_scaled(PKG_RELEASE_FUNC:get(), 0)即把该通道声明为范围 0~1000 的输出(区别于角度的 -4500~4500 范围),并默认输出 0。因此接线时只需确认:伺服 PWM 输出为 0(对应通道范围的起点)时包裹处于"锁定/未释放"状态,为 1000 时触发释放机构。投放瞬间脚本将输出设为满值 1000(plane_package_place.lua),复位时再归零(reset()函数,plane_package_place.lua)。
PKG_RELEASE_HGT:投放触发高度
PKG_RELEASE_HGT以米为单位,表示测距仪(朝下安装)测得的离地高度到达该值时开始投放流程。默认值 10 米适合大部分场景。设置为 0 时则进入"着陆后投放"模式(见下文专节):飞机完全落地、电机停机后再释放。
脚本在下降阶段实时计算remaining_m = dist_m - PKG_RELEASE_HGT(plane_package_place.lua),并在下降剩余高度进入Q_LAND_FINAL_ALT范围内时,主动把下降速率切换为Q_LAND_FINAL_SPD,实现接近投放高度前的减速(plane_package_place.lua)。这两个固件参数:
Q_LAND_FINAL_ALT:进入最终下降速率的切换高度,默认 6 米,范围 0.5~50 米(见 quadplane.cpp);Q_LAND_FINAL_SPD:最终阶段下降速度,默认 0.5 m/s,范围 0.3~2 m/s(见 quadplane.cpp)。
PKG_RELEASE_HOLD:投放前后悬停保持时间
PKG_RELEASE_HOLD默认 1 秒,控制两个等待阶段:
- 投放前:飞机到达
PKG_RELEASE_HGT高度后,先悬停PKG_RELEASE_HOLD秒,让飞机进入稳定悬停、消除下降带来的垂向速度残留,确保投放点的水平精度; - 投放后:触发舵机释放后,再保持
PKG_RELEASE_HOLD秒,确保包裹干净地脱离机构,随后才中止着陆、爬升。
源码通过状态机计时实现该逻辑:now - release_start_t > PKG_RELEASE_HOLD:get()判定第一阶段结束(plane_package_place.lua),> PKG_RELEASE_HOLD:get()*2判定第二阶段结束(plane_package_place.lua)。
任务规划:从测距仪到 PAYLOAD_PLACE 航点
第一步:配置测距仪着陆能力
投放依赖测距仪实时测高,官方文档强调先做好 rangefinder landing 的准备:
- 安装并调试一个质量可靠的朝下测距传感器(激光雷达 Lidar 或雷达 Radar),确认测距数据稳定;
- 设置
RNGFND_LANDING=1,启用测距仪参与 VTOL 着陆的高度判断。
脚本运行时要求测距仪具备向下的有效数据:rangefinder:has_data_orient(RNG_ORIENT_DOWN),其中RNG_ORIENT_DOWN = 25表示朝下安装(plane_package_place.lua)。测距数据同时用于投放高度判定与着陆判定,是整套方案的核心传感器。
第二步:插入 PAYLOAD_PLACE 航点
在任务中目标投放位置插入PAYLOAD_PLACE航点(即 MAVLink 的MAV_CMD_NAV_PAYLOAD_PLACE)。两个关键设置:
- 航点高度设为 0(相对高度):脚本与固件会将下降/中止逻辑建立在相对高度的比较上,无需设置绝对投放高度,实际投放由测距仪高度(
PKG_RELEASE_HGT)决定; - 参数 1 "max descent"(最大下降量,单位米):该值非零时,表示飞机从开始下降的位置允许下降的最大高度。若下降过程中超过该值仍未触发投放,任务会被判定中止——飞机中止着陆、爬升回初始下降高度,然后继续执行后续任务。
底层实现在固件QuadPlane::verify_vtol_land()中:当处于PAYLOAD_PLACE且位于下降/最终阶段时,若cmd.p1 > 0且当前高度低于"初始下降高度 − p1",即发送Payload place aborted信息并切换到QPOS_LAND_ABORT状态(quadplane.cpp,其中 p1 以厘米为单位存储)。这相当于一道"最大下降深度"的安全护栏,防止因测距失效或风况异常导致飞机无限制下坠。
第三步:理解任务执行链路
插入的PAYLOAD_PLACE航点在固件中按 VTOL 着陆命令处理。命令开始时(do_command阶段),固件根据是否启用固定翼螺旋进场选项(Q_OPTIONS的MISSION_LAND_FW_APPROACH)分别走do_landing_vtol_approach或do_vtol_land(commands_logic.cpp);命令完成判定(verify_command阶段)则由verify_vtol_land()完成(commands_logic.cpp)。这正是脚本能够介入的前提:它并不重复实现下降控制,而是监听该航点进入下降阶段后,接管"何时释放、何时中止"的决策。
空中投放:完整工作流程与状态机
脚本核心update()以 20Hz 频率运行(return loop, 50,plane_package_place.lua)。整个投放流程由 5 个状态组成(plane_package_place.lua):
RELEASE_NONE → RELEASE_DESCENT → RELEASE_HOLD1 → RELEASE_HOLD2 → RELEASE_DONERELEASE_NONE(待命):仅在 AUTO 模式、当前航点为
NAV_VTOL_PAYLOAD_PLACE、且已解锁时继续(plane_package_place.lua);同时等待飞机进入 VTOL 着陆下降阶段(quadplane:in_vtol_land_descent(),plane_package_place.lua)。满足条件后转入RELEASE_DESCENT。RELEASE_DESCENT(下降):读取朝下测距数据,计算
remaining_m。当剩余高度进入Q_LAND_FINAL_ALT内时,将下降速率设为Q_LAND_FINAL_SPD减速。当remaining_m <= 0(到达投放高度)且PKG_RELEASE_HGT > 0时,记录时间戳、将下降速率清零,进入RELEASE_HOLD1(plane_package_place.lua)。RELEASE_HOLD1(投放前悬停):悬停
PKG_RELEASE_HOLD秒后,发送Package released at X.Xm信息,将PKG_RELEASE_FUNC通道输出拉满到 1000 触发释放机构,进入RELEASE_HOLD2(plane_package_place.lua)。RELEASE_HOLD2(投放后保持):继续悬停
PKG_RELEASE_HOLD秒确保包裹干净脱离,随后调用quadplane:abort_landing()中止着陆。成功则发送Climbing,失败则发送land abort failed告警(plane_package_place.lua)。RELEASE_DONE(完成):任务继续,飞机爬升回初始下降高度后执行后续航点。
整个流程中若任何前置条件不满足(非 AUTO、离开该航点、解锁丢失),reset()会立刻将状态和舵机输出复位,等待下次进入(plane_package_place.lua)。
着陆后投放模式(Landing Then Release)
当PKG_RELEASE_HGT=0时,脚本切换为"完全着陆后投放":
- 飞机执行完整 VTOL 着陆直至落地,电机完全停机(螺旋桨熄火);
- 着陆状态通过
motors:get_desired_spool_state() == MOTORS_SHUT_DOWN判定(plane_package_place.lua),此状态下测距高度按 0 处理(dist_m = 0.0); - 落地停机后保持
PKG_RELEASE_HOLD秒(此时remaining_m <= 0且已landed,走正常释放流程)再触发舵机释放; - 释放后再保持
PKG_RELEASE_HOLD秒,随后同样调用abort_landing()中止着陆、爬升回初始下降高度继续任务。
该模式下固件侧有专门配合:当处于PAYLOAD_PLACE航点且位置控制器状态为QPOS_LAND_COMPLETE(着陆完成)时,电机保持SHUT_DOWN不启动(quadplane.cpp),确保投放瞬间电机处于熄火安全状态。而QuadPlane::abort_landing()也专门为"已着陆的 payload place"开了绿灯——只要处于PAYLOAD_PLACE且QPOS_LAND_COMPLETE,即使已离开下降状态也能正常触发中止爬升(quadplane.cpp)。
此模式适合"先确认落地、再释放重物"的场景(例如投放较重的包裹,避免空中投放带来的姿态扰动)。
底层原理:固件侧的关键配合机制
PAYLOAD_PLACE 的"着陆命令"身份
MAV_CMD_NAV_PAYLOAD_PLACE在固件中被等同为 VTOL 着陆命令:在 quadplane.cpp 中它与NAV_VTOL_LAND、NAV_LAND一起被is_vtol_land()识别,在 quadplane.cpp 中与 VTOL 着陆共用vtol_position_controller()位置控制器。这解释了为什么脚本只需监听航点 ID 即可复用完整的着陆下降控制——它站在固件成熟着陆逻辑之上,只做投放决策。
下降阶段判定
脚本依赖quadplane:in_vtol_land_descent()判断是否已进入下降。固件实现为:在 QRTL 模式或 AUTO 模式且当前航点为 VTOL 着陆类命令时,位置控制状态处于QPOS_LAND_DESCEND、QPOS_LAND_FINAL或QPOS_LAND_ABORT即视为下降中(quadplane.cpp)。
中止投放的双保险
"max descent" 参数由固件侧强制执行(上文verify_vtol_land()中的 p1 检查),而正常投放完成后的爬升则由脚本主动调用abort_landing()触发——两者共同构成安全网:前者防止下降过深,后者实现"投完就走"。abort_landing()会将位置控制状态置为QPOS_LAND_ABORT(quadplane.cpp),飞机随即爬升,任务继续。
舵机通道与安全复位
投放通道是脚本可控的Script1(功能号 94),脚本在非激活状态下始终把输出保持在 0(锁定位置),只有到达释放时刻才拉高到 1000。这意味着即使脚本运行异常,reset()与protected_wrapper()也会尽量把通道恢复到安全锁定状态。
实战注意事项
- 测距仪质量决定投放精度:脚本完全依赖朝下测距数据触发投放,测距数据抖动或盲区会直接影响高度判定。务必在地面测试
RNGFND_LANDING着陆流程后再启用脚本; - 注意参数名拼写:官方文档中"Landing Then Release"一节提到的
PGK_RELEASE_HGT为笔误,实际参数为PKG_RELEASE_HGT(源码中统一使用PKG_前缀,见 plane_package_place.lua); - 投放机构机械行程:舵机行程需与
SERVOn_FUNCTION=94(Script1,0~1000 范围)匹配,务必确认 0 为锁定、1000 为释放,避免上电默认位置误投; - 先地面联调再实飞:建议先在无负载情况下用模拟投放验证状态机流转(可通过 GCS 消息窗口观察
Loaded package place script、Package released、Climbing等关键日志),再逐步加负载; - 保持 AUTO 模式与航点 ID 匹配:脚本仅在 AUTO 模式下且当前航点为
NAV_VTOL_PAYLOAD_PLACE时工作,若用 QLAND 等手动模式降落,脚本不会介入; - max descent 安全值:根据投放高度(
PKG_RELEASE_HGT)合理设置"max descent"参数,通常应略大于PKG_RELEASE_HGT与一个悬停保持缓冲之和,避免正常流程被误判中止。
参考资料
- 官方文档:libraries/AP_Scripting/applets/plane_package_place.md
- 脚本源码:libraries/AP_Scripting/applets/plane_package_place.lua
- 固件命令处理:ArduPlane/commands_logic.cpp
- 固件 VTOL 着陆/中止实现:ArduPlane/quadplane.cpp
- 脚本通道定义:libraries/SRV_Channel/SRV_Channel.h、libraries/SRV_Channel/SRV_Channel.cpp
【免费下载链接】ardupilotArduPlane, ArduCopter, ArduRover, ArduSub source项目地址: https://gitcode.com/GitHub_Trending/ar/ardupilot
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考