轨迹优化 | Minimum-jerk

使用路径规划可以得到一系列的路径点,如下图所示有5个路径点,这条路径是很曲折的,这不利于机器人的移动,试想一个机器人直接沿着这条路径进行移动,当到达一个路径点后速度减到零,原地旋转,指向下一个路径点,再继续移动,这不仅智障,而且浪费能量。于是我们就想,能不能规划出一条轨迹,使机器人能够在每一个路径点处能够平滑过渡,从而表现得机灵一点。这就是轨迹规划问题。

轨迹优化 | Minimum-jerk_第1张图片 轨迹优化 | Minimum-jerk_第2张图片
路径规划得到的路径点 轨迹优化得到的轨迹(橙色)

二次规划(Quadratic Programming, QP)

由于轨迹规划问题可以归结为一个二次规划问题,所以这里先对二次规划进行一个简单的介绍

二次型

含有 n n n个变量 x = x 1 , x 2 , ⋯   , x n − 1 , x n x=x_1,x_2,\cdots,x_{n-1},x_n x=x1,x2,,xn1,xn的二次齐次函数:
f ( x 1 , x 2 , ⋯   , x n ) = a 11 x 1 2 + a 22 x 2 2 + ⋯ + a n n x n 2 + 2 a 12 x 1 x 2 + 2 a 13 x 1 x 3 + ⋯ + 2 a n − 1 , n x n − 1 x n \begin{aligned} f(x_1,x_2,\cdots,x_n)&=a_{11}x_1^2+a_{22}x_2^2+\cdots+a_{nn}x_n^2\\ &+2a_{12}x_1x_2+2a_{13}x_1x_3+\cdots+2a_{n-1,n}x_{n-1}x_n \end{aligned} f(x1,x2,,xn)=a11x12+a22x22++annxn2+2a12x1x2+2a13x1x3++2an1,nxn1xn
称为二次型。取 a i j = a j i a_{ij}=a_{ji} aij=aji,则有 2 a i j x i x j = a i j x i x j + a j i x j x i 2a_{ij}x_ix_j=a_{ij}x_ix_j+a_{ji}x_jx_i 2aijxixj=aijxixj+ajixjxi,上式可表示为:
f = ∑ i , j = 1 n a i j x i x j f=\sum_{i,j=1}^na_{ij}x_ix_j f=i,j=1naijxixj
矩阵表示为:
f = x T A x f=x^TAx f=xTAx

二次规划问题

当目标函数 f f f为二次型,且约束为线性约束时,该优化问题就是二次规划问题,一般形式表述如下:
m i n x f ( x ) = 1 2 x T Q x + q T x s . t . A x = b G x ≤ h \begin{aligned} \mathop{min}\limits_{x} f(x)&=\frac{1}{2}x^TQx+q^Tx\\ s.t. Ax&=b\\ Gx&≤h \end{aligned} xminf(x)s.t.AxGx=21xTQx+qTx=bh
二次规划是一类凸优化问题,目前有很多商业或者开源的求解器来求解这类问题,不再赘述

轨迹表示形式

使用路径规划可以得到一系列的路径点,这些路径点是不带时间信息的,而轨迹则是时间 t t t的函数,一般用 n n n阶多项式表示,即:
f ( t ) = p 0 + p 1 t + p 2 t 2 + ⋯ + p n t n = ∑ i = 0 n p i t i \begin{aligned} f(t)&=p_0+p_1t+p_2t^2+\cdots+p_nt^n\\ &=\sum_{i=0}^np_it^i \end{aligned} f(t)=p0+p1t+p2t2++pntn=i=0npiti

其中 p 0 , p 1 , ⋯   , p n p_0,p_1,\cdots,p_n p0,p1,,pn是轨迹参数,也是我们的优化参数。将 f ( t ) f(t) f(t)写成向量相乘形式,得到:
f ( t ) = [ 1 t ⋯ t n ] [ p 0 p 1 ⋮ p n ] f(t)=\begin{bmatrix}1&t&\cdots&t^n\end{bmatrix}\begin{bmatrix}p_0\\p_1\\\vdots\\p_n\end{bmatrix} f(t)=[1ttn]p0p1pn
对轨迹函数求导,还能写出速度、加速度、jerk等参数随时间变化的函数:

v e l ( t ) = f ( 1 ) ( t ) = [ 0 1 2 t 3 t 2 ⋯ n ! ( n − 1 ) ! t n − 1 ] ⋅ p a c c ( t ) = f ( 2 ) ( t ) = [ 0 0 2 6 t ⋯ n ! ( n − 2 ) ! t n − 2 ] ⋅ p j e r k ( t ) = f ( 3 ) ( t ) = [ 0 0 0 6 ⋯ n ! ( n − 3 ) ! t n − 3 ] ⋅ p \begin{aligned} vel(t)&=f^{(1)}(t)=\begin{bmatrix}0&1&2t&3t^2&\cdots&\frac{n!}{(n-1)!}t^{n-1}\end{bmatrix}\cdot p\\ acc(t)&=f^{(2)}(t)=\begin{bmatrix}0&0&2&6t&\cdots&\frac{n!}{(n-2)!}t^{n-2}\end{bmatrix}\cdot p\\ jerk(t)&=f^{(3)}(t)=\begin{bmatrix}0&0&0&6&\cdots&\frac{n!}{(n-3)!}t^{n-3}\end{bmatrix}\cdot p\\ \end{aligned} vel(t)acc(t)jerk(t)=f(1)(t)=[012t3t2(n1)!n!tn1]p=f(2)(t)=[0026t(n2)!n!tn2]p=f(3)(t)=[0006(n3)!n!tn3]p
其中: p = [ p 0 p 1 ⋯ p n ] T p=\begin{bmatrix}p_0&p_1&\cdots&p_n\end{bmatrix}^T p=[p0p1pn]T,概括得到轨迹导数的通式, k k k表示 k k k阶导数:
f ( k ) ( t ) = [ 0 0 ⋯ 0 ⏞ k ( k + 0 ) ! 0 ! t 0 ( k + 1 ) ! 1 ! t 1 ( k + 2 ) ! 2 ! t 2 ⋯ n ! ( n − k ) ! t n − k ⏞ n-k+1 ] ⋅ p f^{(k)}(t)=\begin{bmatrix} \overbrace {\begin{matrix}0&0&\cdots&0\end{matrix}}^\text{k} &\overbrace {\begin{matrix}\frac{(k+0)!}{0!}t^{0}&\frac{(k+1)!}{1!}t^{1}&\frac{(k+2)!}{2!}t^{2}&\cdots &\frac{n!}{(n-k)!}t^{n-k}\end{matrix}}^\text{n-k+1} \end{bmatrix}\cdot p f(k)(t)=[000 k0!(k+0)!t01!(k+1)!t12!(k+2)!t2(nk)!n!tnk n-k+1]p
一段复杂的轨迹常常需要用多个多项式来表示,可以将完整轨迹按照时间划分成多段,如下,将完整轨迹划分为 M M M段多项式轨迹:
f ( t ) = { p 1 , 0 + p 1 , 1 t + p 1 , 2 t 2 + ⋯ + p 1 , n t n T 0 ≤ t ≤ T 1 p 2 , 0 + p 2 , 1 t + p 2 , 2 t 2 + ⋯ + p 2 , n t n T 1 ≤ t ≤ T 2 ⋮ p M , 0 + p M , 1 t + p M , 2 t 2 + ⋯ + p M , n t n T M − 1 ≤ t < T M f(t)=\begin{cases} \begin{matrix} p_{1,0}+p_{1,1}t+p_{1,2}t^2+\cdots+p_{1,n}t^n&T_0≤t≤T_1\\ p_{2,0}+p_{2,1}t+p_{2,2}t^2+\cdots+p_{2,n}t^n&T_1≤t≤T_2\\ \vdots\\ p_{M,0}+p_{M,1}t+p_{M,2}t^2+\cdots+p_{M,n}t^n&T_{M-1}≤tf(t)=p1,0+p1,1t+p1,2t2++p1,ntnp2,0+p2,1t+p2,2t2++p2,ntnpM,0+pM,1t+pM,2t2++pM,ntnT0tT1T1tT2TM1t<TM
其中: p i , j p_{i,j} pi,j表示第 i i i段轨迹的第 j j j个参数,每段轨迹的时长都是预先分配好的,分配方法以后再叙述,本文暂时设置为固定值

Minimum-jerk

以下将以Minimum-jerk算法为例来介绍轨迹优化算法的设计流程,Minimum-snap等算法的设计流程与之同理。

Minimum-jerk,顾名思义就是求解每段轨迹的系数 p p p使得总的jerk最小,同时还要满足约束条件,所以这是一个带约束的最优化问题,通过后面的证明知道,它其实是一个二次规划问题。

多项式阶次选择

jerk是轨迹 f ( t ) f(t) f(t)的3阶导数,所以令 K = 3 K=3 K=3。Minimum-jerk会直接对首尾的位置、速度和加速度进行约束,这就有6个等式约束了,所以优化参数必须提供6个以上的自由度,而5阶多项式有6个系数,所以符合要求的多项式的最小阶次为 O r d e r = 5 Order=5 Order=5。同理Minimum-snap还会对首尾的jerk进行约束,所以Minimum-snap的多项式最小阶数为 7 7 7

因此可以选择五阶多项式来表示每一段轨迹,得到:
f ( t ) = { p 1 , 0 + p 1 , 1 t + p 1 , 2 t 2 + p 1 , 3 t 3 + p 1 , 4 t 4 + p 1 , 5 t 5 T 0 ≤ t ≤ T 1 p 2 , 0 + p 2 , 1 t + p 2 , 2 t 2 + p 2 , 3 t 3 + p 2 , 4 t 4 + p 2 , 5 t 5 T 1 ≤ t ≤ T 2 ⋮ p M , 0 + p M , 1 t + p M , 2 t 2 + p M , 3 t 3 + p M , 4 t 4 + p M , 5 t 5 T M − 1 ≤ t < T M f(t)=\begin{cases} \begin{matrix} p_{1,0}+p_{1,1}t+p_{1,2}t^2+p_{1,3}t^3+p_{1,4}t^4+p_{1,5}t^5&T_0≤t≤T_1\\ p_{2,0}+p_{2,1}t+p_{2,2}t^2+p_{2,3}t^3+p_{2,4}t^4+p_{2,5}t^5&T_1≤t≤T_2\\ \vdots\\ p_{M,0}+p_{M,1}t+p_{M,2}t^2+p_{M,3}t^3+p_{M,4}t^4+p_{M,5}t^5&T_{M-1}≤tf(t)=p1,0+p1,1t+p1,2t2+p1,3t3+p1,4t4+p1,5t5p2,0+p2,1t+p2,2t2+p2,3t3+p2,4t4+p2,5t5pM,0+pM,1t+pM,2t2+pM,3t3+pM,4t4+pM,5t5T0tT1T1tT2TM1t<TM
其中包含 M M M段多项式轨迹,每一段多项式轨迹有 O r d e r + 1 = 6 Order+1=6 Order+1=6个系数,一共有 M ( O r d e r + 1 ) = 6 M M(Order+1)=6M M(Order+1)=6M个系数

构造目标函数

j e r k ( t ) jerk(t) jerk(t)可表示为:
j e r k ( t ) = f ( 3 ) ( t ) = 6 p 3 + 24 t p 4 + 60 t 2 p 5 = [ 0 0 0 6 24 t 60 t 2 ] ⋅ p \begin{aligned} jerk(t)=f^{(3)}(t)&=6p_3+24tp_4+60t^2p_5\\ &=\begin{bmatrix}0&0&0&6&24t&60t^2\end{bmatrix}\cdot p \end{aligned} jerk(t)=f(3)(t)=6p3+24tp4+60t2p5=[000624t60t2]p
要使其最小,也就是使 j e r k ( t ) jerk(t) jerk(t)在整段时间上的积分最小,在minimum-jerk中选择使 j e r k ( t ) jerk(t) jerk(t)的2-范数最小即:
m i n p f ( 3 ) ( t ) = m i n p ∑ i = 1 M ∫ T i − 1 T i ( f ( 3 ) ( t ) ) 2 d t \mathop{min}\limits_{p} f^{(3)}(t)=\mathop{min}\limits_{p}\sum_{i=1}^M\int_{T_{i-1}}^{T_i}(f^{(3)}(t))^2dt pminf(3)(t)=pmini=1MTi1Ti(f(3)(t))2dt
所以目标函数 J ( p ) J(p) J(p)定义如下:
J ( p ) = ∑ i = 1 M ∫ T i − 1 T i ( f ( 3 ) ( t ) ) 2 d t J(p)=\sum_{i=1}^M\int_{T_{i-1}}^{T_i}(f^{(3)}(t))^2dt J(p)=i=1MTi1Ti(f(3)(t))2dt

a = [ 0 0 0 6 24 t 60 t 2 ] T a=\begin{bmatrix}0&0&0&6&24t&60t^2\end{bmatrix}^T a=[000624t60t2]T,对 f ( 3 ) ( t ) f^{(3)}(t) f(3)(t)求平方,得到:
( f ( 3 ) ( t ) ) 2 = ( [ 0 0 0 6 24 t 60 t 2 ] ⋅ p ) T ( [ 0 0 0 6 24 t 60 t 2 ] ⋅ p ) = ( a T p ) T ( a T p ) = p T a a T p \begin{aligned} (f^{(3)}(t))^2&=(\begin{bmatrix}0&0&0&6&24t&60t^2\end{bmatrix}\cdot p)^T(\begin{bmatrix}0&0&0&6&24t&60t^2\end{bmatrix}\cdot p)\\ &=(a^Tp)^T(a^Tp)\\ &=p^Taa^Tp \end{aligned} (f(3)(t))2=([000624t60t2]p)T([000624t60t2]p)=(aTp)T(aTp)=pTaaTp
A ( t ) = a a T A(t) = aa^T A(t)=aaT,得到:
A = a a T = [ 0 0 0 6 24 t 60 t 2 ] [ 0 0 0 6 24 t 60 t 2 ] = [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 144 t 360 t 2 0 0 0 144 t 576 t 2 1440 t 3 0 0 0 360 t 2 1440 t 3 3600 t 4 ] \begin{aligned} A=aa^T=\begin{bmatrix}0\\0\\0\\6\\24t\\60t^2\end{bmatrix}\begin{bmatrix}0&0&0&6&24t&60t^2\end{bmatrix} =\begin{bmatrix} 0&0&0&0&0&0\\0&0&0&0&0&0\\0&0&0&0&0&0\\ 0&0&0&36&144t&360t^2\\ 0&0&0&144t&576t^2&1440t^3\\ 0&0&0&360t^2&1440t^3&3600t^4 \end{bmatrix} \end{aligned} A=aaT=000624t60t2[000624t60t2]=00000000000000000000036144t360t2000144t576t21440t3000360t21440t33600t4
所以 ( f ( 3 ) ( t ) ) 2 (f^{(3)}(t))^2 (f(3)(t))2的积分为:
∫ T i − 1 T i ( f ( 3 ) ( t ) ) 2 d t = ∫ T i − 1 T i p T A ( t ) p d t = p T ⋅ ∫ T i − 1 T i A ( t ) d t ⋅ p \begin{aligned} \int_{T_{i-1}}^{T_i}(f^{(3)}(t))^2dt&=\int_{T_{i-1}}^{T_i}p^TA(t)pdt\\ &=p^T\cdot \int_{T_{i-1}}^{T_i}A(t)dt\cdot p \end{aligned} Ti1Ti(f(3)(t))2dt=Ti1TipTA(t)pdt=pTTi1TiA(t)dtp
A ( t ) A(t) A(t)的积分为矩阵 Q Q Q,则:
Q = ∫ T i − 1 T i A ( t ) d t = [ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 36 t 72 t 2 120 t 3 0 0 0 72 t 2 192 t 3 360 t 4 0 0 0 120 t 3 360 t 4 720 t 5 ] T i − 1 T i Q=\int_{T_{i-1}}^{T_i}A(t)dt=\begin{bmatrix} 0&0&0&0&0&0\\0&0&0&0&0&0\\0&0&0&0&0&0\\ 0&0&0&36t&72t^2&120t^3\\ 0&0&0&72t^2&192t^3&360t^4\\ 0&0&0&120t^3&360t^4&720t^5 \end{bmatrix}^{T_i}_{T_{i-1}} Q=Ti1TiA(t)dt=00000000000000000000036t72t2120t300072t2192t3360t4000120t3360t4720t5Ti1Ti
最终的目标函数可表述为:
J ( p ) = ∑ i = 1 M ∫ T i − 1 T i ( f ( 3 ) ( t ) ) 2 = ∑ i = 1 M p i T Q i p i = [ p 1 T p 2 T ⋯ p M T ] [ Q 1 Q 2 ⋱ Q M ] [ p 1 p 2 ⋮ p M ] = p T Q p \begin{aligned} J(p)&=\sum_{i=1}^M\int_{T_{i-1}}^{T_i}(f^{(3)}(t))^2\\ &=\sum_{i=1}^Mp_i^TQ_ip_i\\ &=\begin{bmatrix}p_1^T&p_2^T&\cdots&p_M^T\end{bmatrix} \begin{bmatrix}Q_1&&&\\&Q_2&&\\ &&\ddots&\\ &&&Q_M\end{bmatrix} \begin{bmatrix}p_1\\p_2\\\vdots\\p_M\end{bmatrix}\\ &=p^TQp \end{aligned} J(p)=i=1MTi1Ti(f(3)(t))2=i=1MpiTQipi=[p1Tp2TpMT]Q1Q2QMp1p2pM=pTQp
其中:

  • p = [ p 1 T p 2 T ⋯ p M T ] T = [ p 1 , 0 p 1 , 1 ⋯ p 1 , K p 2 , 0 ⋯ p M , K ] T p=\begin{bmatrix}p_1^T&p_2^T&\cdots&&p_M^T\end{bmatrix}^T=\begin{bmatrix}p_{1,0}&p_{1,1}&\cdots&p_{1,K}&p_{2,0}&\cdots&&p_{M,K}\end{bmatrix}^T p=[p1Tp2TpMT]T=[p1,0p1,1p1,Kp2,0pM,K]T是优化变量,它是每一段多项式轨迹系数的列组合,其维数为 M ( O r d e r + 1 ) × 1 M(Order+1)\times1 M(Order+1)×1
  • Q是一个维数为 M ( O r d e r + 1 ) × M ( O r d e r + 1 ) M(Order+1)\times M(Order+1) M(Order+1)×M(Order+1)的实对称矩阵

显然, J ( p ) J(p) J(p)是一个二次型,所以基于Minimum-jerk的轨迹优化问题可以转换为一个二次规划问题

以上定义了Minimum-jerk中的目标函数,接下来添加约束。如果不考虑障碍物,主要有两类约束,一类是导数约束(Derivative Constraint),它约束了轨迹的初始状态和终止状态,以及每一段轨迹的开始/结束位置,也就是用路径规划得到的路径点对轨迹进行约束;另一类约束是连续性约束(Continuity Constraint),它可以使相邻轨迹平滑过渡。

导数约束

包含以下约束:

  • 初始状态和终止状态约束,如位置、速度、加速度等状态,即: { f ( k ) ( T 0 ) = x 0 ( k ) f ( k ) ( T M ) = x M ( k ) , k = 0 , 1 , ⋯   , K − 1 \begin{cases}f^{(k)}(T_0)=x_0^{(k)}\\f^{(k)}(T_M)=x_M^{(k)}\end{cases},k=0, 1,\cdots,K-1 {f(k)(T0)=x0(k)f(k)(TM)=xM(k),k=0,1,,K1
  • 每一段轨迹的初始位置由路径点给出,也即: f i ( T i − 1 ) = x i − 1 f_i(T_{i-1})=x_{i-1} fi(Ti1)=xi1 i i i表示第 i i i段轨迹,取值为 i = 2 , 3 , ⋯   , M i=2,3,\cdots,M i=2,3,,M

其中 x 0 , x 1 , ⋯   , x M x_0, x_1,\cdots,x_M x0,x1,,xM表示路径规划得到的路径点。

对于有 M + 1 M+1 M+1个路径点的轨迹,一共有 ( 2 K + M − 1 ) (2K+M-1) (2K+M1)个导数约束

连续性约束

在两段轨迹的连接点处,我们希望这个点处的轨迹是平滑的,可以通过施加连续性约束来实现这个要求,也就是使相邻两段轨迹在连接点处的 0 , 1 , ⋯   , K − 1 0,1,\cdots,K-1 0,1,,K1阶导数分别相等,即:
f i ( T i ) = f i + 1 ( T i ) f i ( 1 ) ( T i ) = f i + 1 ( 1 ) ( T i ) ⋮ f i ( k ) ( T i ) = f i + 1 ( k ) ( T i ) \begin{matrix} f_i(T_{i})=f_{i+1}(T_{i})\\ f_i^{(1)}(T_{i})=f_{i+1}^{(1)}(T_{i})\\ \vdots\\ f_i^{(k)}(T_{i})=f_{i+1}^{(k)}(T_{i})\\ \end{matrix} fi(Ti)=fi+1(Ti)fi(1)(Ti)=fi+1(1)(Ti)fi(k)(Ti)=fi+1(k)(Ti)
其中 i i i表示第 i i i段轨迹,取值为 i = 1 , 2 , ⋯   , M − 1 i=1, 2, \cdots, M-1 i=1,2,,M1,对于有 M + 1 M+1 M+1个路径点的轨迹,一共有 M M M段多项式轨迹,其中的连续性约束一共有 K ( M − 1 ) K(M-1) K(M1)个。

对于Minimum-jerk,要求每一段轨迹连接处的位置、速度、加速度一致,也就是:
f i ( T i ) = f i + 1 ( T i ) f i ( 1 ) ( T i ) = f i + 1 ( 1 ) ( T i ) f i ( 2 ) ( T i ) = f i + 1 ( 2 ) ( T i ) \begin{matrix} f_i(T_{i})=f_{i+1}(T_{i})\\ f_i^{(1)}(T_{i})=f_{i+1}^{(1)}(T_{i})\\ f_i^{(2)}(T_{i})=f_{i+1}^{(2)}(T_{i})\\ \end{matrix} fi(Ti)=fi+1(Ti)fi(1)(Ti)=fi+1(1)(Ti)fi(2)(Ti)=fi+1(2)(Ti)

编程实现

使用Python实现一维的Minimum-jerk算法,其中求解二次规划问题需要用到cvxopt库,安装方法:

pip install cvxopt

完整程序如下:

# -*- coding: utf-8 -*-
"""
Created on Fri Dec 10 2021
一维轨迹优化
@author: ghowoght
"""
#%% 生成路径点
import numpy as np
import matplotlib.pyplot as plt

path = [[1, 3], [3, 5], [4, 2], [2.5, 1.2], [2, -2.5]]
path = np.array(path)
# plt.plot(path[:, 0], path[:, 1])
# plt.plot(path[:, 0], path[:, 1], "*")
# plt.show()

#%% 一维轨迹优化
x = path[:, 0]
# 分配时间
deltaT = 2 # 每一段2秒
T = np.linspace(0, deltaT * (len(x) - 1), len(x))

########### 目标函数 ###########
######## 1/2xTQx + qTx ########
K = 3                   # jerk为3阶导数,取K=3
n_order = 2 * K - 1     # 多项式阶数
M = len(x) - 1          # 轨迹的段数
N = M * (n_order + 1)   # 矩阵Q的维数

def getQk(T_down, T_up):
    Q = np.zeros((6, 6))
    Q[3][4] =  72 * (T_up**2 - T_down**2)
    Q[3][5] = 120 * (T_up**3 - T_down**3)
    Q[4][5] = 360 * (T_up**4 - T_down**4)
    Q = Q + Q.T # Q为对称矩阵
    Q[3][3] =  36 * (T_up**1 - T_down**1)
    Q[4][4] = 192 * (T_up**3 - T_down**3)
    Q[5][5] = 720 * (T_up**5 - T_down**5)
    return Q
    
Q = np.zeros((N, N))
for k in range(1, M + 1):
    Qk = getQk(T[k - 1], T[k])
    Q[(6 * (k - 1)) : (6 * k), (6 * (k - 1)) : (6 * k)] = Qk

Q = Q * 2 # 因为标准目标函数为: 1/2xTQx + qTx,所以要乘2

########### 约束 ###########
# 1.导数约束 Derivative Constraint
A0 = np.zeros((2 * K + M - 1, N)) 
b0 = np.zeros(len(A0))

# 添加首末状态约束(包括位置、速度、加速度)
for k in range(K): 
    for i in range(k, 6):
        c = 1
        for j in range(k):
            c *= (i - j)
        A0[0 + k * 2][i]                = c * T[0]**(i - k)
        A0[1 + k * 2][(M - 1) * 6 + i]  = c * T[M]**(i - k)
b0[0] = x[0]
b0[1] = x[M]
# 添加每段轨迹的初始位置约束
for m in range(1, M):
    for i in range(6):
        A0[6 + m - 1][m * 6 + i] = T[m]**i
    b0[6 + m - 1] = x[m]

# 2.连续性约束 Continuity Constraint
A1 = np.zeros(((M - 1) * 3, N))
b1 = np.zeros(len(A1))
for m in range(M - 1):
    for k in range(3): # 最多两阶导数相等    
        for i in range(k, 6):
            c = 1
            for j in range(k):
                c *= (i - j)
            index = m * 3 + k
            A1[index][m * 6 + i] = c * T[m + 1]**(i - k)
            A1[index][(m + 1)* 6 + i] = -c * T[m + 1]**(i - k)
A = np.vstack((A0, A1))
b = np.hstack((b0, b1))
#%% 解二次规划问题
from cvxopt import matrix, solvers
# 目标函数
Q = matrix(Q)
q = matrix(np.zeros(N))
# 等式约束: Ax = b
A = matrix(A)
b = matrix(b)
result = solvers.qp(Q, q, A=A, b=b)
p_coff = np.asarray(result['x']).flatten()

#%% 可视化x轴优化结果
Pos = []
Vel = []
Acc = []
for k in range(M):
    t = np.linspace(T[k], T[k + 1], 100)
    t_pos = np.vstack((t**0, t**1, t**2, t**3, t**4, t**5))
    t_vel = np.vstack((t*0, t**0, 2 * t**1, 3 * t**2, 4 * t**3, 5 * t**4))
    t_acc = np.vstack((t*0, t*0, 2 * t**0, 3 * 2 * t**1, 4 * 3 * t**2, 5 * 4 * t**3))
    coef = p_coff[k * 6 : (k + 1) * 6]
    coef = np.reshape(coef, (1, 6))
    pos = coef.dot(t_pos)
    vel = coef.dot(t_vel)
    acc = coef.dot(t_acc)
    Pos.append([t, pos[0]])
    Vel.append([t, vel[0]])
    Acc.append([t, acc[0]])
Pos = np.array(Pos)
Vel = np.array(Vel)
Acc = np.array(Acc)
plt.subplot(3, 1, 1)
plt.plot(Pos[:, 0, :].T, Pos[:, 1, :].T)
# plt.title("position")
plt.xlabel("time(s)")
plt.ylabel("position(m)")
plt.subplot(3, 1, 2)
plt.plot(Vel[:, 0, :].T, Vel[:, 1, :].T)
# plt.title("velocity")
plt.xlabel("time(s)")
plt.ylabel("velocity(m/s)")
plt.subplot(3, 1, 3)
plt.plot(Acc[:, 0, :].T, Acc[:, 1, :].T)
# plt.title("accel")
plt.xlabel("time(s)")
plt.ylabel("accel(m/s^2)")
plt.show()

x轴上的规划结果如下,可以看到生成轨迹的位置、速度和加速度曲线都是连续的。
轨迹优化 | Minimum-jerk_第3张图片
分别求X轴和Y轴方向的轨迹,合并后的结果如下图,程序见这里
轨迹优化 | Minimum-jerk_第4张图片

参考

Minimum Snap轨迹规划详解

浅谈「正定矩阵」和「半正定矩阵」

你可能感兴趣的:(移动机器人,运动规划,二次规划,移动机器人)