Apollo算法的版本更迭
1. Apollo1.5
EMPlanner引入SL、ST解耦规划,引入凸空间,先决策后规划。
2. Apollo2.5
加入LatticePlanner。
3. Apollo3.5
取消了SL\ST迭代机制,SL只管静态障碍物,ST只管动态障碍物,加入场景模块(scenario模块,不同场景使用不同的算法)。
4. Apollo5.0
取消了SL的dp动态规划模块。
5. Apollo6.0
变动不大。
为什么取消SL/ST迭代机制
车辆的纵向变速能力远强于横向变速能力,SL/ST迭代机制中,ST会影响到SL规划,如果动态障碍的速度剧烈变化,那么ST图也会剧烈变化,则SL也会随之剧烈变化,导致几何线型不稳定。
特定场景需要使用ST去调整SL
1.前方同向行驶的车辆速度很小,自车的速度很大;
2.前方有反向行驶的车辆迎面而来,即对向而来。
这种情况下需要由感知模块对障碍物进行跟踪,生成虚拟障碍物,交付给SL规划模块去重新规划线型。
速度规划方案整体流程
SL图只管静态障碍物,ST图只管动态障碍物,少数场景下ST图会影响SL图。
简化考虑动态障碍物为质点模型(所以ST图是斜直线),运动模型为SL空间下的匀速或者匀加速运动。
1.由动态障碍物生成ST图
2.基于ST图进行动态规划生成凸空间
3.基于凸空间进行二次规划
4.轨迹后处理
具体方案
生成ST图
本周期,以本周期规划的路径为参考线(未和上周期轨迹进行拼接的轨迹),将动态障碍物质点进行投影,并且计算出其纵向速度s0˙和横向速度l0˙,由于我们假设障碍物在SL空间下进行匀速运动,所以s0˙和l0˙不变。
同时我们要讨论障碍物点是在行车范围内,还是在行车范围外:
- 障碍物在行车范围外:∣l0∣>∣K∣

考虑障碍物点到达轨迹线的时刻为t,同时考虑一个安全距离K,则:
t=−l0/l0˙
障碍物点刚刚切入安全边界的时刻为tin,刚刚切出安全边界的时刻tout:
tin=min(t+K/l0˙,t−K/l0˙)tout=max(t+K/l0˙,t−K/l0˙)
若t<0,则说明障碍物是逐渐远离规划轨迹的,对该障碍物不给予考虑。
- 障碍物在在行车范围内:∣l0∣<=∣K∣
tin=0tout=(K−∣l0∣)/∣l0˙∣
然后我们可以计算障碍物在刚刚切入行车范围边界时、刚刚切出行车范围边界时的ST图上的点,将两点进行连接,即可得到该动态障碍物的ST图
sin=s0+tin∗s0˙sout=s0+tout∗s0˙

我们需要依据动态障碍物的具体运动情况来决定是否生成虚拟障碍物,如果当前感知到的动态障碍物:
- 横向速度(l方向速度l˙)很小且横向距离很大(l很大),则不考虑该动态障碍物;
- 横向速度很小且横向距离很小,则该动态障碍物可能堵住车辆前进轨迹,感知模块需要生成虚拟障碍物。大概逻辑:感知模块需要跟踪该障碍物,判断相邻帧之间看到的障碍物是否为同一个障碍物,速度规划模块拿到虚拟障碍物后做决策(怎么绕),然后下一帧路径规划拿到虚拟障碍物标签后做路径规划,然后速度模块进行速度规划,绕过去;
- 横向速度较大则将其投影到ST图。
动态规划
ST速度规划中的动态规划整体逻辑与SL路径规划的整体逻辑一致,细节稍有出入,首先离散点散布的更加稠密,相邻层之间的路段权重计算稍有不同。
确定规划起点
已知上周期的规划轨迹点,当前时刻为t,以t+dt时间的点位(即路径规划的起点)作为速度规划的起点。
规划时间长短
ST图中的纵轴S的最大值依据SL规划中的最大值Send来确定,那么横轴的最大时间Tend如何确定,我们需要考虑未来多长的时间呢?这个时间受到很多因素的影响,首先我们不可能把这个时间定的过长,这样程序计算时间很长,时间也不能定的太短。但是与路径规划不一样的是,我们没有必要一定要把Send或者Tend内全部规划完。所以我们暂定Tend=8s。
布设离散点
由于机动车在纵向(沿参考线的前进方向)上的机动变速能力很强,远强于横向机动能力,所以我们纵向离散点的布设间距可以采用不均匀采样方案,离规划起点较近的路段间距小,较远的路段间距大一些。时间维度每0.5s采样一个点。
路段权重计算
由于采样密度增加了,相邻层之间点与点的连线(即路段)不再使用五次多项式而是使用直线代替。
路段权重由障碍物代价、加速度代价、jerk代价、推荐速度代价组成。
对于一条具体的边(路段),我们在线段上均匀采样N个点,分别计算每个点到障碍物ST图的代价,点到ST图的代价是点到线段最短距离dis的函数,某路段上的采样点到某障碍物ST图的距离计算示意图:

对于路段上某个具体的点p,计算其到ST线段的最短距离,需要先判断点在线段的内侧还是外侧,通过向量的点乘即可判断,点到ST线段的最小距离dis计算如图所示:
图中两个向量叉乘的几何意义为:代表这两个向量围成的平行四边形的面积。
我们定义某路段的点i(共采样5个点)到第j个ST线段的障碍物代价costobi,j为:
其中(dis为点到线段的最短距离)
假设共有K个障碍物的ST图,则某路段的障碍物代价权重LinkCostob
LinkCostob=wob∗k=1∑Ki=1∑5costobi,k
设规划起点的的SL坐标为(s0,l0),有s0=0,l0=0,笛卡尔坐标系下的速度大小为v0,加速度大小为a0,则有s0˙=v0,s0¨=a0,由起点计算到第一层各点的路段的速度、加速度、jerk(速度三阶导数):

直接简单差分即可计算得到速度规划起点到第一层各点路段的速度、加速度和jerk值,加速度的平方乘相应的权重即可得到加速度代价,jerk值的平方乘相应的权重即可得到jerk代价。
但是这里还有一个细节问题需要考虑,由于一条路段的速度、加速度、jerk值的计算不仅与前序层状态有关,还与当前层状态值有关,当我们计算第二层各点到第三层各点的加速度、jerk时,会发现前序层(第二层)各点的状态是不唯一的,以s12为例,由于其前序层有多个点,所以其自身的状态也有多个值,我们应该记录从规划起点到s12的最优路径在第一层中所经过的点x,以这个点x和s12为前后状态计算得到路段状态sta,将该状态sta作为s12向后计算的起始状态。
LinkCostaccel=waccel∗s¨2LinkCostjerk=wjerk∗jerk2
推荐速度vr由导航给出,推荐速度代价为:
LinkCostexp=wexp∗(s˙−vr)2
计算出所有路段的权重后,进行动态规划搜路即可获得ST规划结果粗解。动态规划代码逻辑可参见:juejin.cn/post/714656…
生成凸空间
此步骤和路径规划的凸空间生成类似(依据动态规划的粗解生成凸空间):juejin.cn/post/714656…
但是除了s值的上下边界、还需要计算s˙的上下边界:由于我们已经知道了路径规划的结果s序列和kappa序列,但是速度动态规划的s序列和路径规划的s序列不是完全吻合的,需要通过插值得到速度动态规划的点位斜率值,设允许的最大向心加速度值为ar,然后得到速度规划某点位最小最大速度s˙imin和s˙imax
s˙imin=0s˙imax=(ar/(∣kappai∣+0.0001))0.5
二次规划
通过生成凸空间我们可以得到ST图中的凸空间:
convexS={(t1,s1min,s1max),(t2,s2min,s2max),...,(tn,snmin,snmax)}
决策变量xx
xx=[s1,s˙1,s¨1,s2,s˙2,,s¨2,...,sn,s˙n,s¨n]
约束
若加速超过障碍物,则速度要大于动态障碍物的速度,减速反之。
设允许的最大向心加速度为amaxr,某轨迹点的速度为vi,半径为ri,斜率为ki,依据向心加速度公式可得约束:
vi2/ri≤ amaxr→s˙i2/ri≤ amaxr→s˙i≤ (amaxr/ki)0.5
−6≤ s¨i≤ 4
参考二次规划求路径的文章中分段加加速度法(juejin.cn/post/714944…
si+1=si+s˙i⋅dt+21⋅s¨i⋅dt2+61⋅(dts¨i+1−s¨i)⋅dt3s˙i+1=s˙i+s¨i⋅dt+21⋅(dts¨i+1−s¨i)⋅dt2
si≤ si+1
目标函数
目标函数考虑推荐速度代价、ST曲线平滑代价
cost=i=1∑n[wexp⋅(s˙i−vref)2+w2⋅(s¨i2)+w3⋅(s¨i2)]
第三项应该是si对时间的3阶导, makrdown好像打不出三个点。
考虑上述目标函数和约束可进行ST规划的求解。
后处理
ST规划结果增密
由于控制模块的执行频率是规划模块执行频率的十倍,如果规划结果的点位数量不够,会导致规划的效果不好,但是过多的待规划点位导致计算时间增长,考虑到个人电脑的算力问题,所以我们的方案是减少规划点位数目,待规划出结果后对轨迹进行增密,使用简单的质点运动学模型进行轨迹插值增密即可。
融合SL轨迹结果和ST速度结果
ST规划的点位比SL规划的点位要更加密集,所以需要以ST规划结果的s序列对SL规划结果进行插值后融合。
拼接轨迹
与上周期轨迹进行拼接。
代码实现
写完再更。
参考来源
space.bilibili.com/287989852