Apollo二次规划的应用之PWJ


  基于之前对二次规划的粗鄙描述: Lattice Planner从学习到放弃(二):二次规划的应用与调试发现遗漏了如何建立矩阵P…后来再看,其实理解的并不透彻,这次补上。
  Apollo中lattice planner中存在两种求解方法,一种是撒点后根据起始状态直接求解五次多项式,一种是纵向s均匀采样后根据bound构建二次型实现数值优化求解。基于数值优化求解,lattice和pwj在横向规划方面,构建目标函数存在差异,求解过程并无二致。
  引用老哥 决策规划算法四:Piecewise Jerk Path Optimizer 的话:该路径平滑算法用3次多项式连接每个离散点,即每段曲线的Jerk为常数,该算法因此而得名:Piecewise Jerk Path Optimizer.

优化问题解析

  规划的目的是在有限的约束下按照一定目标计算出我们想要的轨迹。即:目标+约束
  决策:从当前环境中给出一个粗范围,建立一个局部空间将车辆面对的复杂情况凸化,用于后续快速求解
  规划:基于当前空间,求解出符合需求的可行轨迹
用图说话:
凸问题
  对于这个场景而言,决策单一且清晰,只需要设置合理的bound,进行规划求解即可。然而,实际的行车条件是复杂多变的,对于下述场景(凹问题,且障碍物还是静止的),决策结果将会是多样的:左绕行、右绕行、停车。没有合理的决策将会让系统行为显得很傻,一旦明确从左还是从右,剩下的问题自然迎刃而解,这便是决策的重要性。
凹问题
  Planning优化问题的本质便是在这约束内,计算出最优的轨迹。

二次规划求解

  关键在于如何将规划问题转换成如下QP形式。
在这里插入图片描述

构建优化目标

  对于横向规划,以下图情况为例,我们希望自车在车道不沿车道中心线,而是略微靠右行驶:
在这里插入图片描述
定义状态量
x = [ l 0 , l 1 , . . . l n , l 0 ′ , l 1 ′ , . . . l n ′ , l 0 ′ ′ , l 1 ′ ′ , . . . l n ′ ′ ] T x = [l_0, l_1,...l_n,l_0', l_1',...l_n',l_0'', l_1'',...l_n'']^T x=[l0,l1,...ln,l0,l1,...lnl0′′,l1′′,...ln′′]T
整理优化目标:

  • 横向位移
      1.轨迹贴合车道指引线
    J l = ∑ i = 0 n − 1 l i 2 J_l = \sum_{i=0}^{n-1} l_i^2 Jl=i=0n1li2
      2.轨迹贴合期望路径
    J l _ r e f = ∑ i = 0 n − 1 ( l i − l _ r e f i ) 2 J_{l\_ref} = \sum_{i=0}^{n-1} (l_i - l\_ref_i)^2 Jl_ref=i=0n1(lil_refi)2
      3.指定轨迹目标末点
    J l e n d = ∑ i = n − 1 n − 1 ( l n − l e n d ) 2 J_{l_{end}} = \sum_{i=n-1}^{n-1} (l_n-l_{end})^2 Jlend=i=n1n1(lnlend)2

  • 横向速度
      1.轨迹相对于指引线的横向速度
    J l ′ = ∑ i = 0 n − 1 l i ′ 2 J_{l'} = \sum_{i=0}^{n-1} l_i'^2 Jl=i=0n1li′2
      2.轨迹相对末点的横向速度
    J l _ e n d ′ = ∑ i = n − 1 n − 1 ( l i ′ − l _ e n d ′ ) 2 J_{l\_end'} = \sum_{i=n-1}^{n-1} (l_i' - l\_end')^2 Jl_end=i=n1n1(lil_end)2

  • 横向加速度
      轨迹相对于指引线的横向加速度
    J l ′ ′ = ∑ i = 0 n − 1 l i ′ ′ 2 J_{l''} = \sum_{i=0}^{n-1} l_i''^2 Jl′′=i=0n1li′′2
      2.轨迹相对末点的横向速度
    J l _ e n d ′ ′ = ∑ i = n − 1 n − 1 ( l i ′ ′ − l _ e n d ′ ′ ) 2 J_{l\_end''} = \sum_{i=n-1}^{n-1} (l_i'' - l\_end'')^2 Jl_end′′=i=n1n1(li′′l_end′′)2

  • 横向加加速度
      轨迹相对于指引线的横向jerk
    J j e r k = ∑ i = 0 n − 1 j e r k i 2 J_{jerk} = \sum_{i=0}^{n-1} jerk_i^2 Jjerk=i=0n1jerki2
      已知
    j e r k i = l i ′ ′ ′ = l i + 1 ′ ′ − l i ′ ′ Δ s jerk_i = l_i''' = {l_{i+1}'' - l_{i}''\over \Delta s} jerki=li′′′=Δsli+1′′li′′
      可得横向jerk最终形式为
    J j e r k = ∑ i = 0 n − 1 ( l i + 1 ′ ′ − l i ′ ′ Δ s ) 2 J_{jerk} = \sum_{i=0}^{n-1} ({l_{i+1}'' - l_{i}''\over \Delta s})^2 Jjerk=i=0n1(Δsli+1′′li′′)2
    最终,我们对每种优化目标施以权重来得到最终的优化目标:
    J t a r g e t = W l ⋅ J l + W l r e f ⋅ J l _ r e f + W l e n d ⋅ J l e n d + W l ′ ⋅ J l ′ + W l _ e n d ′ ⋅ J l _ e n d ′ + W l ′ ′ ⋅ J l ′ ′ + W l _ e n d ′ ′ ⋅ J l _ e n d ′ ′ + W j e r k ⋅ J j e r k = ( W l + W l r e f ) ⋅ ∑ i = 0 n − 1 l i 2 − 2 W l r e f ⋅ ∑ i = 0 n − 1 l i ⋅ l _ r e f i + W l r e f ⋅ ∑ i = 0 n − 1 l r e f 2 + W l e n d ( l n − 1 ) 2 − 2 W l e n d ⋅ l n − 1 l e n d + W l e n d ( l e n d ) 2 + W l ′ ⋅ ∑ i = 0 n − 1 l i ′ 2 + W l e n d ′ ( l n − 1 ′ ) 2 − 2 W l e n d ′ ⋅ l n − 1 ′ l e n d ′ + W l e n d ′ ( l e n d ′ ) 2 + W l ′ ′ ⋅ ∑ i = 0 n − 1 l i ′ ′ 2 + W l e n d ′ ′ ( l n − 1 ′ ′ ) 2 − 2 W l e n d ′ ′ ⋅ l n − 1 ′ ′ l e n d ′ ′ + W l e n d ′ ′ ( l e n d ′ ′ ) 2 + W l ′ ′ ′ ⋅ ( 1 Δ s ) 2 ⋅ ∑ i = 0 n − 1 ( l i + 1 ′ ′ 2 + l i ′ ′ 2 ) − 2 W l ′ ′ ′ ⋅ 1 Δ s 2 ⋅ ∑ i = 0 n − 1 l i + 1 ′ ′ l i ′ ′ = ( W l + W l r e f ) ⋅ ∑ i = 0 n − 1 l i 2 + W l e n d ( l n − 1 ) 2 + W l ′ ⋅ ∑ i = 0 n − 1 l i ′ 2 + W l e n d ′ ( l n − 1 ′ ) 2 + ( W l ′ ′ + W l ′ ′ ⋅ 1 Δ s 2 ) ⋅ ∑ i = 0 n − 1 l i ′ ′ 2 + W l ′ ′ ⋅ 1 Δ s 2 ⋅ l i + 1 ′ ′ 2 − 2 W l r e f ⋅ ∑ i = 0 n − 1 l i ⋅ l _ r e f i − 2 W l e n d ⋅ l n − 1 l e n d − 2 W l e n d ′ ⋅ l n − 1 ′ l e n d ′ − 2 W l e n d ′ ′ ⋅ l n − 1 ′ ′ l e n d ′ ′ + C o n s t J_{target} = W_l \cdot J_l + W_{l_{ref}} \cdot J_{l\_ref} + W_{l_{end}} \cdot J_{l_{end}} + W_{l'} \cdot J_{l'} + W_{l\_end'} \cdot J_{l\_end'} + W_{l''} \cdot J_{l''} + W_{l\_end''} \cdot J_{l\_end''} + W_{jerk} \cdot J_{jerk} \\ = (W_l+W_{l_{ref}})\cdot \sum_{i=0}^{n-1} l_i^2 - 2W_{l_{ref}}\cdot \sum_{i=0}^{n-1} l_i\cdot l\_ref_i + W_{l_{ref}}\cdot \sum_{i=0}^{n-1} l_{ref}^2 + W_{l_{end}}(l_{n-1})^2 - 2W_{l_{end}}\cdot l_{n-1}l_{end} + W_{l_{end}}(l_{end})^2 \\ + W_{l'}\cdot \sum_{i=0}^{n-1} l_i'^2 + W_{l_{end}'}(l_{n-1}')^2 - 2W_{l_{end}'}\cdot l_{n-1}'l_{end}' + W_{l_{end}'}(l_{end}')^2 \\ + W_{l''}\cdot \sum_{i=0}^{n-1} l_i''^2 + W_{l_{end}''}(l_{n-1}'')^2 - 2W_{l_{end}''}\cdot l_{n-1}''l_{end}'' + W_{l_{end}''}(l_{end}'')^2 \\ + W_{l'''}\cdot ({1\over \Delta s})^2 \cdot \sum_{i=0}^{n-1} (l_{i+1}''^2 + l_{i}''^2 ) - 2W_{l'''}\cdot {1\over \Delta s^2} \cdot \sum_{i=0}^{n-1} l_{i+1}'' l_{i}'' \\ = (W_l+W_{l_{ref}})\cdot \sum_{i=0}^{n-1} l_i^2 + W_{l_{end}}(l_{n-1})^2 + W_{l'}\cdot \sum_{i=0}^{n-1} l_i'^2 + W_{l_{end}'}(l_{n-1}')^2 + (W_{l''} + W_{l''} \cdot {1\over \Delta s^2}) \cdot \sum_{i=0}^{n-1} l_i''^2 + W_{l''} \cdot {1\over \Delta s^2}\cdot l_{i+1}''^2 - 2W_{l_{ref}}\cdot \sum_{i=0}^{n-1} l_i\cdot l\_ref_i - 2W_{l_{end}}\cdot l_{n-1}l_{end} - 2W_{l_{end}'}\cdot l_{n-1}'l_{end}' - 2W_{l_{end}''}\cdot l_{n-1}''l_{end}'' + Const Jtarget=WlJl+WlrefJl_ref+WlendJlend+WlJl+Wl_endJl_end+Wl′′Jl′′+Wl_end′′Jl_end′′+WjerkJjerk=(Wl+Wlref)i=0n1li22Wlrefi=0n1lil_refi+Wlrefi=0n1lref2+Wlend(ln1)22Wlendln1lend+Wlend(lend)2+Wli=0n1li′2+Wlend(ln1)22Wlendln1lend+Wlend(lend)2+Wl′′i=0n1li′′2+Wlend′′(ln1′′)22Wlend′′ln1′′lend′′+Wlend′′(lend′′)2+Wl′′′(Δs1)2i=0n1(li+1′′2+li′′2)2Wl′′′Δs21i=0n1li+1′′li′′=(Wl+Wlref)i=0n1li2+Wlend(ln1)2+Wli=0n1li′2+Wlend(ln1)2+(Wl′′+Wl′′Δs21)i=0n1li′′2+Wl′′Δs21li+1′′22Wlrefi=0n1lil_refi2Wlendln1lend2Wlendln1lend2Wlend′′ln1′′lend′′+Const

拆解目标函数为二次型形式

  目标函数已经列完,合并该合并的,常数项统统并为const,并不会影响目标求解。根据状态量x,
矩阵P如下:
[ W l + W l r e f 0 ⋯ ⋯ 0 0 ⋯ ⋯ 0 0 ⋯ ⋯ ⋯ 0 0 W l + W l r e f 0 ⋯ ⋮ ⋮ ⋯ ⋯ ⋮ ⋮ ⋯ ⋯ ⋯ ⋮ ⋮ 0 W l + W l r e f 0 ⋮ ⋮ ⋯ ⋯ ⋮ ⋮ ⋯ ⋯ ⋯ ⋮ ⋮ ⋮ 0 ⋱ 0 ⋮ ⋯ ⋯ ⋮ ⋮ ⋯ ⋯ ⋯ ⋮ 0 ⋯ ⋯ 0 W l + W l r e f + W l e n d 0 ⋯ ⋯ ⋮ ⋮ ⋯ ⋯ ⋯ ⋮ 0 ⋯ ⋯ ⋯ 0 W l ′ 0 ⋯ ⋮ ⋮ ⋯ ⋯ ⋯ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ 0 W l ′ 0 ⋮ ⋮ ⋯ ⋯ ⋯ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ 0 ⋱ 0 ⋮ ⋯ ⋯ ⋯ ⋮ 0 ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ 0 W l ′ + W l e n d ′ 0 ⋯ ⋯ ⋯ ⋮ 0 ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ 0 W l ′ ′ + W l ′ ′ ′ ⋅ 1 Δ s 2 0 ⋯ ⋯ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ 0 − 2 W l ′ ′ ′ ⋅ 1 Δ s 2 W l ′ ′ + 2 W l ′ ′ ′ ⋅ 1 Δ s 2 0 ⋯ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ 0 ⋱ ⋱ 0 ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ ⋮ 0 − 2 W l ′ ′ ′ ⋅ 1 Δ s 2 W l ′ ′ + 2 W l ′ ′ ′ ⋅ 1 Δ s 2 0 0 ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ ⋯ − 2 W l ′ ′ ′ ⋅ 1 Δ s 2 W l ′ ′ + W l ′ ′ ′ ⋅ 1 Δ s 2 ] \begin{bmatrix} W_{l}+W_{l_{ref}} & 0 &\cdots &\cdots & 0 & 0 &\cdots &\cdots &0 & 0 &\cdots &\cdots &\cdots & 0 \\ 0 & W_{l}+W_{l_{ref}} & 0 &\cdots & \vdots & \vdots &\cdots &\cdots & \vdots & \vdots &\cdots &\cdots &\cdots &\vdots\\ \vdots & 0 & W_{l}+W_{l_{ref}} & 0 & \vdots & \vdots &\cdots &\cdots & \vdots & \vdots &\cdots &\cdots &\cdots &\vdots\\ \vdots & \vdots & 0 & \ddots &0 & \vdots &\cdots &\cdots & \vdots & \vdots &\cdots &\cdots &\cdots &\vdots\\ 0 & \cdots & \cdots &0 & W_{l}+W_{l_{ref}}+W_{l_{end}} & 0 &\cdots &\cdots & \vdots & \vdots &\cdots &\cdots &\cdots &\vdots\\ 0 &\cdots &\cdots &\cdots & 0 & W_{l'} & 0 &\cdots & \vdots & \vdots &\cdots &\cdots &\cdots &\vdots\\ \vdots & \vdots & \vdots &\vdots & \vdots & 0 & W_{l'} & 0 & \vdots & \vdots &\cdots &\cdots &\cdots &\vdots\\ \vdots & \vdots & \vdots &\vdots & \vdots & \vdots & 0 & \ddots & 0 &\vdots &\cdots &\cdots &\cdots &\vdots\\ 0 &\cdots &\cdots &\cdots &\cdots &\cdots &\cdots & 0 & W_{l'}+W_{l_{end}'} & 0 &\cdots &\cdots &\cdots &\vdots\\ 0 & \cdots &\cdots &\cdots &\cdots &\cdots &\cdots &\cdots & 0 & W_{l''}+W_{l'''} \cdot {1\over \Delta s^2} &0 &\cdots &\cdots &\vdots \\ \vdots & \vdots & \vdots &\vdots & \vdots & \vdots & \vdots &\vdots & 0 & -2W_{l'''} \cdot {1\over \Delta s^2} & W_{l''}+2W_{l'''} \cdot {1\over \Delta s^2} &0 &\cdots &\vdots\\ \vdots & \vdots & \vdots &\vdots & \vdots & \vdots & \vdots &\vdots &\vdots & 0 & \ddots & \ddots & 0 & \vdots\\ \vdots & \vdots & \vdots &\vdots & \vdots & \vdots & \vdots &\vdots &\vdots &\vdots & 0 & -2W_{l'''} \cdot {1\over \Delta s^2} & W_{l''}+2W_{l'''} \cdot {1\over \Delta s^2} & 0\\ 0 &\cdots &\cdots &\cdots &\cdots &\cdots &\cdots &\cdots &\cdots &\cdots &\cdots &\cdots & -2W_{l'''} \cdot {1\over \Delta s^2} & W_{l''}+W_{l'''} \cdot {1\over \Delta s^2}\\ \end{bmatrix} Wl+Wlref0000000Wl+Wlref00Wl+Wlref00000Wl+Wlref+Wlend000Wl00Wl00000Wl+Wlend0000Wl′′+Wl′′′Δs212Wl′′′Δs2100Wl′′+2Wl′′′Δs21002Wl′′′Δs210Wl′′+2Wl′′′Δs212Wl′′′Δs2100Wl′′+Wl′′′Δs21
矩阵Q如下:
[ − 2 ⋅ W l ⋅ l r e f ⋮ ⋮ − 2 ⋅ W l ⋅ l r e f − 2 ⋅ W l ⋅ l r e f − 2 ⋅ W l e n d ⋅ l r e f 0 ⋮ 0 − 2 ⋅ W l e n d ′ ⋅ l r e f ′ 0 ⋮ 0 − 2 ⋅ W l e n d ′ ′ ⋅ l r e f ′ ′ ] \begin{bmatrix} -2\cdot W_{l} \cdot {l_{ref}} \\ \vdots \\ \vdots \\ -2\cdot W_{l} \cdot {l_{ref}} \\ -2\cdot W_{l} \cdot {l_{ref}} - 2\cdot W_{l_{end}} \cdot {l_{ref}} \\ 0 \\ \vdots \\ 0 \\ -2\cdot W_{l_{end}'} \cdot {l_{ref}'} \\ 0 \\ \vdots \\ 0 \\ -2\cdot W_{l_{end}''} \cdot {l_{ref}''} \\ \end{bmatrix} 2Wllref2Wllref2Wllref2Wlendlref002Wlendlref002Wlend′′lref′′
高能预警:上述优化目标函数中,ds为定值即求解过程为定步长,在实际问题建立中,s一旦不为定步长,将会导致求解结果不符合预期。

构建约束

  PWJ约束定义没有本质区别,依然是满足运动学约束,外加横向jerk bound,可戳:Lattice Planner从学习到放弃(二):二次规划的应用与调试

代码实现

Apollo源码里结构很清晰,主体函数:

bool PiecewiseJerkProblem::Optimize(const int max_iter) {
  OSQPData* data = FormulateProblem();
  ...
}

在FormulateProblem()函数中实现二次型的构建:

OSQPData* PiecewiseJerkProblem::FormulateProblem() {
  // calculate kernel
  std::vector<c_float> P_data;
  std::vector<c_int> P_indices;
  std::vector<c_int> P_indptr;
  CalculateKernel(&P_data, &P_indices, &P_indptr);

  // calculate affine constraints
  std::vector<c_float> A_data;
  std::vector<c_int> A_indices;
  std::vector<c_int> A_indptr;
  std::vector<c_float> lower_bounds;
  std::vector<c_float> upper_bounds;
  CalculateAffineConstraint(&A_data, &A_indices, &A_indptr, &lower_bounds,
                            &upper_bounds);

  // calculate offset
  std::vector<c_float> q;
  CalculateOffset(&q);

  OSQPData* data = reinterpret_cast<OSQPData*>(c_malloc(sizeof(OSQPData)));
  CHECK_EQ(lower_bounds.size(), upper_bounds.size());

  size_t kernel_dim = 3 * num_of_knots_;
  size_t num_affine_constraint = lower_bounds.size();

  data->n = kernel_dim;
  data->m = num_affine_constraint;
  data->P = csc_matrix(kernel_dim, kernel_dim, P_data.size(), CopyData(P_data),
                       CopyData(P_indices), CopyData(P_indptr));
  data->q = CopyData(q);
  data->A =
      csc_matrix(num_affine_constraint, kernel_dim, A_data.size(),
                 CopyData(A_data), CopyData(A_indices), CopyData(A_indptr));
  data->l = CopyData(lower_bounds);
  data->u = CopyData(upper_bounds);
  return data;
}

拓展

  对于纵向规划而言,换汤不换药,只不过状态量变成了s和t相关。
  对于pwj中函数:

piecewise_jerk_problem.set_x_ref()

可好好利用,通过设置x_ref可以通过软约束的行驶达到使车辆基于参考线实现偏移目的。
  对于osqp求解器的实际求解过程,em…大神的文章着实给力:
路径规划中不得不知的OSQP
交替方向乘子法(ADMM)算法的流程和原理是怎样的

思考

  得力于现在的工作环境,最近一直在从事基于规则优化的规划和基于ML的DDP(Data Driven Planning)规划,目前行业对数据驱动以及深度学习用于规划也是热火朝天,毕竟随着数据的指数级增长,如何使用这些海量数据成了Tire1和车企绕不开的问题。大量数据训练用以驱动自动驾驶的趋势显而易见。对于二者的配合方式,自己也有了一些困惑:ML为主,rule base只用于最后的兜底?亦或是 rule base为主,ML为其提供决策指导? 毕竟开车不是下棋,一步错棋或许还能补救,一个异常轨迹可能就是一个家庭。
  虽然我司采用第一种且效果还不错,但面对依然偶发的异常行为,如果目的是快速落地并真正的服务于大众,或许第二种是最直接和稳定的?期待大佬给锤~~


每天进步一点点…come on

  • 10
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值