【基于机械臂触觉伺服的物体操控研究】几种轨迹规划的算法及代码实现

news2024/12/24 8:32:10

在这里插入图片描述
我的毕设题目定为《基于机械臂触觉伺服的物体操控研究》,这个系列主要用于记录做毕设的过程。

轨迹规划是机器人绕不过去的话题,其目的是为了让机器人的运动更加的平滑。对于四足机器人,贝赛尔曲线的应用比较普遍。而对于机械臂,则需要根据场景来选择适合的规划方式,常用的有样条曲线和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+1pip 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+1pip)/T pdes(t)=ip+vdest(0tT) 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=0npjBjn(t) Bin(t)=(ni)ti(1t)i(0t1)
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)=tpdes(t) ades(t)=tvdes(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=thtbθ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=2tm2θ¨θ¨2tm24θ¨(θ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=tft0
根据运动学公式,即可得到各个分段中的轨迹位置,速度及加速度(这里给出位置的公式,速度和加速度简单求导即可)
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,ttbθb+(θ¨tb)t,tbttftbθfθb+(θ¨tb)t21θ¨t2,tftbttf

带有中间点的情况

在这里插入图片描述

对于内部路径点
θ 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=tdjk21tj21tk
对于第一个路径段,令线性区段速度的两个表达式相等
θ 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 td1221t1θ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¨=td12td122θ1¨2(θ2θ1)  θ12˙=td1221t1θ2θ1 t12=td12t121t2
对于最后一个路径段,与一个路径点处理类似
θ 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(n1)n21tnθn1θ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(θn1θn) θn¨  θn¨=td(n1)ntd(n1)n2+θn¨2(θnθn1)  θ(n1)n˙=td(n1)n21tnθnθn1 t(n1)n=td(n1)ntn21tn1
加速度要满足的条件
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(n1)n2+θn¨2(θnθn1)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(1in),过程点为 θ 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=[a10a11a12a13an0an1an2an3]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]);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/164325.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++】C++ 入门(一)

目录 一、前言 1、什么是C 2、C关键字(C98) 二、第一个C程序 三、命名空间 1、存在意义 2、命名空间定义 3、命名空间的使用 3.1、指定命名空间访问 3.2、全局展开访问 3.3、部分展开访问 四、C输入&输出 五、缺省参数 1、缺省参数概念 2、缺省参数分类 2.…

【Day4】24两两交换链表中的节点、19删除链表的倒数第N个节点、链表相交、142环形链表Ⅱ

【Day4】24两两交换链表中的节点、19删除链表的倒数第N个节点、160链表相交、142环形链表Ⅱ24.两两交换链表的点19.删除链表的倒数第N个节点160链表相交 面试题02.07142 环形链表Ⅱ判断链表是否有环若链表有环&#xff0c;如何找到环的入口24.两两交换链表的点 题目链接&#…

Spacedesk 安装教程及连接后黑屏解放方法

spacedesk 安装教程1. Spacedesk 概述2. Spacedesk 安装教程2.1 下载 Spacedesk2.2 连接计算机的 Spacedesk3. 被拓展的设备连接后黑屏的解决方法结束语1. Spacedesk 概述 Spacedesk 是一款低延迟的免费显示器拓展软件&#xff0c;且不需要线材将不同设备连接&#xff1b; Spa…

MySQL中的普通索引和唯一索引实际开发中的选择

文章目录前言一、普通索引和唯一索引介绍二、查询语句的比较三、更新语句的比较四、索引的选择和实践前言 本文我们将会从针对普通索引与唯一索引的增删改查的具体执行流程&#xff0c;来看看效率的对比。以便让我们在实际业务开发中可以进行更好的选择。 一、普通索引和唯一索…

动态规划系列 —— 背包问题

什么是背包问题 背包问题是有N件物品&#xff0c;容量为V的背包 每个物品有两个属性&#xff1a;体积&#xff0c;价值&#xff0c;分别用数组v&#xff0c;w表示 第i件物品的体积为v[i]&#xff0c;价值为w[i] 计算在背包装得下的情况下&#xff0c;能装的最大价值是多少&…

MATLAB 图像处理大作业

1、基础知识利用 MATLAB 提供的 Image file/IO 函数完成以下处理&#xff1a;&#xff08;a&#xff09;以测试图像中心为圆心&#xff0c;图像长宽中较小值一半为半径画一个红颜色的圆&#xff1b;&#xff08;b&#xff09;将测试图像涂成国际象棋状的‘黑白格’样子&#xf…

华芯片特微 M33内核 KEIL5环境配置不上问题

1 JFLASH连接不上问题 官方手册有说解决这个问题 2 JFLASH能连接上KEIL提示no found sw-dp 在替换keil下载算法后还是提示no found sw-dp 1 怀疑是keil 527版本太高了, 就换了518 还是不行 2 怀疑是keil检测到盗版了就不让下, 替换Jlink为以前老版本还是不行 解决方案: 下…

聊天气泡图片的动态拉伸、适配与镜像

聊天气泡图片的动态拉伸、适配与镜像前情提要创建.9.png格式的图片从资源文件夹加载.9.png图片从本地文件加载“.9.png”图片项目痛点进阶探索iOS中的方式Android中的探索构造chunk数据构造padding数据镜像翻转功能屏幕的适配简单封装演示示例一条线段控制的拉伸两条线段控制的…

Pandas 安装与教程

前言Pandas 是 Python 语言的一个扩展程序库&#xff0c;用于数据分析。Pandas 是一个开放源码、BSD 许可的库&#xff0c;提供高性能、易于使用的数据结构和数据分析工具。Pandas 名字衍生自术语 "panel data"&#xff08;面板数据&#xff09;和 "Python data…

[apidoc]Apidoc-文档生成工具

Apidoc主要是用于生成API文档的工具&#xff0c;可以用于多种语言&#xff0c;包括java、javascript、php等 这里主要是为了写前端的APIDOC&#xff0c;方便交互是双方的使用; 工具的安装 工具包的安装 npm i apidoc [-g|-D]可以-g全局安装&#xff0c;或者-D局部安装,因为…

网盘系统|基于SpringBoot的网盘系统的设计与实现

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

【无功优化】考虑泄流效应的光伏并网点电压系统侧无功优化(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

软考中级,【软件评测师】经验分享

&#xff0c;以下是我的考试成绩&#xff0c;一次通过很是幸运&#xff0c;希望把我的好运传递给大家&#xff0c;大家都能一次通过谈经验之前&#xff0c;先和大家说说考试的题型以及考试的内容&#xff0c;根据往年的考试题目我们可以很容易得知&#xff0c;软件评测师考试分…

Cisco(62)——PBR策略路由案例

场景1-单下一跳: 拓扑: 需求: R1和R2均连接100.100.100.100,R4看做一台PC,当PC访问100.100.100.100的时候优先走左边,当左边down掉之后切换到右边链路,使用PBR操作。 实现: 1.IP地址等基本配置 R4: R4(config)#no ip routingR4(config)#int e0/0 R4(config-if)#ip add…

Typora自动上传文章图片太难折腾?十三行JavaScript代码足矣

前言 Typora是我用过最爽的markdown文本编辑器了。但是有一点很让人难受&#xff0c;就是在写文章的时候&#xff0c;粘贴上的图片是本地路径。这就导致在复制文章到各大博客平台时发表&#xff0c;图片无法显示。然后需要各种办法去处理文章中的图片&#xff0c;不仅要手动上传…

【学习笔记】【Pytorch】十、线性层

【学习笔记】【Pytorch】九、线性层学习地址主要内容一、前言二、Pytorch的线性层三、Linear类的使用1.使用说明2.代码实现学习地址 PyTorch深度学习快速入门教程【小土堆】. 主要内容 一、前言 在神经网络中&#xff0c;我们通常用线性层来完成两层神经元间的线性变换。 …

【C++】面向对象---继承(万字详解)

目录前言一、继承的定义及概念二、继承方式三、基类和派生类之间的转换四、切片五、继承中的作用域六、派生类中的默认成员函数七、继承中的友元与静态成员继承与友元继承中的静态成员八、棱形继承和虚继承棱形继承虚继承总结前言 继承是面向对象的一个重点&#xff0c;而继承…

活动星投票医疗保障案例推介网络评选微信的投票方式线上免费投票

“医疗保障案例推介”网络评选投票_线上免费投票系统_功能齐全的微信投票_在线免费投票用户在使用微信投票的时候&#xff0c;需要功能齐全&#xff0c;又快捷方便的投票小程序。而“活动星投票”这款软件使用非常的方便&#xff0c;用户可以随时使用手机微信小程序获得线上投票…

图形编辑器:标尺功能的实现

大家好&#xff0c;我是前端西瓜哥。今天我们来实现图形编辑器的标尺功能。 项目地址&#xff1a; https://github.com/F-star/suika 线上体验&#xff1a; https://blog.fstars.wang/app/suika/ 标尺指的是画布上边和左边的两个有刻度的尺子&#xff0c;作用让用户知道他正在编…

java 探花交友day2 项目简介,环境搭建 登录验证码

技术方案&#xff1a; 项目结构&#xff1a; 项目概述 通过接口文档&#xff08;API文档&#xff09;定义规范 开发工具安装与配置 Linux虚拟机 YAPI 账号 tanhuaitcast.cn 密码123456 安装个安卓模拟器&#xff0c;然后安装APK 开发环境说明 初始工程搭建 阿里云短…