Skip to content

PiecewiseJerkSpeedNonlinearOptimizer 非线性速度优化器

源码位置:modules/planning/tasks/piecewise_jerk_speed_nonlinear/

模块定位

PiecewiseJerkSpeedNonlinearOptimizer 是两阶段速度优化器:先用 QP(二次规划)求解线性化问题获得初始解,再用 NLP(IPOPT 非线性规划)精细优化,引入路径曲率约束实现向心加速度限制。

继承关系:

Task → SpeedOptimizer → PiecewiseJerkSpeedNonlinearOptimizer
                              ↓ 使用
                        PiecewiseJerkSpeedProblem(QP 阶段)
                        PiecewiseJerkSpeedNonlinearIpoptInterface(NLP 阶段)

PiecewiseJerkSpeedOptimizer(纯 QP)的区别:本优化器额外考虑了路径曲率对速度的约束(向心加速度 = v² × κ),能在弯道处更精确地限速。


Process 主流程

cpp
Status Process(path_data, init_point, speed_data) {
  // 1. 设置状态和边界
  SetUpStatesAndBounds(path_data, *speed_data);

  // 2. QP 阶段:获得初始解
  OptimizeByQP(speed_data, &distance, &velocity, &acceleration);

  // 3. 检查速度限制可行性
  if (CheckSpeedLimitFeasibility()) {
    // 4. 平滑路径曲率
    SmoothPathCurvature(path_data);
    // 5. 平滑速度限制
    SmoothSpeedLimit();
    // 6. NLP 阶段:精细优化
    OptimizeByNLP(&distance, &velocity, &acceleration);
  }

  // 7. 组装 SpeedData 输出
  speed_data = assemble(distance, velocity, acceleration);
}

SetUpStatesAndBounds — 状态与边界设置

cpp
Status SetUpStatesAndBounds(path_data, speed_data) {
  // 初始状态
  s_init_ = 0.0;
  s_dot_init_ = init_point.v();
  s_ddot_init_ = init_point.a();

  // 动力学边界
  s_dot_max_ = max_speed;
  s_ddot_min_ = max_deceleration;
  s_ddot_max_ = max_acceleration;
  s_dddot_min/max_ = jerk_bounds;

  // 安全边界:遍历 ST 边界
  for (t = 0; t < total_time; t += delta_t) {
    for (boundary : st_boundaries) {
      switch (boundary_type) {
        case STOP/YIELD: s_upper = min(s_upper, boundary_s);
        case FOLLOW:     s_upper = min(s_upper, boundary_s);
                         s_soft_upper = s_upper - min(7.0, 2.5*v);
        case OVERTAKE:   s_lower = max(s_lower, boundary_s);
                         s_soft_lower = s_lower + 10.0;
      }
    }
    s_bounds_.push_back({s_lower, s_upper});
    s_soft_bounds_.push_back({s_soft_lower, s_soft_upper});
  }
}

OptimizeByQP — QP 阶段

使用 PiecewiseJerkSpeedProblem(OSQP 求解器):

cpp
Status OptimizeByQP(speed_data, &distance, &velocity, &acceleration) {
  PiecewiseJerkSpeedProblem problem(num_of_knots_, delta_t_, init_states);
  problem.set_dx_bounds(0.0, max_speed);
  problem.set_ddx_bounds(s_ddot_min_, s_ddot_max_);
  problem.set_dddx_bound(s_dddot_min_, s_dddot_max_);
  problem.set_x_bounds(s_bounds_);

  // 权重设置
  problem.set_weight_ddx(config_.acc_weight());
  problem.set_weight_dddx(config_.jerk_weight());

  // 参考:DP 速度曲线
  x_ref = dp_speed_profile;
  problem.set_x_ref(config_.ref_s_weight(), x_ref);

  problem.Optimize();
  // 输出 distance, velocity, acceleration
}

SmoothPathCurvature — 路径曲率平滑

将离散的路径曲率拟合为平滑的 PiecewiseJerk 曲线,供 NLP 使用:

cpp
Status SmoothPathCurvature(path_data) {
  // 采样路径曲率
  for (s = 0; s < path_length; s += delta_s) {
    kappa_ref.push_back(path_data.GetKappa(s));
  }

  // 用 PiecewiseJerkPathProblem 平滑
  PiecewiseJerkPathProblem problem(size, delta_s, {kappa_ref[0], 0, 0});
  problem.set_x_ref(weight, kappa_ref);
  problem.Optimize();

  // 存储为 PiecewiseJerkTrajectory1d
  smoothed_path_curvature_ = result;
}

SmoothSpeedLimit — 速度限制平滑

将阶梯状的速度限制平滑为连续曲线:

cpp
Status SmoothSpeedLimit() {
  // 采样速度限制
  for (s = 0; s < 200m; s += 2.0) {
    speed_ref.push_back(speed_limit_.GetSpeedLimitByS(s));
  }

  // 用 PiecewiseJerkPathProblem 平滑
  PiecewiseJerkPathProblem problem(size, delta_s, {speed_ref[0], 0, 0});
  problem.set_x_ref(10.0, speed_ref);
  problem.Optimize();

  smoothed_speed_limit_ = result;
}

OptimizeByNLP — NLP 阶段(IPOPT)

cpp
Status OptimizeByNLP(&distance, &velocity, &acceleration) {
  auto ptr_interface = new PiecewiseJerkSpeedNonlinearIpoptInterface(
      s_init_, s_dot_init_, s_ddot_init_, delta_t_, num_of_knots_,
      total_length_, s_dot_max_, s_ddot_min_, s_ddot_max_,
      s_dddot_min_, s_dddot_max_);

  // 设置 warm start(QP 结果)
  ptr_interface->set_warm_start({distance, velocity, acceleration});

  // 设置曲率曲线和速度限制曲线
  ptr_interface->set_curvature_curve(smoothed_path_curvature_);
  ptr_interface->set_speed_limit_curve(smoothed_speed_limit_);

  // 设置安全边界
  ptr_interface->set_safety_bounds(s_bounds_);
  ptr_interface->set_soft_safety_bounds(s_soft_bounds_);

  // 设置权重
  ptr_interface->set_w_overall_a(config_.acc_weight());
  ptr_interface->set_w_overall_j(config_.jerk_weight());
  ptr_interface->set_w_overall_centripetal_acc(config_.lat_acc_weight());
  ptr_interface->set_w_reference_speed(config_.ref_v_weight());
  ptr_interface->set_w_reference_spatial_distance(config_.ref_s_weight());

  // IPOPT 求解
  Ipopt::IpoptApplication app;
  app->Options()->SetIntegerValue("max_iter", config_.max_iter());
  app->OptimizeTNLP(ptr_interface);
}

IPOPT 接口 — 目标函数

NLP 目标函数包含:

公式权重
加速度平方Σ a²w_overall_a_
Jerk 平方Σ ((a[i+1]-a[i])/Δt)²w_overall_j_
向心加速度Σ (v² × κ)²w_overall_centripetal_acc_
参考速度偏差Σ (v - v_ref)²w_ref_v_
参考距离偏差Σ (s - s_ref)²w_ref_s_
终点状态(s-s_t)² + (v-v_t)² + (a-a_t)²w_target_*
软边界松弛Σ slack²w_soft_s_bound_

约束条件:

  • 运动学递推:s[i+1] = s[i] + v[i]Δt + 0.5a[i]Δt²
  • 速度递推:v[i+1] = v[i] + a[i]Δt
  • 边界约束:s_lower ≤ s[i] ≤ s_upper
  • 动力学约束:a_min ≤ a[i] ≤ a_max, jerk_min ≤ j ≤ jerk_max

关键配置参数

参数说明
acc_weight加速度代价权重
jerk_weightJerk 代价权重
lat_acc_weight向心加速度代价权重
ref_v_weight参考速度偏差权重
ref_s_weight参考距离偏差权重(DP 结果)
max_iterIPOPT 最大迭代次数

贡献者

页面历史