开源 | DC-PMPPI 扰动补偿模型预测路径积分控制器:项目分析
项目名称:DC-PMPPI — Disturbance-Compensated Model Predictive Path Integral Control
仓库:Robot-Nav/SA-MPPI
分支:DC-PMPPI
项目地址:https://github.com/Robot-Nav/SA-MPPI/tree/DC-PMPPI
ROS:ROS1 Noetic
语言:C++17 / Python
许可证:Apache-2.0
主要依赖:catkin、Eigen3、OpenMP、xtensor、xsimd、xtl
DC-PMPPI 是一个面向轮式移动机器人的局部路径跟踪控制器。它不是重新设计一种与 MPPI 完全不同的控制框架,而是在标准 MPPI 的“采样—预测—评分—加权更新”闭环中加入在线模型失配估计:利用里程计和实际执行命令估计侧向扰动、横摆扰动以及纵向/横摆控制有效性,并把这些估计结果重新注入预测模型和参考控制生成过程,使控制器在湿滑路面、侧滑、执行器响应衰减、移动甲板或其他外部扰动条件下,仍尽可能保持“预测轨迹”和“真实车辆运动”一致。
目录
- 一、项目要解决什么问题
- 二、项目整体结构
- 三、标准 MPPI 基础
- 四、DC-PMPPI 的核心思想
- 五、在线扰动与控制有效性估计
- 六、含扰动的 Rollout 预测模型
- 七、MPCC 式路径跟踪代价
- 八、参考速度与参考控制生成
- 九、采样策略
- 十、自适应温度、ESS 与精英截断
- 十一、三种运动模型与运动约束
- 十二、终点处理与控制平滑
- 十三、核心源码模块说明
- 十四、ROS 输入输出接口
- 十五、关键参数说明
- 十六、项目运行步骤
- 十七、项目依赖库
- 十八、如何做标准 MPPI / DC-PMPPI A-B 对比
- 十九、项目特点与工程注意事项
- 二十、总结
一、项目要解决什么问题
标准 MPPI 的预测过程建立在一个很重要的前提上:
控制器内部使用的运动模型,应当能够比较准确地描述机器人真实运动。
例如,对于非完整约束轮式机器人,最简单的二维模型通常写成:
x ˙ = v cos θ , \dot{x}=v\cos\theta, x˙=vcosθ,
y ˙ = v sin θ , \dot{y}=v\sin\theta, y˙=vsinθ,
θ ˙ = ω . \dot{\theta}=\omega. θ˙=ω.
离散化后:
x k + 1 = x k + v k cos θ k Δ t , x_{k+1}=x_k+v_k\cos\theta_k\Delta t, xk+1=xk+vkcosθkΔt,
y k + 1 = y k + v k sin θ k Δ t , y_{k+1}=y_k+v_k\sin\theta_k\Delta t, yk+1=yk+vksinθkΔt,
θ k + 1 = θ k + ω k Δ t . \theta_{k+1}=\theta_k+\omega_k\Delta t. θk+1=θk+ωkΔt.
在理想路面上,这种模型可以近似认为“控制器给出什么速度,车辆就产生什么速度”。
但在实际系统中并不总是如此。
典型情况包括:
- 湿滑、冰雪、低附着路面导致轮胎纵向打滑;
- 转弯时发生侧滑,车辆真实运动方向与车头朝向不再一致;
- 横摆响应不足,命令角速度与实际角速度存在比例衰减;
- 车体受到外部横向运动,例如船舶、甲板晃动;
- 执行器存在一阶惯性和响应滞后;
- 定位系统或底盘反馈存在持续性偏置。
如果 MPPI 仍然按照名义模型 Rollout,那么采样得到的“未来轨迹”就会和机器人真正执行出来的轨迹产生系统性差异。
DC-PMPPI 的核心做法不是给每一种物理扰动分别建立复杂动力学模型,而是把它们统一看成等价模型失配,在线估计:
d = [ v y d i s t ω d i s t ] , d= \begin{bmatrix} v_y^{dist}\\ \omega^{dist} \end{bmatrix}, d=[vydistωdist],
以及两个控制有效性系数:
η v , η ω . \eta_v,\qquad \eta_\omega. ηv,ηω.
其中:
- v y d i s t v_y^{dist} vydist:车体系下的等价侧向扰动速度;
- ω d i s t \omega^{dist} ωdist:等价横摆角速度扰动;
- η v \eta_v ηv:纵向控制有效性;
- η ω \eta_\omega ηω:横摆控制有效性。
因此,DC-PMPPI 实际解决的是:
当“控制器内部预测模型”和“真实车辆响应”不一致时,如何在线辨识这部分失配,并让 MPPI 在预测时显式考虑这种失配。
二、项目整体结构
当前 DC-PMPPI 分支的代码主体位于:
SA-MPPI/
├── README.md
├── README_CN.md
├── LICENSE
└── rsc/
├── CMakeLists.txt
├── package.xml
├── config/
│ ├── dc_pmppi_params.yaml
│ └── dc_pmppi_test.rviz
├── include/
│ ├── controller.hpp
│ ├── optimizer.hpp
│ ├── motion_models.hpp
│ ├── critics/
│ │ ├── critic_function.hpp
│ │ ├── critic_manager.hpp
│ │ ├── critic_data.hpp
│ │ ├── mpcc_tracking_critic.hpp
│ │ ├── control_rate_critic.hpp
│ │ ├── constraint_critic.hpp
│ │ ├── stability_critic.hpp
│ │ ├── lateral_error_critic.hpp
│ │ ├── path_align_critic.hpp
│ │ ├── path_angle_critic.hpp
│ │ ├── path_follow_critic.hpp
│ │ ├── prefer_forward_critic.hpp
│ │ ├── twirling_critic.hpp
│ │ └── velocity_deadband_critic.hpp
│ ├── models/
│ │ ├── types.hpp
│ │ ├── constraints.hpp
│ │ ├── optimizer_settings.hpp
│ │ ├── path.hpp
│ │ ├── state.hpp
│ │ ├── trajectories.hpp
│ │ └── control_sequence.hpp
│ └── tools/
│ ├── disturbance_estimator.hpp
│ ├── noise_generator.hpp
│ ├── path_projection.hpp
│ ├── path_reference.hpp
│ ├── goal_docking.hpp
│ └── math_utils.hpp
├── src/
│ └── dc_pmppi_node.cpp
├── scripts/
│ ├── JZJ_path.py
│ └── twist_to_ackermann.py
├── test/
│ └── disturbance_estimator_test.cpp
├── xtensor/
├── xsimd/
└── xtl/
系统数据流如下:

从 ROS 节点角度看,控制器主要接收:
/plan:参考路径;/odom1:机器人当前位姿和速度;/constrained_cmd_vel_stamped:真正经过约束器后下发到底盘的执行命令,可选但在 DC 模式下很重要。
控制器输出:
/cmd_vel:最终速度命令;/local_path:当前优化后的预测轨迹;/controller_solve_time_ms:单周期计算耗时。
三、标准 MPPI 基础
3.1 最优控制问题
设机器人离散系统为:
x t + 1 = F ( x t , u t ) , x_{t+1}=F(x_t,u_t), xt+1=F(xt,ut),
控制序列为:
U = { u 0 , u 1 , … , u T − 1 } . U=\{u_0,u_1,\ldots,u_{T-1}\}. U={u0,u1,…,uT−1}.
总成本可以写成:
S ( U ) = ϕ ( x T ) + ∑ t = 0 T − 1 q ( x t , u t ) . S(U)=\phi(x_T)+ \sum_{t=0}^{T-1}q(x_t,u_t). S(U)=ϕ(xT)+t=0∑T−1q(xt,ut).
MPPI 不直接通过梯度优化整个控制序列,而是在当前名义控制序列附近采样。
对第 i i i 条样本:
u i , t = u t + ϵ i , t , u_{i,t}=u_t+\epsilon_{i,t}, ui,t=ut+ϵi,t,
其中:
ϵ i , t ∼ N ( 0 , Σ ) . \epsilon_{i,t}\sim \mathcal{N}(0,\Sigma). ϵi,t∼N(0,Σ).
每一组采样控制序列经过运动模型 Rollout 得到一条未来轨迹,然后计算累计代价 S i S_i Si。
3.2 MPPI 权重
项目使用指数形式构造轨迹权重:
w i = exp [ − ( S i − S r e f ) / λ ] ∑ j exp [ − ( S j − S r e f ) / λ ] . w_i= \frac{ \exp\left[-(S_i-S_{\mathrm{ref}})/\lambda\right] }{ \sum_j \exp\left[-(S_j-S_{\mathrm{ref}})/\lambda\right] }. wi=∑jexp[−(Sj−Sref)/λ]exp[−(Si−Sref)/λ].
其中:
- λ \lambda λ 或代码中的 temperature:温度参数;
- S r e f S_{\mathrm{ref}} Sref 默认使用最小代价;
- 开启
use_mean_normalization时可使用平均代价。
温度越小,权重越集中在少数低成本样本上;温度越大,更多样本会参与更新。
3.3 控制更新
标准形式可以理解为:
U n e w = U + ∑ i w i ϵ i . U^{new} =U+ \sum_i w_i\epsilon_i. Unew=U+i∑wiϵi.
在当前实现中,由于采样控制经过边界、Ackermann 曲率等约束,因此代码实际使用“约束后的采样控制”做加权均值,再向该均值更新:
u t n e w = u t + α ( ∑ i w i u i , t − u t ) , u_t^{new} =u_t+ \alpha \left( \sum_i w_i u_{i,t} -u_t \right), utnew=ut+α(i∑wiui,t−ut),
其中 α \alpha α 对应 elite_update_rate;未启用 elite 截断时更新率为 1。
3.4 为什么最终只执行第一项
虽然 MPPI 每次求得的是整个未来控制序列:
U ∗ = { u 0 ∗ , u 1 ∗ , … , u T − 1 ∗ } , U^*= \{u_0^*,u_1^*,\ldots,u_{T-1}^*\}, U∗={u0∗,u1∗,…,uT−1∗},
但实际只执行:
u 0 ∗ . u_0^*. u0∗.
之后进入下一控制周期,重新读取当前真实状态,再优化新的未来序列。
后面的控制量并不是“没用”,因为 u 0 ∗ u_0^* u0∗ 是否合理,正是通过后续整个预测时域的累计结果判断出来的;同时项目还会将序列左移作为下一周期 warm start:
U k + 1 i n i t = { u 1 ∗ , u 2 ∗ , … , u T − 1 ∗ , u T − 1 ∗ } . U_{k+1}^{init} =\{u_1^*,u_2^*,\ldots,u_{T-1}^*,u_{T-1}^*\}. Uk+1init={u1∗,u2∗,…,uT−1∗,uT−1∗}.
四、DC-PMPPI 的核心思想
DC-PMPPI 可以概括为四层补偿。
4.1 控制有效性补偿
对于理想模型:
v r e a l = v c m d , v_{real}=v_{cmd}, vreal=vcmd,
ω r e a l = ω c m d . \omega_{real}=\omega_{cmd}. ωreal=ωcmd.
低附着时改写为:
v r e a l = η v v c m d , v_{real}=\eta_v v_{cmd}, vreal=ηvvcmd,
ω r e a l = η ω ω c m d , \omega_{real}=\eta_\omega\omega_{cmd}, ωreal=ηωωcmd,
其中:
0.3 ≤ η v , η ω ≤ 1. 0.3\leq\eta_v,\eta_\omega\leq1. 0.3≤ηv,ηω≤1.
η=1 表示控制基本完全生效;数值越低表示执行响应衰减越明显。
4.2 加性扰动补偿
除“控制增益下降”之外,模型还包含不能由控制有效性解释的加性扰动:
v y d i s t , v_y^{dist}, vydist,
ω d i s t . \omega^{dist}. ωdist.
前者用于描述侧向漂移,后者用于描述额外横摆运动。
4.3 未来扰动衰减
控制器不直接假定当前估计到的扰动会在整个预测时域永久不变,而使用:
d ( t ) = d 0 e − t / τ d . d(t)=d_0e^{-t/\tau_d}. d(t)=d0e−t/τd.
其中 τ d \tau_d τd 为:
disturbance_decay_time_constant
默认配置为:
0.8 s
因此,近未来更相信当前扰动估计,预测越远则逐渐回归名义模型。
4.4 置信度渐进启用
扰动估计器不会在刚获得一两个观测时立刻全量接管模型,而维护:
c ∈ [ 0 , 1 ] . c\in[0,1]. c∈[0,1].
只有置信度达到最低阈值后,DisturbanceEstimate.valid 才变为真。
这使得启动瞬态、定位跳变、时间戳异常等情况不容易直接污染 MPPI。
五、在线扰动与控制有效性估计
源码中最关键的 DC 模块是:
include/tools/disturbance_estimator.hpp
5.1 通过位姿差分获得车体系速度
设两个时刻的世界坐标位姿差为:
Δ x = x k − x k − m , \Delta x=x_k-x_{k-m}, Δx=xk−xk−m,
Δ y = y k − y k − m , \Delta y=y_k-y_{k-m}, Δy=yk−yk−m,
Δ θ = w r a p ( θ k − θ k − m ) . \Delta\theta= wrap(\theta_k-\theta_{k-m}). Δθ=wrap(θk−θk−m).
窗口时间:
Δ t = t k − t k − m . \Delta t=t_k-t_{k-m}. Δt=tk−tk−m.
先得到世界坐标速度:
v x w = Δ x Δ t , v_x^w=\frac{\Delta x}{\Delta t}, vxw=ΔtΔx,
v y w = Δ y Δ t . v_y^w=\frac{\Delta y}{\Delta t}. vyw=ΔtΔy.
再根据窗口中点航向 θ ˉ \bar\theta θˉ 转换到车体系:
v x m e a s = cos θ ˉ v x w + sin θ ˉ v y w , v_x^{meas} =\cos\bar\theta\,v_x^w+ \sin\bar\theta\,v_y^w, vxmeas=cosθˉvxw+sinθˉvyw,
v y m e a s = − sin θ ˉ v x w + cos θ ˉ v y w . v_y^{meas} =-\sin\bar\theta\,v_x^w+ \cos\bar\theta\,v_y^w. vymeas=−sinθˉvxw+cosθˉvyw.
横摆角速度:
ω m e a s = Δ θ Δ t . \omega^{meas}= \frac{\Delta\theta}{\Delta t}. ωmeas=ΔtΔθ.
配置中也允许直接使用 odometry twist:
dc_pmppi_use_odom_twist_lateral_velocity: true
dc_pmppi_use_odom_twist_yaw_rate: true
dc_pmppi_use_odom_twist_longitudinal_velocity: true
因此,在仿真或底盘速度反馈可靠时,不必完全依赖位姿差分。
5.2 为什么要建执行器一阶模型
如果直接计算:
η v = v m e a s v c m d , \eta_v=\frac{v^{meas}}{v^{cmd}}, ηv=vcmdvmeas,
那么车辆正常加速时,由于电机和底盘存在惯性,实际速度暂时低于命令速度,控制器可能错误判断为“打滑”。
项目专门建了一个一阶执行器模型:
u ˙ m = u c m d − u m τ a . \dot{u}_m =\frac{u_{cmd}-u_m}{\tau_a}. u˙m=τaucmd−um.
离散实现:
u m k + 1 = u m k + ( 1 − e − Δ t / τ a ) ( u c m d − u m k ) . u_m^{k+1} =u_m^k+ \left(1-e^{-\Delta t/\tau_a}\right) \left(u_{cmd}-u_m^k\right). umk+1=umk+(1−e−Δt/τa)(ucmd−umk).
纵向默认时间常数:
0.10 s
横摆默认:
0.0 s
即当前配置认为纵向通道需要显式处理一阶滞后,而横摆通道不额外建立滞后。
5.3 控制有效性估计
项目支持两种方式。
方法一:稳健比值法
当命令激励足够大:
∣ v c m d ∣ > v d e a d z o n e , |v_{cmd}|>v_{deadzone}, ∣vcmd∣>vdeadzone,
则:
η v o b s = c l i p ( ∣ v x m e a s v x c m d ∣ , 0.3 , 1.0 ) . \eta_v^{obs} =clip \left( \left| \frac{v_x^{meas}} {v_x^{cmd}} \right|, 0.3, 1.0 \right). ηvobs=clip( vxcmdvxmeas ,0.3,1.0).
同理:
η ω o b s = c l i p ( ∣ ω m e a s ω c m d ∣ , 0.3 , 1.0 ) . \eta_\omega^{obs} =clip \left( \left| \frac{\omega^{meas}} {\omega^{cmd}} \right|, 0.3, 1.0 \right). ηωobs=clip( ωcmdωmeas ,0.3,1.0).
默认配置中使用该方式。
方法二:指数加权中心化回归
可选方法为:
η = C o v ( u , y ) V a r ( u ) . \eta =\frac{ Cov(u,y) }{ Var(u) }. η=Var(u)Cov(u,y).
中心化回归的意义是:如果测量中存在一个慢变化的加性扰动,
y = η u + d , y=\eta u+d, y=ηu+d,
那么中心化后常值或慢变的 d d d 对斜率估计影响较小。
不过当前配置:
dc_pmppi_use_centered_effectiveness_regression: false
注释明确说明,在当前闭环 OU 扰动实验中该方法没有优于稳健比值法,所以默认关闭。
5.4 横摆扰动估计
首先根据当前 η ω \eta_\omega ηω 预测正常情况下应该得到的横摆响应:
ω e x p = η ω ω c m d . \omega^{exp} =\eta_\omega\omega_{cmd}. ωexp=ηωωcmd.
实际横摆残差:
ω o b s d i s t = ω m e a s − ω e x p . \omega^{dist}_{obs} =\omega^{meas} -\omega^{exp}. ωobsdist=ωmeas−ωexp.
这部分残差被解释为无法通过正常控制响应解释的“等价横摆扰动”。
5.5 侧向扰动估计
对于非全向 Ackermann / DiffDrive 车辆,正常情况下主动侧向速度应接近 0,因此可把车体系测得的横向速度作为:
v y , o b s d i s t = v y m e a s . v_{y,obs}^{dist} =v_y^{meas}. vy,obsdist=vymeas.
这也是该模型特别适合表达侧滑的原因。
5.6 死区、创新限幅与低通滤波
为了防止定位噪声直接进入控制模型,首先设置死区。
例如:
∣ v y m e a s ∣ < v d e a d ⇒ v y , t a r g e t d i s t = 0. |v_y^{meas}|<v_{dead} \Rightarrow v_{y,target}^{dist}=0. ∣vymeas∣<vdead⇒vy,targetdist=0.
然后计算创新:
Δ v y = c l i p ( v y , t a r g e t d i s t − v ^ y d i s t , − Δ m a x , Δ m a x ) . \Delta v_y= clip \left( v_{y,target}^{dist}-\hat v_y^{dist}, -\Delta_{max}, \Delta_{max} \right). Δvy=clip(vy,targetdist−v^ydist,−Δmax,Δmax).
低通更新:
v ^ y d i s t ← v ^ y d i s t + ( 1 − β ) Δ v y , \hat v_y^{dist} \leftarrow \hat v_y^{dist} + (1-\beta)\Delta v_y, v^ydist←v^ydist+(1−β)Δvy,
其中:
β = e − Δ t / τ f . \beta= e^{-\Delta t/\tau_f}. β=e−Δt/τf.
横摆扰动采用相同处理。
默认:
dc_pmppi_filter_time_constant: 0.20
dc_pmppi_max_vy_innovation: 0.40
dc_pmppi_max_wz_innovation: 0.80
5.7 扰动方差
项目同步维护:
σ v y 2 ← β σ v y 2 + ( 1 − β ) ( Δ v y ) 2 , \sigma_{v_y}^2 \leftarrow \beta\sigma_{v_y}^2+ (1-\beta)(\Delta v_y)^2, σvy2←βσvy2+(1−β)(Δvy)2,
以及:
σ ω 2 . \sigma_\omega^2. σω2.
当:
sample_disturbance_uncertainty: true
时,可在 Rollout 中进一步做扰动 sigma-point 采样。
当前 Gazebo 配置默认关闭:
sample_disturbance_uncertainty: false
避免有限样本下把估计噪声进一步放大。
5.8 traction_scale
代码还计算一个工程化的附着能力指标:
s e v e r i t y = k y ∣ v ^ y d i s t ∣ + k ω ∣ ω ^ d i s t ∣ + 0.2 ( σ v y + σ ω ) , severity =k_y|\hat v_y^{dist}| + k_\omega|\hat\omega^{dist}| + 0.2(\sigma_{v_y}+\sigma_\omega), severity=ky∣v^ydist∣+kω∣ω^dist∣+0.2(σvy+σω),
t r a c t i o n _ s c a l e = c l i p ( 1 − s e v e r i t y , t r a c t i o n m i n , 1 ) . traction\_scale =clip \left( 1-severity, traction_{min}, 1 \right). traction_scale=clip(1−severity,tractionmin,1).
需要注意:
traction_scale不是摩擦系数 μ \mu μ 的在线物理辨识结果。
它只是一个 0~1 的保守能力指标。
而且当前参数:
traction_speed_exponent: 0.0
traction_acceleration_exponent: 0.0
意味着正式配置中不再用 traction_scale 二次降低速度和加速度约束,因为 η v / η ω \eta_v/\eta_\omega ηv/ηω 已经显式进入模型,再继续缩放容易形成重复补偿。

六、含扰动的 Rollout 预测模型
这是 DC-PMPPI 与普通 MPPI 最直接的差异。
6.1 控制有效性进入预测速度
对于每条样本:
v i , t t a r g e t = η v u i , t v , v^{target}_{i,t} =\eta_v u^v_{i,t}, vi,ttarget=ηvui,tv,
ω i , t t a r g e t = η ω u i , t ω . \omega^{target}_{i,t} =\eta_\omega u^\omega_{i,t}. ωi,ttarget=ηωui,tω.
随后再施加加速度约束:
v i , t = c l i p a c c ( v i , t t a r g e t , v i , t − 1 , a m a x Δ t ) . v_{i,t} =clip_{acc} \left( v^{target}_{i,t}, v_{i,t-1}, a_{max}\Delta t \right). vi,t=clipacc(vi,ttarget,vi,t−1,amaxΔt).
注意源码有一个非常合理的细节:
第一预测时刻使用当前测量速度,不会再次乘 η \eta η。
否则就会把已经发生过的控制衰减重复计算一次。
6.2 扰动衰减
在第 j j j 个预测点:
ρ j = exp ( − t j τ d ) . \rho_j= \exp \left( -\frac{t_j}{\tau_d} \right). ρj=exp(−τdtj).
于是:
v y , j d i s t = v ^ y d i s t ρ j , v_{y,j}^{dist} =\hat v_y^{dist}\rho_j, vy,jdist=v^ydistρj,
ω j d i s t = ω ^ d i s t ρ j . \omega_j^{dist} =\hat\omega^{dist}\rho_j. ωjdist=ω^distρj.
6.3 航向积分
θ j + 1 = θ j + ( ω j + ω j d i s t ) Δ t . \theta_{j+1} =\theta_j+ \left( \omega_j+ \omega_j^{dist} \right)\Delta t. θj+1=θj+(ωj+ωjdist)Δt.
6.4 位置积分
对于非全向模型,主动控制侧向速度为 0,但可以存在外部侧向扰动,因此:
v y = v y d i s t . v_y=v_y^{dist}. vy=vydist.
位置更新为:
x j + 1 = x j + ( v x cos θ − v y d i s t sin θ ) Δ t , x_{j+1} =x_j+ \left( v_x\cos\theta -v_y^{dist}\sin\theta \right)\Delta t, xj+1=xj+(vxcosθ−vydistsinθ)Δt,
y j + 1 = y j + ( v x sin θ + v y d i s t cos θ ) Δ t . y_{j+1} =y_j+ \left( v_x\sin\theta + v_y^{dist}\cos\theta \right)\Delta t. yj+1=yj+(vxsinθ+vydistcosθ)Δt.
这意味着控制器在采样阶段看到的不再是“车辆一定沿车头方向运动”,而是能够预测“车头朝这个方向,但由于侧滑,真实质心还会横向漂”。
七、MPCC 式路径跟踪代价
项目的核心跟踪 Critic:
mpcc_tracking_critic.hpp
采用 Model Predictive Contouring Control 的思路,不仅计算机器人与离散路径点的欧氏距离,而是把误差拆分。
7.1 轮廓误差 Contouring Error
轨迹点投影到参考路径后,横向距离记作:
e c . e_c. ec.
它直接反映几何路径跟踪误差。
7.2 滞后误差 Lag Error
设期望弧长进度为:
s e x p , s_{exp}, sexp,
轨迹投影进度为:
s p r o j , s_{proj}, sproj,
则:
e l = s e x p − s p r o j . e_l=s_{exp}-s_{proj}. el=sexp−sproj.
如果只最小化横向误差,机器人可能通过“少往前走”来换取较小的几何误差;Lag Error 用来防止这种现象。
7.3 航向误差
考虑侧滑角:
β s l i p = a t a n 2 ( v y d i s t , max ( v r e f , 0.1 ) ) . \beta_{slip} =atan2 \left( v_y^{dist}, \max(v_{ref},0.1) \right). βslip=atan2(vydist,max(vref,0.1)).
目标车体航向需要对运动方向做补偿,因此:
e h = w r a p [ θ t r a j − ( θ p a t h − β s l i p ) ] . e_h= wrap \left[ \theta_{traj}- (\theta_{path}-\beta_{slip}) \right]. eh=wrap[θtraj−(θpath−βslip)].
7.4 速度误差
e v = v t r a j − v r e f ( s ) . e_v= v_{traj}-v_{ref}(s). ev=vtraj−vref(s).
7.5 横摆角速度误差
曲率前馈关系为:
ω r e f = v r e f κ . \omega_{ref}=v_{ref}\kappa. ωref=vrefκ.
因此:
e ω = ( ω t r a j + ω d i s t ρ ) − v r e f κ . e_\omega =(\omega_{traj}+\omega^{dist}\rho) -v_{ref}\kappa. eω=(ωtraj+ωdistρ)−vrefκ.
7.6 综合代价
可以整理为:
J i = ∑ t w t [ q c e c 2 + q l e l 2 + q h e h 2 + q v e v 2 + q ω e ω 2 ] + J t e r m i n a l . J_i =\sum_t w_t \left[ q_c e_c^2+ q_l e_l^2+ q_h e_h^2+ q_v e_v^2+ q_\omega e_\omega^2 \right] + J_{terminal}. Ji=t∑wt[qcec2+qlel2+qheh2+qvev2+qωeω2]+Jterminal.
项目的主要权重默认值:
mpcc_weight: 8.0
mpcc_contour_weight: 2.2
mpcc_lag_weight: 0.35
mpcc_heading_weight: 1.10
mpcc_velocity_weight: 0.25
mpcc_yaw_rate_weight: 0.20
mpcc_terminal_weight: 2.0
从这些权重可以看出,该配置首先强调几何轮廓跟踪,其次考虑航向,再在进度和速度之间做折中。
八、参考速度与参考控制生成
项目并不是始终用固定:
0.6 m/s
向前跟踪,而是对路径进行速度预览。
8.1 曲率限速
横向加速度近似:
a y = v 2 ∣ κ ∣ . a_y=v^2|\kappa|. ay=v2∣κ∣.
因此:
v κ = a y , m a x ∣ κ ∣ . v_\kappa =\sqrt{ \frac{a_{y,max}}{|\kappa|} }. vκ=∣κ∣ay,max.
曲率越大,允许速度越低。
8.2 终点制动
根据制动距离关系:
v 2 = 2 a d , v^2=2ad, v2=2ad,
得到:
v g o a l = 2 a g o a l d g o a l . v_{goal} =\sqrt{ 2a_{goal}d_{goal} }. vgoal=2agoaldgoal.
机器人越接近终点,参考速度会连续降低。
8.3 弯道前视减速
项目还在:
path_corner_preview_distance
范围内预览未来曲率,并根据允许减速度提前降低速度,而不是等真正进入急弯才突然减速。
8.4 smooth minimum
最终参考速度可以概念性写成:
v r e f = s m o o t h _ m i n ( v c r u i s e , v κ , v c o r n e r , v g o a l ) . v_{ref} =smooth\_min \left( v_{cruise}, v_\kappa, v_{corner}, v_{goal} \right). vref=smooth_min(vcruise,vκ,vcorner,vgoal).
使用 smooth minimum 而不是简单 min(),可以减轻多个限速条件切换时的控制突变。
九、采样策略
noise_generator.hpp 不仅实现普通独立高斯噪声,还保留了多个 MPPI 变体常用的采样策略。
9.1 AR(1) 时间相关噪声
普通白噪声:
ϵ t ∼ N ( 0 , σ 2 ) \epsilon_t\sim\mathcal{N}(0,\sigma^2) ϵt∼N(0,σ2)
在时间上完全独立,容易产生锯齿控制序列。
项目默认:
noise_correlation: 0.85
可以理解为:
$$
\epsilon_t
\beta\epsilon_{t-1}
+
\sqrt{1-\beta^2}\xi_t.
$$
因此采样出来的未来控制天然更加平滑。
9.2 反对称采样
若生成一个噪声:
ϵ , \epsilon, ϵ,
同时生成:
− ϵ . -\epsilon. −ϵ.
这种 antithetic sampling 能提高有限样本下采样空间的对称性,降低蒙特卡洛估计方差。
默认:
antithetic_sampling: true
9.3 名义样本
nominal_sample_count: 1
至少保留一条零噪声样本,即当前 warm-start 控制序列本身。
这样可以避免所有样本都随机偏离当前已经不错的解。
9.4 Guided Sampling
默认:
guided_sampling_ratio: 0.25
guided_sampling_blend: 0.80
即约 25% 的 Rollout 会向基于路径曲率、横向误差和航向误差生成的参考控制序列靠拢。
因此采样分布不是完全盲目的。
对复杂弯道而言,这可以把更多计算预算放在“可能有用”的控制区域。
9.5 KMPPI 风格支持点采样
配置:
sampling_support_points: 0
默认关闭。
启用后,不再对 horizon 中每一个控制时刻独立优化噪声,而是在较少的支持点上采样,再通过 RBF 核插值到整个时域。
优点是降低优化维度。
9.6 Smooth-MPPI 风格控制导数采样
配置:
sample_control_derivatives: false
默认关闭。
开启后噪声不直接作用于绝对控制:
u t + ϵ t , u_t+\epsilon_t, ut+ϵt,
而是作用于控制增量:
Δ u t + ϵ t . \Delta u_t+\epsilon_t. Δut+ϵt.
随后积分得到控制序列,因此可以得到更平滑的控制。
项目注释说明,该方法实测虽然可能提高精度,但会增加角加速度 RMS,所以正式配置没有默认启用。
9.7 跨周期复用噪声
reuse_noise_sequence: true
noise_cycle_correlation: 0.98
上一控制周期的低频采样结构会被左移保留,并只注入少量新探索。
这不仅提高时间连续性,也可以降低相邻控制周期因随机采样产生的指令跳变。
十、自适应温度、ESS 与精英截断
10.1 有效样本量 ESS
若归一化权重为:
∑ i w i = 1 , \sum_iw_i=1, i∑wi=1,
则有效样本量:
E S S = 1 ∑ i w i 2 . ESS= \frac{1} {\sum_iw_i^2}. ESS=∑iwi21.
一般形式也可写为:
E S S = ( ∑ i w i ) 2 ∑ i w i 2 . ESS= \frac{(\sum_iw_i)^2} {\sum_iw_i^2}. ESS=∑iwi2(∑iwi)2.
如果所有权重相近:
E S S ≈ N . ESS\approx N. ESS≈N.
如果几乎只有一个样本有权重:
E S S ≈ 1. ESS\approx1. ESS≈1.
10.2 为什么固定 temperature 有问题
假设两次实验的路径跟踪代价整体尺度不同。
即使轨迹相对优劣完全一样,只要:
S i S_i Si
整体放大,指数项:
e − S i / λ e^{-S_i/\lambda} e−Si/λ
就可能突然变得非常尖锐。
因此同一个 λ \lambda λ 在不同路径、速度、Critic 权重下表现会变化。
10.3 ESS 目标温度
当前配置:
adaptive_temperature: true
target_ess_ratio: 0.15
adaptive_temperature_min: 0.10
adaptive_temperature_max: 3.00
算法通过二分搜索温度 T T T,使:
E S S ( T ) ≈ 0.15 N . ESS(T) \approx 0.15N. ESS(T)≈0.15N.
例如:
batch_size = 400
则目标:
E S S ≈ 60. ESS\approx60. ESS≈60.
这样 temperature 不再只是一个固定调参值,而是围绕“希望多少条轨迹真正参与优化”自动变化。
10.4 CEM-style Elite Truncation
设置:
elite_sample_count > 0
后,只保留成本最低的 Top-K 轨迹。
非 elite 样本:
w i = 0. w_i=0. wi=0.
elite 内仍保持 MPPI 的指数权重:
w i ∝ e − ( S i − S m i n ) / T . w_i \propto e^{-(S_i-S_{min})/T}. wi∝e−(Si−Smin)/T.
所以它不是标准 CEM 的“所有 elite 等权求均值”,而是:
CEM 的截断思想 + MPPI 的相对成本权重。
当前正式配置:
elite_sample_count: 0
默认关闭。
配置注释给出的原因很直接:实测它可以提高精度,但也会增加角加速度 RMS。
十一、三种运动模型与运动约束
项目支持:
DiffDrive
Omni
Ackermann
当前默认:
motion_model: "Ackermann"
11.1 DiffDrive
非全向:
v y c m d = 0. v_y^{cmd}=0. vycmd=0.
控制变量主要是:
u = [ v x , ω ] T . u=[v_x,\omega]^T. u=[vx,ω]T.
11.2 Omni
全向模型额外允许:
v y c m d ≠ 0. v_y^{cmd}\neq0. vycmd=0.
因此控制变量为:
u = [ v x , v y , ω ] T . u=[v_x,v_y,\omega]^T. u=[vx,vy,ω]T.
11.3 Ackermann
项目没有直接把前轮转角 δ \delta δ 作为 MPPI 控制量,而仍通过 Twist:
( v , ω ) (v,\omega) (v,ω)
表达。
几何曲率:
κ = ω v . \kappa=\frac{\omega}{v}. κ=vω.
最小转弯半径要求:
∣ κ ∣ ≤ 1 R m i n . |\kappa| \leq \frac{1}{R_{min}}. ∣κ∣≤Rmin1.
因此:
∣ ω ∣ ≤ ∣ v ∣ R m i n . |\omega| \leq \frac{|v|}{R_{min}}. ∣ω∣≤Rmin∣v∣.
同时横向加速度:
a y = v ω . a_y=v\omega. ay=vω.
要求:
∣ v ω ∣ ≤ a y , m a x , |v\omega| \leq a_{y,max}, ∣vω∣≤ay,max,
于是:
∣ ω ∣ ≤ a y , m a x ∣ v ∣ . |\omega| \leq \frac{a_{y,max}}{|v|}. ∣ω∣≤∣v∣ay,max.
项目最终取:
∣ ω ∣ ≤ min ( ∣ v ∣ R m i n , a y , m a x ∣ v ∣ ) . |\omega| \leq \min \left( \frac{|v|}{R_{min}}, \frac{a_{y,max}}{|v|} \right). ∣ω∣≤min(Rmin∣v∣,∣v∣ay,max).
非常重要的一点是:
约束不仅作用于采样控制,还会在加速度传播后的预测状态上重新投影。
因为如果只分别限制:
Δ v , Δ ω , \Delta v, \qquad \Delta\omega, Δv,Δω,
车辆在启动和制动阶段仍可能临时产生不合理的极大曲率。
十二、终点处理与控制平滑
12.1 GoalDocking
距离终点较近时,单纯 MPPI 容易出现:
- 速度太小提前停住;
- 在目标附近来回震荡;
- 扰动下始终差几厘米到不了;
- 最后阶段轨迹优化不稳定。
因此项目增加:
tools/goal_docking.hpp
在一定距离内逐渐混合终端位姿反馈。
典型距离—速度关系:
v = min ( v m a x , k d d , 2 a g o a l d ) . v =\min \left( v_{max}, k_dd, \sqrt{2a_{goal}d} \right). v=min(vmax,kdd,2agoald).
当前:
goal_docking_distance: 0.20
goal_docking_full_control_distance: 0.12
goal_docking_max_speed: 0.18
12.2 Reacquisition
如果机器人还没到目标,但因为优化或扰动导致速度已经非常低,则启动重捕获:
goal_recovery_distance: 1.20
goal_recovery_speed_threshold: 0.08
goal_recovery_max_speed: 0.35
目的是避免“离目标还有距离,但控制器自己停住”。
12.3 Savitzky-Golay 控制序列平滑
配置:
use_sg_filter: true
优化后使用历史命令和未来控制序列做 Savitzky-Golay 保形平滑。
源码中还有一个关键处理:
SG 滤波结束后必须重新施加运动约束。
否则滤波本身可能让:
- 速度越界;
- 角速度越界;
- Ackermann 曲率约束被破坏。
十三、核心源码模块说明
13.1 controller.hpp
控制器对外总接口。
主要职责:
Controller
├── MotionModel
├── Optimizer
└── CriticManager
上层 ROS 节点不需要直接操作 MPPI 内部数据结构,只需要:
- 设置路径;
- 设置扰动估计;
- 输入当前 pose / speed;
- 调用
computeVelocityCommands()。
13.2 optimizer.hpp
整个项目最核心的文件。
主要实现:
prepare
↓
generateNoisedTrajectories
↓
motion model prediction
↓
integrateStateVelocities
↓
CriticManager::score
↓
updateControlSequence
↓
applyControlSequenceConstraints
↓
SG filter
↓
getControlFromSequence
↓
shiftControlSequence
此外还包含:
- 路径裁剪;
- guided sampling;
- 参考控制生成;
- ESS 温度搜索;
- elite 截断;
- Ackermann 后处理;
- ancillary feedback;
- 终点制动;
- 预测轨迹输出。
13.3 disturbance_estimator.hpp
DC-PMPPI 的主要新增模块。
负责:
里程计/位姿
+
执行器实际命令
↓
车体系速度
↓
执行器滞后补偿
↓
η_v / η_ω
↓
横摆残差 / 侧向残差
↓
低通 + 创新限幅
↓
方差 + confidence
↓
DisturbanceEstimate
13.4 noise_generator.hpp
集中处理各种 sampling policy:
- Gaussian;
- AR(1);
- antithetic;
- nominal sample;
- guided sample 前的随机基础;
- KMPPI 支持点;
- Smooth-MPPI 控制导数采样;
- noise sequence reuse。
13.5 path_projection.hpp
负责将任意二维点投影到分段线性路径,得到:
- 最近投影点;
- 所在线段;
- 路径弧长;
- 有符号横向误差;
- 路径切向航向。
MPCCTrackingCritic、参考控制生成、最近路径点搜索都依赖这部分路径几何信息。
13.6 path_reference.hpp
负责:
- 路径累计弧长;
- 根据弧长插值参考状态;
- 曲率计算;
- 曲率限速;
- 弯道预览减速;
- 终点制动;
smoothMinimum()。
13.7 critics/
Critic 使用统一接口:
score(CriticData & data)
每个 Critic 将自己的代价累加到总 costs。
默认核心组合主要是:
MPCCTrackingCritic
+
ControlRateCritic
其余 Critic 更适合作为可选实验模块。
十四、ROS 输入输出接口
14.1 /plan
类型:
nav_msgs/Path
ROS 节点收到后会:
- 删除距离过近的重复路径点;
- 按固定间距重新采样;
- 重新计算路径切线航向;
- 可选保留原路径终点 orientation。
默认:
path_resample_spacing: 0.10
path_duplicate_epsilon: 0.005
14.2 /odom1
类型:
nav_msgs/Odometry
用于:
- 当前机器人 pose;
- 当前速度;
- 扰动估计;
- odom timeout 判断。
默认:
odom_timeout: 0.30
odom_topic: "/odom1"
planning_frame: "map"
strict_frame_check: true
14.3 /constrained_cmd_vel_stamped
类型:
geometry_msgs/TwistStamped
它的价值是告诉估计器:
“真正到底盘边界的命令到底是多少”。
如果只使用优化器原始 /cmd_vel,而中间还有安全限幅、速度约束器或底盘转换,则估计器会把“中间层改了命令”错误识别为“车辆模型失配”。
当前:
dc_pmppi_use_executed_command: true
dc_pmppi_executed_command_timeout: 0.20
14.4 /cmd_vel
类型:
geometry_msgs/Twist
最终控制命令。
对于 Ackermann 底盘,项目还提供:
scripts/twist_to_ackermann.py
用于将 Twist 形式的:
v
ω
转换为 Ackermann 控制。
14.5 /local_path
类型:
nav_msgs/Path
用于 RViz 可视化当前优化控制序列重新积分得到的名义预测轨迹。
14.6 /controller_solve_time_ms
类型:
std_msgs/Float64
用于实时监测单周期优化耗时。
正式配置:
control_period_ms: 50
因此控制频率约为:
f = 1 0.05 = 20 H z . f=\frac1{0.05}=20Hz. f=0.051=20Hz.
求解时间应尽可能稳定低于:
50 ms
否则无法严格维持 20 Hz 控制周期。
十五、关键参数说明
15.1 MPPI 核心
| 参数 | 默认值 | 含义 |
|---|---|---|
batch_size |
400 | 每周期 Rollout 数 |
time_steps |
40 | 预测步数 |
model_dt |
0.05 s | 模型时间步 |
iteration_count |
1 | 单周期优化迭代数 |
control_period_ms |
50 ms | 控制周期 |
temperature |
0.60 | MPPI 温度初值 |
gamma |
0.015 | 控制扰动正则系数 |
target_ess_ratio |
0.15 | 自适应温度的目标 ESS 比例 |
预测时域:
T h = 40 × 0.05 = 2.0 s . T_h =40\times0.05 =2.0s. Th=40×0.05=2.0s.
15.2 采样
| 参数 | 默认值 |
|---|---|
vx_std |
0.20 m/s |
wz_std |
0.35 rad/s |
noise_correlation |
0.85 |
antithetic_sampling |
true |
guided_sampling_ratio |
0.25 |
reuse_noise_sequence |
true |
noise_cycle_correlation |
0.98 |
nominal_sample_count |
1 |
15.3 车辆约束
| 参数 | 默认值 |
|---|---|
vx_max |
0.70 m/s |
vx_min |
0 |
wz_max |
1.0 rad/s |
ax_max |
1.2 m/s² |
az_max |
2.5 rad/s² |
ackermann_min_turning_radius |
0.50 m |
path_max_lateral_acceleration |
0.60 m/s² |
15.4 路径
| 参数 | 默认值 |
|---|---|
prune_distance |
3.5 m |
path_resample_spacing |
0.10 m |
path_reference_speed |
0.60 m/s |
path_corner_preview_distance |
1.20 m |
path_corner_deceleration |
0.90 m/s² |
goal_deceleration |
0.50 m/s² |
15.5 DC-PMPPI
| 参数 | 默认值 | 说明 |
|---|---|---|
dc_pmppi_enabled |
false | DC 总开关 |
disturbance_decay_time_constant |
0.8 s | 预测扰动衰减 |
dc_pmppi_filter_time_constant |
0.20 s | 扰动低通 |
dc_pmppi_effectiveness_time_constant |
1.50 s | η 低通/回归时间尺度 |
dc_pmppi_confidence_time_constant |
0.50 s | confidence 建立速度 |
dc_pmppi_minimum_confidence |
0.25 | 最低可信阈值 |
dc_pmppi_compensation_gain |
0.85 | 总补偿增益 |
dc_pmppi_pose_velocity_window |
0.10 s | 位姿差分速度窗口 |
dc_pmppi_max_vy_innovation |
0.40 m/s | 侧向创新限幅 |
dc_pmppi_max_wz_innovation |
0.80 rad/s | 横摆创新限幅 |
注意:
dc_pmppi_enabled: false
意味着仓库当前正式默认启动的是标准 MPPI 基线。
要验证 DC 效果必须显式开启。
十六、项目运行步骤
这里需要区分“README 预期方式”和“当前分支实际提交内容”。
16.1 下载分支
cd ~/catkin_ws/src
git clone -b DC-PMPPI \
https://github.com/Robot-Nav/SA-MPPI.git
由于 ROS 包本身位于 rsc/,建议将其作为 dc_pmppi 包放入工作空间:
cd ~/catkin_ws/src
mv SA-MPPI/rsc dc_pmppi
也可以保留仓库结构后自行软链接。
16.2 安装 ROS 依赖
sudo apt update
sudo apt install \
ros-noetic-ackermann-msgs \
libeigen3-dev \
libomp-dev
然后:
cd ~/catkin_ws
rosdep install \
--from-paths src \
--ignore-src \
-r -y
16.3 编译
cd ~/catkin_ws
catkin_make --pkg dc_pmppi
source devel/setup.bash
CMake 会自动检测 OpenMP。
如果成功启用,会打印类似:
dc_pmppi: OpenMP acceleration enabled
否则退化为串行计算。
16.4 当前分支关于 launch 文件的注意事项
CMakeLists.txt 中存在:
install(DIRECTORY launch/
DESTINATION ${CATKIN_PACKAGE_SHARE_DESTINATION}/launch
)
README 也给出了若干:
roslaunch dc_pmppi ...
运行方式。
但当前 DC-PMPPI 分支的 rsc/ 目录树中没有实际提交 launch/ 目录。
因此,如果按当前仓库快照直接复现,不能假设这些 launch 文件一定存在。
方式 A:补齐项目原本的 launch 文件
如果作者后续分支或本地工程中有:
j15_sim.launch
j15_dc_pmppi.launch
j15_path.launch
将其放入:
dc_pmppi/launch/
再按 README 启动。
方式 B:直接运行节点
先加载参数:
rosparam load \
~/catkin_ws/src/dc_pmppi/config/dc_pmppi_params.yaml
注意 YAML 顶层命名空间是:
dc_pmppi_node:
然后运行:
rosrun dc_pmppi dc_pmppi_node \
__name:=dc_pmppi_node
之后确保:
rostopic echo /odom1
rostopic echo /plan
都有有效输入。
16.5 发布路径
项目提供:
scripts/JZJ_path.py
用于生成/发布测试路径。
安装后的脚本可尝试:
rosrun dc_pmppi JZJ_path.py
具体使用时仍应根据脚本中的参数和路径形式调整。
16.6 标准 MPPI
配置:
dc_pmppi_enabled: false
用于建立 baseline。
16.7 DC-PMPPI
修改:
dc_pmppi_enabled: true
并重新加载参数或通过 launch override。
16.8 运行时重点检查
rostopic hz /cmd_vel
预期约:
20 Hz
检查求解耗时:
rostopic echo /controller_solve_time_ms
原则上应满足:
t s o l v e < 50 m s . t_{solve}<50ms. tsolve<50ms.
查看预测轨迹:
/local_path
并在 RViz 中与:
/plan
叠加观察。
十七、项目依赖库
17.1 ROS
项目面向:
ROS1 Noetic
主要依赖:
roscpp
rospy
nav_msgs
geometry_msgs
std_msgs
sensor_msgs
tf
ackermann_msgs
package.xml 还声明:
onboard_detector
为运行依赖。
不过 DC-PMPPI 的纯路径跟踪主节点本身的核心输入仍然是路径、里程计和执行命令。
17.2 Eigen3
CMake:
find_package(Eigen3 REQUIRED)
用于数学与几何相关计算。
17.3 OpenMP
项目将计算密集的批量轨迹处理和 Critic 评分并行化。
CMake 使用:
find_package(OpenMP QUIET)
因此 OpenMP 不存在时仍能编译,只是退化为串行。
17.4 xtensor
xtensor 是项目中非常重要的批量数值计算基础。
例如:
batch_size × time_steps
维度的:
- 采样速度;
- 状态;
- 轨迹;
- costs;
- weights;
都适合使用张量形式处理。
17.5 xsimd
xsimd 为 xtensor 提供 SIMD 向量化能力。
与 OpenMP 的分工可以粗略理解为:
OpenMP:多线程并行
xsimd:单线程内部向量指令并行
17.6 xtl
xtensor 生态中的基础模板依赖。
这三个库在仓库中以内嵌源码形式存在,因此通常不需要单独通过 apt 安装。
十八、如何做标准 MPPI / DC-PMPPI A-B 对比
这个项目特别适合做控制算法实验,因为 DC 功能有总开关。
18.1 Baseline
dc_pmppi_enabled: false
记录:
- 横向误差 RMSE;
- 最大横向误差;
- 航向误差 RMSE;
- 终点误差;
- 线加速度 RMS;
- 角加速度 RMS;
- solve time;
- 成功率。
18.2 DC-PMPPI
保持:
- 相同路径;
- 相同车辆;
- 相同 batch size;
- 相同 random seed;
- 相同扰动序列;
只修改:
dc_pmppi_enabled: true
再比较相同指标。
18.3 推荐扰动场景
纵向有效性衰减
例如:
v a c t u a l = 0.65 v c m d . v_{actual}=0.65v_{cmd}. vactual=0.65vcmd.
检查 η v \eta_v ηv 是否收敛到接近 0.65。
横摆有效性衰减
ω a c t u a l = 0.7 ω c m d . \omega_{actual}=0.7\omega_{cmd}. ωactual=0.7ωcmd.
检查 η ω \eta_\omega ηω。
恒定横向漂移
v y d i s t = 0.1 m / s . v_y^{dist}=0.1m/s. vydist=0.1m/s.
观察标准 MPPI 是否出现稳定横向偏差,以及 DC 是否通过航向补偿降低误差。
时间变化 OU 扰动
可使用:
d k + 1 = d k − Δ t τ d k + σ Δ t ξ k . d_{k+1} =d_k -\frac{\Delta t}{\tau}d_k + \sigma\sqrt{\Delta t}\xi_k. dk+1=dk−τΔtdk+σΔtξk.
这种扰动比恒定 bias 更接近低频随机环境扰动。
十九、项目特点与工程注意事项
19.1 它更像“鲁棒模型修正 MPPI”,而不是重新发明 MPPI
DC-PMPPI 的核心价值在于:
真实反馈
↓
模型失配估计
↓
修正 Rollout
↓
重新做 MPPI
因此它保持了 MPPI 原有的采样优化框架。
19.2 η 和加性扰动拆开是合理的
如果只估计一个总扰动:
d = v m e a s − v c m d , d=v_{meas}-v_{cmd}, d=vmeas−vcmd,
则无法区分:
控制增益下降
和:
额外外部运动
项目分别使用:
η u \eta u ηu
与:
+ d +d +d
表达,可以得到:
y = η u + d . y=\eta u+d. y=ηu+d.
这种模型比纯残差补偿更有解释性。
19.3 executed command 很重要
如果底盘前还有速度约束器:
MPPI cmd
↓
限速器
↓
底盘真正执行 cmd
估计器应该比较:
真实响应
vs
底盘真正收到的命令
而不是比较:
真实响应
vs
MPPI 原始命令
否则会把约束器行为当成地面滑移。
19.4 当前 traction_scale 主要是诊断量
虽然代码支持通过 traction_scale 动态降低速度和加速度,但正式配置指数为 0。
这是一个值得注意的设计选择:
同一种物理效果最好不要在多个模块中重复补偿。
既然 η \eta η 已经缩放了运动模型,再用 traction_scale 大幅压低可用速度可能造成过度保守。
19.5 Ackermann 不能直接“原地旋转”
源码参数中:
heading_alignment_start: 3.00
heading_alignment_stop: 3.14
基本等价于关闭传统“航向差一大就把速度降到 0”的策略。
原因是 Ackermann 车辆本身不能像差速车一样原地旋转。
因此大航向调整主要依靠有限转弯半径圆弧完成。
19.6 路径裁剪不是简单最近点
optimizer.hpp 使用:
局部搜索窗口
+
物理距离
+
航向误差
联合寻找最近进度点。
这对:
- 回头弯;
- 发卡弯;
- 相邻两段空间距离很近但方向相反;
特别重要。
否则只按欧氏距离可能跳到错误路径段。
19.7 当前项目主要是“路径跟踪控制器”,不是完整导航栈
它本身解决的是:
给定参考路径
↓
实时优化速度控制
并不等价于:
建图
+
定位
+
全局规划
+
动态避障
+
局部规划
+
底盘控制
因此实际导航系统中,仍然需要上游模块提供 /plan。
二十、总结
DC-PMPPI 的完整逻辑可以压缩成一句话:
在标准 MPPI 采样优化的基础上,通过里程计与真实执行命令在线估计控制有效性和等价外部扰动,再把估计结果写回 Rollout 预测模型,使优化器看到的未来运动更接近真实车辆。
其控制链路为:
参考路径 + 当前状态
↓
路径裁剪与速度预览
↓
扰动估计
v_y^dist / ω^dist / η_v / η_ω
↓
生成参考控制
↓
批量采样
↓
含扰动 Rollout
↓
MPCC + ControlRate 等 Critic
↓
ESS 自适应 temperature
↓
MPPI 加权更新
↓
控制约束 + SG 平滑
↓
GoalDocking
↓
执行第一项 /cmd_vel
↓
控制序列左移
↓
下一周期重新优化
从工程实现看,这个项目的重点并不只在一条新的 MPPI 更新公式,而在于把以下模块组合到了一起:
- MPPI 路径积分采样控制;
- MPCC 风格路径跟踪目标;
- 在线等价扰动估计;
- 控制有效性在线辨识;
- 执行器一阶滞后补偿;
- 扰动衰减 Rollout;
- ESS 自适应 temperature;
- AR(1)、反对称、引导、可选 KMPPI / Smooth-MPPI 采样;
- Ackermann 运动可行域;
- Savitzky-Golay 控制平滑;
- GoalDocking 终端稳定;
- OpenMP + xtensor/xsimd 的批量并行实现。
如果用于湿滑路面、滑移底盘、移动平台或模型参数变化明显的机器人,DC-PMPPI 相比完全依赖名义运动模型的 MPPI,最主要的优势是能够通过实时反馈持续修正自己的预测模型,而不是等轨迹已经偏离之后才单纯依靠更大的跟踪误差做被动纠偏。
附:建议阅读源码顺序
如果准备继续深入修改代码,建议按下面的顺序阅读:
1. config/dc_pmppi_params.yaml
↓
2. src/dc_pmppi_node.cpp
↓
3. include/controller.hpp
↓
4. include/optimizer.hpp
↓
5. include/tools/disturbance_estimator.hpp
↓
6. include/motion_models.hpp
↓
7. include/critics/mpcc_tracking_critic.hpp
↓
8. include/tools/path_projection.hpp
↓
9. include/tools/path_reference.hpp
↓
10. include/tools/noise_generator.hpp
↓
11. include/tools/goal_docking.hpp
其中真正决定 DC-PMPPI 与标准 MPPI 差异的两处核心代码是:
disturbance_estimator.hpp
和:
optimizer.hpp 中的
updateStateVelocities()
integrateStateVelocities()
buildReferenceControlSequence()
前者回答“扰动怎么估”,后者回答“估出来以后怎么进入 MPPI”。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)