Apollo的的规划算法基于Frenet坐标系,因此道路中心线的平滑性控制着车辆是否左右频繁晃动,而高精地图的道路中心线往往不够平滑。
离散点平滑法,包括
1,FEM_POS_DEVIATION_SMOOTHING有限元位置差异
2,COS_THETA_SMOOTHING余弦)
3,QpSplineReferenceLineSmoother(三次样条插值法)
4,SpiralReferenceLineSmoother(螺旋曲线法)
本文只讲解FEM_POS_DEVIATION_SMOOTHING有限元位置差异的方法。
一,为什么需要重新生成参考线
导航路径存在的问题:1,导航路径过长;2,不平滑
![](https://img-blog.csdnimg.cn/89ea1a9ae34941158aa6f18020a5f8da.png)
导致的结果:
1,不利于主车以及障碍物寻找投影点,甚至出现多个投影点。
2,原本的导航路径不平滑,车辆无法直接进行轨迹跟踪。
解决方案:根据导航路径,生成参考线。
二,生成参考线的具体步骤与方法
![](https://img-blog.csdnimg.cn/3534779e11db47c68fe5718ab266b388.png)
1,找到匹配点以及投影点
2,以匹配点或者投影点为原点,往后取30个点,往前取150个点。对这180个点进行平滑处理,生成符合要求的参考线,作为该规划周期内的参考线,并以此参考线为Frenet坐标系。
三,参考线平滑方法:QP
方法步骤:
1,设计Cost:平滑程度,与原路径的偏离程度,路径点距离分布的均匀程度。
2,整理Cost目标函数,使其符合QP的表达形式。
![minJ=\frac{1}{2}x^{T}Qx+f^{T}x](https://latex.csdn.net/eq?minJ%3D%5Cfrac%7B1%7D%7B2%7Dx%5E%7BT%7DQx+f%5E%7BT%7Dx)
3,考虑约束条件,并整理为QP的约束表达式形式。
![sb: Ax= b](https://latex.csdn.net/eq?sb%3A%20Ax%3C%3D%20b)
4,运用合适的QP求解器进行求解,获取优化后的结果。
四,设计Cost:平滑程度,与原路径的偏离程度,路径点距离分布的均匀程度(长度代价)
1,平滑程度
![](https://img-blog.csdnimg.cn/03114516827e4d44ac72d5688baa5e4c.png)
衡量指标: 。其值越小, 路径越平滑。
![](https://img-blog.csdnimg.cn/8af09170d0e0413a9f10a8d797718cee.png)
2,与原路径的偏离程度
![](https://img-blog.csdnimg.cn/83e83a2256e54fe09a4440ba6bcc231f.png)
如上图所示,平滑前的点记为 ,平滑后的点记为 。
虽然路径平滑了,但与原路径距离偏差太大,不符合要求。
衡量指标:![\left | P_{1} P_{1r} \right |+\left | P_{2} P_{2r} \right |+\left | P_{3} P_{3r} \right |](https://latex.csdn.net/eq?%5Cleft%20%7C%20P_%7B1%7D%20P_%7B1r%7D%20%5Cright%20%7C+%5Cleft%20%7C%20P_%7B2%7D%20P_%7B2r%7D%20%5Cright%20%7C+%5Cleft%20%7C%20P_%7B3%7D%20P_%7B3r%7D%20%5Cright%20%7C)
3,路径点距离分布的均匀程度(长度代价)
![](https://img-blog.csdnimg.cn/d2b576a915a94b439564fb7c8ffc0377.png)
衡量指标: 。其值越小,分布越均匀。
五,实例讲解
1,以3个点为例求解目标函数
![](https://img-blog.csdnimg.cn/c74b5215b20b4e34ad0261b324207c7c.png)
如上图所示,已知变量:原路径点为: ,未知变量:优化后的路径点为: ,求优化后的路径点坐标。
![minJ = (x_{1}+x_{3}-2x_{2})^{2}+(y_{1}+y_{3}-2y_{2})^{2} + \sum_{i =1}^{3}((x_{i}-x_{ir})^{2}+(y_{i}-y_{ir})^{2}) + \sum_{i=1}^{3}((x_{i+1}-x_{i})^{2}+(y_{i+1}-y_{i})^{2})](https://latex.csdn.net/eq?minJ%20%3D%20%28x_%7B1%7D+x_%7B3%7D-2x_%7B2%7D%29%5E%7B2%7D+%28y_%7B1%7D+y_%7B3%7D-2y_%7B2%7D%29%5E%7B2%7D%20+%20%5Csum_%7Bi%20%3D1%7D%5E%7B3%7D%28%28x_%7Bi%7D-x_%7Bir%7D%29%5E%7B2%7D+%28y_%7Bi%7D-y_%7Bir%7D%29%5E%7B2%7D%29%20+%20%5Csum_%7Bi%3D1%7D%5E%7B3%7D%28%28x_%7Bi+1%7D-x_%7Bi%7D%29%5E%7B2%7D+%28y_%7Bi+1%7D-y_%7Bi%7D%29%5E%7B2%7D%29)
2,二次规划的一般形式
![minJ=\frac{1}{2}x^{T}Hx+f^{T}x](https://latex.csdn.net/eq?minJ%3D%5Cfrac%7B1%7D%7B2%7Dx%5E%7BT%7DHx+f%5E%7BT%7Dx)
![st:Ax = b, lb = x = ub](https://latex.csdn.net/eq?st%3AAx%20%3C%3D%20b%2C%20lb%20%3C%3D%20x%20%3C%3D%20ub)
3,n个点的代价函数求解(重点):
平滑性代价:
![j_{1}=\sum_{i=1}^{n-2}((x_{i}+x_{i+2}-2x_{i+1})^{2}+(y_{i}+y_{i+2}-2y_{i+1})^{2}) =](https://latex.csdn.net/eq?j_%7B1%7D%3D%5Csum_%7Bi%3D1%7D%5E%7Bn-2%7D%28%28x_%7Bi%7D+x_%7Bi+2%7D-2x_%7Bi+1%7D%29%5E%7B2%7D+%28y_%7Bi%7D+y_%7Bi+2%7D-2y_%7Bi+1%7D%29%5E%7B2%7D%29%20%3D)
![((x_{1}+x_{3}-2x_{2})^{2}+(y_{1}+y_{3}-2y_{2})^{2}+(x_{2}+x_{4}-2x_{3})^{2}+(y_{2}+y_{4}-2y_{3})^{2}+...) =](https://latex.csdn.net/eq?%28%28x_%7B1%7D+x_%7B3%7D-2x_%7B2%7D%29%5E%7B2%7D+%28y_%7B1%7D+y_%7B3%7D-2y_%7B2%7D%29%5E%7B2%7D+%28x_%7B2%7D+x_%7B4%7D-2x_%7B3%7D%29%5E%7B2%7D+%28y_%7B2%7D+y_%7B4%7D-2y_%7B3%7D%29%5E%7B2%7D+...%29%20%3D)
![((x_{1}+x_{3}-2x_{2}),(y_{1}+y_{3}-2y_{2}),(x_{2}+x_{4}-2x_{3}),(y_{2}+y_{4}-2y_{3}),...)*((x_{1}+x_{3}-2x_{2}),(y_{1}+y_{3}-2y_{2}),(x_{2}+x_{4}-2x_{3}),(y_{2}+y_{4}-2y_{3}),...) ^{T}](https://latex.csdn.net/eq?%28%28x_%7B1%7D+x_%7B3%7D-2x_%7B2%7D%29%2C%28y_%7B1%7D+y_%7B3%7D-2y_%7B2%7D%29%2C%28x_%7B2%7D+x_%7B4%7D-2x_%7B3%7D%29%2C%28y_%7B2%7D+y_%7B4%7D-2y_%7B3%7D%29%2C...%29*%28%28x_%7B1%7D+x_%7B3%7D-2x_%7B2%7D%29%2C%28y_%7B1%7D+y_%7B3%7D-2y_%7B2%7D%29%2C%28x_%7B2%7D+x_%7B4%7D-2x_%7B3%7D%29%2C%28y_%7B2%7D+y_%7B4%7D-2y_%7B3%7D%29%2C...%29%20%5E%7BT%7D)
其中:
![((x_{1}+x_{3}-2x_{2}),(y_{1}+y_{3}-2y_{2}),(x_{2}+x_{4}-2x_{3}),(y_{2}+y_{4}-2y_{3}),...)=](https://latex.csdn.net/eq?%28%28x_%7B1%7D+x_%7B3%7D-2x_%7B2%7D%29%2C%28y_%7B1%7D+y_%7B3%7D-2y_%7B2%7D%29%2C%28x_%7B2%7D+x_%7B4%7D-2x_%7B3%7D%29%2C%28y_%7B2%7D+y_%7B4%7D-2y_%7B3%7D%29%2C...%29%3D)
![](https://img-blog.csdnimg.cn/5c300c4484f347d5af1005b6dbb5dc0d.png)
令![x^{T}=(x_{1},y_{1},x_{2},y_{2}...)_{1*2n}](https://latex.csdn.net/eq?x%5E%7BT%7D%3D%28x_%7B1%7D%2Cy_%7B1%7D%2Cx_%7B2%7D%2Cy_%7B2%7D...%29_%7B1*2n%7D)
则![j_{1}=x^{T}A_{1}^{T}A_{1}x](https://latex.csdn.net/eq?j_%7B1%7D%3Dx%5E%7BT%7DA_%7B1%7D%5E%7BT%7DA_%7B1%7Dx)
均匀性代价(长度代价):
![j_{2}=\sum_{i=1}^{n-1}((x_{i}-x_{i+1})^{2}+(y_{i}-y_{i+1})^{2}) =](https://latex.csdn.net/eq?j_%7B2%7D%3D%5Csum_%7Bi%3D1%7D%5E%7Bn-1%7D%28%28x_%7Bi%7D-x_%7Bi+1%7D%29%5E%7B2%7D+%28y_%7Bi%7D-y_%7Bi+1%7D%29%5E%7B2%7D%29%20%3D)
![(x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2}..)*(x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2}..)^{T} =](https://latex.csdn.net/eq?%28x_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D..%29*%28x_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D..%29%5E%7BT%7D%20%3D)
![(x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2}..)*(x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2}..)^{T}](https://latex.csdn.net/eq?%28x_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D..%29*%28x_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D..%29%5E%7BT%7D)
其中,![(x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2},x_{1}-x_{2}..) =](https://latex.csdn.net/eq?%28x_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D%2Cx_%7B1%7D-x_%7B2%7D..%29%20%3D)
![](https://img-blog.csdnimg.cn/9364e47113d44ca08d1cfc98d31462e1.png)
令![x^{T}=(x_{1},y_{1},x_{2},y_{2}...)_{1*2n}](https://latex.csdn.net/eq?x%5E%7BT%7D%3D%28x_%7B1%7D%2Cy_%7B1%7D%2Cx_%7B2%7D%2Cy_%7B2%7D...%29_%7B1*2n%7D)
则![j_{2}=x^{T}A_{2}^{T}A_{2}x](https://latex.csdn.net/eq?j_%7B2%7D%3Dx%5E%7BT%7DA_%7B2%7D%5E%7BT%7DA_%7B2%7Dx)
与原路径的距离偏差代价:
![j_{3}=\sum_{i=1}^{n}((x_{i}-x_{ir})^{2}+(y_{i}-y_{ir})^{2}) =](https://latex.csdn.net/eq?j_%7B3%7D%3D%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%28%28x_%7Bi%7D-x_%7Bir%7D%29%5E%7B2%7D+%28y_%7Bi%7D-y_%7Bir%7D%29%5E%7B2%7D%29%20%3D)
![\sum_{i=1}^{n}(x_{i}^{2}+y_{i}^{2})-2\sum_{i=1}^{n}(x_{i}x_{ir}+y_{i}y_{ir})+\sum_{i=1}^{n}(x_{ir}^{2}+y_{ir}^{2})](https://latex.csdn.net/eq?%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%28x_%7Bi%7D%5E%7B2%7D+y_%7Bi%7D%5E%7B2%7D%29-2%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%28x_%7Bi%7Dx_%7Bir%7D+y_%7Bi%7Dy_%7Bir%7D%29+%5Csum_%7Bi%3D1%7D%5E%7Bn%7D%28x_%7Bir%7D%5E%7B2%7D+y_%7Bir%7D%5E%7B2%7D%29)
由于 是常数,对目标函数的变化没有影响,故可以删除,以简化表达。
令 ,![h^{T}=(x_{1r},y_{1r},x_{2r},y_{2r}...)_{1*2n}](https://latex.csdn.net/eq?h%5E%7BT%7D%3D%28x_%7B1r%7D%2Cy_%7B1r%7D%2Cx_%7B2r%7D%2Cy_%7B2r%7D...%29_%7B1*2n%7D)
则:![j_{3}=x^{T}x-2f^{T}x](https://latex.csdn.net/eq?j_%7B3%7D%3Dx%5E%7BT%7Dx-2f%5E%7BT%7Dx)
综述所述:
![J=j_{1}+j_{2}+j_{3}=\omega _{1}x^{T}A_{1}^{T}A_{1}x+\omega _{2}x^{T}A_{2}^{T}A_{2}x+\omega _{3}x^{T}x-2h^{T}x =](https://latex.csdn.net/eq?J%3Dj_%7B1%7D+j_%7B2%7D+j_%7B3%7D%3D%5Comega%20_%7B1%7Dx%5E%7BT%7DA_%7B1%7D%5E%7BT%7DA_%7B1%7Dx+%5Comega%20_%7B2%7Dx%5E%7BT%7DA_%7B2%7D%5E%7BT%7DA_%7B2%7Dx+%5Comega%20_%7B3%7Dx%5E%7BT%7Dx-2h%5E%7BT%7Dx%20%3D)
![x^{T}(\omega _{1}A_{1}^{T}A_{1}+\omega _{2}A_{2}^{T}A_{2}+\omega _{3}E)x-2h^{T}x](https://latex.csdn.net/eq?x%5E%7BT%7D%28%5Comega%20_%7B1%7DA_%7B1%7D%5E%7BT%7DA_%7B1%7D+%5Comega%20_%7B2%7DA_%7B2%7D%5E%7BT%7DA_%7B2%7D+%5Comega%20_%7B3%7DE%29x-2h%5E%7BT%7Dx)
一般情况下,平滑的权重系数远远大于其他2项的权重系数
二次规划的标准形式为:
![J=\frac{1}{2}x^{T}Hx+f^{T}x](https://latex.csdn.net/eq?J%3D%5Cfrac%7B1%7D%7B2%7Dx%5E%7BT%7DHx+f%5E%7BT%7Dx)
则![H=2(\omega _{1}A_{1}^{T}A_{1}+\omega _{2}A_{2}^{T}A_{2}+\omega _{3}E)](https://latex.csdn.net/eq?H%3D2%28%5Comega%20_%7B1%7DA_%7B1%7D%5E%7BT%7DA_%7B1%7D+%5Comega%20_%7B2%7DA_%7B2%7D%5E%7BT%7DA_%7B2%7D+%5Comega%20_%7B3%7DE%29)
![f=-2h](https://latex.csdn.net/eq?f%3D-2h)
求解约束条件:
![lb=\left | x-x_{r} \right |=ub](https://latex.csdn.net/eq?lb%3C%3D%5Cleft%20%7C%20x-x_%7Br%7D%20%5Cright%20%7C%3C%3Dub)
![lb+x_{r}=x=ub+x_{r}](https://latex.csdn.net/eq?lb+x_%7Br%7D%3C%3Dx%3C%3Dub+x_%7Br%7D)
至此,参考线平滑问题转化为二次规划的标准形式,采用成熟的求解器求解即可获得 ,从而实现导航轨迹的平滑,获得符合要求的参考线轨迹点。
import osqp
import numpy as np
import matplotlib.pyplot as plt
from scipy import sparse
#计算kappa用来评价曲线
def calcKappa(x_array,y_array):
s_array = []
k_array = []
if(len(x_array) != len(y_array)):
return(s_array , k_array)
length = len(x_array)
temp_s = 0.0
s_array.append(temp_s)
for i in range(1 , length):
temp_s += np.sqrt(np.square(y_array[i] - y_array[i - 1]) + np.square(x_array[i] - x_array[i - 1]))
s_array.append(temp_s)
xds,yds,xdds,ydds = [],[],[],[]
for i in range(length):
if i == 0:
xds.append((x_array[i + 1] - x_array[i]) / (s_array[i + 1] - s_array[i]))
yds.append((y_array[i + 1] - y_array[i]) / (s_array[i + 1] - s_array[i]))
elif i == length - 1:
xds.append((x_array[i] - x_array[i-1]) / (s_array[i] - s_array[i-1]))
yds.append((y_array[i] - y_array[i-1]) / (s_array[i] - s_array[i-1]))
else:
xds.append((x_array[i+1] - x_array[i-1]) / (s_array[i+1] - s_array[i-1]))
yds.append((y_array[i+1] - y_array[i-1]) / (s_array[i+1] - s_array[i-1]))
for i in range(length):
if i == 0:
xdds.append((xds[i + 1] - xds[i]) / (s_array[i + 1] - s_array[i]))
ydds.append((yds[i + 1] - yds[i]) / (s_array[i + 1] - s_array[i]))
elif i == length - 1:
xdds.append((xds[i] - xds[i-1]) / (s_array[i] - s_array[i-1]))
ydds.append((yds[i] - yds[i-1]) / (s_array[i] - s_array[i-1]))
else:
xdds.append((xds[i+1] - xds[i-1]) / (s_array[i+1] - s_array[i-1]))
ydds.append((yds[i+1] - yds[i-1]) / (s_array[i+1] - s_array[i-1]))
for i in range(length):
k_array.append((xds[i] * ydds[i] - yds[i] * xdds[i]) / (np.sqrt(xds[i] * xds[i] + yds[i] * yds[i]) * (xds[i] * xds[i] + yds[i] * yds[i]) + 1e-6));
return(s_array,k_array)
def referenceline():
#add some data for test
x_array = [0.5,1.0,2.0,3.0,4.0,
5.0,6.0,7.0,8.0,9.0,
10.0,11.0,12.0,13.0,14.0,
15.0,16.0,17.0,18.0,19.0]
y_array = [0.1,0.3,0.2,0.4,0.3,
-0.2,-0.1,0,0.5,0,
0.1,0.3,0.2,0.4,0.3,
-0.2,-0.1,0,0.5,0]
length = len(x_array)
#weight , from config
weight_fem_pos_deviation_ = 1e10 #cost1 - x
weight_path_length = 1 #cost2 - y
weight_ref_deviation = 1 #cost3 - z
P = np.zeros((length,length))
#set P matrix,from calculateKernel
#add cost1
P[0,0] = 1 * weight_fem_pos_deviation_
P[0,1] = -2 * weight_fem_pos_deviation_
P[1,1] = 5 * weight_fem_pos_deviation_
P[length - 1 , length - 1] = 1 * weight_fem_pos_deviation_
P[length - 2 , length - 1] = -2 * weight_fem_pos_deviation_
P[length - 2 , length - 2] = 5 * weight_fem_pos_deviation_
for i in range(2 , length - 2):
P[i , i] = 6 * weight_fem_pos_deviation_
for i in range(2 , length - 1):
P[i - 1, i] = -4 * weight_fem_pos_deviation_
for i in range(2 , length):
P[i - 2, i] = 1 * weight_fem_pos_deviation_
with np.printoptions(precision=0):
print(P)
P = P / weight_fem_pos_deviation_
P = sparse.csc_matrix(P)
#set q matrix , from calculateOffset
q = np.zeros(length)
#set Bound(upper/lower bound) matrix , add constraints for x
#from CalculateAffineConstraint
#In apollo , Bound is from road boundary,
#Config limit with (0.1,0.5) , Here I set a constant 0.2
bound = 0.2
A = np.zeros((length,length))
for i in range(length):
A[i, i] = 1
A = sparse.csc_matrix(A)
lx = np.array(x_array) - bound
ux = np.array(x_array) + bound
ly = np.array(y_array) - bound
uy = np.array(y_array) + bound
#solve
prob = osqp.OSQP()
prob.setup(P,q,A,lx,ux)
res = prob.solve()
opt_x = res.x
prob.update(l=ly, u=uy)
res = prob.solve()
opt_y = res.x
#plot x - y , opt_x - opt_y , lb - ub
fig1 = plt.figure(dpi = 100 , figsize=(12, 8))
ax1_1 = fig1.add_subplot(2,1,1)
ax1_1.plot(x_array,y_array , ".--", color = "grey", label="orig x-y")
ax1_1.plot(opt_x, opt_y,".-",label = "opt x-y")
# ax1_1.plot(x_array,ly,".--r",label = "bound")
# ax1_1.plot(x_array,uy,".--r")
ax1_1.legend()
ax1_1.grid(axis="y",ls='--')
#plot kappa
ax1_2 = fig1.add_subplot(2,1,2)
s_orig,k_orig = calcKappa(x_array,y_array)
s_opt ,k_opt = calcKappa(opt_x,opt_y)
ax1_2.plot(s_orig , k_orig , ".--", color = "grey", label="orig s-kappa")
ax1_2.plot(s_opt,k_opt,".-",label="opt s-kappa")
ax1_2.legend()
ax1_2.grid(axis="y",ls='--')
plt.show()
if __name__ == '__main__':
referenceline()
平滑前后的坐标和曲率对比:
![](https://img-blog.csdnimg.cn/4c72e9cf08fa42e2a5c9f4da9b3f20b6.png)
|