轨迹优化——三维空间下通过BVIP生成最小jerk轨迹

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

本文详细介绍了如何使用最优条件理论计算三维空间中的最小jerk轨迹。通过边界值问题(BVP)和边界中间值问题(BIVP),结合机器人运动规划中的轨迹生成,探讨了如何构建线性方程组并求解轨迹系数,从而实现从起始点到终点,经过多个中间位点的平滑轨迹规划。文章还提供了具体的数学公式和代码实现。

写在前面的 

这篇文章主要是记录下深蓝学院开的《移动机器人运动规划》这门课程中第五章-最优轨迹生成的作业即三维空间下通过BVIP生成最小jerk轨迹相关的内容及做作业时的过程。

其课程链接在下面,感兴趣的可以去报名学习:

移动机器人运动规划-深蓝学院 

任务描述

如下图所示,给定三维空间下起始点和终点的位置、速度和加速度,以及(M-1)个中间位点的位置,那么这段轨迹就被分成了 M 段。其中每小段轨迹移动的时间 \Delta T_i 也是给定的。

要求我们用最优条件来计算三维最小jerk轨迹的系数,因为这些系数能描述一条轨迹,这个后面也会讲。

至于最优条件怎么来的,这里就不说明了,后面会讲最优条件是什么。

边界值问题(Boundary value problem,BVP)

在讲BVIP时我们先来讲轨迹生成中的BVP问题,这一部分建议先看下面链接的相关内容:

Robotics: Aerial Robotics(空中机器人)笔记(六):无人机运动规划

简单来说,就是我们已知机器人初始的状态(比如说初始的位置,速度,加速度等),以及最后的状态,也就是我们只考虑起始和最终的状态,不考虑中间的状态。

如下图所示,这是一个无人机接球的例子,只考虑无人机起始的状态和接球的状态来生成轨迹:

最优条件理论告诉我们:如果我们的输入是轨迹的 s 阶导数(如果是位置的话 s=1 ,加速度的话 s=2, jerk的话 s=3,依此类推),那么其描述轨迹的多项式的阶数就是 2s -1。我们现在要生成是jerk轨迹,那么多项式的阶数就是 2 * 3 - 1 = 5。

我们来看一维空间的情况,起点和终点的状态已知,求jerk轨迹:

 

那么我们的jerk轨迹就可以这么描述:

 通过将 t=0, t=T代入到上面的多项式,以及多项式的一阶求导,二阶求导可得:

如果边界条件是这样的则是:

 

这时如果这段轨迹运行的时间 T 已知,那么就可以求出这条轨迹的参数 c_0-c_5 了 。那么轨迹也就知道了。

那么如果我们要设计一条经过指定位点的轨迹,我们就需要指定每个位点的状态,包括位置,速度,加速度等等。 但有时候我们只是要让机器人经过某个位点,而不需要规定其在位点的速度,加速度等状态,那么这就是BIVP(Boundary-intermediate value problem)。

BIVP(Boundary-intermediate value problem) 

最优条件理论告诉我们,如果我们的输入是轨迹的 s 阶导数,那么其 2s-d-1 阶导数也都是连续可导的。也就是说,如果我们的输入是 jerk( s = 3 ),首先位置,速度,加速度肯定是连续的,这没有异议。但是包括 jerk 在内,snap( s = 4 )在位点上也是连续可导的。

我们知道,轨迹是一个多项式来描述,那么我们就可以通过解下面的线性方程来求解轨迹的系数:

对于最小jerk轨迹,我们把轨迹分成 M 段,每段可以用一个五阶的多项式来描述,通过最优条件理论,即每个位点左右两段轨迹的多阶导数的连续性以及位置的约束来求解轨迹的系数:

我们选择下图上方的 T 描述方式,也就是第二段轨迹的起始时刻为 0 ,这样计算起来数值比较稳定,解得更快。

这样,我们就把轨迹的优化问题转化成了线性方程组的求解问题,接下来我们将以下图为基础开始推导相关变量及编写程序。

公式推导及代码编写

我们的目的就是构建关于时间 T 的 M 矩阵和关于边界值的 b 矩阵,然后通过 M 矩阵的逆来求解系数矩阵 c :

首先我们初始化两个矩阵,其中 pieceNum 表示的是轨迹的段数,也就是 M,因为我们算的轨迹是三维的,所以边界值的列数为 3 ,代表x,y,z:

Eigen::MatrixXd M = Eigen::MatrixXd::Zero(6 * pieceNum , 6 * pieceNum );
Eigen::MatrixXd b = Eigen::MatrixXd::Zero(6 * pieceNum , 3);

接下来我们先把问题缩小,先看由三个点(起始点、终点和一个中间位点)构成的轨迹,注意这里的 \large C_1 是指系数矩阵: 

 \large M=\begin{bmatrix} F_0& 0 \\ E_1& F_1\\ 0& E_2 \end{bmatrix} c=\begin{bmatrix}C_1\\C_2 \end{bmatrix} b=(D_0^T, D_1^T, 0_{m\times \bar{d}_1},D_M^T)^T

 // coefficientMatrix is a matrix with 6*piece num rows and 3 columes
    // As for a polynomial c0+c1*t+c2*t^2+c3*t^3+c4*t^4+c5*t^5,
    // each 6*3 sub-block of coefficientMatrix is
    // --              --
    // | c0_x c0_y c0_z |
    // | c1_x c1_y c1_z |
    // | c2_x c2_y c2_z |
    // | c3_x c3_y c3_z |
    // | c4_x c4_y c4_z |
    // | c5_x c5_y c5_z |
    // --              --

我们知道,最小jerk的轨迹是由一个五阶多项式来描述的:

\large x(t)=c_0+c_1t+c_2t^2+c_3t^3+c_4t^4+c_5t^5

其一阶导的形式:

\large \dot{x}(t)=c_1+2c_2t+3c_3t^2+4c_4t^3+5c_5t^4

依此类推: 

\large \ddot{x}(t)=2c_2+6c_3t+12c_4t^2+20c_5t^3

\large \dddot{x}(t)=6c_3+24c_4t+60c_5t^2

\large \ddddot{x}(t)=24c_4+120c_5t

我们首先知道了起始点的位置,速度和加速度,那么把 t=0代入进去就有:

\large Initpos = {x}(0)=c_0 =\begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0\end{bmatrix}\begin{bmatrix} c_0 & c_1 & c_2 & c_3 & c_4 & c_5\end{bmatrix}^T

\large Initvel = \dot{x}(0)=c_1 =\begin{bmatrix} 0 & 1 & 0 & 0 & 0 & 0\end{bmatrix}\begin{bmatrix} c_0 & c_1 & c_2 & c_3 & c_4 & c_5\end{bmatrix}^T

\large Initacc = \ddot{x}(0)=2c_2 =\begin{bmatrix} 0 & 0 & 2 & 0 & 0 & 0\end{bmatrix}\begin{bmatrix} c_0 & c_1 & c_2 & c_3 & c_4 & c_5\end{bmatrix}^T

再看回原式,就有第一个表达式:

\large F_0C_1 = D_0^T

其中:

\large D_0^T=\begin{bmatrix} Initpos\\Initvel \\ Initacc \end{bmatrix} F_0=\begin{bmatrix} 1 & 0&0&0&0&0\\0 & 1&0&0&0&0 \\ 0 & 0&2&0&0&0 \end{bmatrix} C_1=\begin{bmatrix} c_0&c_1&c_2&c_3&c_4&c_5 \end{bmatrix}^T

那么我们就可以往 M 矩阵和 b 矩阵填入相应的元素:

 Eigen::MatrixXd F_0(3,6);
 F_0 <<  1, 0, 0, 0, 0, 0,
         0, 1, 0, 0, 0, 0,
         0, 0, 2, 0, 0, 0;
 M.block(0, 0, 3, 6) = F_0;
 b.block(0, 0, 3, 3) <<  initialPos(0), initialPos(1), initialPos(2), 
                         initialVel(0), initialVel(1), initialVel(2), 
                         initialAcc(0), initialAcc(1), initialAcc(2);

 终止位置也同理,这里我们假设最后一段轨迹的表达式为:

\large x_M(t) = c_0' + c_1't + c_2't^2+ c_3't^3+c_4't^4 + c_5't^5

那么就有:

\large Terminalpos = {x_2}(t_m)\\=c_0 + c_1t_{m} + c_2t_{m}^{2}+ c_3t_{m}^{3}+ c_4t_{m}^{4}+ c_5t_{m}^{5} \\=\begin{bmatrix} 1 & t_m & t_m^2 & t_m^3 & t_m^4 & t_m^5\end{bmatrix}\begin{bmatrix} c_0' & c_1' & c_2' & c_3' & c_4' & c_5'\end{bmatrix}^T

\large Terminalvel=\begin{bmatrix} 0 &1 &2 t_m & 3t_m^2 & 4t_m^3 & 5t_m^4\end{bmatrix}\begin{bmatrix} c_0' & c_1' & c_2' & c_3' & c_4' & c_5'\end{bmatrix}^T

\large Terminalacc=\begin{bmatrix} 0 &0 &2 & 6t_m & 12t_m^2 & 20t_m^3\end{bmatrix}\begin{bmatrix} c_0' & c_1' & c_2' & c_3' & c_4' & c_5'\end{bmatrix}^T

因为我们现在是拿三个点组成的两段轨迹做例子,实际上下标2已经表示最后一段轨迹 M,再看回原式,就有最后一个表达式:

\large E_MC_M=E_2C_2 = D_2^T

其中:

\large D_M^T=D_2^T=\begin{bmatrix} Terminalpos\\Terminalvel \\ Terminalacc \end{bmatrix} E_M=E_2=\begin{bmatrix} 1 & t_m & t_m^2 & t_m^3 & t_m^4 & t_m^5\\0 &1 &2 t_m & 3t_m^2 & 4t_m^3 & 5t_m^4 \\ 0 &0 &2 & 6t_m & 12t_m^2 & 20t_m^3\end{bmatrix}

\large C_M=C_2=\begin{bmatrix} c_0'&c_1'&c_2'&c_3'&c_4'&c_5' \end{bmatrix}^T

那么我们又可以往 M 矩阵和 b 矩阵填入相应的元素,相应的代码编写如下,其中 t 就是最后一段轨迹运行的时间:

double t(timeAllocationVector(pieceNum-1));
Eigen::MatrixXd E_M(3,6);
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);
M.block(6 * pieceNum -3, 6 * (pieceNum - 1), 3, 6) = E_M;
b.block(6 * pieceNum -3, 0, 3, 3) <<    terminalPos(0), terminalPos(1), terminalPos(2), 
                                        terminalVel(0), terminalVel(1), terminalVel(2), 
                                        terminalAcc(0), terminalAcc(1), terminalAcc(2);

接下来我们就要考虑中间点的边界条件问题了,此时我们注意到要计算的是:

\large E_1C_1+F_1C_2

也就是说,现在我们需要考虑中间点左右两端轨迹的表达式了,同时我们将轨迹相关的表达式都移到等式左边的话,右边就是 b 矩阵对应的元素。

首先中间位点需要满足以下约束,也就是该点如果作为前一段轨迹的终点,位置应该就是提供的中间位点的位置:

\large x(t_1) = c_0 + c_1t_1 + c_2t_1^2+ c_3t_1^3+c_4t_1^4 + c_5t_1^5=IntermediatePos

此时跟 \large C_2 无关,那么我们可以令 \large F_1 的第一行(C++索引为0)元素为0,就有:

\large E_{1,0}=\begin{bmatrix} 1 & t_1 & t_1^2 & t_1^3 & t_1^4 & t_1^5\end{bmatrix}\ \ \ F_{1,0} = \begin{bmatrix} 0 & 0 & 0 & 0 & 0 &0\end{bmatrix}

\large E_{1,0}C_1 + F_{1,0}C_2 = IntermediatePos= D_1^T

之后根据最优条件理论我们可以知道,如果我们的输入是轨迹的 s 阶导数,那么其 2s-d-1 阶导数也都是连续可导的,接下来我们来写相应的表达式满足这个条件。

首先是轨迹在中间位点的位置是要连续的,那么就有前一段轨迹的终点位置等于后一段轨迹的起点位置:

\large x(t_1) = c_0 + c_1t_1 + c_2t_1^2+ c_3t_1^3+c_4t_1^4 + c_5t_1^5=x_1(0)=c_0'

移一下项就有:

\large c_0 + c_1t_1 + c_2t_1^2+ c_3t_1^3+c_4t_1^4 + c_5t_1^5-c_0' = E_{1,1}C_1 + F_{1,1}C_2=0

其中:

\large E_{1,1}=\begin{bmatrix} 1 & t_1 & t_1^2 & t_1^3 & t_1^4 & t_1^5\end{bmatrix}\ \ \ F_{1,1} = \begin{bmatrix} -1 & 0 & 0 & 0 & 0 &0\end{bmatrix}

我们再具体考虑速度,也就是轨迹在中间位点的速度也是连续的:

\large \dot{x}(t_1) = c_1 + 2c_2t_1+ 3c_3t_1^2+4c_4t_1^3 + 5c_5t_1^4=\dot{x}_1(0)=c_1'

\large c_1 + 2c_2t_1+ 3c_3t_1^2+4c_4t_1^3 + 5c_5t_1^4-c_1' = E_{1,2}C_1 + F_{1,2}C_2=0

其中:

\large E_{1,2}=\begin{bmatrix} 0 & 1 & 2t_1 & 3t_1^2 & 4t_1^3 & 5t_1^4\end{bmatrix}\ \ \ F_{1,2} = \begin{bmatrix} 0 & -1 & 0 & 0 & 0 &0\end{bmatrix}

最优条件理论说了,如果我们生成的是jerk轨迹,那么在中间位点上直到snap都是连续的,如下图所示:

那么我们就可以依此类推,最终得到:

\large E_1 = \begin{bmatrix} 1 & t_1 & t_1^2 & t_1^3 & t_1^4 & t_1^5 \\ 1 & t_1 & t_1^2 & t_1^3 & t_1^4 & t_1^5 \\ 0 & 1 & 2t_1& 3t_1^2& 4t_1^3& 5t_1^4\\ 0& 0& 2& 6t_1& 12t_1^2& 20t_1^3\\ 0& 0& 0& 6& 24t_1& 60t_1^2\\ 0& 0& 0& 0& 24& 120t_1\end{bmatrix} \ \ F_1 = \begin{bmatrix} 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\end{bmatrix}

\large \begin{bmatrix} D_T^1 & 0_{M \times \bar{d_1}} \end{bmatrix}^T=[IntermediatePos, 0, 0, 0, 0, 0]^T

那么随着中间点增多,我们就可以用循环把这些元素依次填进去:

for (int i=1; i < pieceNum ; i++){
        double t(timeAllocationVector(i-1));
        Eigen::MatrixXd F_i(6,6), E_i(6,6);
        Eigen::Vector3d D_i(intermediatePositions.transpose().row(i-1));
        E_i <<  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;
        F_i <<  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;
        int j = 6 * (i-1);
        M.block(3+6*(i-1), j + 6, 6, 6) = F_i;
        M.block(3+6*(i-1), j, 6, 6) = E_i;
        b.block(3+6*(i-1), 0, 6, 3) <<  D_i(0), D_i(1), D_i(2),
                                        0, 0, 0,
                                        0, 0, 0,
                                        0, 0, 0,
                                        0, 0, 0,
                                        0, 0, 0;
    }

最后,我们就得到了最终的 M 矩阵和 b 矩阵, 接下来通过对 M 矩阵求逆就可以解出系数矩阵 c:

\large Mc=b\rightarrow c=M^{-1}b

coefficientMatrix = M.inverse() * b;

至此,完成作业的代码已经编写完成,其最终效果和实现最小jerk轨迹函数的完整代码如下: 

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)
{
    // coefficientMatrix is a matrix with 6*piece num rows and 3 columes
    // As for a polynomial c0+c1*t+c2*t^2+c3*t^3+c4*t^4+c5*t^5,
    // each 6*3 sub-block of coefficientMatrix is
    // --              --
    // | c0_x c0_y c0_z |
    // | c1_x c1_y c1_z |
    // | c2_x c2_y c2_z |
    // | c3_x c3_y c3_z |
    // | c4_x c4_y c4_z |
    // | c5_x c5_y c5_z |
    // --              --
    // Please computed coefficientMatrix of the minimum-jerk trajectory
    // in this function

    // ------------------------ Put your solution below ------------------------
    Eigen::MatrixXd M = Eigen::MatrixXd::Zero(6 * pieceNum , 6 * pieceNum );
    Eigen::MatrixXd b = Eigen::MatrixXd::Zero(6 * pieceNum , 3);

    Eigen::MatrixXd F_0(3,6);
    F_0 <<  1, 0, 0, 0, 0, 0,
            0, 1, 0, 0, 0, 0,
            0, 0, 2, 0, 0, 0;
    M.block(0, 0, 3, 6) = F_0;
    b.block(0, 0, 3, 3) <<  initialPos(0), initialPos(1), initialPos(2), 
                            initialVel(0), initialVel(1), initialVel(2), 
                            initialAcc(0), initialAcc(1), initialAcc(2);
    
    for (int i=1; i < pieceNum ; i++){
        double t(timeAllocationVector(i-1));
        Eigen::MatrixXd F_i(6,6), E_i(6,6);
        Eigen::Vector3d D_i(intermediatePositions.transpose().row(i-1));
        E_i <<  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;
        F_i <<  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;
        int j = 6 * (i-1);
        M.block(3+6*(i-1), j + 6, 6, 6) = F_i;
        M.block(3+6*(i-1), j, 6, 6) = E_i;
        b.block(3+6*(i-1), 0, 6, 3) <<  D_i(0), D_i(1), D_i(2),
                                        0, 0, 0,
                                        0, 0, 0,
                                        0, 0, 0,
                                        0, 0, 0,
                                        0, 0, 0;
    }
    double t(timeAllocationVector(pieceNum-1));
    Eigen::MatrixXd E_M(3,6);
    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);
    M.block(6 * pieceNum -3, 6 * (pieceNum - 1), 3, 6) = E_M;
    b.block(6 * pieceNum -3, 0, 3, 3) <<    terminalPos(0), terminalPos(1), terminalPos(2), 
                                            terminalVel(0), terminalVel(1), terminalVel(2), 
                                            terminalAcc(0), terminalAcc(1), terminalAcc(2);
                                        

    coefficientMatrix = M.inverse() * b;
    // ------------------------ Put your solution above ------------------------
}

学习笔记4:Minimum Jerk轨迹跟踪实验(算法原理及代码框架) 1、matlab文件line_tracker_min_jerk_numerical_issues.m计算minimum jerk轨迹多项式系数。输入:初始位置、最终位置、初始速度、最终速度、初始加速度、最终加速度、yaw角、yaw角速率;2、line_tracker_min_jerk_server.cpp为轨迹生成的主体服务;使用nodelet启动所有类型的轨迹生成(跟踪),包括直线轨迹、圆形轨迹等等。输出:轨迹多项式的6个系数、表示yaw角的4个系数。为求得5阶多项式轨迹,需要求得多项式系数p。 阅读详情

相关推荐

Robotics: Aerial Robotics(空中机器人)笔记(六):无人机运动规划

在之前的学习中我们已经讨论了如何根据给定轨迹对四旋翼进行控制,在这一章里,我们将探索四旋翼无人机在三维空间中的运动规划,即给定一个三维的环境,我们希望能够在这个三维环境中指定具体的点,进而让四旋翼无人机在这个环境中规划出无障碍的轨迹路线。

qq_42286607的博客 4954

Minimum jerk / Minimum snap后端轨迹优化

Minimum jerk / Minimum snap后端轨迹优化,在深蓝学院的课程中有对这部分进行讲解,详细的内容可以去 b 站找视屏看一看,这里主要是理解运用,包含程序。

YUE__zy的博客 4089

轨迹优化实战:基于Minimum-jerk的机器人平滑运动规划

本文深入探讨了基于Minimum-jerk的机器人平滑运动规划技术,详细解析了其数学原理与工程实现。通过轨迹优化算法,机器人能够实现如人类般自然的运动轨迹,显著降低机械磨损和能耗。文章包含从理论推导到代码实践的完整指南,特别分享了路径点约束处理、求解器选择等实战经验,并展望了机器学习辅助优化等前沿方向。

weixin_29048309的博客 270

运动规划课程第四次作业——考虑运动约束的路径规划代码全解析

深蓝学院运动规划课程第四次作业代码解析

Jason_C_的博客 2178

最优轨迹生成(四)—— 带约束轨迹优化

本系列文章是学习深蓝学院-移动机器人运动规划课程第五章最优轨迹生成 过程中所记录的笔记,本系列文章共包含四篇文章,依次介绍了微分平坦特性、无约束BVP轨迹优化、无约束BIVP轨迹优、 带约束轨迹优化等内容

慕羽★的博客 3791

最优轨迹生成(三)—— 无约束BIVP轨迹优化

本系列文章是学习深蓝学院-移动机器人运动规划课程第五章最优轨迹生成 过程中所记录的笔记,本系列文章共包含四篇文章,依次介绍了微分平坦特性、无约束BVP轨迹优化、无约束BIVP轨迹优、 带约束轨迹优化等内容

慕羽★的博客 2699

轨迹规划理论(二)无约束BVP轨迹优化和BIVP轨迹优化

本系列笔记主要为笔者对轨迹规划的基础理论归纳整理,方便学习,如有问题,望各位大佬指出。

weixin_45534376的博客 1763

用友U8库龄分析避坑指南:物料出入库日期计算的5个常见错误

本文深入剖析了在用友U8系统中进行库龄分析时,物料出入库日期计算的五个常见陷阱。从数据源选择、业务类型过滤、计价方式逻辑、期初数据处理到查询性能优化,逐一解析错误根源并提供避坑指南,帮助企业获得准确的库龄数据,有效管理库存与资金风险。

weixin_29209801的博客 455

深蓝路径规划作业-第二章

其中在A*寻找这个函数中,首先将障碍物、目标和起始点进行定义:Obstacle=-1, Target = 0, Start=1,并将这个地图乘以一个系数k。其中g(n)表示当前点的cost,h(n)表示对终点的预测,这个预测可以用0、1、2和∞范数,但L1范数(曼哈顿/出租车距离)无法保证其最优性。此外,A*算法扩展效率慢,当地图变大的时候,效率很低,计算耗时很大。这个obstacle_map主要是生成地图上的障碍,当rand小于0.45并且不是起始点和终止点的时候产生障碍map点。之后的功能主要是维护。

weixin_47765522的博客 1725

树莓派IgH EtherCAT主站部署与实时内核调优实战

本文详细介绍了在树莓派上部署开源IgH EtherCAT主站并进行实时内核调优的完整实战流程。通过编译实时内核(RT-Preempt)、交叉编译IgH主站、系统集成配置及性能优化,实现了低成本、高定制的工业控制解决方案,有效满足了EtherCAT通信对微秒级实时性的严苛要求。

weixin_29166013的博客 299

Excel转LaTeX表格神器:excel2latex.xla插件使用全攻略(含下载链接与配置教程)

本文详细介绍了Excel转LaTeX表格神器excel2latex.xla插件的完整使用攻略。从下载安装、基础转换到高级配置,深入讲解了如何利用该插件高效生成LaTeX代码,特别针对IEEE双栏等复杂排版需求提供了专业解决方案,帮助用户彻底告别手动编码,提升学术与专业文档的排版效率。

app77的博客 295

仅轨迹生成和跟踪

无人机快速穿圈,输入圈中心的位置,根据位置生成轨迹,并跟踪轨迹

asd22222984565的博客 4385

脑影像分析软件推荐 | JuSpace

JuSpace是一种允许基于 MRI 测量与核成像衍生估计的跨模态关联的工具包,它涵盖各种神经递质系统,包括多巴胺能、血清素能、去甲肾上腺素能和 GABA(γ-氨基丁酸) 神经传递。JuSpace 由一组 Matlab 功能以及涵盖各种受体系统的 PET 受体图谱组成。

NHKJ_ZF的博客 1707

【自看】Eigen 库 函数

/1.使用旋转的角度和旋转轴向量(此向量为单位向量)来初始化四元数,即使用q=[cos(A/2),n_x*sin(A/2),n_y*sin(A/2),n_z*sin(A/2)]//2.2 使用旋转向量的成员函数toRotationMatrix()来对旋转矩阵赋值。

weixin_52867897的博客 2770

基于Transformer模型实现交通流量时序预测(PyTorch版)

Transformer模型,作为一种基于自注意力机制的深度学习模型,最初在自然语言处理领域取得了突破性进展,其出色的长距离依赖关系捕捉能力使其在处理时序数据时也表现出色。将Transformer模型应用于交通流量时序预测,可以充分利用其优势,实现对交通流量更加精准、高效的预测。

时序笔记 2570

把 OData V4 服务真正发布出去:事务码 /IWFND/V4_ADMIN 在 SAP S/4HANA On-Premise 里的定位与用法

本文介绍了SAP S/4HANA中的事务码/IWFND/V4_ADMIN,这是SAP Gateway管理OData V4服务的关键工具。该事务码主要负责将后端注册的OData V4服务以服务组形式发布到前端,并维护系统别名路由、测试入口和日志跳转。与OData V2不同,V4采用服务组概念以支持跨服务导航,类似商场统一管理多个专柜。文章还通过实际案例说明,未发布服务组会导致BAS等工具无法发现OData V4服务,并提供了验证服务组状态的访问路径和ABAP示例代码。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 207

Boundary Value Problem (BVP) 两点边界最优控制问题

OBVP在路径规划当中的应用

世界仙境与冷酷尽头's Blog 5370

采用了fluent模拟了平壁面结霜过程。udf,很经典,可以试试。

利用该模型作为FLUENT中的源项,模拟了在局部冷却下冷表面上的霜形成,以预测霜的形态、温度分布和霜的重量,结果与实验结果吻合良好。结果显示,霜首先围绕冷却块形成,然后逐渐向其他方向扩展,冷却块上方的霜密度最大。随着时间的推移,平均霜厚度逐渐增加,生长速率减慢,而平均霜密度随增长速率变快而增加。相变传递微观过程与机理、蒸发及冷凝换热、强化传热、高效传热管、热泵、制冷、节水节能新技术、电子元器件冷却、余热回收及梯级利用等。udf,很经典,可以试试。工程热物理、空调、热能、低温制冷、化工、物理等。

qq_15963745的博客 922

c++ eigen MatrixXd基础介绍和使用

是Eigen库中用于表示动态大小双精度浮点矩阵的类。MatrixXd是的别名,支持任意大小的矩阵,且数据类型为double。

HJQD777的博客 1934

【Python机器学习】零基础掌握TweedieRegressor广义线性回归模型

本次文章主要介绍了如何使用Tweedie回归模型预测电动汽车的实际续航里程。基于车速、气温和驾驶习惯等多种因素,模型能够准确地预测出电动汽车的续航里程,从而为生产商和消费者提供有用的信息。优点总结,Tweedie回归模型在处理具有多元性和高度散布的数据方面表现出色,特别适用于需要考虑多种影响因素的预测任务。优点名称对应描述说明多元性强可以同时处理多种类型和维度的数据高度可定制允许用户自定义损失函数和正则项对异常值鲁棒能够较好地处理数据中的异常值易于解释参数和预测结果都相对容易解释。

Mr数据杨 1006

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Eigen::MatrixXd的一个坑

Eigen3.2的一个BUG,换成Eigen3.4恢复正常

u011208918的专栏 750

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

笔记5:Minimum Jerk/Snap代码架构详解、运行方法

安装完成后,编译器会去 /usr/local/include 或者 /usr/include 目录找头文件,但找到的是eigen3,并没有Eigen和unsupported,因此需要建立一个软连接,链接到这两个文件夹即可。其中包含了求解轨迹多项式系数矩阵的函数SolveQPClosedForm()。config.yaml文件用于设置轨迹约束(路径点、每段轨迹时间)类中包含了处理系数矩阵、生成轨迹、发布轨迹话题所需要的函数。此处可以将轨迹多项式系数矩阵cout出来,或者发布话题。声明了planner类,

Hanamizukimr的博客 740

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

视觉SLAM学习笔记3——eigen库的基础编程

视觉SLAM学习笔记3——eigen库的基础编程

weixin_52519143的博客 1049

深蓝学院 运动规划作业ch5 轨迹平滑优化

每两端之间的连续性约束的表达形式如下所示,黄色的是第一段和第二段之间的连续性约束,红色的是第二段和第三段之间的连续性约束。后面的约束项分为两部分,第一部分为各阶导数约束(包含了起始点和终点的各阶导数约束,和中间点的位置约束)这个还是上面的5阶,4个点的情况,从上倒下每一个绿块分别代表起始点,终止点,第二个,第三个点。第二部分为每两端之间的连续性约束,第一段和第二段之间的表达形式分别如下所示。

Tipriest的博客 801

Eigen学习笔记(2)-Matrix类

原文:Eigen官网-The Matrix class 在Eigen中,所有的矩阵Matrix和向量Vector都是由Matrix类构造的。向量只不过是矩阵的特殊形式,只有一列(列向量)或者一行。 1. Matrix类的参数 Matrix有6个模板参数,主要使用前三个参数,剩下的三个参数有默认值。 Matrix<typename Scalar, int RowsAtCompileTime, ...

ClaireQi的博客 2899

深蓝学院-移动机器人运动规划重点笔记

移动机器人运动规划笔记,转载自https://blog.youkuaiyun.com/wqwqqwqw1231/article/details/107310965 感谢原作者的总结!

weixin_37705221的博客 1388
上一篇: Robotics: Computational Motion Planning(路径规划)笔记(二):配置空间(Configuration Space)
下一篇: Robotics: Computational Motion Planning(路径规划)笔记(三):基于采样的方法-PRM和RRT算法
向南而行灬
博客等级 码龄8年 1万+粉丝 25原创
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向南而行灬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值