| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 人工智能 -> Apollo学习笔记(15)Mini-Snap -> 正文阅读 |
|
[人工智能]Apollo学习笔记(15)Mini-Snap |
1.背景知识机器人导航系统,是期望机器人从A点运动到B点,根据当前的物理环境规划出一条合适的路线,可以使得机器人可以移动到目标点的过程,就是运动规划。无人车其实也是机器人的一种,有着其独特的运动特性。 无人车的运动规划一般分为两个步骤:
一般来说,轨迹输出的方式都是用多项式来表示(五阶就可以了,有个大佬已经证明了这个结论,太高的阶增加了很大的计算量,对处理的结果改善却没有太大的作用):
p
(
t
)
=
p
0
+
p
1
t
+
p
2
t
2
…
+
p
n
t
n
=
∑
i
=
0
n
p
i
t
i
p(t)=p_{0}+p_{1}t+p_{2}t^{2} \ldots + p_{n}t^{n}=\displaystyle\sum_{i=0}^{n}p_{i}t^{i}
p(t)=p0?+p1?t+p2?t2…+pn?tn=i=0∑n?pi?ti 基于上式,可以根据参数计算出轨迹的位置
P
o
s
i
t
o
n
Positon
Positon,速度
V
e
l
o
c
i
t
y
Velocity
Velocity,加速度
A
c
c
e
l
e
r
a
t
i
o
n
Acceleration
Acceleration,加加速度
J
e
r
k
Jerk
Jerk,加加加速度
S
n
a
p
Snap
Snap,如下, 由于routing出的路点有很多个,很难找到一条多项式表示,为了保证多项式尽量能涵盖所有的路点(起码能最大层度上能拟合到所有的路点),所以将轨迹按时间分为很多段,每段都用一个多项式曲线来表示,如下, 此外,实际工程问题中的轨迹往往是多维度的,通常的做法是单独求每个维度的轨迹。 可以看出,轨迹规划的最终目标就是求解出不同时间段内的轨迹多项式的参数 p 1 , p 2 , … , p k p_1,p_2,\ldots,p_k p1?,p2?,…,pk?,同时,希望轨迹能满足一系列的约束条件,比如:设定起点和终点的位置、加速度、速度等,希望相邻的轨迹连接处足够平滑(位置连续,速度连续等),希望轨迹经过某些特定的路点,设定最大速度,最大加速度等,为了壁障还会希望轨迹在规定的空间内(corridor)。 通常,满足预先设定的约束的估计会有无数多个,而实际的工程问题中,往往需要满足特定条件的一条最优解,因此又会构建一个cost function,从而在可行的轨迹中找到一条最合适的特定轨迹。 因此,综上所述,我们就可以将目标问题就建立成了一个有约束的优化问题,如下:
m
i
n
f
(
p
)
,
s
.
t
.
A
e
q
=
b
e
q
,
A
i
e
q
=
b
i
e
q
min f(p), \hspace*{1em} s.t. \hspace*{0.5em} A_{eq}=b_{eq},A_{ieq}=b_{ieq}
minf(p),s.t.Aeq?=beq?,Aieq?=bieq? 看到这个公式,是不是有点激动,这不是又到了最优化控制的东西了吗?是的,没错,只要解出来这个方程,就可以求解出目标轨迹参数 p p p。剩下的就是将优化问题中的 A e q A_{eq} Aeq?, b e q b_{eq} beq?, A i e q A_{ieq} Aieq?, b i e q b_{ieq} bieq?详细参数列出来,使用优化求解器求解即可。 至于cost function的选择,既然文章名字叫做 Mini-Snap,那最小化的目标函数 snap(加加加速度)肯定是可以的,也有人使用acceleration(加速度)和jerk(加加速度),至于速度和位置这两个为什么不可以做cost目标,你可以想想一下车子蜗牛速度行驶的场景。。。。。。 2.实际应用首先给定包含起点在内的 k + 1 k+1 k+1个二维路点 ( x i , y i ) (x_i,y_i) (xi?,yi?),同时给定起始点的速度和加速度 v 0 , a 0 v_0,a_0 v0?,a0?,末端速度和加速度为 v e , a e v_e,a_e ve?,ae?,给定了时间T,然后需要根据以上的条件规划出一条经过所有点的平滑轨迹。 2.1初始轨迹分段与时间分配根据路径点,将轨迹分为k段,计算每段的距离,按距离平分时间T(匀速时间分配),得到时间序列 t 0 , t 1 , … , t k t_0,t_1,\ldots,t_k t0?,t1?,…,tk?。然后对 x , y x,y x,y维度单独规划轨迹。(后面都是单独讨论单一的维度) 在时间如何进行分配这一点上,这里稍微讨论一下,如果两个点之间的时间间隔太短,车辆可能由于自身的物理特性,导致在设置的间隔时间内无法到达下一个路点,而如果时间间隔设置的太大的话,很可能规划出的曲线会出现绕弯的情况,这两中情况都是我们不希望看到的。为了避免这个问题,时间分配的方法目前主流的大致有两种方式: 注意,这里的轨迹分段和时间分配都是初始分配,在迭代算法中,如果corridor check 和 feasiblility check 不满足条件,会插点或增大某一段时间,具体在后面有描述。 2.2构建优化函数Mini-Snap的优化函数为: min ? ∫ 0 T ( p ( 4 ) ( t ) ) 2 d t = min ? ∑ i = 1 k ∫ t i ? 1 t i ( p ( 4 ) ( t ) ) 2 d t = min ? ∑ i = 1 k ∫ t i ? 1 t i ( [ 0 , 0 , 0 , 0 , 24 , … , n ! ( n ? 4 ) ! t n ? 4 ] ? p ) T ( [ 0 , 0 , 0 , 0 , 24 , … , n ! ( n ? 4 ) ! t n ? 4 ] ? p ) ? d t = min ? ∑ i = 1 k p T ∫ t i ? 1 t i [ 0 , 0 , 0 , 0 , 24 , … , n ! ( n ? 4 ) ! t n ? 4 ] T [ 0 , 0 , 0 , 0 , 24 , … , n ! ( n ? 4 ) ! t n ? 4 ] d t ? p = min ? ∑ i = 1 k p T Q i p \min \int_{0}^{T}(p^{(4)}(t))^{2}dt=\min \displaystyle\sum_{i=1}^{k} \int_{t_{i}-1}^{t_{i}}(p^{(4)}(t))^{2}dt\\ =\min \displaystyle\sum_{i=1}^{k} \int_{t_{i}-1}^{t_{i}} ([0,0,0,0,24,\ldots,\frac{n!}{(n-4)!}t^{n-4}]\cdot p)^{T}([0,0,0,0,24,\ldots,\frac{n!}{(n-4)!}t^{n-4}]\cdot p) \space dt \\ =\min \displaystyle\sum_{i=1}^{k} p^{T} \int_{t_{i}-1}^{t_{i}} [0,0,0,0,24,\ldots,\frac{n!}{(n-4)!}t^{n-4}]^{T}[0,0,0,0,24,\ldots,\frac{n!}{(n-4)!}t^{n-4}] dt \space p \\ =\min \displaystyle\sum_{i=1}^{k} p^{T}Q_{i}p min∫0T?(p(4)(t))2dt=mini=1∑k?∫ti??1ti??(p(4)(t))2dt=mini=1∑k?∫ti??1ti??([0,0,0,0,24,…,(n?4)!n!?tn?4]?p)T([0,0,0,0,24,…,(n?4)!n!?tn?4]?p)?dt=mini=1∑k?pT∫ti??1ti??[0,0,0,0,24,…,(n?4)!n!?tn?4]T[0,0,0,0,24,…,(n?4)!n!?tn?4]dt?p=mini=1∑k?pTQi?p 式中, 注意:式中r为行索引,c为列索引,索引从0开始,第一行和第一列均为0。 因此有, 所以优化目标方程为, 2.3构建等式约束
合并所有的等式约束,有 上述等式约束的个数设定为: 3(起始位置pva)+(k-1)(中间点的p)+3(终点pva)+3(k-1)(中间点pva连续)=4k+2 这里需要注意的是,上述公式中 i i i的范围是从 1 1 1到 k ? 1 k-1 k?1,所以中间点的项和最后三个有 i i i的公式并不是一项。 2.4构建不等式约束不等式的约束和等式约束的设置方式类似,也是设置某个点的 p , v , a p,v,a p,v,a小于某一特定的值,从而构建 A i e q p ≤ b i e q A_{ieq}p \le b_{ieq} Aieq?p≤bieq?,不等式约束一般是在corridor中使用的比较多,后面会有详细的说明,这里就不赘述了。 2.5求解不等式建立之后,可以直接丢给非线性求解器求解,比如说Ipopt,OOQP等,具体的自己查一下非线性求解器。 2.6Matlab 例子这里还是借用大佬的代码,项目地址。 初始条件: 根据上述条件,生成 x , y x,y x,y两个维度的轨迹,合并后如下图所示(包含起始终止共5个点,用四段poly来描述,中间点也就是poly之间的交界点)。 从上图中可以看出,上图规划出的轨迹并不是很好,第二个和第三个路点之间还出现了打结的现象,另外y轴的最大加速度甚至到了20m/s,这明显超过了车辆的物理极限。造成这种现象的最主要的原因,是因为时间分配的不合理,至于时间分配的问题,下面会有详细的讨论。 因此实际轨迹需要进行 feasibility check (可行性检测),确保满足车辆的实际物理可行性,比如前轮偏角,加速度,jerk等。 3.corridor 与时间分配为了解决上述合理分配时间的问题,现在主要有两个四路:
3.1corridor为了限制规划出的轨迹的形状,引入了corridor的概念,就是人为的添加一条可行通道,如下图,使得规划出的轨迹必须在corridor内。其实也就是给QP问题加入了一个新的条件,这样就可以保证求解出的轨迹在corridor内了。 3.2corridor 如何添加很容易想到,把之前的等式约束 A p = d Ap=d Ap=d改成不等式约束 A p ≤ d 1 Ap \le d_1 Ap≤d1?和 A p ≥ d 2 Ap \ge d_2 Ap≥d2?。然而,不管是等式约束还是不等式约束,都是针对一个特定时刻,然而实际希望的是对所有的时刻 t ∈ [ 0 , T ] t \in [0,T] t∈[0,T],都需要在corridor中。 一个简单粗暴的思路:在路径上多采样一些中间点,每个中间点都加corridor约束。尽管这种方法理论上只能保证采样点在corridor中,但实际过程中,如果corridor大小和采样步长设置得合理,而且不Fix waypoints,能得到比较好效果。这里不固定中间点的位置,是为了去掉中间点的强约束,尽量避免轨迹打结,实际中,我们也是不一样要求轨迹完全经过中间点,只要在那附近(corridor)内就行。 3.3构造corridor不等式约束为了方便构造,对于每一个采样点
p
t
p_t
pt?,我们施加一个矩形的corridor,即, 这里用矩形corridor是因为斜线corridor(平行四边形)不太好构造,另外我们也只是需要大致放在corridor里面就可以了,对corridor的要求并不是非常的严格,没必要设置一个严格的斜线corridor。 对于每个采样点,设矩形corridor的边长为2r,增加两个位置不等式约束: [ 1 , t i , t i 2 , … , t i n ] ? p ≤ p ( t i ) + r [ ? 1 , ? t i , ? t i 2 , … , ? t i n ] ? p ≤ ? [ p ( t i ) + r ] [1,t_{i},t_{i}^{2},\ldots,t_{i}^{n}] \cdot p \le p(t_{i})+r \\ [-1,-t_{i},-t_{i}^{2},\ldots,-t_{i}^{n}] \cdot p \le -[p(t_{i})+r] \\ [1,ti?,ti2?,…,tin?]?p≤p(ti?)+r[?1,?ti?,?ti2?,…,?tin?]?p≤?[p(ti?)+r] 大佬的代码在这里:https://github.com/symao/minimum_snap_trajectory_generation 初始条件:
优化结果如下图所示,绿色的点为按固定步长新采样的中间点,每个中间点都有一个矩形corridor,红色为优化后的轨迹。 可以看到,去掉中间点的位置强约束(等式约束)改成弱约束(corridor不等式约束)后,轨迹比之前要好很多,而且尽管轨迹有小部分超出了corridor(因为只加了采样时刻的位置corridor约束),但基本不会超出太多。 针对这个问题,
3.4广义corridor上面介绍了位置corridor,也就是位置的不等式约束,同样的,corridor也适用于速度corridor、加速度 这样是不是就会想,通过这种方式来限制车辆行驶的速度和加速度了。不过,实际情况是,这么做并不合适。 为什么呢?举个简单的例子,假设一维空间规划一条轨迹从0到10,给定总时间T=1s,要求最大限速2m/s,满足要求的轨迹根本不存在,即使你加很多中间点并加速度corridor,得到的轨迹在采样点中间肯定会速度蹭的巨高。 速度、加速度之所以很大,是因为时间给的不合理(时间太小),所以,这种情况光靠加corridor是行不通的,还是要从时间分配的层面来解决。 4.时间分配时间分配是轨迹规划中很关键的一个问题,会直接影响到规划结果的好坏。 4.1初始时间分配
设各段的时间分别为
t
1
′
,
t
2
′
,
…
,
t
n
′
t_{1}^{'},t_{2}^{'},\ldots,t_{n}^{'}
t1′?,t2′?,…,tn′?,前
k
k
k项之和就可以得到轨迹分段的时刻向量: 4.2feasibility check有了时间分配,就可以规划得到轨迹参数,对于轨迹参数,求速度和加速度曲线的极值,判断是否超过最大限幅,如果所有极值都小于最大限幅,则得到可行轨迹。如果不满足,则需要调整该段的时间。 调整的方法是:增大unfeasible段poly的时间,显然,增大时间会使得速度和加速度都变小。通常以一个固定的比例来调整时间如(k=1.2~1.5),并进行迭代,每调整一次,重新规划轨迹并check feasibility,如若不满足,再次加大时间,直至满足为止。 4.3corridor与时间分配的关联不等式corridor约束实际上也有时间分配的效果,可以这么想,polynomial的分段点(轨迹中间点)在corridor内移动,实际上就相当于分段点的时刻在移动,中间点在corridor内移动,也就变相调整了前后两段poly分配的时间。 举个简单的例子,如下图所示,两段轨迹的分段点为 a a a,初始时间分配为 t 1 , t 2 t1,t2 t1,t2,比如说想减少前一段的时间 t 1 t1 t1,加大后一段的时间 t 2 t2 t2,其实就相当于把分段点 a a a向右挪。也就是说,还是前段poly仍然分配 t 1 t1 t1时间,但走的路程更多了(相当于原来路程所用的时间减少了),后一段poly在 t 2 t2 t2时间走的路程更少了(相当于原来的路程所用时间增加了)。 所以,如果corridor比较大的话,时间调整的空间就会更大,规划出的轨迹会更加的平滑。 4.4归一化时间参数轨迹规划中容易出现一些数值问题,比如需要求t的高阶指数,如果t比较大,计算数值就会很大,而且最终轨迹的参数会很小,特别是高阶项系数,比如很有可能小于float的精度,所以一般计算过程中最好用double。 但还有一种办法,是把轨迹参数做时间归一化,将时间归一化到 [ 0 , 1 ] [0,1] [0,1]之间。 设未归一化的轨迹
p
(
t
)
=
p
0
+
p
1
t
+
…
+
p
n
t
n
p(t)=p_0+p_1t+\ldots+p_nt^n
p(t)=p0?+p1?t+…+pn?tn,令时间
t
 ̄
=
t
/
T
\overline{t}=t/T
t=t/T,则 其中, p  ̄ i = p i × T i \overline{p}_{i}=p_{i} \times T^{i} p?i?=pi?×Ti, T T T为轨迹总时间, [ p  ̄ i ] i = 0 → n [\overline p_{i}]_{i=0 \to n} [p?i?]i=0→n?就是归一化时间的轨迹参数,它们不像非归一化参数那么小,便于参数传递。 对于任意时刻
t
t
t,先除以总时间
T
T
T得到归一化时间
t
 ̄
\overline{t}
t, 注意:归一化事件参数后,位置计算和原来相同,但速度计算需要除以 T T T,加速度需要除以 T 2 T^{2} T2,即每求一阶导需要除以一个 T T T。 5.闭式求解如果QP问题只有等式约束没有不等式约束,那么是可以闭式求解(close form)的。闭式求解效率要快很多,而且只需要用到矩阵运算,不需要QPsolver。 5.1QP等式约束构建闭式求解的
Q
Q
Q矩阵和之前的一样,请看上面的文章,但约束的形式与之前略为不同,在之前的方法中,等式约束只要构造成
A
e
q
?
p
=
b
A_{eq}\cdot p =b
Aeq??p=b的形式就可以了,而闭式求解中,每段轨迹都可以构造成 其中, d 0 d_0 d0?, d T d_T dT?为第 i i i段poly的起点和终点的各阶导数组成的向量,比如只考虑 p v a pva pva时: d 0 = [ p 0 , v 0 , a 0 ] T d_0=[p_0,v_0,a_0]^T d0?=[p0?,v0?,a0?]T,当然也可以把更高阶的jerk,snap加入到向量。 注意:不管每段的 p v a pva pva是否已知,都要写到向量中。 合并各段轨迹的约束方程得到 上式中, k k k为轨迹段数, n n n为轨迹阶数,设值考虑 p v a pva pva,这里的 A t o t a l A_{total} Atotal?的阶数为 ( n + 1 ) k × 6 k (n+1)k \times 6k (n+1)k×6k。 这里为了简化,没有把每段poly的时间戳都改成从0开始,但是实际使用中,为了避免时间戳太大引起的数值问题,每段poly 的时间戳都是设置成从0开始的。 从上式可以看出, A t o t a l A_{total} Atotal?是已知的,而 d d d中只有少部分(起点、终点的 p v a pva pva)是已知的,其他的大部分是未知的。如果可以求出 d d d,那么轨迹的参数 p p p可以通过 p = A ? 1 d p=A^{-1}d p=A?1d直接求出。 5.2求解d闭式法的思路是:将 d d d向量中的变量分成两部分:” d d d中所有已知量组成的Fix部分 d F d_{F} dF?”和”所有未知量组成的Free部分 d P d_{P} dP?”。然后通过推导,根据 d F d_{F} dF?求得 d P d_{P} dP?,从而得到 d d d,最后求得 p p p。 下面介绍整个推导过程。 5.2.1消除重复变量(连续性约束)可以会发现,上面构造等式约束时,并没有加入连续性约束,连续性约束并不是直接加到等式约束中。 因此需要一个映射矩阵将一个变量映射到两个重复的变量上,怎么映射?
因此,构造映射矩阵
M
6
k
×
3
(
k
+
1
)
M_{6k\times 3(k+1)}
M6k×3(k+1)?: 即 d = M d ′ d=Md^{'} d=Md′。 5.2.2向量元素置换消除掉重复变量之后,需要调整
d
′
d^{'}
d′中的变量,把fix部分和free部分分开排列,可以构成一个置换矩阵
C
C
C,使得: 那么 C C C矩阵如何构造?
[ a b c d ] = [ 1 0 0 0 0 0 0 1 0 1 0 0 0 0 1 0 ] ? C [ a c d b ] \begin{bmatrix} a \\ b \\ c \\ d \\ \end{bmatrix}=\underbrace{ \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ \end{bmatrix}}_{C} \begin{bmatrix} a \\ c \\ d \\ b \\ \end{bmatrix} ?????abcd??????=C ?????1000?0010?0001?0100?????????????acdb?????? 5.2.3 转成无约束优化问题由上面两步可得 代入优化函数 Q 对 称 ? R 对 称 ? = d F T R F F d F + 2 d F T R F P d P + d P T R P P d P Q对称 \Rarr R对称 \Rarr =d^{T}_{F}R_{FF}d_{F}+2d^{T}_{F}R_{FP}d_{P}+d^{T}_{P}R_{PP}d_{P} Q对称?R对称?=dFT?RFF?dF?+2dFT?RFP?dP?+dPT?RPP?dP? 令 J J J对 d P d_{P} dP?的倒数 ? J ? d P = 0 \frac{\partial J}{\partial d_{P}}=0 ?dP??J?=0,则有极值点, 2 d F T R F P + d P T R P P d P = 0 d P = ? R P P ? 1 R F P T d F 2d^{T}_{F}R_{FP}+d^{T}_{P}R_{PP}d_{P}=0 \\ d_{P}=-R_{PP}^{-1}R_{FP}^{T}d_{F} 2dFT?RFP?+dPT?RPP?dP?=0dP?=?RPP?1?RFPT?dF? 5.3闭式求解步骤现在做一下总结:
在对计算效率要求比较高或者不想用QPsolver时,可以使用闭式法求解。最后附上大神的代码。 参考文献:
|
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/27 0:26:11- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |