PX4-Autopilot UORB 消息深度解析:FixedWingRunwayControl 与固定翼跑道起降状态机
PX4-Autopilot UORB 消息深度解析:FixedWingRunwayControl 与固定翼跑道起降状态机
本文围绕 PX4-Autopilot 中的 FixedWingRunwayControl UORB 消息(TOPIC:fixed_wing_runway_control)展开,讲解它在固定翼(Fixed-wing)跑道起飞/降落流程中所扮演的"状态与转向指令传递通道"角色:从 fw_mode_manager 模块发布,到 fw_att_control 模块的前轮转向控制与 land_detector 模块的起降状态判定。读完本文,你将掌握该消息的完整字段语义、四个跑道起飞状态常量的取值与触发条件、前轮转向(wheel steering)使能与偏航设定值的传递链路,以及落地/起飞判定如何依赖这条消息,能够据此理解并排查固定翼自动起飞相关日志与参数(如 FW_W_EN、RWTO_NUDGE)。
消息定位:辅助控制字段,连接三个飞行控制模块
根据 msg/FixedWingRunwayControl.msg 的头部注释,该消息的定位非常明确:
"Passes information from the FixedWingModeManager to the FixedWingAttitudeController (wheel control) and FixedWingLandDetector (takeoff state)"
也就是说,它是一条单向的信息传递通道,把跑道起飞状态机的状态(runway_takeoff_state)和前轮转向控制所需的指令(使能标志、偏航设定值、手动微调量)从模式管理模块传递给姿态控制模块与着陆检测模块。消息本身不参与气动舵面控制环,只承载"当前处于跑道起降的哪个阶段、前轮要不要转、朝哪个方向转"这些辅助控制信息。
从源码结构看,这条消息的完整生命周期由三个模块共同构成:
- 发布端:src/modules/fw_mode_manager/FixedWingModeManager.cpp 中的
FixedWingModeManager,通过成员_fixed_wing_runway_control_pub(定义见 FixedWingModeManager.hpp)周期发布; - 消费端 1:src/modules/fw_att_control/FixedwingAttitudeControl.cpp 中的轮转向控制器(wheel steering / 前轮转向);
- 消费端 2:src/modules/land_detector/FixedwingLandDetector.cpp 中的固定翼着陆检测器,利用
runway_takeoff_state判断起飞状态。
此外,该消息被列入固定翼飞行日志的记录主题(见 src/modules/logger/logged_topics.cpp),因此排查起飞/转向问题时可直接在 .ulg 日志中回放该主题数据。
消息字段详解
FixedWingRunwayControl 共包含 4 个数据字段,语义如下(完整定义见 msg/FixedWingRunwayControl.msg):
| 字段名 | 类型 | 单位/帧 | 取值范围 | 含义 |
|---|---|---|---|---|
timestamp |
uint64 |
us(微秒) | — | 系统启动以来的时间戳,用于消费端判断消息时效性 |
runway_takeoff_state |
uint8 |
— | 见下方 4 个状态常量 | 跑道起飞状态机的当前状态 |
wheel_steering_enabled |
bool |
— | — | 是否启用前轮转向(使能标志) |
wheel_steering_yaw_setpoint |
float32 |
rad | [-pi : pi] |
前轮转向控制器要跟踪的偏航角设定值;NAN 表示保持转向接合时捕获的航向 |
wheel_steering_nudging_rate |
float32 |
FRD(机体坐标系) | [-1 : 1] |
手动前轮微调量,叠加到控制器输出上;NAN 视为 0 |
字段行为要点:
wheel_steering_yaw_setpoint的NAN语义:当设定值为NAN时,姿态控制器将保持"转向接合瞬间"的航向(详见下文源码分析),这在着陆滑跑等不主动给目标航向的场景下非常有用;wheel_steering_nudging_rate的NAN语义:消息定义中明确"NANis interpreted as 0",即缺失值按零处理,不会叠加异常输入;wheel_steering_nudging_rate的坐标系:定义为 FRD(Front-Right-Down 机体坐标系),取值范围为归一化的[-1, 1],作为叠加量直接加到轮控制器输出上。
跑道起飞状态机常量
消息内联定义了 4 个状态常量(uint8 枚举),构成固定翼跑道起飞状态机的完整状态序列:
| 常量名 | 值 | 描述 |
|---|---|---|
STATE_THROTTLE_RAMP |
0 |
油门爬升阶段(ramping up throttle) |
STATE_CLAMPED_TO_RUNWAY |
1 |
贴地滑跑阶段,直接用前轮或方向舵控制偏航(clamped to runway, controlling yaw directly) |
STATE_CLIMBOUT |
2 |
爬升离场,爬升至安全高度后再进入导航(climbout to safe height before navigation) |
STATE_FLYING |
3 |
自由导航飞行(navigate freely) |
在 C++ 侧,这些常量以 fixed_wing_runway_control_s::STATE_XXX 形式被引用。例如 FixedwingLandDetector.cpp 中判断起飞状态时使用 fixed_wing_runway_control_s::STATE_CLIMBOUT 作为阈值,而 FixedWingModeManager.cpp 在非起飞场景下发布 fixed_wing_runway_control_s::STATE_FLYING 作为默认状态。
发布端源码剖析:FixedWingModeManager 如何填充消息
FixedWingModeManager 是这条消息的唯一发布者。从 FixedwingAttitudeControl.cpp 与 FixedWingModeManager.cpp 中的多处发布代码可以梳理出三种典型发布场景:
场景一:自动起飞滑跑阶段(地面滚转)
在自动起飞(takeoff)流程中,FixedWingModeManager.cpp 发布的消息内容为:
fixed_wing_runway_control_s fw_runway_control{};
fw_runway_control.timestamp = now;
fw_runway_control.runway_takeoff_state = _runway_takeoff.getState(); // 取自 RunwayTakeoff 状态机
fw_runway_control.wheel_steering_enabled = true; // 地面滚转阶段启用前轮转向
// 机头对齐跑道指向起飞航点(takeoff waypoint)的方位角
fw_runway_control.wheel_steering_yaw_setpoint = takeoff_bearing;
// 若 RWTO_NUDGE 参数开启,将摇杆 yaw 作为手动微调量
fw_runway_control.wheel_steering_nudging_rate = _param_rwto_nudge.get() ? _sticks.getYaw() : 0.f;
_fixed_wing_runway_control_pub.publish(fw_runway_control);
关键点:
runway_takeoff_state直接取自RunwayTakeoff状态机实例_runway_takeoff(头文件 FixedWingModeManager.hpp 中声明的RunwayTakeoff _runway_takeoff),即跑道起飞状态的权威来源在模式管理器内部;- 偏航设定值取
takeoff_bearing(跑道指向起飞航点的方位角),保证地面滑跑时机头始终对齐跑道中心线; - 手动微调量由参数
RWTO_NUDGE控制:参数开启时把摇杆 yaw 输入直接作为 nudge 量发布,否则发布0.f(对应消息定义中"NANis interpreted as 0"的宽容设计,发布端直接给 0 更简单明确)。
场景二:着陆滑跑阶段
在着陆流程中(FixedWingModeManager.cpp),发布逻辑与起飞类似,但偏航设定值发布为 NAN:
fw_runway_control.runway_takeoff_state = _runway_takeoff.getState();
fw_runway_control.wheel_steering_enabled = true;
fw_runway_control.wheel_steering_yaw_setpoint = NAN; // 保持转向接合时的航向
fw_runway_control.wheel_steering_nudging_rate = _param_rwto_nudge.get() ? _sticks.getYaw() : 0.f;
NAN 的语义在这里得到实际运用:着陆滑跑时不主动给出目标航向,姿态控制器会保持转向接合瞬间捕获的航向,避免着陆后飞机在跑道上跑偏。
场景三:非起降的默认发布(正常飞行)
在普通飞行(非起飞/着陆)状态下(FixedWingModeManager.cpp),状态被显式置为 STATE_FLYING 作为默认值:
fw_runway_control.runway_takeoff_state = fixed_wing_runway_control_s::STATE_FLYING; // 默认
fw_runway_control.wheel_steering_enabled = true;
fw_runway_control.wheel_steering_yaw_setpoint = NAN;
// 着陆 nudge 由 FW_LND_* 参数族控制(如 FW_LND_NUDGE 选项)
fw_runway_control.wheel_steering_nudging_rate = _param_fw_lnd_nudge.get() > LandingNudgingOption::kNudgingDisabled ? ... : 0.f;
注意此处 nudge 量受 _param_fw_lnd_nudge(着陆微调选项)控制,说明发布端针对起飞/着陆场景分别使用 RWTO_NUDGE 与 FW_LND_NUDGE 两组参数来决定是否叠加手动微调。
消费端源码剖析:轮转向控制与起飞状态判定
前轮转向控制器(fw_att_control)
src/modules/fw_att_control/FixedwingAttitudeControl.cpp 中的 "steering wheel control" 代码块是消息的主要消费逻辑,其工作流程可归纳为:
- 订阅并检查时效:拷贝
fixed_wing_runway_control_s,并通过hrt_elapsed_time(&runway_control.timestamp) < 1_s检查消息是否在 1 秒内新鲜到达; - 使能条件:轮控制器仅在满足以下全部条件时启用:
- 参数
FW_W_EN为真(前轮转向总开关,参数声明见 FixedwingAttitudeControl.hpp); - 处于自动控制模式(
_vcontrol_mode.flag_control_auto_enabled); - 消息新鲜(1 秒内到达);
- 消息中
wheel_steering_enabled == true;
- 参数
- 地速比例缩放:根据地面速度与失速空速(
FW_AIRSPD_STALL)计算groundspeed_scale,当地速超过失速空速时按gspd_scaling_trim / groundspeed缩小轮控制器增益,避免高速滑跑时转向过猛; - 偏航设定值处理(FixedwingAttitudeControl.cpp):
- 若
wheel_steering_yaw_setpoint是有限值(非NAN),则更新_steering_wheel_yaw_setpoint,跟踪模式管理器给出的目标航向(如起飞时的takeoff_bearing); - 若为
NAN且此前没有设定值,则把当前偏航角euler_angles.psi()捕获为设定值——这正是消息定义中"hold the heading captured when steering engaged"的实现;
- 若
- 控制器输出合成:
wheel_u = wheel_controller_output + runway_control.wheel_steering_nudging_rate,即轮控制器输出与手动微调量直接相加,随后发布到landing_gear_wheel.normalized_wheel_setpoint; - 非使能时的回退:当轮控制器未使能(如手动飞行),积分器被复位、设定值重置为
NAN,此时wheel_u直接取手动摇杆 yaw,实现"手动模式摇杆直控前轮"。
起飞状态判定(land_detector)
src/modules/land_detector/FixedwingLandDetector.cpp 是第二个消费端,其逻辑为:
fixed_wing_runway_control_s fixed_wing_runway_control{};
_fixed_wing_runway_control_sub.copy(&fixed_wing_runway_control);
const bool runway_status_fresh = hrt_elapsed_time(&fixed_wing_runway_control.timestamp) < 500_ms;
// ...
// 消息新鲜,且起飞状态尚未越过 CLIMBOUT(即仍在 THROTTLE_RAMP/CLAMPED_TO_RUNWAY)
&& fixed_wing_runway_control.runway_takeoff_state < fixed_wing_runway_control_s::STATE_CLIMBOUT;
// 且处于自动任务/自动起飞导航状态
const bool in_auto_takeoff_mode = (_vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_MISSION)
|| (_vehicle_status.nav_state == vehicle_status_s::NAVIGATION_STATE_AUTO_TAKEOFF);
着陆检测器用 runway_takeoff_state < STATE_CLIMBOUT 作为"仍在地面滑跑阶段"的判据(时效窗口为 500 ms),结合 in_auto_takeoff_mode 与发射检测状态(launch_detection_state == STATE_WAITING_FOR_LAUNCH)共同决定是否处于待起飞状态。这印证了消息定义中"FixedWingLandDetector 消费 takeoff state"的设计初衷:状态机推进到 STATE_CLIMBOUT 之后,着陆检测器便不再认为飞机仍贴着跑道。
相关参数与实战排查建议
围绕这条消息,当前仓库中存在一组直接相关的可调参数:
| 参数 | 定义位置 | 作用 |
|---|---|---|
FW_W_EN |
FixedwingAttitudeControl.hpp | 前轮转向总开关,关闭后姿态控制器不启用轮控制器 |
RWTO_NUDGE |
FixedWingModeManager.hpp | 起飞滑跑时是否把摇杆 yaw 作为手动微调量叠加 |
RWTO_PSP |
FixedWingModeManager.hpp | 跑道起飞相关设定值参数(与状态机推进相关) |
FW_LND_NUDGE(族) |
着陆 nudge 选项 | 着陆滑跑时的手动微调开关 |
FW_AIRSPD_STALL |
失速空速 | 用于地速缩放,决定轮控制器增益随速度衰减的起点 |
排查固定翼跑道起飞/着陆问题的实用建议:
- 日志回放优先:
fixed_wing_runway_control已被纳入飞行日志(见 src/modules/logger/logged_topics.cpp),通过ulog分析工具(仓库提供 Tools/ecl_ekf/process_logdata_ekf.py 等日志分析脚本)回放该主题,可直接观察runway_takeoff_state是否按 0→1→2→3 正常推进,以及wheel_steering_yaw_setpoint是否与跑道方位一致; - 检查使能链路:若地面滑跑时前轮不转向,依次确认
FW_W_EN、自动模式标志、消息新鲜度(1 秒窗口)与wheel_steering_enabled四要素是否同时满足(对应 FixedwingAttitudeControl.cpp 的使能条件); - 观察 nudge 量:若滑跑方向被摇杆"带偏",检查
RWTO_NUDGE/FW_LND_NUDGE是否误开,以及日志中wheel_steering_nudging_rate是否持续非零; - 结合着陆检测:若自动起飞后着陆检测器误判未离地,检查
runway_takeoff_state是否已越过STATE_CLIMBOUT(500 ms 时效窗口内),这是 FixedwingLandDetector.cpp 判定"已离地"的硬性前提。
小结
FixedWingRunwayControl 是 PX4 固定翼跑道起降链路中一条"小而关键"的 UORB 消息:它承载的 4 个状态常量定义了从油门爬升到自由飞行的完整起飞状态机,其 wheel_steering_enabled、wheel_steering_yaw_setpoint(含 NAN 保持航向语义)与 wheel_steering_nudging_rate 三个字段则完整刻画了前轮转向控制从模式管理器到姿态控制器的指令传递。理解这条消息,就等于同时理解了固定翼自动起降状态机的推进节奏、前轮转向的使能与目标航向来源,以及着陆检测器如何感知"飞机是否还在跑道上",是阅读固定翼起飞/着陆控制源码与日志的最佳切入点。