从零开始实现TEB局部轨迹规划算法(优化器基于ceres-solver)

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={(xioidmin),0,if xioi<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=∣∣xip∣∣(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+1xi∣∣(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={vivmax0,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={wiwmax0,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+1vi)(7)
这里求线性加速度的时候就需要考虑线速度的正负了, 这里可以考虑使用点乘的方法来确定线速度的方向, 点乘 a ⋅ b = ∥ a ∥ ∥ b ∥ c o s ( θ ) a\cdot b = \|a\|\|b\|cos(\theta) ab=a∥∥bcos(θ), 几何含义是向量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+1wi)(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={vaccivaccmax0,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={wacciwaccmax0,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+1xi, 这个代价函数的功能就是让参数 θ \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=∣∣xixi+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+1acci)(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=0nfi(x)22=i=0nfsafetyi(x)2+i=0mfviai(x)2+i=0n1flinear_veli(x)2+i=0n1fangular_veli(x)2+i=0n2flinear_acci(x)2+i=0n2fangular_acci(x)2+i=0n3fjerki(x)2+i=0n1fkinematici(x)2+i=0n1ffastesti(x)2+i=0n1fshortesti(x)2+(15)
teb开源算法使用的优化器是g2o,我觉得使用g2o太麻烦了,这里我采用的是ceres-solver的最小二乘求解器

experiment

本测试参数,最大角速度为0.35, 最大线速度为0.45, 最大角加速度和线加速度都是0.6
为了测试优化效果,我把优化时间,路径长度,线速度,角速度,加速度,加加速度的数据都画出来了

with jerk

在这里插入图片描述

在这里插入图片描述在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

从上述图片很容易看得出来, 哪一个是轨迹是比较平滑的,我跑过teb的源码, 从rviz上看他的结果,路径还是挺光滑的,但是没有速度加速度方面的数据,也不知道速度会不会存在突变的情况,我自己实现的如果代价函数不包括jerk,轨迹速度变化会比较剧烈,不知道是否是参数没有调好, 加了jerk后参数轨迹就很平滑了, teb这个算法还是挺简单的,主要是建模部分,优化部分也不需要自己动手,调包就完事儿了。这个算法的速度对硬件要求比较高,并且优化时长随着路径点数量的增多(dt越小),优化需要的时间会相应增加。如果路径总长度大约在3m左右,优化的平均时间可以维持在50ms,这是在X86笔记本上,如果在一些比较垃圾的板子上,时间估计就的100ms+了

为什么叫弹性带算法呢? 请看视频

vokoscreen-2023-11-03_15-52-32

reference

C. Rösmann, W. Feiten, T. Wösch, F. Hoffmann and T. Bertram: Trajectory modification considering dynamic constraints of autonomous robots. Proc. 7th German Conference on Robotics, Germany, Munich, May 2012, pp 74–79.

C. Rösmann, W. Feiten, T. Wösch, F. Hoffmann and T. Bertram: Efficient trajectory optimization using a sparse model. Proc. IEEE European Conference on Mobile Robots, Spain, Barcelona, Sept. 2013, pp. 138–143.

http://ceres-solver.org/tutorial.html

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值