Apollo决策规划 - EM planner

news2024/10/6 0:32:55

旨在对b站老王所讲的百度Apollo - EM planner算法做浓缩版总结

0 决策规划背景

基于图搜索
在这里插入图片描述

优点
可以得到全局层面最优解,适用于比较低维数的规划问题
缺点
规划问题维数较高时,面临指数爆炸问题

基于采样
在这里插入图片描述

优点:
计算量低,曲率连续,行驶平顺性好
缺点:
曲线通常是四阶或者更高,系数的计算难以使车辆到达确定的运动状态

基于插值的曲率规划
在这里插入图片描述

优点
算法总是可以收敛到满足条件的解,适用于全局规划和局部规划
缺点
产生的轨迹不连续而且不平稳,路径的最优性受时间影响

基于函数优化
在这里插入图片描述

优点
影响因素考虑多,包含道路限制条件、自车限制,便于处理约束,可以满足不同优化目标,求解速度快
缺点
最优解一般比较贴近约束,转化为优化问题本身较为困难

自动驾驶总共分成了六个等级:L0 - L5

等级详述
L0没有任何自动驾驶功能
L1有横向和纵向的自动驾驶功能,但是横纵向无法联合作用
L2横纵向可以联合作用,但是驾驶员必须对一切情况负责
L3功能和L2基本相同,最大的区别在于责任,对于部分场景,驾驶员不必负责
L4大部分道路皆可自动驾驶,大部分场景都不需要驾驶员负责
L5完全自动驾驶

EM Planner是Apollo的经典决策规划算法,擅长处理复杂环境下的决策规划问题。

2 规划需要的背景知识

2.1 五次多项式
  1. 位置
    x ( t ) = a 0 + a 1 t + a 2 t 2 + a 3 t 3 + a 4 t 4 + a 5 t 5 y ( t ) = b 0 + b 1 t + b 2 t 2 + b 3 t 3 + b 4 t 4 + b 5 t 5 x(t) = a_{0}+a_{1}t+a_{2}t^2+a_{3}t^3+a_{4}t^4+a_{5}t^5\\ y(t) = b_{0}+b_{1}t+b_{2}t^2+b_{3}t^3+b_{4}t^4+b_{5}t^5 x(t)=a0+a1t+a2t2+a3t3+a4t4+a5t5y(t)=b0+b1t+b2t2+b3t3+b4t4+b5t5
  2. 速度
    x ˙ ( t ) = a 1 + 2 a 2 t + 3 a 3 t 2 + 4 a 4 t 3 + 5 a 5 t 4 y ˙ ( t ) = b 1 + 2 b 2 t + 3 b 3 t 2 + 4 b 4 t 3 + 5 b 5 t 4 \dot{x} (t)=a_{1}+2a_{2}t+3a_{3}t^2+4a_{4}t^3+5a_{5}t^4\\ \dot{y} (t)=b_{1}+2b_{2}t+3b_{3}t^2+4b_{4}t^3+5b_{5}t^4 x˙(t)=a1+2a2t+3a3t2+4a4t3+5a5t4y˙(t)=b1+2b2t+3b3t2+4b4t3+5b5t4
  3. 加速度
    x ¨ ( t ) = 2 a 2 + 6 a 3 t + 12 a 4 t 2 + 20 a 5 t 3 y ¨ ( t ) = 2 b 2 + 6 b 3 t + 12 b 4 t 2 + 20 b 5 t 3 \ddot{x} (t)=2a_{2}+6a_{3}t+12a_{4}t^2+20a_{5}t^3\\ \ddot{y} (t)=2b_{2}+6b_{3}t+12b_{4}t^2+20b_{5}t^3 x¨(t)=2a2+6a3t+12a4t2+20a5t3y¨(t)=2b2+6b3t+12b4t2+20b5t3

化为矩阵形式。
X = [ x ( 0 ) x ( 0 ) ˙ x ( 0 ) ¨ x ( T ) x ( T ) ˙ x ( T ) ¨ ] = [ t 0 5 t 0 4 t 0 3 t 0 2 t 0 1 5 t 0 4 4 t 0 3 3 t 0 2 2 t 0 1 0 20 t 0 3 12 t 0 2 6 t 0 2 0 0 t 1 5 t 1 4 t 1 3 t 1 2 t 1 1 5 t 1 4 4 t 1 3 3 t 1 2 2 t 1 1 0 20 t 1 3 12 t 1 2 6 t 1 2 0 0 ] [ a 5 a 4 a 3 a 2 a 1 a 0 ] = T X A X=\begin{bmatrix}x(0) \\\dot{x(0)} \\\ddot{x(0)} \\x(T) \\\dot{x(T)} \\\ddot{x(T)} \end{bmatrix}=\begin{bmatrix} t_{0}^5& t_{0}^4 & t_{0}^3 & t_{0}^2 & t_{0} &1 \\ 5t_{0}^4 & 4t_{0}^3 & 3t_{0}^2 & 2t_{0} & 1 & 0\\ 20t_{0}^3 & 12t_{0}^2 & 6t_{0} & 2 & 0 & 0\\ t_{1}^5& t_{1}^4 & t_{1}^3 & t_{1}^2 & t_{1}& 1\\ 5t_{1}^4 & 4t_{1}^3 & 3t_{1}^2 & 2t_{1} & 1 & 0\\ 20t_{1}^3 & 12t_{1}^2 & 6t_{1} & 2 & 0 & 0 \end{bmatrix}\begin{bmatrix}a_{5} \\a_{4} \\a_{3} \\a_{2} \\a_{1} \\a_{0} \end{bmatrix}=TXA X= x(0)x(0)˙x(0)¨x(T)x(T)˙x(T)¨ = t055t0420t03t155t1420t13t044t0312t02t144t1312t12t033t026t0t133t126t1t022t02t122t12t010t110100100 a5a4a3a2a1a0 =TXA
Y = [ y ( 0 ) y ( 0 ) ˙ y ( 0 ) ¨ y ( T ) y ( T ) ˙ y ( T ) ¨ ] = [ t 0 5 t 0 4 t 0 3 t 0 2 t 0 1 5 t 0 4 4 t 0 3 3 t 0 2 2 t 0 1 0 20 t 0 3 12 t 0 2 6 t 0 2 0 0 t 1 5 t 1 4 t 1 3 t 1 2 t 1 1 5 t 1 4 4 t 1 3 3 t 1 2 2 t 1 1 0 20 t 1 3 12 t 1 2 6 t 1 2 0 0 ] [ a 5 b 4 b 3 b 2 b 1 b 0 ] = T X B Y=\begin{bmatrix}y(0) \\\dot{y(0)} \\\ddot{y(0)} \\y(T) \\\dot{y(T)} \\\ddot{y(T)} \end{bmatrix}=\begin{bmatrix} t_{0}^5& t_{0}^4 & t_{0}^3 & t_{0}^2 & t_{0} &1 \\ 5t_{0}^4 & 4t_{0}^3 & 3t_{0}^2 & 2t_{0} & 1 & 0\\ 20t_{0}^3 & 12t_{0}^2 & 6t_{0} & 2 & 0 & 0\\ t_{1}^5& t_{1}^4 & t_{1}^3 & t_{1}^2 & t_{1}& 1\\ 5t_{1}^4 & 4t_{1}^3 & 3t_{1}^2 & 2t_{1} & 1 & 0\\ 20t_{1}^3 & 12t_{1}^2 & 6t_{1} & 2 & 0 & 0 \end{bmatrix}\begin{bmatrix}a_{5} \\b_{4} \\b_{3} \\b_{2} \\b_{1} \\b_{0} \end{bmatrix}=TXB Y= y(0)y(0)˙y(0)¨y(T)y(T)˙y(T)¨ = t055t0420t03t155t1420t13t044t0312t02t144t1312t12t033t026t0t133t126t1t022t02t122t12t010t110100100 a5b4b3b2b1b0 =TXB
X , Y , T X,Y,T XYT已知,就可以求出 A A A B B B

衡量舒适性的物理量为跃度 J e r k Jerk Jerk
J e r k = d a d t {Jerk = \frac{da}{dt}} Jerk=dtda

J e r k Jerk Jerk的绝对值越小, a a a的变化越平缓,意味着越舒适。

find f ( t ) f(t) f(t) 使得 ∫ 0 T ( d 3 f d t 3 ) 2 d t {\normalsize \int_{0}^{T} (\frac{d^3f}{dt^3})^2dt} 0T(dt3d3f)2dt最小
subject to :
S ( 0 ) = S 0 , S ( T ) = S n S ˙ ( 0 ) = v 0 , S ˙ ( T ) = v n S ¨ ( 0 ) = a 0 , S ¨ ( T ) = a n S(0)=S_{0},S(T)=S_{n}\\ \dot S(0)=v_{0},\dot S(T)=v_{n}\\ \ddot S(0)=a_{0},\ddot S(T)=a_{n} S(0)=S0S(T)=SnS˙(0)=v0S˙(T)=vnS¨(0)=a0S¨(T)=an

显然 f ( t ) f(t) f(t)只可能是在 [ 0 , T ] [0,T] [0,T]上是有界连续函数,因为无论是无界函数,还是有界间断函数都会使 J e r k Jerk Jerk出现无穷大
f ( t ) f(t) f(t):五次多项式

化简约束:
S ( T ) − S ( 0 ) = ∫ 0 T f ˙ d t = C 0 S ˙ ( T ) − S ˙ ( 0 ) = ∫ 0 T f ¨ d t = C 1 S ¨ ( T ) − S ¨ ( 0 ) = ∫ 0 T f ( 3 ) d t = C 2 S(T)-S(0)=\int_{0}^{T} \dot fdt=C_{0}\\ \dot S(T)-\dot S(0)=\int_{0}^{T} \ddot fdt=C_{1}\\ \ddot S(T)-\ddot S(0)=\int_{0}^{T} {f}^{(3)} dt=C_{2} S(T)S(0)=0Tf˙dt=C0S˙(T)S˙(0)=0Tf¨dt=C1S¨(T)S¨(0)=0Tf(3)dt=C2

问题描述:
问题变为求 ∫ 0 T f ( 3 ) d t \int_{0}^{T} {f}^{(3)} dt 0Tf(3)dt在约束 ∫ 0 T ( f ˙ − C 0 T ) d t = 0 , ∫ 0 T ( f ¨ − C 1 T ) d t = 0 , ∫ 0 T ( f ( 3 ) − C 2 T ) d t = 0 \int_{0}^{T} (\dot f-\frac{C_{0}}{T})dt=0,\int_{0}^{T} (\ddot f-\frac{C_{1}}{T})dt=0,\int_{0}^{T} ({f}^{(3)}-\frac{C_{2}}{T})dt=0 0T(f˙TC0)dt=0,0T(f¨TC1)dt=0,0T(f(3)TC2)dt=0下的极小值

拉格朗日法:
∫ 0 T f ( 3 ) d t + λ 1 ∫ 0 T ( f ˙ − C 0 T ) d t + λ 2 ∫ 0 T ( f ¨ − C 1 T ) d t + λ 3 ∫ 0 T ( f ( 3 ) − C 2 T ) d t =   ∫ 0 T ( λ 1 f ˙ + λ 2 f ¨ + λ 3 f ( 3 ) + f ( 3 ) 2 − λ 1 C 0 T − λ 2 C 1 T − λ 3 C 2 T ) d t   = ∫ 0 T L d t \int_{0}^{T} {f}^{(3)}dt+ \lambda _{1}\int_{0}^{T} (\dot f-\frac{C_{0}}{T})dt+\lambda _{2}\int_{0}^{T} (\ddot f-\frac{C_{1}}{T})dt+\lambda _{3}\int_{0}^{T} ({f}^{(3)}-\frac{C_{2}}{T})dt\\ =\ \int_{0}^{T} (\lambda _{1}\dot f +\lambda _{2}\ddot f+\lambda _{3}{f}^{(3)} +{{f}^{(3)}}^2- \lambda _{1}\frac{C_{0}}{T} -\lambda _{2}\frac{C_{1}}{T}-\lambda _{3}\frac{C_{2}}{T})dt\ =\int_{0}^{T} Ldt 0Tf(3)dt+λ10T(f˙TC0)dt+λ20T(f¨TC1)dt+λ30T(f(3)TC2)dt= 0T(λ1f˙+λ2f¨+λ3f(3)+f(3)2λ1TC0λ2TC1λ3TC2)dt =0TLdt

用到广义 E u l e r − L a g r a r g e Euler-Lagrarge EulerLagrarge方程
∂ L ∂ f − d d t ( ∂ L ∂ f ˙ ) + d 2 d t 2 ( ∂ L ∂ f ¨ ) − d 3 d t 3 ( ∂ L ∂ f ( 3 ) ) = 0 \frac{\partial L}{\partial f} -\frac{d}{dt} (\frac{\partial L}{\partial \dot f} )+\frac{d^2}{dt^2} (\frac{\partial L}{\partial \ddot f})-\frac{d^3}{dt^3} (\frac{\partial L}{\partial {f}^{(3)}})=0 fLdtd(f˙L)+dt2d2(f¨L)dt3d3(f(3)L)=0

∂ L ∂ f = 0 , ∂ L ∂ f ˙ = λ 1 , ∂ L ∂ f ¨ = λ 2 , ∂ L ∂ f ( 3 ) = λ 3 + 2 f ( 3 ) \frac{\partial L}{\partial f} =0,\frac{\partial L}{\partial \dot f} =\lambda _{1},\frac{\partial L}{\partial \ddot f} =\lambda _{2},\frac{\partial L}{\partial {f}^{(3)} } =\lambda _{3}+2{f}^{(3)} fL=0,f˙L=λ1,f¨L=λ2,f(3)L=λ3+2f(3)代入广义 E u l e r − L a g r a r g e Euler-Lagrarge EulerLagrarge方程得:
d 3 d t 3 ( λ 3 + 2 f ( 3 ) ) = 0 \frac{d^3}{dt^3}(\lambda _{3}+2{f}^{(3)})=0 dt3d3(λ3+2f(3))=0

推导过程:
f ( 6 ) ( t ) = 0 f ( 5 ) ( t ) = a 0 f ( 4 ) ( t ) = a 0 t + a 1 f ( 3 ) ( t ) = 1 2 a 0 t 2 + a 1 t + a 2 f ( 2 ) ( t ) = 1 6 a 0 t 3 + 1 2 a 1 t 2 + a 2 t + a 3 f ( 1 ) ( t ) = 1 24 a 0 t 4 + 1 6 a 1 t 3 + 1 2 a 2 t + a 3 t + a 4 f ( t ) = 1 120 a 0 t 5 + 1 24 a 1 t 4 + 1 6 a 2 t 3 + 1 2 a 3 t 2 + a 4 t + a 5 \begin{array}{l} f^{(6)}(t)=0 \\ f^{(5)}(t)=a_{0} \\ f^{(4)}(t)=a_{0} t+a_{1} \\ f^{(3)}(t)=\frac{1}{2} a_{0} t^{2}+a_{1} t+a_{2} \\ f^{(2)}(t)=\frac{1}{6} a_{0} t^{3}+\frac{1}{2} a_{1} t^{2}+a_{2} t+a_{3} \\ f^{(1)}(t)=\frac{1}{24} a_{0} t^{4}+\frac{1}{6} a_{1} t^{3}+\frac{1}{2} a_{2} t+a_{3} t+a_{4} \\ \\ \LARGE f(t)=\frac{1}{120} a_{0} t^{5}+\frac{1}{24} a_{1} t^{4}+\frac{1}{6} a_{2} t^3+\frac{1}{2} a_{3} t^2+a_{4} t+a_{5} \end{array} f(6)(t)=0f(5)(t)=a0f(4)(t)=a0t+a1f(3)(t)=21a0t2+a1t+a2f(2)(t)=61a0t3+21a1t2+a2t+a3f(1)(t)=241a0t4+61a1t3+21a2t+a3t+a4f(t)=1201a0t5+241a1t4+61a2t3+21a3t2+a4t+a5

2.2 凸优化和非凸优化

① 自动驾驶规划目标算出一条满足约束的最优轨迹

衡量轨迹质量往往用cost function表示,代价函数越小,意味着越平滑,越舒适,当然也要满足各种约束。

指标:平滑、舒适、尽可能短
约束:轨迹连续、无碰撞、交规、车辆动力学

凸优化性质
(a) 代价函数只有一个极小值点且为最小值(凸函数)
(b) 约束空间是一块完整的、不破碎的空间(凸空间)
凸优化:求凸函数在凸空间的最小值问题

自动驾驶避障约束空间是非凸的
(a) 静态和动态避障约束空间都不是凸空间
静态避障:
在这里插入图片描述
动态避障:
在这里插入图片描述

(b) 求解非凸问题的主要思路是找非凸问题中的凸结构

非凸空间 => 离散化 => 粗解(base) => 迭代 => 最终解

启发式算法:
先随机在约束空间采样一些离散的函数值比大小,取最小的作为迭代初值。
在这里插入图片描述

2.3 直角坐标与自然坐标转换

龙格现象:高次多项式拟合可能会出现震荡,慎用高次多项式。

在这里插入图片描述
以Cartesian坐标为准

r n ⃗ \vec{r_n} rn :车的位矢
v ⃗ \vec{v} v :车的速度
a ⃗ \vec{a} a :车的加速度
k h k_h kh:车的位矢在车的轨迹上的曲率
τ h ⃗ \vec{\tau _h} τh :车的位矢在车的轨迹上的切线方向单位向量
n h ⃗ \vec{ n_h} nh :车的位矢在车的轨迹上的法线方向单位向量
r r ⃗ \vec{r_r} rr :投影位矢
S ˙ \dot S S˙:投影速率
k r k_r kr:投影位矢在道路几何上的曲率
τ r ⃗ \vec{\tau _r} τr :投影位矢在道路几何上的切线方向单位向量
n r ⃗ \vec{n _r} nr :投影位矢在道路几何上的法线方向单位向量

已知 r ⃗ h , v ⃗ h , a ⃗ h , k h , τ ⃗ h , n ⃗ h \vec{r}_{h}, \vec{v}_{h}, \vec{a}_{h}, k_{h}, \vec{\tau}_{h}, \vec{n}_{h} r h,v h,a h,kh,τ h,n h
己知 frenet 坐标系起点 ( x 0 , y 0 ) \left(x_{0}, y_{0}\right) (x0,y0)
s , s ˙ , s ¨ , l , l ′ , l ′ ′ s ˙ = d s d t l ′ = d l d s s, \dot{s}, \ddot{s}, l, l^{\prime}, l^{\prime \prime} \quad \dot{s}=\frac{d s}{d t} \quad l^{\prime}=\frac{d l}{d s} \quad s,s˙,s¨,l,l,l′′s˙=dtdsl=dsdl d s ds ds 为frenet坐标轴的弧长

主要思路
(1)找车在Frenet坐标系下的投影点在笛卡尔坐标下的坐标,记为 ( x r , y r , k r , θ r ) (x_r,y_r,k_r,\theta_r) (xr,yr,kr,θr)
(2)利用向量三角形,以及微积分求 s , s ˙ , s ¨ , l , l ′ , l ′ s,\dot s,\ddot s,l,l_{}',l_{}' s,s˙,s¨,l,l,l
核心公式 r ⃗ r + l n ⃗ r = r ⃗ h \vec r_r+l\vec n_r=\vec r_h r r+ln r=r h

7个辅助公式:
r ˙ → h = v ⃗ = ∣ v ⃗ ∣ τ ⃗ h r ˙ ⃗ r = s ˙ τ ⃗ r τ ⃗ h = k h ∣ v ⃗ ∣ n ⃗ h n ⃗ h = − k h ∣ v ⃗ ∣ τ ⃗ h τ ˙ ⃗ r = k r s ˙ n ⃗ r n ˙ → r = − k r s ˙ τ ⃗ r a ⃗ = ∣ v ˙ ⃗ ∣ τ ⃗ h + ∣ v ⃗ ∣ 2 k h n ⃗ h \begin{array}{l} \overrightarrow{\dot{r}}_{h}=\vec{v}=|\vec{v}| \vec{\tau}_{h} \\ \vec{\dot r}_{r}=\dot{s} \vec{\tau}_{r} \\ \vec{\tau}_{h}=k_{h}|\vec{v}| \vec{n}_{h} \\ \vec{n}_{h}=-k_{h}|\vec{v}| \vec{\tau}_{h} \\ \vec{\dot \tau}_{r}=k_{r} \dot{s} \vec{n}_{r} \\ \overrightarrow{\dot{n}}_{r}=-k_{r} \dot{s} \vec{\tau}_{r} \\ \vec{a}=|\vec{\dot v}| \vec{\tau}_{h}+|\vec{v}|^{2} k_{h} \vec{n}_{h} \end{array} r˙ h=v =v τ hr˙ r=s˙τ rτ h=khv n hn h=khv τ hτ˙ r=krs˙n rn˙ r=krs˙τ ra =v˙ τ h+v 2khn h
向量法详细推导见博客
s , s ˙ , s ¨ , l , l ˙ , l ¨ , l ′ , l ′ ′ s,\dot s,\ddot s,l,\dot l,\ddot l,l_{}',l_{}'' s,s˙,s¨,l,l˙,l¨,l,l′′八个变量,独立的只有6个,因为 l ˙ , l ¨ \dot l,\ddot l l˙,l¨可以由 l ′ , l ′ ′ l_{}',l_{}'' l,l′′推导过来
l ˙ = l ′ ∗ s ˙ l ¨ = d l d t = d ( l ′ s ˙ ) d t = d l ′ d t s ˙ + l ′ ⋅ s ¨ = d l ′ d s ⋅ d s d t ⋅ s ˙ + l ′ s ¨ = l ′ ′ s ˙ 2 + l ′ s ¨ \dot l= l'*\dot s\\ \\ \begin{aligned} \ddot{l}=\frac{d l}{d t}=\frac{d\left(l^{\prime} \dot{s}\right)}{d t} & =\frac{d l^{\prime}}{d t} \dot{s}+l^{\prime} \cdot \ddot{s} \\ & =\frac{d l^{\prime}}{d s} \cdot \frac{d s}{d t} \cdot \dot{s}+l^{\prime} \ddot{s} \\ & =l^{\prime \prime} \dot{s}^{2}+l^{\prime} \ddot{s} \end{aligned} l˙=ls˙l¨=dtdl=dtd(ls˙)=dtdls˙+ls¨=dsdldtdss˙+ls¨=l′′s˙2+ls¨
EM planner: s , s ˙ , s ¨ , l , l ′ , l ′ s,\dot s,\ddot s,l,l_{}',l_{}' s,s˙,s¨,l,l,l
Lattice planner: s , s ˙ , s ¨ , l , l ˙ , l ¨ s,\dot s,\ddot s,l,\dot l,\ddot l s,s˙,s¨,l,l˙,l¨

s的计算方法
主要思路:
用直线长度代替弧长,当路径点足够密集,误差可以忽略
在这里插入图片描述
这里直接给出Frenet和Cartesian互转的公式:
在这里插入图片描述
百度Apollo Frenet和Cartesian互转的代码:
modules/common/math/cartesian_frenet_conversion.h

static void cartesian_to_frenet(const double rs, const double rx,
                                  const double ry, const double rtheta,
                                  const double rkappa, const double rdkappa,
                                  const double x, const double y,
                                  const double v, const double a,
                                  const double theta, const double kappa,
                                  std::array<double, 3>* const ptr_s_condition,
                                  std::array<double, 3>* const ptr_d_condition);

static void frenet_to_cartesian(const double rs, const double rx,
                                  const double ry, const double rtheta,
                                  const double rkappa, const double rdkappa,
                                  const std::array<double, 3>& s_condition,
                                  const std::array<double, 3>& d_condition,
                                  double* const ptr_x, double* const ptr_y,
                                  double* const ptr_theta,
                                  double* const ptr_kappa, double* const ptr_v,
                                  double* const ptr_a);                                  

modules/common/math/cartesian_frenet_conversion.cpp

void CartesianFrenetConverter::cartesian_to_frenet(
    const double rs, const double rx, const double ry, const double rtheta,
    const double rkappa, const double rdkappa, const double x, const double y,
    const double v, const double a, const double theta, const double kappa,
    std::array<double, 3>* const ptr_s_condition,
    std::array<double, 3>* const ptr_d_condition) {
  const double dx = x - rx;
  const double dy = y - ry;

  const double cos_theta_r = std::cos(rtheta);
  const double sin_theta_r = std::sin(rtheta);

  const double cross_rd_nd = cos_theta_r * dy - sin_theta_r * dx;
  ptr_d_condition->at(0) =
      std::copysign(std::sqrt(dx * dx + dy * dy), cross_rd_nd);

  const double delta_theta = theta - rtheta;
  const double tan_delta_theta = std::tan(delta_theta);
  const double cos_delta_theta = std::cos(delta_theta);

  const double one_minus_kappa_r_d = 1 - rkappa * ptr_d_condition->at(0);
  ptr_d_condition->at(1) = one_minus_kappa_r_d * tan_delta_theta;

  const double kappa_r_d_prime =
      rdkappa * ptr_d_condition->at(0) + rkappa * ptr_d_condition->at(1);

  ptr_d_condition->at(2) =
      -kappa_r_d_prime * tan_delta_theta +
      one_minus_kappa_r_d / cos_delta_theta / cos_delta_theta *
          (kappa * one_minus_kappa_r_d / cos_delta_theta - rkappa);

  ptr_s_condition->at(0) = rs;

  ptr_s_condition->at(1) = v * cos_delta_theta / one_minus_kappa_r_d;

  const double delta_theta_prime =
      one_minus_kappa_r_d / cos_delta_theta * kappa - rkappa;
  ptr_s_condition->at(2) =
      (a * cos_delta_theta -
       ptr_s_condition->at(1) * ptr_s_condition->at(1) *
           (ptr_d_condition->at(1) * delta_theta_prime - kappa_r_d_prime)) /
      one_minus_kappa_r_d;
}

void CartesianFrenetConverter::frenet_to_cartesian(
    const double rs, const double rx, const double ry, const double rtheta,
    const double rkappa, const double rdkappa,
    const std::array<double, 3>& s_condition,
    const std::array<double, 3>& d_condition, double* const ptr_x,
    double* const ptr_y, double* const ptr_theta, double* const ptr_kappa,
    double* const ptr_v, double* const ptr_a) {
  ACHECK(std::abs(rs - s_condition[0]) < 1.0e-6)
      << "The reference point s and s_condition[0] don't match";

  const double cos_theta_r = std::cos(rtheta);
  const double sin_theta_r = std::sin(rtheta);

  *ptr_x = rx - sin_theta_r * d_condition[0];
  *ptr_y = ry + cos_theta_r * d_condition[0];

  const double one_minus_kappa_r_d = 1 - rkappa * d_condition[0];

  const double tan_delta_theta = d_condition[1] / one_minus_kappa_r_d;
  const double delta_theta = std::atan2(d_condition[1], one_minus_kappa_r_d);
  const double cos_delta_theta = std::cos(delta_theta);

  *ptr_theta = NormalizeAngle(delta_theta + rtheta);

  const double kappa_r_d_prime =
      rdkappa * d_condition[0] + rkappa * d_condition[1];
  *ptr_kappa = (((d_condition[2] + kappa_r_d_prime * tan_delta_theta) *
                 cos_delta_theta * cos_delta_theta) /
                    (one_minus_kappa_r_d) +
                rkappa) *
               cos_delta_theta / (one_minus_kappa_r_d);

  const double d_dot = d_condition[1] * s_condition[1];
  *ptr_v = std::sqrt(one_minus_kappa_r_d * one_minus_kappa_r_d *
                         s_condition[1] * s_condition[1] +
                     d_dot * d_dot);

  const double delta_theta_prime =
      one_minus_kappa_r_d / cos_delta_theta * (*ptr_kappa) - rkappa;

  *ptr_a = s_condition[2] * one_minus_kappa_r_d / cos_delta_theta +
           s_condition[1] * s_condition[1] / cos_delta_theta *
               (d_condition[1] * delta_theta_prime - kappa_r_d_prime);
}

3 参考线reference_line

3.0 前言

决策规划流程:
① 全局规划生成一条参考线
② 静态障碍物投影到以参考线为坐标轴的Frenet坐标系上
③ 决策算法对障碍物做决策(往左绕,往右绕,忽略)开辟最优凸空间
④ 规划算法在凸空间搜素出最优的路径
⑤ 后处理,在规划轨迹中选一个点,坐标转成Cartesian,输出给控制跟踪

在这里插入图片描述
需要参考线的原因:
(1)参考线是解决方案,能够解决导航路径过长,不平滑的问题
(2)过长的路径不利于坐标转换(找匹配点,计算s的长度)
(3)过长的路径,障碍物投影可能不唯一
(4)路径不平滑

在这里插入图片描述
在每个规划周期内,找到车在导航路径上的投影点,以投影点为坐标原点,往后取30m,往前取150m范围内的点,做平滑,平滑后的点的集合称为参考线。

3.1 参考线平滑算法

参考线的三个代价函数:
(1)平滑代价
在这里插入图片描述
∣ P 1 P 3 ⃗ ∣ |\vec {P_1P_3}| P1P3 衡量平滑与不平滑的标准。 ∣ P 1 P 3 ⃗ ∣ |\vec {P_1P_3}| P1P3 越小,越平滑。

(2)紧凑型代价
在这里插入图片描述
长度尽可能均匀、紧凑
在这里插入图片描述

(3)相似代价
在这里插入图片描述
∣ P 1 P 1 r ⃗ ∣ + ∣ P 2 P 2 r ⃗ ∣ + ∣ P 3 P 3 r ⃗ ∣ |\vec {P_1P_{1r}}|+|\vec {P_2P_{2r}}|+|\vec {P_3P_{3r}}| P1P1r +P2P2r +P3P3r 越小,越接近原路径几何。

总结:
x 1 , x 2 , x 3 x_1,x_2,x_3 x1,x2,x3为优化后的路径点。希望cost function越小越好
在这里插入图片描述
本质是二次规划问题
1 2 X T H X + f T X = X T ( H 2 ) X + f T X \begin{array}{l} \frac{1}{2} X^{T} H X+f^{T} X=X^{T} (\frac{H}{2} )X+f^{T} X \end{array} 21XTHX+fTX=XT(2H)X+fTX

H = 2 ( w smooth  A 1 T A 1 + w length  A 2 T A 2 + w ref  A 3 T A 3 ) , f T = w ref  h T H=2\left(w_{\text {smooth }} A_{1}^{T} A_{1}+w_{\text {length }} A_{2}^{T} A_{2}+w_{\text {ref }} A_{3}^{T} A_{3}\right), f^{T}=w_{\text {ref }} h^{T} H=2(wsmooth A1TA1+wlength A2TA2+wref A3TA3),fT=wref hT

约束:
x = ( x 1 , y 1 , . . . , x n , y n ) x = (x_1,y_1,...,x_n,y_n) x=(x1,y1,...,xn,yn)
x r e f = ( x 1 r , y 1 r , . . . , x n r , y n r ) x_{ref}=(x_{1r},y_{1r},...,x_{nr},y_{nr}) xref=(x1r,y1r,...,xnr,ynr)
x x x x r e f x_{ref} xref不要太远

在这里插入图片描述
曲率约束:非线性约束(一般与车的最大侧向加速度有关)
在这里插入图片描述

3.2 Fem smooth平滑

在Apollo中叫 Fem smoother
优势:优化变量少
缺点:无法保证曲率是连续的,添加曲率约束求解麻烦
在这里插入图片描述
主要步骤
(1)找匹配点
(2)采样(前150m,后30m)
(3)Fem smooth 平滑
目标:快,节省计算量(参考线是决策规划的基础和前提,因此必须要快)

怎么快?
(1)减少规划频率,规划算法会100ms执行一次,控制算法每10ms执行一次
(2)充分利用上一个规划周期的结果

一般做法:每个周期做遍历,但是这样速度慢,导航路径可能很长,遍历很费时
在这里插入图片描述
改进:
如何充分利用上一个规划周期的结果
在这里插入图片描述
以上个周期的match point为起点做遍历,一旦有 l i + 1 > l i l_{i+1}>l_{i} li+1>li,立即退出遍历。 l i l_i li对应的点作为本周期的匹配点。
判断遍历的方向:
在这里插入图片描述
a ) 向前遍历: d → ⋅ τ ⃗ > 0 b ) 向后遍历: d → ⋅ τ ⃗ < 0 c ) 本周期的匹配点 = 上周期的匹配点: ∣ d → ⋅ τ ⃗ ∣ < 1 e − 3 a) 向前遍历: \overrightarrow{\mathrm{d}} \cdot \vec{\tau}>0 \\ b) 向后遍历: \overrightarrow{\mathrm{d}} \cdot \vec{\tau}<0 \\ c)本周期的匹配点=上周期的匹配点: |\overrightarrow{\mathrm{d}} \cdot \vec{\tau}|<1e-3 a)向前遍历:d τ >0b)向后遍历:d τ <0c)本周期的匹配点=上周期的匹配点:d τ <1e3
本方法可以大大加速找匹配点
带来的问题:只适用于上个匹配点结果附近只有一个极小值点
在这里插入图片描述
一般情况不会有这种问题,规划周期100ms,即使车速50m/s,车也只走了五米。五米的道路不会像上图一样扭曲的道路几何,在上一个规划周期的匹配点一般只有一个极小值。
改进:
增加increase变量记录l连续增加的次数
在这里插入图片描述
在这里插入图片描述

在Github算法里
(1)遍历
第一次运行遍历
在这里插入图片描述
不是第一次运行
在这里插入图片描述
(2)点不够的情况
在这里插入图片描述
(3)参考线拼接
在这里插入图片描述
如何拼接:
在这里插入图片描述
在这里插入图片描述
注意:
Fem smoother至少需要3个点
在这里插入图片描述

3.3 避障
3.3.1 规划起点

在这里插入图片描述
确定规划起点:
错误做法:定位得到的host_x,host_y投影到referenceline,得到SL坐标(0, l 0 l_0 l0),以此点为路径规划的起点
正确做法:判断当前定位和上一个周期规划的结果是否误差太大
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以( s 0 , l 0 s_0,l_0 s0,l0)作为规划的起点
为什么不能从定位的点作为规划起点:考虑到控制不完美,导致帧与帧之间的曲线是跳变的。

判断定位与轨迹的误差不太大的话,用上个轨迹的T+100ms的点作为本周期的规划起点,若误差较大,用车辆运动学进行外推

3.3.2 轨迹拼接

结合上一节,本人觉得理解老王对于规划起点的描述有点模糊,故拜读了下面这篇大佬写的博客,对于轨迹拼接思路一下子就通了。

参考博客:百度Apollo规划算法——轨迹拼接
在apollo的规划算法中,在每一帧规划开始时会调用一个轨迹拼接函数,返回一段拼接轨迹点集,并告诉我们是否重规划以及重规划的原因。

轨迹拼接:在每一帧轨迹规划的开始,我们需要确定规划的起始点 p 0 = ( x , y , v , a , θ , k , t ) p_0=(x,y,v,a,\theta,k,t) p0=(x,y,v,a,θ,k,t),起始点给定了规划的初始状态,然后结合当前帧的环境信息并调用规划算法规划生成当前帧轨迹。

方案1
根据ADC(Autonomous Driving Car)实际位置状态信息,通过车辆运动学推导100ms后的位置状态信息,作为规划起始点状态,在Apollo中,这一方案叫做重规划Replan。
方案2:考虑的是连续帧之间轨迹的平滑性和连续性
根据当前帧时间戳以及ADC实际位置信息,在上一帧轨迹中寻找匹配点,将上一帧轨迹中匹配点往后100ms所对应的轨迹点作为当前帧的规划起始状态点,待当前帧规划生成轨迹后,再和上一帧轨迹中所选择的规划起始点前一段距离的轨迹点进行拼接,形成一条完整的车辆运动轨迹(思路一下就清晰了,牛逼!),发送给下游控制模块。

理论上,如果控制跟踪和定位完美,不会出现任何误差,则完全可以使用方案1选择规划起始点,但是,由于定位误差和控制误差/滞后的原因,会导致每一规划时刻ADC位置大概率的偏离上一帧所规划的轨迹点,如果此时仍采用方案1,会导致当前帧所规划轨迹和上一帧规划轨迹的不平滑和不连续,从而导致控制的抖动,也可能会引起ADC行驶轨迹发散,跟踪误差越来越大,偏离设定参考线。而方案2可以保证ADC附近一段范围内前后两帧轨迹的平滑性,从而不断引导ADC沿着期望轨迹行驶。

3.3.3 结合Apollo代码理解轨迹拼接的细节

在这里插入图片描述
选择方案1的情况:

  1. 上一帧不存在轨迹(一般是起步或上一帧规划失败的情况)
  2. 没有使能方案2进行轨迹拼接
  3. 没有处在自动驾驶模式
  4. 上一帧存在轨迹但是没有轨迹点
  5. 当前时间相对于上一帧的相对时间戳小于上一帧起点相对时间戳
  6. 时间匹配点超出上一帧轨迹点的终点实际范围
  7. 匹配点处不存在匹配的path_point
  8. ADC实际位置和匹配点横纵向偏差超过给定阈值

方案1生成轨迹拼接点主要有两种情况:
起步阶段:由于起步阶段属于规划算法执行的第一帧,且速度、加速度值很小,可以直接使用当前状态点作为规划的起始状态点
非起步阶段:则根据当前ADC状态点结合运动学模型外推T时间之后的状态点作为本帧规划起始点

[ x t + 1 y t + 1 ψ t + 1 ] = [ x t y t ψ t ] + [ cos ⁡ ( ψ ) sin ⁡ ( ψ ) tan ⁡ ( δ f ) l ] ⋅ v \left[\begin{array}{l} x_{t+1} \\ y_{t+1} \\ \psi_{t+1} \end{array}\right]=\left[\begin{array}{l} x_{t} \\ y_{t} \\ \psi_{t} \end{array}\right]+\left[\begin{array}{c} \cos (\psi) \\ \sin (\psi) \\ \frac{\tan \left(\delta_{f}\right)}{l} \end{array}\right] \cdot v xt+1yt+1ψt+1 = xtytψt + cos(ψ)sin(ψ)ltan(δf) v

方案二(以上情况均不满足时):
该方案同时考虑了时间匹配和位置匹配
时间匹配:根据当前时间戳和上一帧轨迹起点的时间戳对比,计算当前时间ADC应该到达的时间匹配点(图中t_pos)及该匹配点在上一帧轨迹中对应的索引值t_index,若t_pos不存在路径点,则选择方案1。
位置匹配:根据ADC当前位置点在上一帧轨迹中寻找最近的匹配点(图中p_pos)及该匹配点在上一帧轨迹中对应的索引值p_index,并比较实际位置点和匹配点之间的横纵向位置偏差,若任一偏差超过给定阈值,则选择方案1。

若以上判断均通过,根据 (当前时刻的绝对时间 - 上一时刻轨迹的初始时间 + planning_cycle_time) 得到forward_rel_time,选取时间匹配索引和位置匹配索引中的较小索引作为匹配点索引值matched_index,在上一帧的轨迹上截取出matched_index往前n个点开始,至forward_rel_time的一段轨迹,作为stitching_trajectory。最后,遍历这段轨迹,对其relative_time和s进行赋值。最终,使用stitching_trajectory的最后一个点,即图中的 p 0 p_0 p0,作为当前帧轨迹规划的起始点。

选择当前时间+planning_cycle_time的时间对应的上一帧轨迹的位置点作为本帧规划起点的原因:当本帧规划需要时间planning_cycle_time,将生成轨迹送到规划模块时对应的实际时间理论上就是当前时间+planning_cycle_time。

TrajectoryStitcher::ComputeStitchingTrajectory

/* Planning from current vehicle state if:
1. the auto-driving mode is off
(or) 2. we don't have the trajectory from last planning cycle
(or) 3. the position deviation from actual and target is too high
*/
std::vector<TrajectoryPoint> TrajectoryStitcher::ComputeStitchingTrajectory(
const VehicleState& vehicle_state, const double current_timestamp,
const double planning_cycle_time, const size_t preserved_points_num,
const bool replan_by_offset, const PublishableTrajectory* prev_trajectory,
std::string* replan_reason) {
    //a.是否使能轨迹拼接
    if (!FLAGS_enable_trajectory_stitcher) {
        *replan_reason = "stitch is disabled by gflag.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    //b.上一帧是否生成轨迹
    if (!prev_trajectory) {
        *replan_reason = "replan for no previous trajectory.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    //c.是否处于自动驾驶模式
    if (vehicle_state.driving_mode() != canbus::Chassis::COMPLETE_AUTO_DRIVE) {
        *replan_reason = "replan for manual mode.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    //d.上一帧是否存在轨迹点 
    size_t prev_trajectory_size = prev_trajectory->NumOfPoints();
    if (prev_trajectory_size == 0) {
        *replan_reason = "replan for empty previous trajectory.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    const double veh_rel_time = current_timestamp - prev_trajectory->header_time();
    size_t time_matched_index = prev_trajectory->QueryLowerBoundPoint(veh_rel_time);

    //e.判断当前时间相对于上一帧的相对时间戳是否小于上一帧起点相对时间戳
    if (time_matched_index == 0 &&
        veh_rel_time < prev_trajectory->StartPoint().relative_time()) {
        *replan_reason =
            "replan for current time smaller than the previous trajectory's first "
            "time.";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }
    
    //f.判断时间匹配点是否超出上一帧轨迹点范围
    if (time_matched_index + 1 >= prev_trajectory_size) {
        *replan_reason =
            "replan for current time beyond the previous trajectory's last time";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    auto time_matched_point = prev_trajectory->TrajectoryPointAt(
    static_cast<uint32_t>(time_matched_index));

    //g.判断时间匹配点处是否存在path_point
    if (!time_matched_point.has_path_point()) {
        *replan_reason = "replan for previous trajectory missed path point";
        return ComputeReinitStitchingTrajectory(planning_cycle_time, vehicle_state);
    }

    size_t position_matched_index = prev_trajectory->QueryNearestPointWithBuffer(
    {vehicle_state.x(), vehicle_state.y()}, 1.0e-6);

    //计算实际位置点和匹配点的横纵向偏差
    auto frenet_sd = ComputePositionProjection(
    vehicle_state.x(), vehicle_state.y(),
    prev_trajectory->TrajectoryPointAt(
    static_cast<uint32_t>(position_matched_index)));

    //h.判断横纵向偏差
    if (replan_by_offset) {
        auto lon_diff = time_matched_point.path_point().s() - frenet_sd.first;
        auto lat_diff = frenet_sd.second;
        //h.1:横向偏差不满足条件
        if (std::fabs(lat_diff) > FLAGS_replan_lateral_distance_threshold) {
            const std::string msg = absl::StrCat(
            "the distance between matched point and actual position is too "
            "large. Replan is triggered. lat_diff = ",
            lat_diff);
            *replan_reason = msg;
            return ComputeReinitStitchingTrajectory(planning_cycle_time,
            vehicle_state);
    	}
        //h.2:纵向偏差不满足条件
        if (std::fabs(lon_diff) > FLAGS_replan_longitudinal_distance_threshold) {
            const std::string msg = absl::StrCat(
            "the distance between matched point and actual position is too "
            "large. Replan is triggered. lon_diff = ",
            lon_diff);
            *replan_reason = msg;
            return ComputeReinitStitchingTrajectory(planning_cycle_time,
            vehicle_state);
    	}
    } else {
        ADEBUG << "replan according to certain amount of lat and lon offset is "
        "disabled";
    }

    //计算当前时刻后T时刻的时间,并计算其在上一帧轨迹中对应的索引值
    double forward_rel_time = veh_rel_time + planning_cycle_time;
    size_t forward_time_index =
    prev_trajectory->QueryLowerBoundPoint(forward_rel_time);

    ADEBUG << "Position matched index:\t" << position_matched_index;
    ADEBUG << "Time matched index:\t" << time_matched_index;

    //选择时间匹配索引和位置匹配索引中的较小索引作为匹配点索引
    auto matched_index = std::min(time_matched_index, position_matched_index);

    //构建拼接轨迹,<匹配索引点前n个点,当前时刻后的T时刻所对应的匹配点>
    std::vector<TrajectoryPoint> stitching_trajectory(
    prev_trajectory->begin() +
    std::max(0, static_cast<int>(matched_index - preserved_points_num)),
    prev_trajectory->begin() + forward_time_index + 1);

    const double zero_s = stitching_trajectory.back().path_point().s();
    for (auto& tp : stitching_trajectory) {
        if (!tp.has_path_point()) {
            *replan_reason = "replan for previous trajectory missed path point";
            return ComputeReinitStitchingTrajectory(planning_cycle_time,
            vehicle_state);
        }
        //适配时间和s值
        tp.set_relative_time(tp.relative_time() + prev_trajectory->header_time() -
        current_timestamp);
        tp.mutable_path_point()->set_s(tp.path_point().s() - zero_s);
    }
    return stitching_trajectory;
}
3.4 避障

避障问题是非凸问题,存在多个极小值点,要怎样找到最终解?找粗解

3.4.1 避障流程

避障流程:
① 在离散空间上求最优路径,此最优路径开辟一个凸空间,在此凸空间上做二次规划,离散空间的最优路径称为粗解,粗解开辟凸空间,在这个凸空间上开辟最优解。
② 在离散空间上找到粗解:DP;在凸空间上优化最终解:QP
在这里插入图片描述
在这里插入图片描述

连接两点的曲线:五次多项式
l = f ( s ) = a 0 + a 1 s + a 2 s 2 + . . . + a 5 s 5 l = f(s)=a_0+a_1s+a_2s^2+...+a_5s^5 l=f(s)=a0+a1s+a2s2+...+a5s5
在这里插入图片描述

3.4.2 代价函数

代价函数:评价路径的优劣
在这里插入图片描述
① 平滑代价 f ( ) f() f()
越像直线越平滑,两点之间直线最短,期望 ∫ ( 1 + f ′ ( x ) 2 ) \int \sqrt{\left(1+f^{\prime}(x)^{2}\right)} (1+f(x)2) 最小,等价于 ∫ ( f ′ ( x ) 2 ) \int \sqrt{\left(f^{\prime}(x)^{2}\right)} (f(x)2) 最小,即 ∑ f ′ ( s i ) 2 \sum f^{\prime}\left(s_{i}\right)^{2} f(si)2最小
② 障碍物距离代价 g ( ) g() g()
在这里插入图片描述
③ 参考线距离代价 l ( ) l() l()

代价函数
在这里插入图片描述

图的最短问题
① 每个路径都有对应的cost,问题变成了找图最优问题:A*,Dijstra
②EM planner用动态规划解决了这类问题

控制接口:
规划发出的轨迹信息包含 x , y , θ , k , v , a , t x,y,\theta,k,v,a,t x,y,θ,k,v,a,t,时间为绝对时间。控制根据当前控制周期的时间搜索轨迹

3.5 自动驾驶之轻决策与重决策
3.5.1 二次规划

求解使二次型 1 2 x T H x + f T x \frac{1}{2}x^THx+f^Tx 21xTHx+fTx值最小的x,并且满足约束 A x ≤ u b Ax≤ub Axub

无需在意二次规划的约束形式( l b ≤ u b , a ≤ b , A x ≤ b lb≤ub,a≤b,Ax≤b lbubabAxb
在这里插入图片描述
二次规划要求解空间是凸的,而动态规划(决策)开辟了凸空间。
在这里插入图片描述

3.5.2 轻决策与重决策

决策算法:轻决策(基于代价函数)和重决策(基于人给定的规则)
重决策

在这里插入图片描述
优点:
(1)计算量小
(2)在感知不强的情况下仍然能做决策(融合了人的智慧)
缺点:
(1)场景多无法覆盖
(2)人给出的决策所开辟的凸空间未必满足约束
在这里插入图片描述
if-else条件语句,不利于最优控制问题的求解。

轻决策

轻决策:无先验规则,空间离散化,设计cost function,动态规划算法求解离散空间的最优路径,该最优路径开辟凸空间。
在这里插入图片描述
优点:
(1)无人为规则,可以处理复杂场景
(2)有粗解,通过设计代价函数,可以使粗解“满足”硬约束(碰撞、最小曲率),这样使二次规划求解成功的机率大大增加(因为粗解在凸空间内部,所以该凸空间的“扭曲”程度至少有粗解兜底)大大缓解了基于人为规则的决策所造成的凸空间扭曲情况
缺点:
(1)复杂场景计算量很大
(2)依赖预测
(3)对感知,定位要求高
(4)代价函数设计 / 最优解未必符合人的驾驶习惯

L2+ 高速L3 => 重决策
L4 => 轻决策
轻决策和重决策的融合(博弈论)

3.5.3 二次规划算法

在这里插入图片描述
l m i n 1 , l m i n 2 , . . . , l m a x 1 . l m a x 2 , . . . 构成凸空间 l_{min1},l_{min2},...,l_{max1}.l_{max2},...构成凸空间 lmin1,lmin2,...,lmax1.lmax2,...构成凸空间
二次规划的求解空间就在此凸空间中搜索
在这里插入图片描述
Apollo 3.5/5.0新增,f(s)尽可能在凸空间的中央
分段加加速度优化法
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
设有 l 1 , l 1 ′ , l 1 ′ ′ , . . . , l n , l n ′ , l n ′ ′ l_1,l_1^{'},l_1^{''},...,l_n,l_n^{'},l_n^{''} l1,l1,l1′′,...,ln,ln,ln′′需要优化
则分段加加速度约束为
在这里插入图片描述
记为 A e q x = b e q A_{eq}x=b_{eq} Aeqx=beq等式约束

在这里插入图片描述
这样做并不准确
在这里插入图片描述
在这里插入图片描述
d 1 d_1 d1:汽车质心到车头距离
d 2 d_2 d2:汽车质心到车尾距离
w w w:汽车宽度
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
记为 A x ≤ b Ax≤b Axb
在这里插入图片描述
求解出 l 1 , l 1 ′ , l 1 ′ ′ , . . . , l n , l n ′ , l n ′ ′ l_1,l_1^{'},l_1^{''},...,l_n,l_n^{'},l_n^{''} l1,l1,l1′′,...,ln,ln,ln′′ s 1 , s 2 , . . . , s n s_1,s_2,...,s_n s1,s2,...,sn结合即得到二次规划下的最优路径,再转化为Cartesian坐标,路径规划完成。

3.5.4 二次规划崩溃

靠近障碍物时,二次规划崩溃
在这里插入图片描述
在这里插入图片描述
为什么在无避障时不会崩溃?
在这里插入图片描述
为什么规划的路径会贴着边界?
在这里插入图片描述
因为二次规划的性质决定,带约束的二次规划最小值只会在极小值点或边界点取得
在这里插入图片描述
改善二次规划崩溃的方法
① 规划起点不管了,障碍物放大一点做安全缓冲
在这里插入图片描述
② 改极小值点的位置
在这里插入图片描述
c e n t r e l i n e = 1 2 ( l m i n + l m a x ) centre_{}line=\frac{1}{2}(l_{min}+l_{max}) centreline=21(lmin+lmax)
优点:几何稳定
缺点: w c e n t r e w_{centre} wcentre调小不起明显作用,调大了路径不平滑。
在这里插入图片描述在这里插入图片描述
优点:dp曲线平滑相对好做
缺点: d p p a t h dp_{path} dppath几何不稳定

dp_path每一帧之间的几何形状都会有巨大变化,若二次规划以dp_path为centre line,qp_path也会震荡。相反, c e n t r e l i n e = 1 2 ( l m i n + l m a x ) centre_{}line=\frac{1}{2}(l_{min}+l_{max}) centreline=21(lmin+lmax)就很稳定
在这里插入图片描述

3.5.5 车控制不稳,抖动剧烈

根源:车规划的路径会天然往边界靠拢的趋势
在这里插入图片描述
车在边界上当方唐镜,左右横跳。
解决办法:
加不允许反复横跳的约束
在这里插入图片描述
新的问题:约束越多,求解越慢
(1)搜索空间增大,需要对更多的可能性进行搜索和验证
(2)约束之间的冲突,需要进行额外的处理来解决这些冲突
(3)优化目标的复杂性,约束条件的增加可能会导致优化目标的复杂性增加

解决:削二次规划的规模,由60 => 20,二次规划求解完毕后再进行插值增密。

在这里插入图片描述
在这里插入图片描述

3.5.6 决策“朝令夕改”

一会决策向右绕行,一会决策向左绕行
在这里插入图片描述
Apollo方法:打标签
这一帧:只对无标签的obs做动态规则决策,若障碍物已经有标签,直接使用标签的决策
在这里插入图片描述

3.5.7 速度规划对路径规划的影响

Path只处理静态障碍物,有问题
这种情况无论速度规划怎么规划,都会碰撞(除非倒车)
在这里插入图片描述
已知上一帧的速度规划为10m/s匀速,上一帧的path为直线
在这里插入图片描述
路径规划要拿上一帧的轨迹去判断与动态障碍物的交互
在这里插入图片描述
EM planner是SL planning与ST planning反复迭代的过程

上一帧的SL,ST => 当前SL => 当前ST => 下一帧SL

4 SL、ST迭代优化

4.1 ST图、预测

已有cartesian的path,作速度规划
在这里插入图片描述
ST图画法
在这里插入图片描述
在这里插入图片描述

4.2 SL、ST迭代求解

在这里插入图片描述
当前帧规划端
在这里插入图片描述
在这里插入图片描述
当前帧的规划结果是下一帧的上一次的规划结果
在这里插入图片描述
在这里插入图片描述
SL、ST迭代过程
上一帧的trajectory + 当前帧的预测 => 当前帧SL的虚拟障碍物 => 当前帧SL(几何受影响)=> 当前帧ST => 改变当前帧ST => 当前帧轨迹trajectory改变

下一帧拿当前帧的trajectory + 下一帧的预测 => 下一帧SL => 下一帧ST

EM planner核心思想
① 将SLT三维规划问题降维,分解成两个二维的SL、ST规划问题大大降低了规划难度
② 上一帧的trajectory优化当前帧的SL、SL优化ST,不断迭代

4.3 SL与ST迭代

规划的基本工具:ST图
ST图依赖预测(预测、博弈、感知最难)
预测模型:恒定 v ⃗ \vec v v 或者恒定 a ⃗ \vec a a 模型(简化问题)
在这里插入图片描述
SL、ST迭代问题

Apollo 1.5 EM planner 引入SL,ST解耦规划,凸空间,先决策后规划。在一些复杂工况以及强算力的这个场景下,SL和ST分开优化求解是工业界最广泛最流行的方法。
Apollo 2.5 加入了lattice planner
Apollo 3.5 大幅修改EM planner,变成了public road planner(取消了SL,ST迭代机制,SL只管静态障碍物,ST只管动态障碍物,加入scenario模块)
Apollo 5.0 再次大幅修改public road planner,SL的dp被取消
Apollo 6.0~7.0 改动不大

取消了SL,ST迭代机制:

减轻ST对SL的干扰
因为车的纵向变化能力高于横向,导致动态障碍物车的速度变化剧烈程度远高于路径,预测难以测准,预测不准导致ST图剧烈变化=>速度规划结果剧烈变化
若ST影响SL,会导致SL规划容易不稳定,朝令夕改

车百公里加速:4-5秒 汽油车:5-7秒
百公里刹停距离:32-45m不等
证明汽车在一个非常短的时间、距离内,纵向的速度可以发生剧烈的变化。变化能力远高于横向的。
在这里插入图片描述
SL只管静态,ST只管动态,是一种兼顾灵活性和稳定性的一种做法

有没有一种方法既能保证路径稳定,又能保证速度稳定,还能应对这个剧烈环境(动态障碍物速度)的剧烈变化,做出相应的完美策略?一般没有。

这种方法SL还是会影响ST,ST不影响SL,因为SL会生成一个路径,路径的几何形状会影响到动态障碍物的交互。所以SL影响ST,ST不影响SL。

有两种场景ST需要影响SL:
① 上一帧的host trajectory与obs trajectory在纵向s有交互的区域内,obs所走过的空间仍然是host不能去的。
在这里插入图片描述
在这里插入图片描述
② 纵向有相交,相向而行
在这里插入图片描述
在这里插入图片描述
下一帧
在这里插入图片描述

特殊情况:
在这里插入图片描述
同向而行,动态障碍物很快的方向向前行驶,主车更快,Apollo认为这种情况过于危险,通过变道解决。


百度Apollo EM planner决策规划算法到这里,理论结束。不正之处望读者指教

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1499967.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

各大厂商常用的弱口令集合

Oms呼叫中心 KXTsoft2010 Glodon控制台 admin TRENDnet趋势网络摄像头 admin/admin MOBOTIX-视频监控 admin/meinsm 思科Cisco 没有原始密码, 第一次登录时需要创建 DRS admin/1234 Honeywell admin/1234 安迅士Axis root/pass, 新安迅士摄像头在用户第一登录时要求创建…

Winform窗体随着屏幕的DPI缩放,会引起窗体变形及字体变形,superTabControl标签字体大小不匹配

一、前言 superTabControl做的浏览器标签(cefsharp)在缩放比例(125%,150%时字体不协调) 物联网浏览器,定制浏览器,多媒体浏览器(支持H264)参考栏目文章即可 二、配置参数 app.manifest参数 dpiAware =true <application xmlns="urn:schemas-microsoft-c…

保持自律,改变形象,认真对待自己

不知道一年365天里究竟有多少个节日&#xff0c;昨天网络上刚过了“女生节”&#xff0c;今天又来了“三八妇女节”。笔者从来都是女权支持者&#xff0c;但也主张切勿支持过了头而形成“女尊男卑”&#xff0c;认为应当遵循“顺其自然”这一规律为好。 有鉴于此&#xff0c;本…

LORA: LOW-RANK ADAPTATION OF LARGE LAN-GUAGE MODELS

TOC 1 前言2 方法2.1 LOW-RANK-PARAMETRIZED UPDATE MATRICES 1 前言 1) 提出背景 大模型时代&#xff0c;通常参数都是上亿级别的&#xff0c;若对于每个具体任务都要去对大模型进行全局微调&#xff0c;那么算力和资源的浪费是巨大的。 根据流形学习思想&#xff0c;对于数…

基于SSM的房客源信息管理系统设计与实现

目 录 摘 要 I Abstract II 引 言 1 1 相关技术 3 1.1 SSM框架 3 1.2 Vue框架 3 1.3 ECharts 3 1.4 JQuery技术 3 1.5 本章小结 4 2系统分析 5 2.1 需求分析 5 2.2 非功能需求 8 2.3 本章小节 8 3 系统设计 9 3.1 系统总体设计 9 3.1.1 系统体系结构 9 3.1.2 系统目录结构 9 3…

高效办公-浏览器基本操作

日常我们使用电脑&#xff0c;其实很大部分是用于网络功能&#xff0c;这里面除了客户端程序剩余的就是通过我们的浏览器获取信息或者使用业务系统了&#xff0c;这里就简单学习下浏览器基本常识与操作。 一、浏览器是什么&#xff1f; 白话讲浏览器就是一个软件&#xff0c;我…

Docker安装Redis (全网最详细教程!!!)

一、Redis简介 二、简易版本启动&#xff08;学习版&#xff09; 1、一条命令直接搞定 2、docker ps 命令&#xff0c;查看本机docker运行的容器 3、docker logs 查看日志 4、测试连接 5、优缺点 三、生产版本启动 四、Docker 停止、删除、重启、启动容器 一、Redis简介…

mysql的语法学习总结3(一些常见的问题)

执行后&#xff0c;MySQL 会重新加载授权表并更新权限。 FLUSH PRIVILEGES; 怎么检查自己的电脑端口3306有没有被占用&#xff1f; ESTABLISHED表示被占用&#xff0c;LISTENING表示端口正在被监听&#xff0c;22696是占用该端口的进程的PID&#xff08;进程标识符&#xff0…

手持气象站的优势

【TH-SQ5】手持气象站作为一种便携式的气象监测设备&#xff0c;具有许多显著的优势&#xff0c;主要体现在以下几个方面&#xff1a; 便携性&#xff1a;手持气象站设计精巧&#xff0c;重量轻&#xff0c;易于携带&#xff0c;这使得用户能够轻松地在不同地点进行气象观测&a…

常见数据类型

目录 数据类型 字符串 char nchar varchar varchar2 nvarchar 数字 number integer binary_float binary_double float 日期 date timestamp 大文本数据 大对象数据 Oracle从入门到总裁:https://blog.csdn.net/weixin_67859959/article/details/135209645 数…

通俗深入的理解Sora的架构原理

作者公众号 大数据与AI杂谈 &#xff08;TalkCheap&#xff09;&#xff0c;转载请标明出处 开始之前&#xff0c;先解释一下为什么深入和通俗这两个看似自相矛盾的词可以并列在这里。因为后续的一些文章可能也是类似的思路&#xff0c;所以先简单做一下文章定位的说明。要看正…

it-tools工具箱

it-tools 是一个在线工具集合&#xff0c;包含各种实用的开发工具、网络工具、图片视频工具、数学工具等 github地址&#xff1a;https://github.com/CorentinTh/it-tools 部署 docker run -d --name it-tools --restart unless-stopped -p 8080:80 corentinth/it-tools:lat…

ConGMC

employ I I I(A, B) to represent mutual information Z u v f u → v ( Z u ) Z_{uv}f_{u\to v}(Z_u) Zuv​fu→v​(Zu​) 辅助信息 作者未提供代码

STM32 学习10 PWM输出

STM32 学习10 PWM输出 一、PWM简介1. PWM的概念2. PWM的工作原理3. PWM 常用的应用场景 二、一些概念1. 频率2. 占空比 三、STM32F1 PWM介绍1. 定时器与寄存器&#xff08;1&#xff09;**自动重装载寄存器&#xff08;ARR&#xff09;**&#xff1a;&#xff08;2&#xff09;…

leetcode刷题(2):链表

文章目录 1. 两数相加1.1 解题思路1. 2 c 实现 2 删除排序链表中的重复元素 ||2.1 解题思路2.2 c 实现 3 旋转链表3.1 解题思路3.2 c 实现 4 剑指 Offer 06: 从尾到头打印链表4.1 解题思路4.2 c 实现 5 剑指 Offer 24. 反转链表5.1 解题思路5.2 c实现 21. 合并两个有序链表解题…

【传输层】进程之间基于网络的通信(湖科大慕课自学笔记)

进程之间基于网络的通信 我们正式进入运输层的学习&#xff0c;先介绍进程之间基于网络的通信&#xff0c;我们在之前的学习中&#xff0c;已经介绍了物理层&#xff0c;数据链路层&#xff0c;网络层&#xff0c;它们共同解决并实现了主机到主机的通信 举例如下图所示&#x…

DDS技术概述及测试策略与方案

随着车载通信技术的快速发展&#xff0c;传统的通信技术在满足车载通信需求方面面临着一些挑战。车载通信对实时性、可靠性以及通信带宽的需求越来越高&#xff0c;同时车载通信环境存在多路径衰落、信号干扰等问题&#xff0c;这些都给通信技术的选择和应用带来了一定的挑战。…

VMware 集群-虚拟机配置反亲和性(互斥)

简介 博客&#xff1a;https://songxwn.com/ 为实现应用系统的冗余&#xff0c;经常会双机或者多机部署&#xff08;如数据库集群等&#xff09;。在VMware 集群里面&#xff0c;要保证不同应用集群的节点虚拟机在不同的物理宿主机上&#xff0c;防止单个宿主机故障&#xff…

Web Servlet

目录 1 简介2 创建Servlet项目并成功发布运行3 新加Servlet步骤4 Servlet项目练习5 Servlet运行原理6 操作 HTTP Request头的方法(部分方法示例)7 操作 HTTP Response头的方法(部分方法示例)8 两种重定向(页面跳转)方法9 Cookie9.1 Cookie工作原理9.2 cookie构成9.3 Servlet 操…

Unity DropDown 组件 详解

Unity版本 2022.3.13f1 Dropdown下拉菜单可以快速创建大量选项 一、 Dropwon属性详解 属性&#xff1a;功能&#xff1a;Interactable此组件是否接受输入&#xff1f;请参阅 Interactable。Transition确定控件以何种方式对用户操作进行可视化响应的属性。请参阅过渡选项。Nav…