- 嵌入式
- 物联网
- 机器人
- 自动驾驶
- 智能硬件
【免费下载链接】PX4-Autopilot
PX4 Autopilot Software
本篇基于 PX4 官方文档 standard_modes.md 整理并深入源码。自 PX4 v1.15 起,PX4 实现了 MAVLink 标准模式协议(Standard Modes Protocol),使地面站或外部系统(包括通过 PX4 ROS 2 控制接口创建的外部模式)能够统一地发现所有可用飞行模式、查询当前模式,并以跨飞行栈通用的标准模式枚举来切换模式。读完本文,你将掌握协议涉及的全部消息与命令、各类飞行器(多旋翼 / 固定翼 / VTOL)的标准模式映射表,以及 PX4 中从命令下发到导航状态切换的完整源码实现链路。
协议概述:标准模式与自定义模式
在 MAVLink 体系中,模式分为两类:
- 标准模式(Standard Modes):各飞行栈普遍支持、行为大致一致的模式,例如位置悬停、定高、任务、降落、起飞、安全返航等。地面站可以只依赖标准模式枚举即可对多种飞行栈的飞行器执行相同的操作;
- 自定义模式(Custom Modes):飞行栈私有的模式,通过
custom_mode整数(在 PX4 中即px4_custom_mode位域编码)表达。
该协议提供的能力包括:
| 能力 | 所用消息 / 命令 |
|---|---|
| 发现系统(PX4 及 ROS 2 侧)支持的全部模式 | MAV_CMD_REQUEST_MESSAGE请求AVAILABLE_MODES |
| 发现当前模式 | CURRENT_MODE(周期性发送) |
| 设置标准模式 | MAV_CMD_DO_SET_STANDARD_MODE(推荐方式) |
| 模式集合变化通知 | AVAILABLE_MODES_MONITOR |
此外,PX4 也支持通过传统SET_MODE消息设置自定义模式(结合AVAILABLE_MODES中的自定义模式信息)。需要注意的是,文档明确说明:在当前版本中MAV_CMD_DO_SET_MODE尚不受支持,切换模式应使用MAV_CMD_DO_SET_STANDARD_MODE(标准模式)或SET_MODE(自定义模式)。
支持的 MAVLink 标准模式及 PX4 映射表
PX4 对外宣称支持下列标准飞行模式——即可以调用MAV_CMD_DO_SET_STANDARD_MODE并传入对应的MAV_STANDARD_MODE枚举值来启动这些模式。PX4 内部将其映射到导航状态(nav_state)。
多旋翼(MC)标准模式
| 标准模式 | 对应 PX4 模式 | 内部导航状态 |
|---|---|---|
MAV_STANDARD_MODE_POSITION_HOLD | MC Position 模式 | POSCTL |
MAV_STANDARD_MODE_ALTITUDE_HOLD | MC Altitude 模式 | ALTCTL |
MAV_STANDARD_MODE_ORBIT | MC Orbit 模式 | POSCTL(实际导航状态 ORBIT) |
MAV_STANDARD_MODE_SAFE_RECOVERY | Return 模式 | AUTO_RTL |
MAV_STANDARD_MODE_MISSION | MC Mission 模式 | AUTO_MISSION |
MAV_STANDARD_MODE_LAND | MC Land 模式 | AUTO_LAND |
MAV_STANDARD_MODE_TAKEOFF | MC Takeoff 模式 | AUTO_TAKEOFF |
固定翼(FW)标准模式
| 标准模式 | 对应 PX4 模式 | 内部导航状态 |
|---|---|---|
MAV_STANDARD_MODE_CRUISE | FW Cruise 模式 | POSCTL |
MAV_STANDARD_MODE_ALTITUDE_HOLD | FW Altitude 模式 | ALTCTL |
MAV_STANDARD_MODE_ORBIT | FW Hold 模式 | AUTO_LOITER |
MAV_STANDARD_MODE_SAFE_RECOVERY | Return 模式 | AUTO_RTL |
MAV_STANDARD_MODE_MISSION | FW Mission 模式 | AUTO_MISSION |
MAV_STANDARD_MODE_LAND | FW Land 模式 | AUTO_LAND |
MAV_STANDARD_MODE_TAKEOFF | FW Takeoff 模式 | AUTO_TAKEOFF |
VTOL 标准模式
VTOL 飞行器支持的标准模式同样取决于当前是作为多旋翼飞行还是作为固定翼飞行,行为随构型切换而变化:
| 标准模式 | 对应 PX4 模式 | 内部导航状态 |
|---|---|---|
MAV_STANDARD_MODE_ALTITUDE_HOLD | FW Altitude 模式 | ALTCTL |
MAV_STANDARD_MODE_SAFE_RECOVERY | Return 模式 | AUTO_RTL |
MAV_STANDARD_MODE_MISSION | Mission 模式 | AUTO_MISSION |
MAV_STANDARD_MODE_LAND | Land 模式 | AUTO_LAND |
MAV_STANDARD_MODE_TAKEOFF | Takeoff 模式 | AUTO_TAKEOFF |
注意:VTOL 理论上还可在旋翼/固定翼构型下分别支持MAV_STANDARD_MODE_POSITION_HOLD(MC)、MAV_STANDARD_MODE_CRUISE(FW)与MAV_STANDARD_MODE_ORBIT,但文档明确指出这部分尚未实现——这与下文源码中映射函数对 VTOL 的保守处理一一对应。
全飞行器通用标准模式
以下标准模式对所有飞行器类型都有映射:
| 标准模式 | 对应 PX4 模式 | 内部导航状态 |
|---|---|---|
MAV_STANDARD_MODE_SAFE_RECOVERY | Return 模式 | AUTO_RTL |
MAV_STANDARD_MODE_MISSION | Mission 模式 | AUTO_MISSION |
MAV_STANDARD_MODE_LAND | Land 模式 | AUTO_LAND |
MAV_STANDARD_MODE_TAKEOFF | Takeoff 模式 | AUTO_TAKEOFF |
源码解析(一):标准模式 ↔ 导航状态双向映射
文档指向的核心实现位于 src/lib/modes/standard_modes.hpp。该头文件定义了与 MAVLinkMAV_STANDARD_MODE枚举完全对齐的 C++ 枚举:
// src/lib/modes/standard_modes.hpp enum class StandardMode : uint8_t { NON_STANDARD = 0, POSITION_HOLD = 1, ORBIT = 2, CRUISE = 3, ALTITUDE_HOLD = 4, SAFE_RECOVERY = 5, MISSION = 6, LAND = 7, TAKEOFF = 8, };映射逻辑由两个内联函数完成,均需要飞行器类型(vehicle_type)与是否 VTOL(is_vtol)作为输入:
1.getNavStateFromStandardMode()(L104-L152)——标准模式到导航状态的转换,这是"设置标准模式"路径的核心:
static inline uint8_t getNavStateFromStandardMode(StandardMode mode, uint8_t vehicle_type, bool is_vtol) { switch (mode) { case StandardMode::SAFE_RECOVERY: return vehicle_status_s::NAVIGATION_STATE_AUTO_RTL; case StandardMode::MISSION: return vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION; case StandardMode::LAND: return vehicle_status_s::NAVIGATION_STATE_AUTO_LAND; case StandardMode::TAKEOFF: return vehicle_status_s::NAVIGATION_STATE_AUTO_TAKEOFF; case StandardMode::ALTITUDE_HOLD: // VTOL 或 纯 MC / 纯 FW 均支持 if (is_vtol || vehicle_type == ROTARY_WING || vehicle_type == FIXED_WING) { return vehicle_status_s::NAVIGATION_STATE_ALTCTL; } break; case StandardMode::POSITION_HOLD: // 仅非 VTOL 的多旋翼支持(VTOL 未实现,与文档说明一致) if (!is_vtol && vehicle_type == ROTARY_WING) { return vehicle_status_s::NAVIGATION_STATE_POSCTL; } break; case StandardMode::CRUISE: // 仅非 VTOL 的固定翼支持 if (!is_vtol && vehicle_type == FIXED_WING) { return vehicle_status_s::NAVIGATION_STATE_POSCTL; } break; case StandardMode::ORBIT: if (vehicle_type == ROTARY_WING) { return vehicle_status_s::NAVIGATION_STATE_ORBIT; } if (vehicle_type == FIXED_WING) { return vehicle_status_s::NAVIGATION_STATE_AUTO_LOITER; // FW 的 Orbit 即 Hold/Loiter } break; default: break; } return vehicle_status_s::NAVIGATION_STATE_MAX; // 不支持时返回 MAX }几个关键细节:
- 返回值
NAVIGATION_STATE_MAX表示该标准模式对当前飞行器类型不适用,调用方据此给出失败应答; - MC 的
ORBIT与POSITION_HOLD都最终落到 POSCTL 类导航状态,但ORBIT有独立的NAVIGATION_STATE_ORBIT;FW 的ORBIT则映射为AUTO_LOITER(即 Hold/Loiter),这解释了文档中"Orbit 在 MC 上是 Orbit 模式、在 FW 上是 Hold 模式"的说法; - VTOL 的保守处理:
POSITION_HOLD与CRUISE均要求!is_vtol,因此 VTOL 请求这两个标准模式会返回NAVIGATION_STATE_MAX——正是文档中"VTOL 可支持但未实现"备注的代码依据。
2.getStandardModeFromNavState()(L59-L99)——导航状态到标准模式的反向转换,用于把 PX4 自身的自定义模式"包装"成标准模式上报给地面站(例如CURRENT_MODE消息中的standard_mode字段)。无法对应任何标准模式的导航状态返回NON_STANDARD。
这种"双向映射"设计意味着:PX4 对外用标准模式呈现自身能力,对外部则同时保留完整的自定义模式视图。
源码解析(二):命令处理链路与两条 MAVLink 消息流
设置标准模式:Commander 中的命令分发
当地面站发出MAV_CMD_DO_SET_STANDARD_MODE时,MAVLink 模块将其转换为vehicle_command_s传入 Commander。处理逻辑位于 src/modules/commander/Commander.cpp:
case vehicle_command_s::VEHICLE_CMD_DO_SET_STANDARD_MODE: { mode_util::StandardMode standard_mode = (mode_util::StandardMode) roundf(cmd.param1); uint8_t nav_state = mode_util::getNavStateFromStandardMode(standard_mode, _vehicle_status.vehicle_type, _vehicle_status.is_vtol); if (nav_state == vehicle_status_s::NAVIGATION_STATE_MAX) { answer_command(cmd, vehicle_command_ack_s::VEHICLE_CMD_RESULT_FAILED); } else { if (_user_mode_intention.change(nav_state, getSourceFromCommand(cmd))) { answer_command(cmd, vehicle_command_ack_s::VEHICLE_CMD_RESULT_ACCEPTED); } else { answer_command(cmd, vehicle_command_ack_s::VEHICLE_CMD_RESULT_TEMPORARILY_REJECTED); } } }从源码结构可以确认完整的处理语义:
param1即MAV_STANDARD_MODE枚举值(见上一节的映射表),Commander 将其转换为内部导航状态;- 若该飞行器类型不支持该标准模式(映射结果为
NAVIGATION_STATE_MAX),直接应答VEHICLE_CMD_RESULT_FAILED; - 否则请求用户模式意图变更(
_user_mode_intention.change),该路径还记录了命令来源(getSourceFromCommand),成功则应答ACCEPTED,失败(例如被其他控制源抢占或状态不允许)则应答TEMPORARILY_REJECTED。
发现模式:AVAILABLE_MODES消息流
模式发现通过MAV_CMD_REQUEST_MESSAGE请求AVAILABLE_MODES消息触发,实现在 src/modules/mavlink/streams/AVAILABLE_MODES.hpp:
- 请求参数:
param2为mode_index。传0表示请求全部模式(遍历vehicle_status.valid_nav_states_mask中所有有效导航状态逐一发送);传1..N表示只请求第 N 个模式(request_message(),L144-L198)。 - 每条
AVAILABLE_MODES消息携带的字段(send_single_mode(),L86-L142):custom_mode:PX4 的px4_custom_mode位域编码(get_px4_custom_mode(nav_state)),供传统SET_MODE使用;standard_mode:由mode_util::getStandardModeFromNavState()计算,若该导航状态无法对应标准模式则为MAV_STANDARD_MODE_NON_STANDARD;mode_name:非标准模式的名字来源——内部模式取自mode_util::nav_state_names[]静态表;外部模式(External modes)来自register_ext_component_reply主题,即可由 ROS 2 组件动态注册的模式名;properties:包含MAV_MODE_PROPERTY_ADVANCED(高级模式,由mode_util::isAdvanced()判定)与MAV_MODE_PROPERTY_NOT_USER_SELECTABLE(不可由用户选择,当vehicle_status.can_set_nav_states_mask中该导航状态未置位时设置)。
- 低速链路的保护:全部模式逐一发送时按链路速率计算每帧之间的延迟,且以
MAX_DELAY_US = 2500000 / NAVIGATION_STATE_MAX(注释说明:为所有可能模式预留最多 2.5 秒,避免地面站 ACK 超时)为上限,L62-L65。 - 模式集合变化通知:
update_data()(L200-L255)持续监视register_ext_component_reply、valid_nav_states_mask与can_set_nav_states_mask三类动态变化;一旦变化就递增seq,随后send()发出带有序列号的AVAILABLE_MODES_MONITOR消息,地面站收到后应重新请求全部AVAILABLE_MODES。这正是协议中"模式集合变化通知"的实现。
这一机制是 PX4 将ROS 2 外部模式纳入标准模式协议的入口:通过 PX4 ROS 2 控制接口 注册的外部模式会出现在AVAILABLE_MODES列表中并带有注册时的模式名;若某外部模式尚未注册(不可选择),列表中会以(Mode not available)占位。
查询当前模式:CURRENT_MODE消息流
当前模式的周期性上报由 src/modules/mavlink/streams/CURRENT_MODE.hpp 实现:
mavlink_current_mode_t current_mode{}; current_mode.custom_mode = get_px4_custom_mode(vehicle_status.nav_state_display).data; current_mode.intended_custom_mode = get_px4_custom_mode(vehicle_status.nav_state_user_intention).data; current_mode.standard_mode = (uint8_t) mode_util::getStandardModeFromNavState(vehicle_status.nav_state_display, vehicle_status.vehicle_type, vehicle_status.is_vtol);值得注意的三个字段语义:
custom_mode:基于nav_state_display(当前实际导航状态);intended_custom_mode:基于nav_state_user_intention(用户意图模式),用于区分"期望进入"与"实际处于"的模式;standard_mode:通过同一套mode_util::getStandardModeFromNavState()映射,若当前为 PX4 私有模式则上报NON_STANDARD。
从 src/modules/mavlink/mavlink_main.cpp 中各通道流注册表可以确认默认发送频率:AVAILABLE_MODES约 0.3 Hz,CURRENT_MODE约 0.5 Hz。
其他可切换模式的 MAVLink 命令
除标准模式协议外,一些标准模式与自定义模式还可通过更早的传统命令设置,尤其在消息允许附带额外参数时更为便利。PX4 支持下列模式切换命令(部分仅限特定飞行器类型):
| 命令 | 对应模式 |
|---|---|
MAV_CMD_NAV_TAKEOFF | Takeoff 模式 |
MAV_CMD_NAV_RETURN_TO_LAUNCH | Return 模式 |
MAV_CMD_NAV_LAND | Land 模式 |
MAV_CMD_DO_FOLLOW | MC Follow 模式 |
MAV_CMD_DO_FOLLOW_REPOSITION | 从新位置发起的 Follow 模式 |
MAV_CMD_DO_ORBIT | MC Orbit 模式 |
MAV_CMD_NAV_VTOL_TAKEOFF | VTOL 专用起飞模式 |
MAV_CMD_DO_REPOSITION | 重定位 |
MAV_CMD_DO_PAUSE_CONTINUE | 将飞行器置入 Hold/Loiter 以暂停任务 |
MAV_CMD_MISSION_START | 启动任务 |
文档特别提示了一个容易踩坑的语义差异:这些命令早于标准模式协议出现,映射到的是"飞行器类型特定的自定义模式",而非标准模式。也就是说,即使某个标准模式对多类飞行器通用,传统命令也可能只对特定飞行器生效。原文给出的例子:Orbit 标准模式在 MC 上映射为 Orbit 模式、在 FW 上映射为 Hold/Loiter;但截至文档撰写时,MAV_CMD_DO_ORBIT只会在 MC 上启动 Orbit 模式,在 FW 上会被忽略。
小结
PX4 v1.15 引入的标准模式协议,让地面站/外部系统能够以飞行栈无关的方式完成"发现 → 查询 → 切换"飞行模式的闭环:MAV_CMD_REQUEST_MESSAGE+AVAILABLE_MODES完成模式发现(含 ROS 2 外部模式),CURRENT_MODE周期上报当前模式(标准 + 自定义双视图),MAV_CMD_DO_SET_STANDARD_MODE完成标准模式切换,AVAILABLE_MODES_MONITOR保证模式集合变化时的同步。实现侧的核心只有三处:映射函数 src/lib/modes/standard_modes.hpp、命令分发 src/modules/commander/Commander.cpp、消息流 src/modules/mavlink/streams/AVAILABLE_MODES.hpp 与 src/modules/mavlink/streams/CURRENT_MODE.hpp。需要注意的前提限制:MAV_CMD_DO_SET_MODE尚不支持、VTOL 对POSITION_HOLD/CRUISE/ORBIT标准模式的支持未实现,且具体支持情况以当前版本固件与地面站(QGroundControl Daily 构建)的实际联调为准。
- 嵌入式
- 物联网
- 机器人
- 自动驾驶
- 智能硬件
【免费下载链接】PX4-Autopilot
PX4 Autopilot Software
相关推荐
OptScale 监控和警报设置:实时追踪云成本异常和优化机会 🚨
OptScale 监控和警报设置:实时追踪云成本异常和优化机会 🚨 OptScale 是一款强大的开源 FinOps 和云成本优化工具,它不仅能帮助您节省云成
后端运维PX4-Autopilot通信协议解析:MAVLink消息格式与应用开发终极指南
PX4 Autopilot通信协议解析:MAVLink消息格式与应用开发终极指南 MAVLink通信协议是PX4 Autopilot自动驾驶系统中最核心的数据交
嵌入式物联网机器人自动驾驶智能硬件PX4 飞行模式开发指南:内部模式、外部(ROS 2)模式与模式约束机制详解
PX4 飞行模式开发指南:内部模式、外部(ROS 2)模式与模式约束机制详解 飞行模式(Flight Mode)是 PX4 自动驾驶仪的核心概念——它定义了自动
嵌入式物联网机器人自动驾驶智能硬件
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考