TEB学习总结
TEB introduction
时间弹性:TEB算法考虑了机器人在路径规划过程中的运动时间,通过对路径特征进行建模,可以根据不同的速度限制和运动约束生成时间弹性的轨迹。这意味着算法可以根据需要自动调整运动速度和规划时间,以适应不同的应用场景和运动要求。
局部优化:TEB算法是一种局部路径规划算法,主要用于解决机器人在具体环境中的实时路径规划问题。它将机器人当前状态和目标状态作为输入,考虑机器人的动力学约束、障碍物避障和平滑性等因素,生成包含时间信息的平滑路径。
多目标支持:TEB算法能够有效处理机器人面临的多个目标点或轨迹约束。通过灵活的轨迹生成和优化策略,可以在考虑多个目标的情况下生成最优的运动轨迹。这对于需要在复杂环境中进行导航或任务执行的机器人特别有用。
高效性:TEB算法通过合理的优化策略和启发式方法,在保证路径质量的同时,能够实现较高的计算效率。这使得算法适合于实时机器人路径规划应用,并能够处理较复杂的环境和运动要求。
TEB parameters
X i = [ x i , y i , θ i , δ T i ] \mathbf{X_i} = [ x_i, y_i , \theta_i , \delta T_i ] Xi=[xi,yi,θi,δTi]
TEB constraints
safety constraint
f
s
a
f
e
t
y
=
{
(
∥
x
i
−
o
i
∥
−
d
m
i
n
)
,
if
∥
x
i
−
o
i
∥
<
d
m
i
n
0
,
else
(1)
f_{safety} = \begin{cases} (\mathbf{\|x_i - o_i\|}- d_{min}), & \text{if }\mathbf{\|x_i - o_i\|} < d_{min} \\ 0, & \text{else} \end{cases}\tag{1}
fsafety={(∥xi−oi∥−dmin),0,if ∥xi−oi∥<dminelse(1)
公式中
x
i
=
[
x
i
,
y
i
]
\mathbf{x_i} = [x_i,y_i]
xi=[xi,yi]路径点,
o
i
=
[
o
x
,
o
y
]
\mathbf{o_i} = [o_x, o_y]
oi=[ox,oy] 是距离当前点最近的一个障碍物点,
d
m
i
n
d_{min}
dmin 是允许的障碍物和机器人的最小距离, 所以这个代价函数的目的就是计算每一个点和障碍物的距离,如果距离小于
d
m
i
n
d_{min}
dmin 这个代价函数就会对整体代价引入新误差,这样计算梯度的时候就会把当前点往远离障碍物的方向踢,这里会有一个问题,就是当路径点被障碍物包围的时候, 优化就会很大概率会失败,因为障碍物附近的梯度如下图, 中间的白色区域是距离障碍物最远的,那么优化的就会把在障碍物里面的点往中间推, 把外面的关键点往远离障碍物的方向推, 优化的结果可能会变成右图(左图是优化前), 为了解决这个问题可以参考一下ego planner的论文
via-point constraint
f
v
i
a
=
∣
∣
x
i
−
p
∣
∣
(2)
f_{via} = ||\mathbf{x_i - p}|| \tag{2}
fvia=∣∣xi−p∣∣(2)
公式中的
p
\mathbf{p}
p 是希望轨迹穿过的点,比如有三个点
p
1
,
p
2
,
p
3
\mathbf{p_1,p_2, p_3}
p1,p2,p3,希望机器人在运动的时候经过,优化开始前首先需要找到距离这三个点最近的轨迹点,分别是
x
1
,
x
2
,
x
3
\mathbf{x_1,x_2,x_3}
x1,x2,x3, 优化过程中代价函数只对这三个点起作用
x
1
,
x
2
,
x
3
\mathbf{x_1,x_2,x_3}
x1,x2,x3,这种需要经过的点,如果是距离初始轨迹比较远的话,往往单次优化的效果都会很不好甚至可能收敛的结果很不好,因此最好是分多次优化,每次优化之前都需要根据需要调整轨迹点
velocity constraint
v
i
=
∣
∣
x
i
+
1
−
x
i
∣
∣
δ
T
i
\begin{equation} v_i = \frac{\mathbf{||x_{i+1} - x_i||}}{\delta T_i} \tag{3} \end{equation}
vi=δTi∣∣xi+1−xi∣∣(3)
w
i
=
N
o
r
m
a
l
i
z
e
(
θ
i
+
1
−
θ
i
)
δ
T
i
\begin{equation} w_i = \frac{Normalize(\theta_{i+1} - \theta_i)}{\delta T_i} \tag{4} \end{equation}
wi=δTiNormalize(θi+1−θi)(4)
函数
N
o
r
m
a
l
i
z
e
(
)
Normalize()
Normalize()是把角度插值限定在[-pi,pi]之间,不然角速度就计算出错了, 线速度的计算不考虑正负的话直接求两个点的距离除时间就完事了,后续求加速度的时候才需要考虑正负线速度, 速度计算公式有了,对应的代价函数就好处理了
f
l
i
n
e
a
r
_
v
e
l
=
{
v
i
−
v
m
a
x
if
v
i
>
v
m
a
x
0
,
else
(5)
f_{linear\_vel} = \begin{cases} v_i - v_{max} & \text{if }v_i > v_{max} \\ 0, & \text{else} \end{cases}\tag{5}
flinear_vel={vi−vmax0,if vi>vmaxelse(5)
f a n g u l a r _ v e l = { ∣ w i ∣ − w m a x if ∣ w i ∣ > w m a x 0 , else (6) f_{angular\_vel} = \begin{cases} |w_i| - w_{max} & \text{if }|w_i| > w_{max} \\ 0, & \text{else} \end{cases}\tag{6} fangular_vel={∣wi∣−wmax0,if ∣wi∣>wmaxelse(6)
accleration constraint
v
a
c
c
i
=
2
(
v
i
+
1
−
v
i
)
δ
T
i
+
1
+
δ
T
i
\begin{equation} vacc_i = \frac{2(v_{i+1} - v_i)}{\delta T_{i+1} + \delta T_i} \tag{7} \end{equation}
vacci=δTi+1+δTi2(vi+1−vi)(7)
这里求线性加速度的时候就需要考虑线速度的正负了, 这里可以考虑使用点乘的方法来确定线速度的方向, 点乘
a
⋅
b
=
∥
a
∥
∥
b
∥
c
o
s
(
θ
)
a\cdot b = \|a\|\|b\|cos(\theta)
a⋅b=∥a∥∥b∥cos(θ), 几何含义是向量a在b上的投影乘b的模, 根据点乘的结果的正负来判断速度的方向, 点乘为正,则速度为正,反之为负数, 其中
θ
\theta
θ 是
x
i
x_i
xi上的航向
w
a
c
c
i
=
2
(
w
i
+
1
−
w
i
)
δ
T
i
+
1
+
δ
T
i
\begin{equation} wacc_i = \frac{2(w_{i+1} - w_i)}{\delta T_{i+1} + \delta T_i} \tag{8} \end{equation}
wacci=δTi+1+δTi2(wi+1−wi)(8)
同样加速度公式有了,代价函数也就可以写了
f
l
i
n
e
a
r
_
a
c
c
=
{
∣
v
a
c
c
i
∣
−
v
a
c
c
m
a
x
if
∣
v
a
c
c
i
∣
>
v
a
c
c
m
a
x
0
,
else
(9)
f_{linear\_acc} = \begin{cases} |vacc_i| - vacc_{max} & \text{if }|vacc_i| > vacc_{max} \\ 0, & \text{else} \end{cases}\tag{9}
flinear_acc={∣vacci∣−vaccmax0,if ∣vacci∣>vaccmaxelse(9)
f a n g u l a r _ a c c = { ∣ w a c c i ∣ − w a c c m a x if ∣ w a c c i ∣ > w a c c m a x 0 , else (10) f_{angular\_acc} = \begin{cases} |wacc_i| - wacc_{max} & \text{if }|wacc_i| > wacc_{max} \\ 0, & \text{else} \end{cases}\tag{10} fangular_acc={∣wacci∣−waccmax0,if ∣wacci∣>waccmaxelse(10)
non-holonomic kinematics
f
k
i
n
e
m
a
t
i
c
=
∣
(
cos
(
θ
i
+
1
)
+
cos
(
θ
i
)
)
⋅
d
x
[
1
]
−
(
sin
(
θ
i
+
1
)
+
sin
(
θ
i
)
)
⋅
d
x
[
0
]
∣
\begin{equation} f_{kinematic} = \left| (\cos(\theta_{i+1}) + \cos(\theta_i)) \cdot \mathbf{dx}[1] - (\sin(\theta_{i+1}) + \sin(\theta_i)) \cdot \mathbf{dx}[0] \right|\tag{11} \end{equation}
fkinematic=∣(cos(θi+1)+cos(θi))⋅dx[1]−(sin(θi+1)+sin(θi))⋅dx[0]∣(11)
公式中的
d
x
=
x
i
+
1
−
x
i
\mathbf{dx} = \mathbf{x_{i+1} - x_i}
dx=xi+1−xi, 这个代价函数的功能就是让参数
θ
\theta
θ要符合运动学约束,也就是把机器人的角度和位置给耦合在一起了,如果没有这个约束,
θ
,
x
i
\theta, \mathbf{x_i}
θ,xi这两个参数就不会有联系
fastest constraint
这个约束的目的就是让优化出来的轨迹在符合运动学约束的情况下, 轨迹的速度要尽可能大, 也就是 δ T i \delta T_i δTi尽可能小
f f a s t e s t = δ T i \begin{equation} f_{fastest} = \delta T_i\tag{12} \end{equation} ffastest=δTi(12)
shortest constraint
仅仅是有速度最快是不够的, 速度快不代表路径短,轨迹符合运动学的前提下,我们还希望轨迹越短越好
f f a s t e s t = ∣ ∣ x i − x i + 1 ∣ ∣ (13) \begin{equation} f_{fastest} = ||\mathbf{x_i} - \mathbf{x_{i+1}}|| \end{equation}\tag{13} ffastest=∣∣xi−xi+1∣∣(13)
jerk constraint
teb论文中是没有对机器人的jerk做约束的,但是实际使用上有的场合可能希望机器人运动的要平稳一点,速度不要突变, 所以我觉得jerk也是挺重要的
f j e r k = 3 ( a c c i + 1 − a c c i ) δ T i + δ T i + 1 + δ T i + 2 (14) \begin{equation} f_{jerk} = \frac{3(acc_{i+1} - acc_i)}{\delta T_i + \delta T_{i+1} + \delta T_{i+2}} \end{equation}\tag{14} fjerk=δTi+δTi+1+δTi+23(acci+1−acci)(14)
least square problem
所有代价函数都写好啦,现在剩下的就是如何把这些代价函数给建模成最小二乘问题,下面公式15就是我自己建模后的结果,其中n是路径点的个数, m是需要经过的点的个数, 公式中的
x
\mathbf{x}
x需要根据代价函数来确定, 比如安全约束中
x
=
x
i
\mathbf{x = x_i}
x=xi,线速度约束中
x
=
[
x
i
,
x
i
+
1
]
\mathbf{x = [x_i, x_{i+1}]}
x=[xi,xi+1], 运动学约束中
x
=
[
x
i
,
x
i
+
1
,
θ
i
,
θ
i
+
1
]
\mathbf{x = [x_i, x_{i+1}, \theta_i, \theta_{i+1}]}
x=[xi,xi+1,θi,θi+1]
min
x
∑
i
=
0
n
∥
f
i
(
x
)
∣
2
2
=
∑
i
=
0
n
f
s
a
f
e
t
y
i
(
x
)
2
+
∑
i
=
0
m
f
v
i
a
i
(
x
)
2
+
∑
i
=
0
n
−
1
f
l
i
n
e
a
r
_
v
e
l
i
(
x
)
2
+
∑
i
=
0
n
−
1
f
a
n
g
u
l
a
r
_
v
e
l
i
(
x
)
2
+
∑
i
=
0
n
−
2
f
l
i
n
e
a
r
_
a
c
c
i
(
x
)
2
+
∑
i
=
0
n
−
2
f
a
n
g
u
l
a
r
_
a
c
c
i
(
x
)
2
+
∑
i
=
0
n
−
3
f
j
e
r
k
i
(
x
)
2
+
∑
i
=
0
n
−
1
f
k
i
n
e
m
a
t
i
c
i
(
x
)
2
+
∑
i
=
0
n
−
1
f
f
a
s
t
e
s
t
i
(
x
)
2
+
∑
i
=
0
n
−
1
f
s
h
o
r
t
e
s
t
i
(
x
)
2
+
(15)
\begin{aligned} \min_{\mathbf{x}} \sum_{i=0}^n \|f_i(\mathbf{x})|_2^2 = &\sum_{i=0}^{n} f^{i}_{safety}(\mathbf{x})^2 + \sum_{i=0}^{m} f^{i}_{via}(\mathbf{x})^2 + \sum_{i=0}^{n-1} f^{i}_{linear\_vel}(\mathbf{x})^2 + \sum_{i=0}^{n-1} f^{i}_{angular\_vel}(\mathbf{x})^2 +\\ &\sum_{i=0}^{n-2} f^{i}_{linear\_acc}(\mathbf{x})^2 + \sum_{i=0}^{n-2} f^{i}_{angular\_acc}(\mathbf{x})^2 + \sum_{i=0}^{n-3} f^{i}_{jerk}(\mathbf{x})^2 + \sum_{i=0}^{n-1} f^{i}_{kinematic}(\mathbf{x})^2 + \\ &\sum_{i=0}^{n-1} f^{i}_{fastest}(\mathbf{x})^2 + \sum_{i=0}^{n-1} f^{i}_{shortest}(\mathbf{x})^2 + \end{aligned}\tag{15}
xmini=0∑n∥fi(x)∣22=i=0∑nfsafetyi(x)2+i=0∑mfviai(x)2+i=0∑n−1flinear_veli(x)2+i=0∑n−1fangular_veli(x)2+i=0∑n−2flinear_acci(x)2+i=0∑n−2fangular_acci(x)2+i=0∑n−3fjerki(x)2+i=0∑n−1fkinematici(x)2+i=0∑n−1ffastesti(x)2+i=0∑n−1fshortesti(x)2+(15)
teb开源算法使用的优化器是g2o,我觉得使用g2o太麻烦了,这里我采用的是ceres-solver的最小二乘求解器
experiment
本测试参数,最大角速度为0.35, 最大线速度为0.45, 最大角加速度和线加速度都是0.6
为了测试优化效果,我把优化时间,路径长度,线速度,角速度,加速度,加加速度的数据都画出来了
从上述图片很容易看得出来, 哪一个是轨迹是比较平滑的,我跑过teb的源码, 从rviz上看他的结果,路径还是挺光滑的,但是没有速度加速度方面的数据,也不知道速度会不会存在突变的情况,我自己实现的如果代价函数不包括jerk,轨迹速度变化会比较剧烈,不知道是否是参数没有调好, 加了jerk后参数轨迹就很平滑了, teb这个算法还是挺简单的,主要是建模部分,优化部分也不需要自己动手,调包就完事儿了。这个算法的速度对硬件要求比较高,并且优化时长随着路径点数量的增多(dt越小),优化需要的时间会相应增加。如果路径总长度大约在3m左右,优化的平均时间可以维持在50ms,这是在X86笔记本上,如果在一些比较垃圾的板子上,时间估计就的100ms+了
为什么叫弹性带算法呢? 请看视频
vokoscreen-2023-11-03_15-52-32