编辑推荐: |
本文是基于几何追踪的方法去实现无人车轨迹追踪 ,详细内容请看下文。
本文来自csdn,由火龙果软件Anna编辑、推荐。
|
|
无人驾驶算法——使用Stanley method实现无人车轨迹追踪
Date: 2019/08/03
Editor:萧潇子(Jesse)
Contact: 1223167600@qq.com |
基于几何追踪的方法
关于无人车追踪轨迹,目前的主流方法分为两类:基于几何追踪的方法和基于模型预测的方法,其中几何追踪方法主要包含纯跟踪和Stanley两种方法,纯跟踪方法已经广泛应用于移动机器人的路径跟踪中,网上也有很多详细的介绍,本文主要介绍斯坦福大学无人车使用的Stanley方法。
Stanley method
Stanley方法是一种基于横向跟踪误差(cross-track error
:eee 为前轴中心到最近路径点(px,py)的距离)的非线性反馈函数,并且能实现横向跟踪误差指数收敛于0。根据车辆位姿与给定路径的相对几何关系可以直观的获得控制车辆方向盘转角的控制变量,其中包含横向偏差e和航向偏差θe。
在不考虑横向跟踪误差的情况下,前轮偏角和给定路径切线方向一致,如图所示。其中θe表示车辆航向与最近路径点切线方向之间的夹角,在没有任何横向误差的情况下,前轮方向与所在路径点的方向相同:
在不考虑航向跟踪偏差的情况下,横向跟踪误差越大,前轮转向角越大,假设车辆预期轨迹在距离前轮d(t)d(t)d(t)处与给定路径上最近点切线相交,根据几何关系得出如下非线性比例函数:
其中d(t)与车速相关,最后用车速v(t),增益参数kkk表示。随着横向误差的增加,arctan函数产生一个直接指向期望路径的前轮偏角,并且收敛受车速v(t)限制。
综合两方面控制因素,基本转向角控制率如下:
使用线性自行车运动模型,可以得到横向误差的变化率:
其中sinδe(t)根据几何关系可知:
so:
当横向跟踪误差e(t)很小时,(ke(t)/v(t))2→0
通过积分上式:
因此横向误差指数收敛于e(t)=0e(t) = 0e(t)=0,参数kkk决定了收敛速度。对于任意横向误差,微分方程都单调的收敛到0。
基于Python的Stanley算法跟踪直线仿真
Stanley控制转向角度,使用一个简单的P控制器控制速度,首先我们定义参数数值如下:
import numpy
as np
import math
import matplotlib.pyplot as plt
k = 0.5 # 增益参数
Kp = 1.0 # 速度P控制器系数
dt = 0.1 # 时间间隔,单位:s
L = 3.0 # 车辆轴距,单位:m
|
这里将增益参数kkk设置为0.3,速度P控制器的比例系数Kp设置为1.0,时间间隔为0.1 秒,车的轴距我们定为3.0米。
定义车辆状态类,在简单的自行车模型中,我们只考虑车辆的当前位置 (x,y)(x,y)(x,y)
,车辆的偏航角度yawyawyaw以及车辆的速度vvv,为了仿真模拟,我们定义车辆的状态更新函数来模拟真实车辆的状态更新:
class VehicleState:
def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0):
self.x = x
self.y = y
self.yaw = yaw
self.v = vdef update(state, a, delta):
state.x = state.x + state.v * math.cos(state.yaw)
* dt
state.y = state.y + state.v * math.sin(state.yaw)
* dt
state.yaw = state.yaw + state.v / L * math.tan(delta)
* dt
state.v = state.v + a * dt
return state
|
仿真中,纵向控制使用一个简单的P控制器,横向控制(即转角控制)使用Stanley控制器,并且限制车轮转角范围[-30,
30],这两个控制器定义如下:
def PControl(target,
current):
a = Kp * (target - current)
return adef stanley_control(state, cx, cy, ch,
pind):
ind = calc_target_index(state, cx, cy)
if pind >= ind:
ind = pind
if ind < len(cx):
tx = cx[ind]
ty = cy[ind]
th = ch[ind]
else:
tx = cx[-1]
ty = cy[-1]
th = ch[-1]
ind = len(cx) - 1
# 计算横向误差
if ((state.x - tx) * th - (state.y - ty)) >
0:
error = abs(math.sqrt ((state.x - tx) ** 2 + (state.y
- ty) ** 2))
else:
error = -abs(math.sqrt ((state.x - tx) ** 2 + (state.y
- ty) ** 2))
delta = ch[ind] - state.yaw + math.atan2(k * error,
state.v)
# 限制车轮转角 [-30, 30]
if delta > np.pi / 6.0:
delta = np.pi / 6.0
elif delta < - np.pi / 6.0:
delta = - np.pi / 6.0
return delta, ind
|
定义函数用于搜索最临近的路点:
def calc_target_index(state,
cx, cy):
# 搜索最临近的路点
dx = [state.x - icx for icx in cx]
dy = [state.y - icy for icy in cy]
d = [abs(math.sqrt(idx ** 2 + idy ** 2)) for (idx,
idy) in zip(dx, dy)]
ind = d.index(min(d))
return ind
|
主函数:
def main():
# 设置目标路点
cx = np.arange(0, 50, 1)
cy = [0 * ix for ix in cx]
ch = [0 * ix for ix in cx]
target_speed = 5.0 / 3.6 # [m/s]
T = 200.0 # 最大模拟时间
# 设置车辆的初始状态
state = VehicleState(x=-0.0, y=-3.0, yaw=-0.0,
v=0.0)
lastIndex = len(cx) - 1
time = 0.0
x = [state.x]
y = [state.y]
yaw = [state.yaw]
v = [state.v]
t = [0.0]
target_ind = calc_target_index (state, cx, cy)
while T >= time and lastIndex > target_ind:
ai = PControl(target_speed, state.v)
di, target_ind = stanley_control(state, cx, cy,
ch, target_ind)
state = update(state, ai, di)
time = time + dt
x.append(state.x)
y.append(state.y)
yaw.append(state.yaw)
v.append(state.v)
t.append(time)
plt.cla()
plt.plot(cx, cy, ".r", label="course")
plt.plot(x, y, "-b", label="trajectory")
plt.plot(cx[target_ind], cy[target_ind], "go",
label="target")
plt.axis("equal")
plt.grid(True)
plt.title("Speed[km/h]:" + str(state.v
* 3.6)[:4])
plt.pause(0.001)if __name__ == '__main__':
main()
|
仿真结果:
通过仿真结果图,我们看到红点表示实现规划好的直线路径,蓝线则表示我们的车辆实际运行的轨迹,绿点表示距离当前位置最近路径点,在这段代码中,我们设置了增益参数kkk为0.3,通过进一步去改变kkk的大小对比结果,可以减小kkk值得到更平滑的跟踪轨迹,但是更加平滑的结果会引起某些急剧的转角处会存在转向不足的情况。
、
|