ros moveit机械臂轨迹 三次插补

2022-03-30  本文已影响0人  瀚文文文问问

问题引入

front_tpva.png

通过这张图可以看到moveit输出的轨迹并不圆滑,尤其是加速度曲线,这代表电机的力矩变化很大,会造成机械臂在运动的过程中抖动。

第一行是时间,第二行是位置,第三行是速度,第四行是加速度,至于数据具体含义以及怎么使用moveit导出这个轨迹数据我在这篇文章中不去具体阐述。

工程目录.png

实现流程

1.读取tractory.txt文件并转化为double数组

这一部分我感觉写的有一些麻烦,因为我本身c++编程能力并不好,我本科是机械专业,之前编成用python比较多,这里谁有简单实现可以分享以下!

struct String_data
{
    string t_str;
    string pos_str;
    string vel_str; 
    string acc_str;
};

class Deal_data
{
public:


    void load_data(const char * name)
    {
        ifstream openfile;
        openfile.open(name,ios::in);
        if (!openfile.is_open())
        {
            cout << "file can't open!" << endl;
        }
        string buf;
        int count = 0;
        while(getline(openfile,buf))
        {
            if (count == 0)
            {
                str_data.t_str = buf;
                
            }
            if(count==1)
            {
                str_data.pos_str = buf;
            }
            if(count==2)
            {
                str_data.vel_str = buf;
            }   
            if(count==3)
            {
                str_data.acc_str = buf;
            }   
            count ++;   
        }
    }

    void get_point_num()
    {
        int p = 0;
        int num = 0;
        int splite_position[100];
        string t_str_inner = str_data.t_str; 
        while(t_str_inner.find(",",p)!=string::npos)
        {
            p = t_str_inner.find(",",p);
            // int型数组用来储存所有,的位置
            splite_position[num] = p;
            p = p + 1;
            num ++;
        }
        point_num = num;

    }

    double * get_data_t()
    {
        int p = 0;
        int num = 0;
        int splite_position[100];
        string t_str_inner = str_data.t_str; 
        while(t_str_inner.find(",",p)!=string::npos)
        {
            p = t_str_inner.find(",",p);
            splite_position[num] = p;
            p = p + 1;
            num ++;
        }
        char t_char[point_num];
        double * t = new double[point_num];
        for (int i=0;i<point_num;i++)
        {
            int end = splite_position[i];
            if(i==0)
            {
                // 字符串分割
                string str = t_str_inner.substr(0,end);
                // char转double,并存入数组
                t[i] = atof(str.c_str());
                // cout << t[i] << endl;
            }
            else
            {
                int start = splite_position[i-1]+1;
                string str = t_str_inner.substr(start,end - start); 
                t[i] = atof(str.c_str());
                // cout << t[i] << endl;
            }
        }
        return t;
    }

    double * get_data_pos()
    {
        int p = 0;
        int num = 0;
        int splite_position[100];
        string pos_str_inner = str_data.pos_str; 
        while(pos_str_inner.find(",",p)!=string::npos)
        {
            p = pos_str_inner.find(",",p);
            // int型数组用来储存所有,的位置
            splite_position[num] = p;
            p = p + 1;
            num ++;
        }
        char t_char[point_num];
        double * pos = new double[point_num];
        for (int i=0;i<point_num;i++)
        {
            int end = splite_position[i];
            if(i==0)
            {
                string str = pos_str_inner.substr(0,end);
                pos[i] = atof(str.c_str());
            }
            else
            {
                int start = splite_position[i-1]+1;
                string str = pos_str_inner.substr(start,end - start); 
                pos[i] = atof(str.c_str());
            }
        }
        return pos;
    }
    double * get_data_vel()
    {
        int p = 0;
        int num = 0;
        int splite_position[100];
        string vel_str_inner = str_data.vel_str; 
        while(vel_str_inner.find(",",p)!=string::npos)
        {
            p = vel_str_inner.find(",",p);
            // int型数组用来储存所有,的位置
            splite_position[num] = p;
            p = p + 1;
            num ++;
        }
        char t_char[point_num];
        double * vel = new double[point_num];
        for (int i=0;i<point_num;i++)
        {
            int end = splite_position[i];
            if(i==0)
            {
                string str = vel_str_inner.substr(0,end);
                vel[i] = atof(str.c_str());
            }
            else
            {
                int start = splite_position[i-1]+1;
                string str = vel_str_inner.substr(start,end - start); 
                vel[i] = atof(str.c_str());
            }
        }
        return vel;
    }

    double * get_data_acc()
    {
        int p = 0;
        int num = 0;
        int splite_position[100];
        string acc_str_inner = str_data.acc_str; 
        while(acc_str_inner.find(",",p)!=string::npos)
        {
            p = acc_str_inner.find(",",p);
            // int型数组用来储存所有,的位置
            splite_position[num] = p;
            p = p + 1;
            num ++;
        }
        char t_char[point_num];
        double * acc = new double[point_num];
        for (int i=0;i<point_num;i++)
        {
            int end = splite_position[i];
            if(i==0)
            {
                string str = acc_str_inner.substr(0,end);
                acc[i] = atof(str.c_str());
            }
            else
            {
                int start = splite_position[i-1]+1;
                string str = acc_str_inner.substr(start,end - start); 
                acc[i] = atof(str.c_str());
            }
        }
        return acc;
    }
    int point_num;
private:
    struct String_data str_data;

};

1.进行轨迹三次插补

插补的具体实现我参照了古月老师的方法。边界条件都为0。
cublicSpline.h头文件

#ifndef _CUBIC_SPLINE_H_
#define _CUBIC_SPLINE_H_
 
class cubicSpline
{
public:
    typedef enum _BoundType
    {
        BoundType_First_Derivative,
        BoundType_Second_Derivative
    }BoundType;
 
public:
    cubicSpline();
    ~cubicSpline();
 
    void initParam();
    void releaseMem();
 
    bool loadData(double *x_data, double *y_data, int count, double bound1, double bound2, BoundType type);
    bool getYbyX(double &x_in, double &y_out);
 
protected:
    bool spline(BoundType type);
 
protected:
    double *x_sample_, *y_sample_;
    double *M_;
    int sample_count_;
    double bound1_, bound2_;
};
#endif /* _CUBIC_SPLINE_H_ */

cublicSpine.cpp源文件

/* 三次样条插补 */
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include "cubicSpline.h"

using namespace std;
/* 初始化输入输出速度加速度 */
double acc = 0, vel = 0;
double x_out = 0, y_out = 0;

/* 三次样条无参构造 */
cubicSpline::cubicSpline()
{
}
/* 析构 */
cubicSpline::~cubicSpline()
{
    releaseMem();
}
/* 初始化参数 */
void cubicSpline::initParam()
{
    x_sample_ = y_sample_ = M_ = NULL;
    sample_count_ = 0;
    bound1_ = bound2_ = 0;
}
/* 释放参数 */
void cubicSpline::releaseMem()
{
    delete x_sample_;
    delete y_sample_;
    delete M_;
 
    initParam();
}
/* 加载关节位置数组等信息 */
bool cubicSpline::loadData(double *x_data, double *y_data, int count, double bound1, double bound2, BoundType type)
{
    if ((NULL == x_data) || (NULL == y_data) || (count < 3) || (type > BoundType_Second_Derivative) || (type < BoundType_First_Derivative))
    {
        return false;
    }
 
    initParam();
 
    x_sample_ = new double[count];
    y_sample_ = new double[count];
    M_        = new double[count];
    sample_count_ = count;
 
    memcpy(x_sample_, x_data, sample_count_*sizeof(double));
    memcpy(y_sample_, y_data, sample_count_*sizeof(double));
 
    bound1_ = bound1;
    bound2_ = bound2;
 
    return spline(type);
}
/* 计算样条插值 */
bool cubicSpline::spline(BoundType type)
{
    if ((type < BoundType_First_Derivative) || (type > BoundType_Second_Derivative))
    {
        return false;
    }
 
    //  追赶法解方程求二阶偏导数
    double f1=bound1_, f2=bound2_;
 
    double *a=new double[sample_count_];                //  a:稀疏矩阵最下边一串数
    double *b=new double[sample_count_];                //  b:稀疏矩阵最中间一串数
    double *c=new double[sample_count_];                //  c:稀疏矩阵最上边一串数
    double *d=new double[sample_count_];
 
    double *f=new double[sample_count_];
 
    double *bt=new double[sample_count_];
    double *gm=new double[sample_count_];
 
    double *h=new double[sample_count_];
 
    for(int i=0;i<sample_count_;i++)
        b[i]=2;                                //  中间一串数为2
    for(int i=0;i<sample_count_-1;i++)
        h[i]=x_sample_[i+1]-x_sample_[i];      // 各段步长
    for(int i=1;i<sample_count_-1;i++)
        a[i]=h[i-1]/(h[i-1]+h[i]);
    a[sample_count_-1]=1;
 
    c[0]=1;
    for(int i=1;i<sample_count_-1;i++)
        c[i]=h[i]/(h[i-1]+h[i]);
 
    for(int i=0;i<sample_count_-1;i++)
        f[i]=(y_sample_[i+1]-y_sample_[i])/(x_sample_[i+1]-x_sample_[i]);
 
    for(int i=1;i<sample_count_-1;i++)
        d[i]=6*(f[i]-f[i-1])/(h[i-1]+h[i]);
 
    //  追赶法求解方程
    if(BoundType_First_Derivative == type)
    {
        d[0]=6*(f[0]-f1)/h[0];
        d[sample_count_-1]=6*(f2-f[sample_count_-2])/h[sample_count_-2];
 
        bt[0]=c[0]/b[0];
        for(int i=1;i<sample_count_-1;i++)
            bt[i]=c[i]/(b[i]-a[i]*bt[i-1]);
 
        gm[0]=d[0]/b[0];
        for(int i=1;i<=sample_count_-1;i++)
            gm[i]=(d[i]-a[i]*gm[i-1])/(b[i]-a[i]*bt[i-1]);
 
        M_[sample_count_-1]=gm[sample_count_-1];
        for(int i=sample_count_-2;i>=0;i--)
            M_[i]=gm[i]-bt[i]*M_[i+1];
    }
    else if(BoundType_Second_Derivative == type)
    {
        d[1]=d[1]-a[1]*f1;
        d[sample_count_-2]=d[sample_count_-2]-c[sample_count_-2]*f2;
 
        bt[1]=c[1]/b[1];
        for(int i=2;i<sample_count_-2;i++)
            bt[i]=c[i]/(b[i]-a[i]*bt[i-1]);
 
        gm[1]=d[1]/b[1];
        for(int i=2;i<=sample_count_-2;i++)
            gm[i]=(d[i]-a[i]*gm[i-1])/(b[i]-a[i]*bt[i-1]);
 
        M_[sample_count_-2]=gm[sample_count_-2];
        for(int i=sample_count_-3;i>=1;i--)
            M_[i]=gm[i]-bt[i]*M_[i+1];
 
        M_[0]=f1;
        M_[sample_count_-1]=f2;
    }
    else
        return false;
 
    delete a;
    delete b;
    delete c;
    delete d;
    delete gm;
    delete bt;
    delete f;
    delete h;
 
    return true;
}
/* 得到速度和加速度数组 */
bool cubicSpline::getYbyX(double &x_in, double &y_out)
{
    int klo,khi,k;
    klo=0;
    khi=sample_count_-1;
    double hh,bb,aa;
 
    //  二分法查找x所在区间段
    while(khi-klo>1)
    {
        k=(khi+klo)>>1;
        if(x_sample_[k]>x_in)
            khi=k;
        else
            klo=k;
    }
    hh=x_sample_[khi]-x_sample_[klo];
 
    aa=(x_sample_[khi]-x_in)/hh;
    bb=(x_in-x_sample_[klo])/hh;
 
    y_out=aa*y_sample_[klo]+bb*y_sample_[khi]+((aa*aa*aa-aa)*M_[klo]+(bb*bb*bb-bb)*M_[khi])*hh*hh/6.0;
 
    //test
    acc = (M_[klo]*(x_sample_[khi]-x_in) + M_[khi]*(x_in - x_sample_[klo])) / hh;
    vel = M_[khi]*(x_in - x_sample_[klo]) * (x_in - x_sample_[klo]) / (2 * hh)
          - M_[klo]*(x_sample_[khi]-x_in) * (x_sample_[khi]-x_in) / (2 * hh)
          + (y_sample_[khi] - y_sample_[klo])/hh
          - hh*(M_[khi] - M_[klo])/6;
    //test end
 
    return true;
}

3.main.cpp以及CMakeLists.txt

别忘了把读取tractory.txt数据的程序,放到主函数的上面,我在上面写过了就不放上去了。

#include<iostream>
#include<stdio.h>
#include<stddef.h>
#include<string.h>
#include<fstream>
#include<vector>
#include "cubicSpline.h"
double acc = 0, vel = 0;
double x_out = 0, y_out = 0;
int main()
{
    setlocale(LC_ALL,"");
    char file_name[] = "/home/zhw/slam/learn_c++/TRY_SPLINE/src/tractory.txt";
    Deal_data opf;
    opf.load_data(file_name);
    opf.get_point_num();
    int point_num = opf.point_num;
    cout << opf.point_num << endl;
    double * time = opf.get_data_t();
    double * pos = opf.get_data_pos();
    double * vel_ = opf.get_data_vel();
    double * acc_ = opf.get_data_acc();

    cubicSpline spline;
    // lumbar test
    spline.loadData(time,pos, point_num, 0, 0, cubicSpline::BoundType_First_Derivative);
    double rate = (time[point_num-1] - time[0])/(point_num*4);
    double deal_pos[point_num*4];
    double deal_vel[point_num*4];
    double deal_acc[point_num*4];
    double time_from_start_[point_num*4];
    for (int k = 0; k <= point_num*4 ; k++) {
        printf("[---位置、速度、加速度---]");
        printf("%0.9f, %0.9f, %0.9f\n",y_out, vel, acc);
        spline.getYbyX(x_out, y_out);
        time_from_start_[k] = x_out;
        deal_pos[k] = y_out;
        deal_vel[k] = vel;
        deal_acc[k] = acc;
        x_out += rate;
    }
    FILE *f;
    f = fopen("/home/zhw/slam/learn_c++/TRY_SPLINE/deal_tractory.txt","a");
    for(int j=0;j<=point_num*4;j++)
    {
        fprintf(f,"%f,",time_from_start_[j]);//6
    }
    fprintf(f,"\n");
    for(int j=0;j<=point_num*4;j++)
    {
        fprintf(f,"%f,",deal_pos[j]);//7
    }
    fprintf(f,"\n");
    for(int j=0;j<=point_num*4;j++)
    {
        fprintf(f,"%f,",deal_vel[j]);//8
    }
    fprintf(f,"\n");
    for(int j=0;j<=point_num*4;j++)
    {
        fprintf(f,"%f,",deal_acc[j]);//9
    }
    fprintf(f,"\n");
    fclose(f);

    return 0;
}

这段程序中包含了将插值后的数据保存到deal_tractory.txt文件中。

cmake_minimum_required(VERSION 3.0.2)
include_directories(${CMAKE_SOURCE_DIR}/include)
add_library(cubicSpline SHARED cubicSpline.cpp)
add_executable(main main.cpp)
target_link_libraries(main cubicSpline)

结果

最后把插值前插值后的对比图show一下!!!


deal_tpva.png

感觉整体来看变化不是很大,就是轨迹点多了一些,我这里插值了四倍,还是放到机械臂上跑一下看一下变化,这里我的机械臂还没有搭建完成,搭建完成再测试把!

上一篇下一篇

猜你喜欢

热点阅读