很幸运的搜到了这门课程,作为某实验室的一个小白,对这个行业很有兴趣,希望真的会有那么一天,L5的实现给人们带来极大的便利。记录一下课程重要的ppt和课后作业,这个是多伦多大学的一门课程,COURSERA上可以找的到,配套的作业很不错,有精力的可以去申请一下。
https://www.coursera.org/specializations/self-driving-cars
potholes: 坑洼
sidewalks:人行道
sensor occlusion:传感器阻塞
inertial:惯性的
stereo:立体的
LIDAR——Light Detection And Ranging,GPS+IMU,更精确,900-1500nm,激光
RADAR——radio detection and ranging,4-12mm,无线电
CARLA:
感知,建图,规划,控制,监督
三种地图
参考这篇文章有几个常见的单词
ego-vehicle 表示自我概念呢,用来表示被自动控制的车辆,相对于没被自动控制的车辆,或者也叫self-vehicle
类似的,经常用exo来表示其他的车辆,如exo-agent表示外智能体
由于定位测绘(localization mapping)只涉及识别车辆在环境中的姿势,因此可以使用点特征或物体位置,不需要密集地覆盖整个环境,而占位网格测绘(occupancy grid mapping)必须捕捉所有需要避开的障碍物的位置,因此必须密集。
localization mapping是估计自主车辆如何在环境中移动的关键测量,依赖于将当前时间的传感器测量结果与定位图进行匹配。占位网格图以车辆周围被占用和未被占用的单元格的形式存储实时避撞数据。
FMEA: Failure Mode and Effects Analysis
一种由下而上(bottom up)的失败分析方法,衡量个别原因和决定其在更高层系统中的影响
rollover 车辆翻滚
intersection 交叉路口
lane change 变道
rear-end 追尾
road departure 失控冲出路面事故
扩展:
decouple:解耦
tire force:轮胎力
stiffness:刚性
kinematics:动力学
gear ratios 齿轮比
whell torque 扭矩
在本笔记本中,你将实现自行车运动学模型。该模型接受速度和转向率的输入,并通过自行车运动学方程来实现。一旦模型实现,你将提供一组输入来驱动自行车在图8的轨迹。
自行车运动学由以下方程组控制。
其中输入为自行车速度v和转向角率ω。输入也可以直接是转向角δ,而不是简化后的速率。Python模型将允许我们实现这两种情况。
为了创建这个模型,利用Python类对象是个好主意。这使我们可以存储状态变量,以及为实现自行车运动学而制作函数。
自行车的初始条件为零,最大转弯速率为1.22rad/s,轴距长度为2m,从后轴到其质量中心的长度为1.2m。
从这些条件出发,我们初始化Python类如下。
from notebook_grader import BicycleSolution, grade_bicycle
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
class Bicycle():
def __init__(self):
self.xc = 0
self.yc = 0
self.theta = 0
self.delta = 0
self.beta = 0
self.L = 2
self.lr = 1.2
self.w_max = 1.22
self.sample_time = 0.01
def reset(self):
self.xc = 0
self.yc = 0
self.theta = 0
self.delta = 0
self.beta = 0
当通过时间传播运动学时,数值积分需要一个采样时间。这个时间被设置为10毫秒。我们还有一个复位函数,将所有的状态变量设置为0。
有了这个采样时间,使用下一个单元格中定义的函数步骤来实现运动学模型。该函数应该将速度+角速率作为输入,并更新状态变量。不要忘了自行车的最大转弯率!
class Bicycle(Bicycle):
def step(self, v, w):
# ==================================
# Implement kinematic model here
# ==================================
class Bicycle(Bicycle):
def step(self, v, w):
# ==================================
# Implement kinematic model here
# ==================================
if w > 0:
w = min(w,self.w_max)
else:
w = max(w,-self.w_max)
sample_T = 10e-3
# bicycle kinematics
xc_dot= v * np.cos(self.theta + self.beta)
yc_dot= v * np.sin(self.theta+self.beta)
theta_dot= v * np.cos(self.beta) * np.tan(self.delta) / self.L
delta_dot= w
# update the state variables
self.xc += xc_dot * sample_T
self.yc += yc_dot * sample_T
self.theta += theta_dot * sample_T
self.delta += delta_dot * sample_T
pass
pass
有了模型设置,我们现在可以开始给自行车输入并产生轨迹。
假设我们希望模型在20秒内走完一个半径为10米的圆。利用曲率半径和转向角之间的关系,可以计算出所需的转向角。
如果使用模拟自行车模型直接将转向角设置为0.1974,那么自行车将在圆周内行驶,而不需要任何额外的转向输入。
所需的速度可以从圆周上计算出来。
现在,我们可以在循环中实现这一点,以逐步完成模型方程。我们还将与您的模型一起运行我们的自行车模型解决方案,以显示您的预期轨迹。这将帮助您验证模型的正确性。
sample_time = 0.01
time_end = 20
model = Bicycle()
solution_model = BicycleSolution()
# set delta directly
model.delta = np.arctan(2/10)
solution_model.delta = np.arctan(2/10)
t_data = np.arange(0,time_end,sample_time)
x_data = np.zeros_like(t_data)
y_data = np.zeros_like(t_data)
x_solution = np.zeros_like(t_data)
y_solution = np.zeros_like(t_data)
for i in range(t_data.shape[0]):
x_data[i] = model.xc
y_data[i] = model.yc
model.step(np.pi, 0)
x_solution[i] = solution_model.xc
y_solution[i] = solution_model.yc
solution_model.step(np.pi, 0)
#model.beta = 0
#solution_model.beta=0
plt.axis('equal')
plt.plot(x_data, y_data,label='Learner Model')
plt.plot(x_solution, y_solution,label='Solution Model')
plt.legend()
plt.show()
上图显示了所需的半径为10米的圆,路径略有偏移,这是由于β造成的侧滑效应。通过取消循环中最后一行的注释,强制β=0,你可以看到偏移消失了,圆的中心位置变成了(0,10)。
然而,在实践中,转向角不能直接设置,必须通过角速率输入ω来改变。下面的单元格对此进行了修正,并设置角速率输入,生成相同的圆轨迹。速度v仍然保持在π m/s。
sample_time = 0.01
time_end = 20
model.reset()
solution_model.reset()
t_data = np.arange(0,time_end,sample_time)
x_data = np.zeros_like(t_data)
y_data = np.zeros_like(t_data)
x_solution = np.zeros_like(t_data)
y_solution = np.zeros_like(t_data)
for i in range(t_data.shape[0]):
x_data[i] = model.xc
y_data[i] = model.yc
if model.delta < np.arctan(2/10):
model.step(np.pi, model.w_max)
else:
model.step(np.pi, 0)
x_solution[i] = solution_model.xc
y_solution[i] = solution_model.yc
if solution_model.delta < np.arctan(2/10):
solution_model.step(np.pi, model.w_max)
else:
solution_model.step(np.pi, 0)
plt.axis('equal')
plt.plot(x_data, y_data,label='Learner Model')
plt.plot(x_solution, y_solution,label='Solution Model')
plt.legend()
plt.show()
下面是一些其他的轨迹示例:正方形路径、螺旋路径和波浪路径。取消标注每个部分来查看。
sample_time = 0.01
time_end = 60
model.reset()
solution_model.reset()
t_data = np.arange(0,time_end,sample_time)
x_data = np.zeros_like(t_data)
y_data = np.zeros_like(t_data)
x_solution = np.zeros_like(t_data)
y_solution = np.zeros_like(t_data)
# maintain velocity at 4 m/s
v_data = np.zeros_like(t_data)
v_data[:] = 4
w_data = np.zeros_like(t_data)
# ==================================
# Square Path: set w at corners only
# ==================================
w_data[670:670+100] = 0.753
w_data[670+100:670+100*2] = -0.753
w_data[2210:2210+100] = 0.753
w_data[2210+100:2210+100*2] = -0.753
w_data[3670:3670+100] = 0.753
w_data[3670+100:3670+100*2] = -0.753
w_data[5220:5220+100] = 0.753
w_data[5220+100:5220+100*2] = -0.753
# ==================================
# Spiral Path: high positive w, then small negative w
# ==================================
# w_data[:] = -1/100
# w_data[0:100] = 1
# ==================================
# Wave Path: square wave w input
# ==================================
#w_data[:] = 0
#w_data[0:100] = 1
#w_data[100:300] = -1
#w_data[300:500] = 1
#w_data[500:5700] = np.tile(w_data[100:500], 13)
#w_data[5700:] = -1
# ==================================
# Step through bicycle model
# ==================================
for i in range(t_data.shape[0]):
x_data[i] = model.xc
y_data[i] = model.yc
model.step(v_data[i], w_data[i])
x_solution[i] = solution_model.xc
y_solution[i] = solution_model.yc
solution_model.step(v_data[i], w_data[i])
plt.axis('equal')
plt.plot(x_data, y_data,label='Learner Model')
plt.plot(x_solution, y_solution,label='Solution Model')
plt.legend()
plt.show()
现在我们想让自行车走一个图八的轨迹。图八中的两个圆的半径都是8米,路径应该在30秒内完成。路径从左边圆的底部开始,如下图所示。
确定产生这种轨迹所需的速度和转向率输入,并在下面的单元格中实现。确保将您的输入保存到数组v_data和w_data中,这些将用于对您的解决方案进行评分。下面的单元格也绘制了你自己的模型所产生的轨迹。
sample_time = 0.01
time_end = 30
model.reset()
t_data = np.arange(0,time_end,sample_time)
x_data = np.zeros_like(t_data)
y_data = np.zeros_like(t_data)
v_data = np.zeros_like(t_data)
w_data = np.zeros_like(t_data)
# ==================================
# Learner solution begins here
# ==================================
radius=8
#delta=np.arctan(np.arctan(np.arctan(np.arctan(model.L/radius))))
#delta=np.arctan(np.arctan(np.arctan(model.L/radius)))
delta=np.arctan(np.arctan(model.L/radius))
#delta=np.arctan(model.L/radius)
delta=0.983*np.arctan(model.L/radius)
print(delta)
print(np.arctan(np.arctan(model.L/radius)))
v_data[:]=2*2*np.pi*radius/time_end
for i in range(t_data.shape[0]):
x_data[i]=model.xc
y_data[i]=model.yc
#w direction will change in first 1/4 circle (t/8) and 5/4 circle (5t/8)
if i< t_data.shape[0]/8:
# if model delta < delta then we should use max w
if model.delta<delta:
temp_w=abs(model.delta-delta)/model.delta*model.w_max
if temp_w>0:
w=min(temp_w,model.w_max)
else:
w=max(temp_w,-model.w_max)
model.step(v_data[i],w)
w_data[i]=w
#print(w_data[i],t_data[i])
#else we should use w=0 don't turn your front wheel
else:
model.step(v_data[i],0)
#w_data[i]=0
elif i< 5*t_data.shape[0]/8:
#print(model.delta,delta,t_data[i])
if model.delta>-delta:
model.step(v_data[i],-model.w_max)
w_data[i]=-model.w_max
#print(w_data[i],t_data[i])
else:
model.step(v_data[i],0)
#w_data[i]=0
else:
if model.delta<delta:
model.step(v_data[i],model.w_max)
w_data[i]=model.w_max
else:
model.step(v_data[i],0)
#w_data[i]=0
# model.beta = 0
# solution_model.beta=0
# ==================================
# Learner solution ends here
# ==================================
plt.axis('equal')
plt.plot(x_data, y_data)
plt.show()
现在我们将通过自行车模型解决方案运行您的速度和角速率输入。这是为了确保你的轨迹与你的模型是正确的。下面的单元格将显示由我们的模型生成的路径,以及一些航点在所需的图8上。这些航点周围是半径为1.5米的误差容差圈,如果生成的轨迹保持在这些容差圈的80%以内,你的解决方案将通过分级机。
grade_bicycle(t_data,v_data,w_data)
下面的单元格将把时间和车辆输入保存为名为fig8.txt的文本文件。要找到该文件,请将网络目录的末尾改为/notebooks/Course_1_Module_4/figure8.txt。
到了那里,你就可以下载文件,然后提交给Coursera评分器来完成这个评估。
data = np.vstack([t_data, v_data, w_data]).T
np.savetxt('figure8.txt', data, delimiter=', ')
class Vehicle(Vehicle):
def step(self, throttle, alpha):
# ==================================
# Implement vehicle model here
# ==================================
w_w=self.GR*self.w_e
s=(w_w*self.r_e-self.v)/self.v
if abs(s)<1:
F_x=self.c*s
else:
F_x=self.F_max
F_aero=self.c_a*(self.v**2)
R_x=self.c_r1*self.v
F_g=self.m*self.g*np.sin(alpha)
F_load=R_x+F_aero+F_g
self.a=(F_x-F_load)/self.m
self.v += self.a * self.sample_time
self.x += self.v * self.sample_time
T_e=throttle*(self.a_0+self.a_1*self.w_e+self.a_2*self.w_e**2)
self.w_e_dot = (T_e - self.GR*self.r_e*F_load)/self.J_e
self.w_e += self.w_e_dot * self.sample_time
pass
sample_time = 0.01
time_end = 100
model = Vehicle()
t_data = np.arange(0,time_end,sample_time)
v_data = np.zeros_like(t_data)
# throttle percentage between 0 and 1
throttle = 0.2
# incline angle (in radians)
alpha = 0
for i in range(t_data.shape[0]):
v_data[i] = model.v
model.step(throttle, alpha)
plt.plot(t_data, v_data)
plt.show()
throttle_data = np.zeros_like(t_data)
alpha_data = np.zeros_like(t_data)
for i,t in enumerate(t_data):
if t<5:
throttle_data[i]=0.2+(0.5-0.2)*t/5
elif t<15:
throttle_data[i]=0.5
else:
throttle_data[i]=0.5-0.5*(t-15)/5
for i in range(t_data.shape[0]):
v_data[i]=model.v
if model.x<60:
alpha_data[i]=np.arctan(3/60)
elif model.x<150:
alpha_data[i]=np.arctan((12-3)/90)
else:
alpha_data[i]=0
model.step(throttle_data[i], alpha_data[i])
x_data[i]=model.x
v_data[i]=model.v
w_w=model.GR*model.w_e
s_data[i]=(w_w*model.r_e-model.v)/model.v
增加微分控制可改善超调量和调节时间方面的阶跃响应,但会降低上升时间。相反,添加积分项可保持较短的上升时间,并且能够减少振荡和超调量,从而也缩短了调节时间。将导数和积分控制项相加会带来这两种方法的优点。
详情见这里CLICK