1. 项目概述:AL-iLQR求解器在自动驾驶轨迹规划中的应用
这个开源项目实现了一套完整的增广拉格朗日迭代LQR(AL-iLQR)求解器,专门针对自动驾驶和机器人领域的轨迹规划问题。不同于传统优化方法,AL-iLQR通过结合迭代线性二次调节器(iLQR)的高效性和增广拉格朗日(AL)方法的约束处理能力,实现了在复杂约束条件下的实时轨迹优化。
核心价值在于:
- 提供了从理论到代码的完整实现路径,让研究者能直观理解算法细节
- 模块化设计使得各组件(动力学模型、约束条件、优化核心)可独立替换
- 包含从基础到高级的示例,特别适合自动驾驶避障场景的开发验证
提示:项目采用C++实现,需要CMake构建系统,建议在Ubuntu 18.04+/Windows WSL2环境下运行,核心依赖包括Eigen3和matplotlib-cpp。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 算法原理深度解析
2.1 离散最优控制问题建模
AL-iLQR求解的问题形式可表述为:
code复制minimize J = Σ[lₖ(xₖ,uₖ)] + l_N(x_N) (总代价函数)
subject to xₖ₊₁ = f(xₖ,uₖ) (动力学约束)
gₖ(xₖ,uₖ) ≤ 0 (路径约束)
项目中通过ConstrainedOptimalControlProblem类实现这一建模:
- 动力学模型:支持自定义实现,内置自行车模型(KinematicBicycleModel)
- 代价函数:包含状态偏差和控制量惩罚项
- 路径约束:采用可扩展的约束接口设计
2.2 无约束iLQR工作原理
iLQR的核心在于迭代执行:
- 前向仿真:基于当前控制序列生成轨迹
- 反向传播:计算价值函数二次近似
- 前向更新:通过线搜索确定最优控制更新量
项目中的关键实现细节:
cpp复制// ilqr_solver.cpp 核心流程
while (!converged) {
trajectory = ForwardRollout(x0, U); // 前向仿真
UpdateTaylorExpansions(trajectory); // 计算A,B矩阵
BackwardPass(trajectory, K, d); // Riccati递推
alpha = LineSearch(x0, U, K, d); // 步长选择
UpdateControls(U, K, d, alpha); // 控制量更新
}
2.3 增广拉格朗日约束处理
AL方法将约束问题转化为一系列无约束子问题:
code复制L_ρ(x,u,λ) = J(x,u) + Σ[λᵀg(x,u) + ρ/2 ||g(x,u)||²]
项目中的实现亮点:
- 分层更新策略:先固定(λ,ρ)优化控制量,再更新乘子和惩罚系数
- 自适应惩罚调整:根据约束违反程度动态调整ρ
- 双重近似处理:同时处理动力学线性化和约束二次近似
3. 代码架构与核心实现
3.1 类继承关系解析
系统采用模块化设计,主要包含以下核心类:
code复制├── OptimalControlProblem(抽象基类)
│ ├── ConstrainedOptimalControlProblem
│ └── AugmentedLagrangianProblem
├── DynamicsModel(接口类)
│ ├── KinematicBicycleModel
│ └── LinearPointMassModel
├── Constraint(接口类)
│ ├── RoadBoundaryConstraint
│ └── VehicleObstacleConstraint
└── Solver
├── ILQRSolver
└── ALILQRSolver
3.2 关键算法实现细节
3.2.1 数值微分实现
由于解析雅可比矩阵难以获取,项目采用中心差分法:
cpp复制// ilqr_solver.cpp
MatrixXd ILQRSolver::DynamicsJacobianState(const VectorXd& x, const VectorXd& u) {
MatrixXd A(x.size(), x.size());
const double h = 1e-6; // 差分步长
for (int i = 0; i < x.size(); ++i) {
VectorXd dx = VectorXd::Zero(x.size());
dx[i] = h;
VectorXd x_plus = dynamics_->NextState(x + dx, u, dt_);
VectorXd x_minus = dynamics_->NextState(x - dx, u, dt_);
A.col(i) = (x_plus - x_minus) / (2 * h);
}
return A;
}
3.2.2 正则化与线搜索
为保证算法数值稳定性,实现了:
- 控制量更新正则化:添加Levenberg-Marquardt项
- 自适应线搜索:Armijo条件结合二次/三次插值
注意:正则化系数需要根据具体问题调整,过大导致收敛慢,过小可能引发数值不稳定。
3.3 约束处理实现
碰撞约束采用多圆近似法:
cpp复制// multi_circle_vehicle_obstacle_constraint.cpp
VectorXd MultiCircleVehicleObstacleConstraint::Evaluate(
const VectorXd& x, const VectorXd& u) const {
auto centers = vehicle_model_->EvaluateWorldCenters(x);
VectorXd violations(centers.size() * obstacles_.size());
for (int i = 0; i < centers.size(); ++i) {
for (int j = 0; j < obstacles_.size(); ++j) {
double dist = (centers[i] - obstacles_[j].center).norm();
violations[i*obstacles_.size() + j] =
obstacles_[j].radius + vehicle_radius_ - dist;
}
}
return violations;
}
4. 实战应用:自动驾驶避障案例
4.1 静态避障场景配置
通过CreateAutodriveDemoScenario()构建典型场景:
cpp复制// demo_scenario.cpp
Scenario CreateAutodriveDemoScenario() {
Scenario scenario;
// 1. 初始化状态(位置、航向、速度)
scenario.initial_state << 0, 0, 0, 5.0;
// 2. 创建自行车模型
auto model = std::make_shared<KinematicBicycleModel>(2.9, 0.3);
// 3. 添加道路边界约束
auto road_constraint = std::make_shared<RoadBoundaryConstraint>(-2.0, 2.0);
scenario.problem->AddStageConstraint(road_constraint);
// 4. 添加静态障碍物
CircleObstacle obs{{10.0, 1.5}, 2.0};
auto obstacle_constraint = std::make_shared<VehicleObstacleConstraint>(
model, std::vector{obs}, 1.2);
scenario.problem->AddStageConstraint(obstacle_constraint);
return scenario;
}
4.2 求解过程可视化
项目提供两种可视化方式:
-
Matplotlib交互界面(planner_gui)
- 显示轨迹迭代过程
- 实时绘制代价下降曲线
- 支持参数调优交互
-
ImGui前端(imgui_frontend)
- 3D视角查看轨迹
- 支持障碍物位置动态调整
- 显示约束违反情况
4.3 典型问题排查
4.3.1 发散问题处理
现象:代价函数突然增大或出现NaN
解决方法:
- 检查正则化系数(solver_options.regularization)
- 减小最大步长(solver_options.max_alpha)
- 验证动力学模型实现是否正确
4.3.2 收敛慢问题
优化策略:
- 调整AL外层循环容忍度(al_options.outer_tolerance)
- 优化iLQR内层迭代次数(ilqr_options.max_iterations)
- 改进初始猜测(如使用简化模型预计算)
5. 扩展应用与性能优化
5.1 动态障碍物处理
项目支持时变约束:
cpp复制// dynamic_obstacle_demo.cpp
for (int k = 0; k < N; ++k) {
double t = k * dt;
CircleObstacle obs = GetObstaclePositionAtTime(t);
auto constraint = std::make_shared<VehicleObstacleConstraint>(
model, std::vector{obs}, safety_margin);
problem->AddStageConstraint(k, constraint);
}
5.2 计算性能优化技巧
-
并行化处理:
- 使用OpenMP并行计算差分矩阵
- 各时间段的约束评估可并行执行
-
代码级优化:
- 启用Eigen的向量化指令(-mavx2)
- 热点函数手动展开循环
-
近似方法:
- 稀疏化处理雅可比矩阵
- 降低反向传播频率
这个实现最值得借鉴的是其清晰的架构设计——将复杂的约束优化问题分解为可组合的模块,每个组件都有明确的职责边界。在实际应用中,我发现将车辆模型与约束条件解耦特别重要,这使得算法能快速适配不同的机器人平台。对于想深入理解优化算法的开发者,建议从phase0示例开始逐步调试,观察每次迭代中轨迹和代价函数的变化规律。
