共计 1552 个字符,预计需要花费 4 分钟才能阅读完成。
背景痛点:为什么控制算法这么难?
在 b 站老王的自动驾驶项目里,最让人头疼的就是过弯道时车辆像喝醉了一样左右摇摆。实测数据显示:
- 使用传统 PID 控制时,60km/ h 过 90 度弯横向误差最大达到 0.8 米
- 紧急制动时产生明显 ” 点头 ” 现象(俯仰角超 3 度)
这些问题背后的根本原因是:
- 系统延迟 :从感知到执行的 200ms 延迟相当于 5.6 米的盲开距离(60km/ h 时)
- 耦合干扰 :转向和制动控制相互影响,PID 的独立控制结构难以处理
核心技术对决:PID vs MPC
PID 控制(传统派)
就像用三根弹簧拉小车:
u(t) = K_p e(t) + K_i \int_0^t e(\tau)d\tau + K_d \frac{de(t)}{dt}
- 优势:计算快(<1ms)、调参直观
- 致命伤:处理延迟就像用后视镜开车
MPC 控制(预言家)
提前计算未来 N 步的最优解:
\min_{u} \sum_{k=1}^{N} (\|x_k - x_{ref}\|_Q + \|u_k\|_R)
\quad \text{s.t.} \quad x_{k+1} = Ax_k + Bu_k

关键突破:
- 显式处理延迟(将延迟建模为系统状态)
- 天生支持多约束(方向盘转角限制 / 制动压力梯度)
工业级代码实现
PID 抗饱和处理(C++20)
class PIDController {
public:
void update(double error, double dt) {integral_ = clamp(integral_ + error * dt, -i_max_, i_max_); // 抗饱和核心
double p = kp_ * error;
double i = ki_ * integral_;
double d = kd_ * (error - last_error_) / dt;
last_error_ = error;
return p + i + d;
}
private:
double integral_{0}, last_error_{0};
double i_max_{1.0}; // 积分限幅
};
MPC 求解器(Eigen 版)
MPCResult solveQP(const MatrixXd& H, const VectorXd& f,
const MatrixXd& A_constraint, const VectorXd& b_constraint) {
// 使用 OSQP 或 qpOASES 求解
Eigen::VectorXd u_opt = QPSolver::solve(H, f, A_constraint, b_constraint);
return {u_opt.head(ctrl_dim), solver_time_us};
}
性能注释 :
– i7-1185G7 上平均求解时间 2.8ms(预测时域 N =10)
– 内存占用 <512KB
避坑实战指南
PID 调参口诀
- 先调 Kp 直到出现轻微震荡
- 然后加 Kd 直到震荡消失
- 最后加 Ki 补偿稳态误差
MPC 部署陷阱
- QP 求解超时 :将 H 矩阵预处理为对角占优
- 雅可比矩阵瓶颈 :用自动微分工具(Ceres Solver)
- ROS2 配置建议 :
mpc_controller: prediction_horizon: 10 # 时域步数 q_weights: [10.0, 1.0] # 状态权重 r_weights: [0.1] # 控制量权重 solver_timeout: 5ms # 超时保护
仿真验证:双移线见真章
在 CARLA 中设计测试场景:
- 干燥沥青路面,速度 60km/h
- 参考路径振幅±3.5m
结果对比 (RMS 误差):
| 算法类型 | 横向误差 (m) | 计算耗时 (ms) |
|---|---|---|
| PID | 0.42 | 0.1 |
| MPC | 0.18 | 3.2 |
测试平台:NVIDIA Jetson AGX Xavier
思考题:预测时域的平衡术
MPC 的预测时域就像望远镜:
– 看太远(N=20):计算爆炸
– 看太近(N=5):预见性不足
你的选择是 :
– 固定时域 + 降采样预测?
– 变时域 + 滚动规划?
– 还是其他黑科技?
欢迎在评论区分享你的实战经验!
正文完
