我的毕设题目定为《基于机械臂触觉伺服的物体操控研究》,这个系列主要用于记录做毕设的过程。
轨迹规划是机器人绕不过去的话题,其目的是为了让机器人的运动更加的平滑。对于四足机器人,贝赛尔曲线的应用比较普遍。而对于机械臂,则需要根据场景来选择适合的规划方式,常用的有样条曲线和LSPB等。下面我将给出四种比较常用的轨迹规划方法的推导过错,以及相应的代码,以供读者参考。
注:所有给出的代码主要是为了展示对应算法的编程思路,虽然代码都验证过可行,但是由于还需要关联其它库,所以无法直接运行。也建议读者根据自己的要求进行重新编写。等我的毕设答辩结束后,我会将整份工程进行开源。
规划时间
因为轨迹规划所得的轨迹是关于时间t的函数,在实际应用时,为了保证机械臂运动的平滑,一般要将运动速度设为恒值,即根据过程点的距离来确定规划时间。这里给出一种思路以供参考。
d
=
∣
i
+
1
p
−
i
p
∣
T
=
d
/
v
s
e
t
d = \left | ^{i+1}p - ^{i}p\right |\\ T = d / v_{set}
d=
i+1p−ip
T=d/vset
v
s
e
t
v_{set}
vset:人为设定的速度值
代码实现
/**
* @brief
* @param p1 point 1
* @param p2 point 1
* @param vel motion velocity
*/
template <typename T>
T getDeltaTime(Vec18<T> p1, Vec18<T> p2, T vel) {
T distance = 0;
for (int i = 0; i < 3; i++) {
distance += abs(p1(i) - p2(i));
}
/* set delta time refer to distance */
return distance / vel;
}
1. 线性插值
这种方式假定机械臂以直线的形式在给定过程点之间运动,并且因为拐角的加速度值不可求,所以我们可以假定其一直做匀速运动,加速度恒为零。
v
d
e
s
(
t
)
=
(
i
+
1
p
−
i
p
)
/
T
p
d
e
s
(
t
)
=
i
p
+
v
d
e
s
∗
t
(
0
≤
t
≤
T
)
a
d
e
s
(
t
)
=
0
v_{des}(t) = (\\^{i+1}p - \\^{i}p) / T \\~\\ p_{des}(t) = \\^{i}p + v_{des}*t(0 \le t \le T)\\~\\ a_{des}(t) = 0
vdes(t)=(i+1p−ip)/T pdes(t)=ip+vdes∗t(0≤t≤T) ades(t)=0
代码实现
/**
* @brief compute Line trajectory
* @param points control points(including start point and end point)
* @param resolution the point number between two control points
*/
template <typename T>
void LineTrajectory(std::vector<Vec18<T>> points, int resolution) {
int points_num = points.size();
Vec18<T> point;
Vec6<T> pDes, vDes, aDes;
/* Set acceleration to zero */
aDes.setZero();
/* push back start point */
_trajectory.push_back(points[0]);
for (int i = 0; i < points_num - 1; i++) {
T dt = getDeltaTime(points[i], points[i + 1]) / (resolution + 1);
for (int j = 1; j <= resolution + 1; j++) {
/* only consider position */
for (int k = 0; k < 6; k++) {
vDes(k) = (points[i + 1](k) - points[i](k)) / (resolution + 1);
pDes(k) = points[i](k) + vDes(k) * j;
}
point.block(0, 0, 6, 1) = pDes;
point.block(6, 0, 6, 1) = vDes * getDeltaTime(points[i], points[i + 1]);
point.block(12, 0, 6, 1) = aDes;
_trajectory.push_back(point);
_deltaT.push_back(dt);
}
}
}
2. 贝赛尔曲线
贝赛尔曲线的推导可以参考我之前的文章。
贝赛尔曲线学习
位置
p
d
e
s
(
t
)
=
∑
j
=
0
n
p
j
B
j
n
(
t
)
B
i
n
(
t
)
=
(
n
i
)
t
i
(
1
−
t
)
i
(
0
≤
t
≤
1
)
p_{des}(t) = \sum_{j=0}^{n}p_jB_j^n(t) \\~\\ B_i^n(t) =\begin{pmatrix}n\\i\end{pmatrix}t^i(1-t)^i(0 \le t \le 1)
pdes(t)=j=0∑npjBjn(t) Bin(t)=(ni)ti(1−t)i(0≤t≤1)
p
j
p_j
pj:轨迹控制点的坐标
B
i
n
(
t
)
B_i^n(t)
Bin(t):贝赛尔曲线系数
注:n = 控制点总数(包含起点和终点) - 1
速度,加速度
v
d
e
s
(
t
)
=
∂
p
d
e
s
(
t
)
∂
t
a
d
e
s
(
t
)
=
∂
v
d
e
s
(
t
)
∂
t
v_{des}(t) = \frac{\partial p_{des}(t)}{\partial t} \\~\\ a_{des}(t) = \frac{\partial v_{des}(t)}{\partial t}
vdes(t)=∂t∂pdes(t) ades(t)=∂t∂vdes(t)
代码实现
/**
* @brief compute Bezier trajectory
* @param points control points(including start point and end point)
* @param resolution trajectory points number
*/
template <typename T>
void BezierTrajectory(std::vector<Vec18<T>> points, int resolution) {
int poinets_num = points.size(); /* the number of control points */
T dt = 1 / (T)resolution;
Vec18<T> point;
T pDes, vDes, aDes;
/* push back start point */
_trajectory.push_back(points[0]);
/* get motion time */
T motion_T = 0;
for (int k = 0; k < poinets_num - 1; k++) {
motion_T += getDeltaTime(points[k], points[k + 1]);
}
motion_T /= resolution;
/* apply Bezier algorithm */
point.setZero();
for (int i = 1; i <= resolution; i++) {
/* only consider position */
for (int j = 0; j < 6; j++) {
pDes = 0;
vDes = 0;
aDes = 0;
for (int k = 0; k < poinets_num; k++) {
pDes += CombinatorialNumber(poinets_num - 1, k) * points[k](j) * pow(dt * i, k) *
pow((1 - dt * i), poinets_num - 1 - k);
vDes += CombinatorialNumber(poinets_num - 1, k) * points[k](j) *
FirstDerivation(dt * i, poinets_num - 1, k);
aDes += CombinatorialNumber(poinets_num - 1, k) * points[k](j) *
SecondDerivation(dt * i, poinets_num - 1, k);
}
point(j) = pDes;
point(j + 6) = vDes;
point(j + 12) = aDes;
}
/* Add to trajectory */
_trajectory.push_back(point);
_deltaT.push_back(motion_T);
}
}
/**
* @brief return the first derivation value of t^i((1-t)^(n-i))
*
*/
template <typename T>
T FirstDerivation(T t, T n, T i) {
T value = 0;
if ((i - 1) >= 0)
value += i * pow(t, i - 1) * pow(1 - t, n - i);
if ((n - i - 1) >= 0)
value += -(n - i) * pow(t, i) * pow(1 - t, n - i - 1);
return value;
}
/**
* @brief return the second derivation value of t^i((1-t)^(n-i))
*
*/
template <typename T>
T SecondDerivation(T t, T n, T i) {
T value = 0;
if ((i - 2) >= 0 && (n - i) >= 0)
value += i * (i - 1) * pow(t, i - 2) * pow(1 - t, n - i);
if ((i - 1) >= 0 && (n - i - 1) >= 0)
value += -2 * i * (n - i) * pow(t, i - 1) * pow(1 - t, n - i - 1);
if (i >= 0 && (n - i - 2) >= 0)
value += (n - i) * (n - i - 1) * pow(t, i) * pow(1 - t, n - i - 2);
return value;
}
/* compute Statistics combination number */
int CombinatorialNumber(int n, int i)
{
int out;
out = factorial(n);
out /= factorial(i) * factorial(n-i);
}
3. LSPB曲线(抛物线-直线-抛物线)
LSPB是机械臂最常用的轨迹规划算法之一,但要注意的是,LSPB得到的轨迹不经过中间点,
并且过渡区间的加速度需要在符合要求的区间内自行定义。一般来说,加速度的取值要足够大,以保证各路径段有足够长的直线区段。
只有起始点和终点的情况
参数定义
t
h
:
时间中点
θ
h
:
位置中点
θ
b
:
过渡区段终点位置
θ
¨
:
过渡区段加速度
t_h: 时间中点\\ \theta_h:位置中点\\ \theta_b:过渡区段终点位置\\ \ddot{\theta}:过渡区段加速度
th:时间中点θh:位置中点θb:过渡区段终点位置θ¨:过渡区段加速度
过渡区终点速度等于直线部分速度
θ
¨
t
b
=
θ
h
−
θ
b
t
h
−
t
b
\ddot{\theta}t_b = \frac{\theta_h - \theta_b}{t_h - t_b}
θ¨tb=th−tbθh−θb
运动学公式
θ
b
=
θ
0
+
1
2
θ
¨
t
b
2
\theta_b = \theta_0 + \frac{1}{2}\ddot{\theta}t_b^2
θb=θ0+21θ¨tb2
联立得
t
b
=
t
m
2
−
θ
¨
2
t
m
2
−
4
θ
¨
(
θ
f
−
θ
0
)
2
θ
¨
t_b = \frac{t_m}{2}-\frac{\sqrt{\ddot{\theta}^2t_m^2-4\ddot{\theta}(\theta_f-\theta_0)}}{2\ddot{\theta}}
tb=2tm−2θ¨θ¨2tm2−4θ¨(θf−θ0)
加速度要满足的条件
θ
¨
≥
4
θ
¨
(
θ
f
−
θ
0
)
t
m
2
t
m
=
t
f
−
t
0
\ddot{\theta} \ge \frac{4\ddot{\theta}(\theta_f-\theta_0)}{t_m^2}\\~\\ t_m = t_f - t_0
θ¨≥tm24θ¨(θf−θ0) tm=tf−t0
根据运动学公式,即可得到各个分段中的轨迹位置,速度及加速度(这里给出位置的公式,速度和加速度简单求导即可)
p
d
e
s
=
{
θ
0
+
1
2
θ
¨
t
2
,
t
≤
t
b
θ
b
+
(
θ
¨
t
b
)
t
,
t
b
≤
t
≤
t
f
−
t
b
θ
f
−
θ
b
+
(
θ
¨
t
b
)
t
−
1
2
θ
¨
t
2
,
t
f
−
t
b
≤
t
≤
t
f
p_{des} = \begin{cases} \theta_0 + \frac{1}{2}\ddot{\theta}t^2, t\le t_b\\ \theta_b + (\ddot{\theta}t_b)t, t_b \le t \le t_f - t_b\\ \theta_f - \theta_b + (\ddot{\theta}t_b)t - \frac{1}{2}\ddot{\theta}t^2, t_f - t_b \le t \le t_f \end{cases}
pdes=⎩
⎨
⎧θ0+21θ¨t2,t≤tbθb+(θ¨tb)t,tb≤t≤tf−tbθf−θb+(θ¨tb)t−21θ¨t2,tf−tb≤t≤tf
带有中间点的情况
对于内部路径点
θ
j
k
˙
=
θ
k
−
θ
j
t
d
j
k
θ
k
¨
=
S
G
N
(
θ
k
l
˙
−
θ
j
k
˙
)
∣
θ
k
¨
∣
t
k
=
θ
k
l
˙
−
θ
j
k
˙
θ
k
¨
t
j
k
=
t
d
j
k
−
1
2
t
j
−
1
2
t
k
\dot{\theta_{jk}} = \frac{\theta_k - \theta_j}{t_{djk}}\\~\\ \ddot{\theta_{k}} = SGN(\dot{\theta_{kl}}-\dot{\theta_{jk}})\left | \ddot{\theta_{k}} \right |\\~\\ t_k = \frac{\dot{\theta_{kl}}-\dot{\theta_{jk}}}{\ddot{\theta_{k}}}\\~\\ t_{jk}=t_{djk} - \frac{1}{2}t_j - \frac{1}{2}t_k
θjk˙=tdjkθk−θj θk¨=SGN(θkl˙−θjk˙)
θk¨
tk=θk¨θkl˙−θjk˙ tjk=tdjk−21tj−21tk
对于第一个路径段,令线性区段速度的两个表达式相等
θ
2
−
θ
1
t
d
12
−
1
2
t
1
=
θ
1
¨
t
1
\frac{\theta_2-\theta_1}{t_{d12}-\frac{1}{2}t_1} = \ddot{\theta_{1}}t_1
td12−21t1θ2−θ1=θ1¨t1
由此即可解出其余量
θ
1
¨
=
S
G
N
(
θ
2
−
θ
1
)
∣
θ
1
¨
∣
θ
k
¨
=
t
d
12
−
t
d
12
2
−
2
(
θ
2
−
θ
1
)
θ
1
¨
θ
12
˙
=
θ
2
−
θ
1
t
d
12
−
1
2
t
1
t
12
=
t
d
12
−
t
1
−
1
2
t
2
\ddot{\theta_{1}} = SGN(\theta_{2}-\theta_{1})\left | \ddot{\theta_{1}} \right |\\~\\ \ddot{\theta_{k}} =t_{d12} - \sqrt{t_{d12}^2-\frac{2(\theta_2-\theta_1)}{\ddot{\theta_{1}}}}\\~\\ \dot{\theta_{12}} = \frac{\theta_2 - \theta_1}{t_{d12}-\frac{1}{2}t_1}\\~\\ t_{12}=t_{d12} - t_1 - \frac{1}{2}t_2
θ1¨=SGN(θ2−θ1)
θ1¨
θk¨=td12−td122−θ1¨2(θ2−θ1) θ12˙=td12−21t1θ2−θ1 t12=td12−t1−21t2
对于最后一个路径段,与一个路径点处理类似
θ
n
−
1
−
θ
n
t
d
(
n
−
1
)
n
−
1
2
t
n
=
θ
n
¨
t
n
\frac{\theta_{n-1}-\theta_{n}}{t_{d(n-1)n}-\frac{1}{2}t_n} = \ddot{\theta_{n}}t_n
td(n−1)n−21tnθn−1−θn=θn¨tn
由此即可解出其余量
θ
n
¨
=
S
G
N
(
θ
n
−
1
−
θ
n
)
∣
θ
n
¨
∣
θ
n
¨
=
t
d
(
n
−
1
)
n
−
t
d
(
n
−
1
)
n
2
+
2
(
θ
n
−
θ
n
−
1
)
θ
n
¨
θ
(
n
−
1
)
n
˙
=
θ
n
−
θ
n
−
1
t
d
(
n
−
1
)
n
−
1
2
t
n
t
(
n
−
1
)
n
=
t
d
(
n
−
1
)
n
−
t
n
−
1
2
t
n
−
1
\ddot{\theta_{n}} = SGN(\theta_{n-1}-\theta_{n})\left | \ddot{\theta_{n}} \right |\\~\\ \ddot{\theta_{n}} =t_{d(n-1)n} - \sqrt{t_{d(n-1)n}^2+\frac{2(\theta_n-\theta_{n-1})}{\ddot{\theta_{n}}}}\\~\\ \dot{\theta_{(n-1)n}} = \frac{\theta_n - \theta_{n-1}}{t_{d(n-1)n}-\frac{1}{2}t_n}\\~\\ t_{(n-1)n}=t_{d(n-1)n} - t_n - \frac{1}{2}t_{n-1}
θn¨=SGN(θn−1−θn)
θn¨
θn¨=td(n−1)n−td(n−1)n2+θn¨2(θn−θn−1) θ(n−1)n˙=td(n−1)n−21tnθn−θn−1 t(n−1)n=td(n−1)n−tn−21tn−1
加速度要满足的条件
t
d
12
2
−
2
(
θ
2
−
θ
1
)
θ
1
¨
≥
0
t
d
(
n
−
1
)
n
2
+
2
(
θ
n
−
θ
n
−
1
)
θ
n
¨
≥
0
t_{d12}^2-\frac{2(\theta_2-\theta_1)}{\ddot{\theta_{1}}} \ge 0 \\~\\ t_{d(n-1)n}^2+\frac{2(\theta_n-\theta_{n-1})}{\ddot{\theta_{n}}} \ge 0
td122−θ1¨2(θ2−θ1)≥0 td(n−1)n2+θn¨2(θn−θn−1)≥0
代码实现
/**
* @brief compute LSPB trajectory
* @param points control points(including start point and end point)
* @param resolution the point number between two control points
*/
template <typename T>
void pathPlanner<T>::LSPBTrajectory(std::vector<Vec18<T>> points, int resolution) {
int len = points.size();
std::vector<Vec18<T>> trajectory(resolution * (len - 1) + len);
;
/* push back start point */
trajectory[0] = points[0];
std::vector<T> acc(len);
std::vector<T> deltaT(len - 1);
/* define acceleration and deltaT to constant value */
for (int i = 0; i < len; i++) {
acc[i] = 150.;
if (i != len - 1)
deltaT[i] = getDeltaTime(points[i], points[i + 1]);
}
std::vector<T> Vd(len - 1); /* line velocity between two points */
std::vector<T> Td(len - 1); /* line motion time between two points */
std::vector<T> Ti(len); /* nearby time of a point */
T dp, a_;
T pDes, vDes, aDes;
for (int j = 0; j < 6; j++) {
if (len == 1)
return;
/* no middle points */
else if (len == 2) {
dp = points[1](j) - points[0](j);
a_ = sign(dp) * abs(acc[0]);
assert(abs(a_) >= 4 * abs(dp / pow(deltaT[0], 2)));
Ti[0] = 0.5 * deltaT[0] - sqrt((pow(a_ * deltaT[0], 2) - 4 * a_ * dp)) / (2 * a_);
Ti[1] = Ti[0];
Vd[0] = a_ * Ti[0];
Td[0] = deltaT[0] - 2 * Ti[0];
}
/* have middle points */
else {
/* compute start time and velocity */
dp = points[1](j) - points[0](j);
a_ = sign(dp) * abs(acc[0]);
assert((pow(deltaT[0], 2) - 2. * dp / a_) >= 0);
Ti[0] = deltaT[0] - sqrt(pow(deltaT[0], 2) - 2. * dp / a_);
Vd[0] = dp / (deltaT[0] - 0.5 * Ti[0]);
/* compute velocity of middle points */
for (int i = 1; i < len - 2; i++) {
dp = points[i + 1](j) - points[i](j);
Vd[i] = dp / deltaT[i];
}
//* compute end time and velocity */
dp = points[len - 1](j) - points[len - 2](j);
a_ = sign(-dp) * abs(acc[len - 1]);
assert((pow(deltaT[len - 2], 2) + 2. * dp / a_) >= 0);
Ti[len - 1] = deltaT[len - 2] - sqrt(pow(deltaT[len - 2], 2) + 2. * dp / a_);
Vd[len - 2] = dp / (deltaT[len - 2] - 0.5 * Ti[len - 1]);
/* compute time of middle points */
for (int i = 1; i < len - 1; i++) {
a_ = sign(Vd[i] - Vd[i - 1]) * abs(acc[i]);
Ti[i] = (Vd[i] - Vd[i - 1]) / a_;
}
/* compute delta time of middle points */
for (int i = 1; i < len - 2; i++) {
Td[i] = deltaT[i] - 0.5 * Ti[i] - 0.5 * Ti[i + 1];
}
/* supplemental data */
Td[len - 2] = deltaT[len - 2] - Ti[len - 1] - 0.5 * Ti[len - 2];
Td[0] = deltaT[0] - Ti[0] - 0.5 * Ti[1];
}
T dt, t_;
for (int i = 0; i < len - 1; i++) {
/* delta time between two points */
dt = deltaT[i] / (T)(resolution + 1);
/* start and end point */
double start = points[i](j);
double end = points[i + 1](j);
for (int k = 1; k <= resolution + 1; k++) {
/* define value refer to time range */
t_ = k * dt;
/* judge start or end point */
T Tb1 = (i == 0) ? Ti[i] : Ti[i] / 2.;
T Tm = Tb1 + Td[i];
T Tb2 = Tm + (i == len - 2) ? Ti[i + 1] : Ti[i + 1] / 2.;
if (t_ <= Tb1) {
pDes = start + 0.5 * acc[i] * pow(t_, 2);
vDes = acc[i] * t_;
aDes = acc[i];
} else if (t_ > Tb1 && t_ < Tm) {
pDes = start + 0.5 * acc[i] * pow(Ti[i], 2) + Vd[i] * (t_ - Tb1);
vDes = Vd[i];
aDes = 0;
} else {
pDes = start + 0.5 * acc[i] * pow(Ti[i], 2) + Vd[i] * Td[i] + Vd[i] * (t_ - Tm) -
0.5 * acc[i] * pow((t_ - Tm), 2);
vDes = -acc[i] * (t_ - Tm);
aDes = -acc[i];
}
trajectory[i * (resolution + 1) + k](j) = pDes;
trajectory[i * (resolution + 1) + k](j + 6) = vDes;
trajectory[i * (resolution + 1) + k](j + 12) = aDes;
/* set delta time */
if (!j) {
_deltaT.push_back(dt);
}
}
}
}
/* Add to trajectory */
for (int i = 0; i < resolution * (len - 1) + len; i++) {
_trajectory.push_back(trajectory[i]);
}
}
4. 三次样条法
根据过程点列写方程,并写成矩阵形式。
三次样条表示形式
θ ( t ) = a 0 + a 1 t + a 2 t 2 + a 3 t 3 θ ˙ ( t ) = a 1 + 2 a 2 t + 3 a 3 t 2 θ ¨ ( t ) = 2 a 2 + 6 a 3 t \theta(t) = a_0 + a_1t + a_2t^2+a_3t^3\\~\\ \dot{\theta}(t) = a_1 + 2a_2t+3a_3t^2\\~\\ \ddot{\theta}(t) = 2a_2+6a_3t θ(t)=a0+a1t+a2t2+a3t3 θ˙(t)=a1+2a2t+3a3t2 θ¨(t)=2a2+6a3t
根据过程点列写方程
在一个时间段内,每个三次曲线的起始时刻 t = 0 t = 0 t=0。终止时刻 t = t f i ( 1 ≤ i ≤ n ) t=t_{fi}(1 \le i \le n) t=tfi(1≤i≤n),过程点为 θ i \theta_i θi
要求解的参数
X
=
[
a
10
a
11
a
12
a
13
…
a
n
0
a
n
1
a
n
2
a
n
3
]
T
n
:过程点个数
−
1
X = \begin{bmatrix} a_{10} & a_{11} & a_{12} & a_{13} & \dots & a_{n0} & a_{n1} & a_{n2} & a_{n3} \end{bmatrix}^T\\~\\ n:过程点个数-1
X=[a10a11a12a13…an0an1an2an3]T n:过程点个数−1
初末速度为0
0
=
a
11
0
=
a
n
1
+
2
a
n
2
t
f
n
+
3
a
n
3
t
f
n
2
0 = a_{11} \\~\\ 0 = a_{n1} + 2a_{n2}t_{fn} + 3a_{n3}t_{fn}^2
0=a11 0=an1+2an2tfn+3an3tfn2
位置满足设定值
θ
i
=
a
i
0
θ
i
+
1
=
a
i
0
+
a
i
1
t
f
i
+
a
i
2
t
f
i
2
+
a
i
3
t
f
i
3
\theta_i = a_{i0}\\~\\ \theta_{i+1} = a_{i0} + a_{i1}t_{fi} + a_{i2}t_{fi}^2+a_{i3}t_{fi}^3
θi=ai0 θi+1=ai0+ai1tfi+ai2tfi2+ai3tfi3
中间点速度和加速度一致
a
i
1
+
2
a
i
2
t
f
i
+
3
a
i
3
t
f
i
2
=
a
(
i
+
1
)
1
2
a
i
2
+
6
a
i
3
t
f
i
=
2
a
(
i
+
1
)
2
a_{i1}+ 2a_{i2}t_{fi}+3a_{i3}t_{fi}^2 = a_{(i+1)1}\\~\\ 2a_{i2}+6a_{i3}t_{fi} = 2a_{(i+1)2}
ai1+2ai2tfi+3ai3tfi2=a(i+1)1 2ai2+6ai3tfi=2a(i+1)2
联立即可求解。
代码实现
/**
* @brief compute Spline trajectory
* @param points control points(including start point and end point)
* @param resolution the point number between two control points
*/
template <typename T>
void SplineTrajectory(std::vector<Vec18<T>> points, int resolution) {
T pDes, vDes, aDes, a_;
int len = points.size();
/* Set start point */
std::vector<Vec18<T>> trajectory(resolution * (len - 1) + len);
trajectory[0] = points[0];
/* set delta time */
std::vector<T> dT(len - 1);
for (int i = 0; i < len - 1; i++) {
// dT[i] = 1;
dT[i] = getDeltaTime(points[i], points[i + 1]);
}
const int M_SIZE = 4 * (len - 1);
/* deine variable matrix */
Eigen::MatrixXd A;
A.setZero(M_SIZE, M_SIZE);
Eigen::VectorXd X(M_SIZE);
Eigen::VectorXd b(M_SIZE);
Eigen::VectorXd solve(M_SIZE);
for (int j = 0; j < 6; j++) {
int index = 0;
/* Set end velocity to zero */
A(index, 1) = 1;
b(index) = 0;
index++;
A(index, 4 * (len - 2) + 1) = 1;
A(index, 4 * (len - 2) + 2) = 2 * dT[len - 2];
A(index, 4 * (len - 2) + 3) = 3 * pow(dT[len - 2], 2);
b(index) = 0;
index++;
for (int i = 0; i < len - 1; i++) {
/* position */
A(index, i * 4 + 0) = 1;
b(index) = points[i](j);
index++;
A(index, i * 4 + 0) = 1;
A(index, i * 4 + 1) = dT[i];
A(index, i * 4 + 2) = pow(dT[i], 2);
A(index, i * 4 + 3) = pow(dT[i], 3);
b(index) = points[i + 1](j);
index++;
/* velocity */
if (i != 0) {
A(index, (i - 1) * 4 + 1) = 1;
A(index, (i - 1) * 4 + 2) = 2 * dT[i - 1];
A(index, (i - 1) * 4 + 3) = 3 * pow(dT[i - 1], 2);
A(index, i * 4 + 1) = -1;
b(index) = 0;
index++;
}
/* acceleration */
if (i != 0) {
A(index, (i - 1) * 4 + 2) = 2;
A(index, (i - 1) * 4 + 3) = 6 * dT[i - 1];
A(index, i * 4 + 2) = -2;
b(index) = 0;
index++;
}
}
/* solve function */
X = A.colPivHouseholderQr().solve(b);
double dt, t_;
for (int i = 0; i < len - 1; i++) {
/* delta time between two points */
dt = dT[i] / (resolution + 1);
for (int k = 1; k <= resolution + 1; k++) {
/* substitute into cubic polynomial */
t_ = k * dt;
pDes = X(i * 4) + X(i * 4 + 1) * t_ + X(i * 4 + 2) * pow(t_, 2) + X(i * 4 + 3) * pow(t_, 3);
vDes = X(i * 4) + X(i * 4 + 1) + 2 * X(i * 4 + 2) * t_ + 3 * X(i * 4 + 3) * pow(t_, 2);
aDes = 2 * X(i * 4 + 2) + 6 * X(i * 4 + 3) * t_;
trajectory[i * (resolution + 1) + k](j) = pDes;
trajectory[i * (resolution + 1) + k](j + 6) = vDes;
trajectory[i * (resolution + 1) + k](j + 12) = aDes;
/* set delta time */
if (!j) {
_deltaT.push_back(dt);
}
}
}
}
/* Add to trajectory */
for (int i = 0; i < resolution * (len - 1) + len; i++) {
_trajectory.push_back(trajectory[i]);
}
}