一、Run() 主循环结构 MulticopterPositionControl 运行在 wq:nav_and_controllers WorkQueue 上,由 vehicle_local_position 话题到达时触发(数据驱动),同时设置 100 ms 看门狗定时调度(防止 EKF 停发时模块锁死):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 void MulticopterPositionControl::Run () { if (should_exit ()) { ... return ; } ScheduleDelayed (100 _ms); vehicle_local_position_s vl_pos; if (!_local_pos_sub.update (&vl_pos)) return ; const float dt = math::constrain ( (vl_pos.timestamp_sample - _time_stamp_last_loop) * 1e-6f , 0.002f , 0.04f ); _time_stamp_last_loop = vl_pos.timestamp_sample; parameters_update (false ); PositionControlStates states = set_vehicle_states (vl_pos, dt); if (_goto_control.checkForSetpoint (...)) _goto_control.update (...); _trajectory_setpoint_sub.update (&_setpoint); adjustSetpointForEKFResets (vl_pos, _setpoint); _control.setInputSetpoint (_setpoint); _control.setState (states); _control.update (dt); publish_local_pos_sp (); publish_attitude_sp (); }
dt 使用物理采样时间戳 (timestamp_sample)而非 CPU 接收时间,消除调度抖动对微分项的影响。
二、模式管理与悬停推力自适应 1 2 3 4 5 6 7 8 9 10 11 12 13 14 if (!previous_enabled && now_enabled) { _time_position_control_enabled = _vehicle_control_mode.timestamp; } else if (previous_enabled && !now_enabled) { _setpoint = PositionControl::empty_trajectory_setpoint; } if (_param_mpc_use_hte.get ()) { hover_thrust_estimate_s hte; if (_hover_thrust_estimate_sub.update (&hte) && hte.valid) { _control.updateHoverThrust (hte.hover_thrust); } }
HTE(Hover Thrust Estimate) :EKF2 通过加速度和推力的比较估计实时悬停推力,补偿电池电压下降(推力随电压下降而降低)或载荷变化(挂载掉落导致质量减小),提高 Z 轴位置保持精度。
三、set_vehicle_states() — 多级滤波数据清洗 EKF2 发布的速度数据包含两类典型噪声:
机架共振尖峰 :机臂/桨叶在特定频率产生强振动(如 120 Hz)
高频白噪声 :传感器和电调开关噪声,分布广泛
处理策略:先陷波(精确消除共振峰),再低通(整体压制高频)
1 2 3 4 5 6 states.velocity.xy () = _vel_xy_lp_filter.update ( _vel_xy_notch_filter.apply (velocity_xy)); states.acceleration.xy () = _vel_deriv_xy_lp_filter.update ( (current_vel_lp - prev_vel_lp) / dt);
3.1 陷波滤波器数学 二阶陷波(带阻)滤波器传递函数:
在共振频率处 ,精确消除该频率的振动分量,其他频率几乎不受影响。关键参数:
MPC_VEL_NF_FRQ:陷波中心频率(Hz),需与实际机架共振频率匹配
MPC_VEL_NF_BW:陷波带宽(Hz),决定 ζ,太窄则对频率漂移敏感
3.2 一阶低通滤波器(EMA) 离散实现为指数移动平均(EMA):
MPC_VEL_LP 参数设置截止频率 (Hz)。
3.3 处理流程 1 2 3 4 5 6 7 flowchart LR EKF["EKF2<br/>vz(含机架共振+白噪声)"] --> NF["陷波滤波<br/>_vel_z_notch_filter<br/>消除共振尖峰"] NF --> LP["低通滤波<br/>_vel_z_lp_filter<br/>压制高频白噪声"] LP --> STATE["states.velocity(2)<br/>干净的速度信号"] LP --> DIFF["差分估计<br/>(vel_now - vel_prev) / dt"] DIFF --> LP2["加速度低通<br/>_vel_deriv_z_lp_filter"] LP2 --> ACC["states.acceleration(2)<br/>用于 PID D 项"]
有效性保护 :若 EKF 数据无效(v_z_valid == false),对应状态写入 NAN 并重置所有滤波器,防止传感器恢复时出现加速度尖峰。
四、adjustSetpointForEKFResets() — EKF 重置鲁棒补偿 当 EKF 发生坐标系重置(如 GPS 回环修正、SLAM 重定位,产生 1 m 量级的瞬时跳变)时,若不处理,控制器会看到巨大的瞬时误差 ,导致满舵响应。
解决方案 :维持控制误差的连续性:
当观测值发生跳变 时,同步修正设定点:
PX4 通过 reset_counter(计数器)机制实现:
1 2 3 4 5 6 7 8 9 if (vl_pos.xy_reset_counter != _xy_reset_counter) { setpoint.position[0 ] += vl_pos.delta_xy[0 ]; setpoint.position[1 ] += vl_pos.delta_xy[1 ]; _vel_xy_lp_filter.reset (_vel_xy_lp_filter.getState () + Vector2f (vl_pos.delta_vxy)); _vel_xy_notch_filter.reset (); } _xy_reset_counter = vl_pos.xy_reset_counter;
五种独立的 reset_counter:xy、z、vxy、vz、heading,各自独立处理。
五、TakeoffHandling — 起飞状态机与保护 5.1 起飞状态机 1 2 3 4 5 6 7 stateDiagram-v2 [*] --> disarmed disarmed --> spoolup : armed spoolup --> ready_for_takeoff : 电机预热完成 ready_for_takeoff --> rampup : want_takeoff == true rampup --> flight : 离地高度达到 flight --> [*]
5.2 推力斜坡(rampup 阶段) 避免离地瞬间推力突变和姿态抖动:
MPC_TKO_RAMP_T 控制斜坡时间(默认 3 s)。
5.3 关键保护机制
地面压制 :在 not_taken_off 或触地(flying_but_ground_contact)状态时,设置 100 m/s² 向下加速度,使 PID 输出饱和在最小推力,确保不因传感器抖动而蹦跳
积分清零 :地面阶段清空 _control.resetIntegral(),防止高度误差积分导致离地时突然弹射
倾角限制 :起飞前限制最大倾角(MPC_TILTMAX_LND,默认 12°),离地后恢复正常(MPC_TILTMAX_AIR)
悬停推力重置 :未起飞时强制用参数预设值,不使用 HTE 估计(避免地面状态下 HTE 估计偏差影响起飞)
1 2 3 4 Vector3f (0.f , 0.f , 100.f ).copyTo (_setpoint.acceleration);
六、故障回退 generateFailsafeSetpoint() 当 trajectory_setpoint 无效或 PositionControl::update() 返回失败时:
1 2 3 4 5 6 7 8 9 10 flowchart TD A["控制更新失败"] --> B{"上次有效设定点<br/>是否在 200ms 内?"} B -->|是| C["使用上次有效设定点<br/>重试 update"] B -->|否| D{"XY 速度是否有效?"} C --> E{"重试成功?"} E -->|否| D D -->|是| F["生成 stop-and-wait<br/>水平速度设为0,等待原地"] D -->|否| G{"Z 速度是否有效?"} G -->|是| H["blind land<br/>缓慢垂直下降"] G -->|否| I["blind descent<br/>最大下降速度直至落地"]
三级故障回退确保在任何传感器失效情况下都有安全的下降策略。
七、小结 MulticopterPositionControl.cpp 的核心价值在于:
数据清洗 :多级滤波(陷波+低通)为 PID D 项提供干净信号,直接影响飞行稳定性
EKF 重置保护 :误差连续性维护机制,防止传感器重定位时的满舵响应
起飞安全 :状态机 + 斜坡 + 积分清零 + 倾角限制,处理最危险的起飞阶段
故障容错 :三级回退策略,保证任何情况下都有安全的降落路径
上一篇:mc_pos_control 总览与控制链路 下一篇:PositionControl 串级控制算法 系列总目录:PX4 v1.16 源码解读总目录