2011年,Vijay Kumar的论文提出了QP形式的Minimum-snap方法,2016年,Nicholas Roy的论文提出了closed-form minimum snap,2021年,Zhepei Wang与Fei Gao在论文Geometrically Constrained Trajectory Optimization for Multicopters中,提出了一种无代价函数的minimum-snap方法。本文使用最后这种方法,构建Minimum-jerk的轨迹。

Theorem and coding

BVIP其实就是根据最优性条件把问题变成Mc=b。M是关于c在t等于不同时刻的系数,c就是我们待求的多段多项式样条的系数矩阵。

函数的输入输出为

void minimumJerkTrajGen(
    // Inputs:
    const int pieceNum,
    const Eigen::Vector3d &initialPos,
    const Eigen::Vector3d &initialVel,
    const Eigen::Vector3d &initialAcc,
    const Eigen::Vector3d &terminalPos,
    const Eigen::Vector3d &terminalVel,
    const Eigen::Vector3d &terminalAcc,
    const Eigen::Matrix3Xd &intermediatePositions,
    const Eigen::VectorXd &timeAllocationVector,
    // Outputs:
    Eigen::MatrixX3d &coefficientMatrix)
{

由原文,

Untitled

第一步,声明矩阵M, b

int s = 3;                                     // minimum-jerk
int dim = timeAllocationVector.size() * 2 * s; // dimension of matrix M
Eigen::MatrixXd M = Eigen::MatrixXd::Zero(dim, dim);
Eigen::MatrixXd b = Eigen::MatrixXd::Zero(dim, 3);

Eigen学习笔记2:C++矩阵运算库Eigen介绍

第二步,计算F0与D0,并填入矩阵中。

Untitled

// get F0 and D0
Eigen::MatrixXd F0(s, 2 * s);
Eigen::MatrixXd D0(s, 3);

F0 << 1, 0, 0, 0, 0, 0,
    0, 1, 0, 0, 0, 0,
    0, 0, 2, 0, 0, 0;

D0 << initialPos(0), initialPos(1), initialPos(2),
    initialVel(0), initialVel(1), initialVel(2),
    initialAcc(0), initialAcc(1), initialAcc(2);

M.block(0, 0, s, 2 * s) << F0;
b.block(0, 0, s, 3) << D0;

第三步,计算Fi, Ei, Di,并通过循环填入矩阵中

Untitled

// get Fi, Ei, and Di, use for loop to fill them into M and b
for (int i = 0; i < dim - 2 * s; i += 2 * s)
{
    int index = i / (2 * s);
    double t = timeAllocationVector(index);
    Eigen::MatrixXd Fi(2 * s, 2 * s);
    Eigen::MatrixXd Ei(2 * s, 2 * s);
    Eigen::MatrixXd Di(1, 3);

    Fi << 0, 0, 0, 0, 0, 0,
        -1, 0, 0, 0, 0, 0,
        **0, -1, 0, 0, 0, 0,
        0, 0, -2, 0, 0, 0,
        0, 0, 0, -6, 0, 0,
        0, 0, 0, 0, -24, 0;

    Ei << 1, t, pow(t, 2), pow(t, 3), pow(t, 4), pow(t, 5),
        1, t, pow(t, 2), pow(t, 3), pow(t, 4), pow(t, 5),
        0, 1, 2 * t, 3 * pow(t, 2), 4 * pow(t, 3), 5 * pow(t, 4),
        0, 0, 2, 6 * t, 12 * pow(t, 2), 20 * pow(t, 3),
        0, 0, 0, 6, 24 * t, 60 * pow(t, 2),
        0, 0, 0, 0, 24, 120 * t;

    Di << intermediatePositions.col(index).transpose();

    M.block(s + i, 2 * s + i, 2 * s, 2 * s) << Fi;
    M.block(s + i, i, 2 * s, 2 * s) << Ei;
    b.block(s + i, 0, 1, 3) << Di;
}

第四步,计算E_M与D_M

Untitled

// get E_M and D_M
Eigen::MatrixXd E_M(s, 2 * s);
Eigen::MatrixXd D_M(s, 3);

double t = timeAllocationVector(timeAllocationVector.size() - 1);

E_M << 1, t, pow(t, 2), pow(t, 3), pow(t, 4), pow(t, 5),
    0, 1, 2 * t, 3 * pow(t, 2), 4 * pow(t, 3), 5 * pow(t, 4),
    0, 0, 2, 6 * t, 12 * pow(t, 2), 20 * pow(t, 3);

D_M << terminalPos(0), terminalPos(1), terminalPos(2),
    terminalVel(0), terminalVel(1), terminalVel(2),
    terminalAcc(0), terminalAcc(1), terminalAcc(2);

M.block(dim - s, dim - 2 * s, s, 2 * s) << E_M;
b.block(dim - s, 0, s, 3) << D_M;

第五步,解Mc=b