mpu6050 arduino串口 通讯在ros下的可视化实验

瞎忙好几天,草草做个总结,贴上混乱代码一堆 涉及内容如下

dmp iic  mpu6050的通讯

获取加速度 角速度

二者结合求出角姿势 四元数,发送到计算机。

串口协议编写解析

ros发布位姿里程数据

试验了卡尔曼滤波 ,

加速度积分成位移(漂移问题)

加速度转到频域下积分成位移(高频)参考文章

fft变换卡尔曼滤波等算法

结论

mpu6050做角姿还不错,求位置很难。

是否是精度问题?噪声问题?低精度信号淹没在大噪声中?

算法问题?没有合适的算法求出纯加速度,进行恰当的滤波?

有待深入学习。


arduino 使用官方库的示例mpu_dmp.ino,使用自定格式串口通讯,部分代码如下;

#ifdef OUTPUT_READABLE_WORLDACCEL
            // display initial world-frame acceleration, adjusted to remove gravity
            // and rotated based on known orientation from quaternion
            mpu.dmpGetQuaternion(&q, fifoBuffer);
            mpu.dmpGetAccel(&aa, fifoBuffer);
            mpu.dmpGetGravity(&gravity, &q);
            mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity);
            mpu.dmpGetLinearAccelInWorld(&aaWorld, &aaReal, &q);

            byte* pw=(byte*)&(q.w);
            byte* px=(byte*)&(q.x);
            byte* py=(byte*)&(q.y);
            byte* pz=(byte*)&(q.z);

            byte* pwx=(byte*)&(aa.x);
            byte* pwy=(byte*)&(aa.y);
            byte* pwz=(byte*)&(aa.z);
            byte data[26]={'$',0x1a,
              *pw,*(pw+1),*(pw+2),*(pw+3),
              *px,*(px+1),*(px+2),*(px+3),
              *py,*(py+1),*(py+2),*(py+3),
              *pz,*(pz+1),*(pz+2),*(pz+3),
              
              *pwx,*(pwx+1),
              *pwy,*(pwy+1),
              *pwz,*(pwz+1),
              
            '\r', '\n' };
            Serial.write(data, 26);
           /* Serial.print("aworld\t");
            Serial.print(aaWorld.x);
            Serial.print("\t");
            Serial.print(aaWorld.y);
            Serial.print("\t");
            Serial.println(aaWorld.z);*/
        #endif
    



ros  rviz可视化:

mpu6050 arduino串口 通讯在ros下的可视化实验_第1张图片


冗长的代码:

#include 
#include 
#include 
//#include "gy85/imu.h"
#include 
//ROS已经内置了的串口包

#include                   //包含boost库函数
#include "math.h"
#include "helper_3dmath.h"
#include "polyfit.hpp"
#define DOUBLE_PI 6.283185307179586476925286766559
#define DATA_LENGTH 16
// 一维滤波器信息结构体
typedef  struct{
  double a;  //
  double b;   //   Kalamn增益

}  complex;

complex dataX[DATA_LENGTH];
complex dataY[DATA_LENGTH];
complex dataZ[DATA_LENGTH];
complex odataX[DATA_LENGTH];
complex odataY[DATA_LENGTH];
complex odataZ[DATA_LENGTH];
complex r1dataX[DATA_LENGTH];
complex r1dataY[DATA_LENGTH];
complex r1dataZ[DATA_LENGTH];
complex r2dataX[DATA_LENGTH];
complex r2dataY[DATA_LENGTH];
complex r2dataZ[DATA_LENGTH];
double dataXA[DATA_LENGTH];
double dataYA[DATA_LENGTH];
double dataZA[DATA_LENGTH];
double dataXB[DATA_LENGTH];
double dataYB[DATA_LENGTH];
double dataZB[DATA_LENGTH];
void resfft1(){
  unsigned int n=0;
  for(n=0;n>= 1;        // a = a / 2;
            }
        if ( b > i)
            {
            swap (xreal [i], xreal [b]);
            swap (ximag [i], ximag [b]);
            }
        }
}

void FFT(double xreal [], double ximag [], int n)
{
    // 快速傅立叶变换,将复数 x 变换后仍保存在 x 中,xreal, ximag 分别是 x 的实部和虚部
    double wreal [N / 2], wimag [N / 2], treal, timag, ureal, uimag, arg;
    int m, k, j, t, index1, index2;

    bitrp (xreal, ximag, n);

    // 计算 1 的前 n / 2 个 n 次方根的共轭复数 W'j = wreal [j] + i * wimag [j] , j = 0, 1, ... , n / 2 - 1
    arg = - 2 * PI / n;
    treal = cos (arg);
    timag = sin (arg);
    wreal [0] = 1.0;
    wimag [0] = 0.0;
    for (j = 1; j < n / 2; j ++)
        {
        wreal [j] = wreal [j - 1] * treal - wimag [j - 1] * timag;
        wimag [j] = wreal [j - 1] * timag + wimag [j - 1] * treal;
        }

    for (m = 2; m <= n; m *= 2)
        {
        for (k = 0; k < n; k += m)
            {
            for (j = 0; j < m / 2; j ++)
                {
                index1 = k + j;
                index2 = index1 + m / 2;
                t = n * j / m;    // 旋转因子 w 的实部在 wreal [] 中的下标为 t
                treal = wreal [t] * xreal [index2] - wimag [t] * ximag [index2];
                timag = wreal [t] * ximag [index2] + wimag [t] * xreal [index2];
                ureal = xreal [index1];
                uimag = ximag [index1];
                xreal [index1] = ureal + treal;
                ximag [index1] = uimag + timag;
                xreal [index2] = ureal - treal;
                ximag [index2] = uimag - timag;
                }
            }
        }
}

void  IFFT (double xreal [], double ximag [], int n)
{
    // 快速傅立叶逆变换
    double wreal [N / 2], wimag [N / 2], treal, timag, ureal, uimag, arg;
    int m, k, j, t, index1, index2;

    bitrp (xreal, ximag, n);

    // 计算 1 的前 n / 2 个 n 次方根 Wj = wreal [j] + i * wimag [j] , j = 0, 1, ... , n / 2 - 1
    arg = 2 * PI / n;
    treal = cos (arg);
    timag = sin (arg);
    wreal [0] = 1.0;
    wimag [0] = 0.0;
    for (j = 1; j < n / 2; j ++)
        {
        wreal [j] = wreal [j - 1] * treal - wimag [j - 1] * timag;
        wimag [j] = wreal [j - 1] * timag + wimag [j - 1] * treal;
        }

    for (m = 2; m <= n; m *= 2)
        {
        for (k = 0; k < n; k += m)
            {
            for (j = 0; j < m / 2; j ++)
                {
                index1 = k + j;
                index2 = index1 + m / 2;
                t = n * j / m;    // 旋转因子 w 的实部在 wreal [] 中的下标为 t
                treal = wreal [t] * xreal [index2] - wimag [t] * ximag [index2];
                timag = wreal [t] * ximag [index2] + wimag [t] * xreal [index2];
                ureal = xreal [index1];
                uimag = ximag [index1];
                xreal [index1] = ureal + treal;
                ximag [index1] = uimag + timag;
                xreal [index2] = ureal - treal;
                ximag [index2] = uimag - timag;
                }
            }
        }

    for (j=0; j < n; j ++)
        {
        xreal [j] /= n;
        ximag [j] /= n;
        }
}
void swap(complex *v1, complex *v2)
{
    complex tmp = *v1;
    *v1 = *v2;
    *v2 = tmp;
}

void fftshift(complex *data, int count)
{
    int k = 0;
    int c = (int) floor((float)count/2);
    // For odd and for even numbers of element use different algorithm
    if (count % 2 == 0)
    {
        for (k = 0; k < c; k++)
            swap(&data[k], &data[k+c]);
    }
    else
    {
        complex tmp = data[0];
        for (k = 0; k < c; k++)
        {
            data[k] = data[c + k + 1];
            data[c + k + 1] = data[k + 1];
        }
        data[c] = tmp;
    }
}

void ifftshift(complex *data, int count)
{
    int k = 0;
    int c = (int) floor((float)count/2);
    if (count % 2 == 0)
    {
        for (k = 0; k < c; k++)
            swap(&data[k], &data[k+c]);
    }
    else
    {
        complex tmp = data[count - 1];
        for (k = c-1; k >= 0; k--)
        {
            data[c + k + 1] = data[k];
            data[k] = data[c + k];
        }
        data[c] = tmp;
    }
}
void detrend(double array[], int n)
{
     double x, y, a, b;
     double sy = 0.0,
            sxy = 0.0,
            sxx = 0.0;
     int i;

     for (i=0, x=(-(double)n/2.0+0.5); i dxa(DATA_LENGTH);
std::vector dya(DATA_LENGTH);
std::vector dza(DATA_LENGTH);
std::vector dxb(DATA_LENGTH);
std::vector dyb(DATA_LENGTH);
std::vector dzb(DATA_LENGTH);
void res12v(){

  unsigned int n=0;
  for(n=0;n rdx(DATA_LENGTH),rdy(DATA_LENGTH),rdz(DATA_LENGTH),rdx2(DATA_LENGTH),rdy2(DATA_LENGTH),rdz2(DATA_LENGTH);
std::vector  vel_avrg_result(3);
std::vector  result(3);
double velintX[DATA_LENGTH];
double velintY[DATA_LENGTH];
double velintZ[DATA_LENGTH];
void count(){
  //% 频域积分
      double ts=0.02;
      //velint =  iomega(acc, ts, 3, 2);
      iomega( ts, 3, 2);
      resfft1();
      //velint = detrend(velint);
      //ROS_INFO("----------------");
      for(int i=0;iA = 1;  //标量卡尔曼
  info->H = 1;  //
  info->P = 10;  //后验状态估计值误差的方差的初始值(不要为0问题不大)
  info->Q = Q;    //预测(过程)噪声方差 影响收敛速率,可以根据实际需求给出
  info->R = R;    //测量(观测)噪声方差 可以通过实验手段获得
  info->filterValue = 0;// 测量的初始值
}
double KalmanFilter(KalmanInfo* kalmanInfo, double lastMeasurement)
{
  //预测下一时刻的值
  double predictValue = kalmanInfo->A* kalmanInfo->filterValue;   //x的先验估计由上一个时间点的后验估计值和输入信息给出,此处需要根据基站高度做一个修改

  //求协方差
  kalmanInfo->P = kalmanInfo->A*kalmanInfo->A*kalmanInfo->P + kalmanInfo->Q;  //计算先验均方差 p(n|n-1)=A^2*p(n-1|n-1)+q
  double preValue = kalmanInfo->filterValue;  //记录上次实际坐标的值

  //计算kalman增益
  kalmanInfo->kalmanGain = kalmanInfo->P*kalmanInfo->H / (kalmanInfo->P*kalmanInfo->H*kalmanInfo->H + kalmanInfo->R);  //Kg(k)= P(k|k-1) H’ / (H P(k|k-1) H’ + R)
  //修正结果,即计算滤波值
  kalmanInfo->filterValue = predictValue + (lastMeasurement - predictValue)*kalmanInfo->kalmanGain;  //利用残余的信息改善对x(t)的估计,给出后验估计,这个值也就是输出  X(k|k)= X(k|k-1)+Kg(k) (Z(k)-H X(k|k-1))
  //更新后验估计
  kalmanInfo->P = (1 - kalmanInfo->kalmanGain*kalmanInfo->H)*kalmanInfo->P;//计算后验均方差  P[n|n]=(1-K[n]*H)*P[n|n-1]

  return  kalmanInfo->filterValue;
}
KalmanInfo klmx;
KalmanInfo klmy;
KalmanInfo klmz;

using namespace boost::asio;           //定义一个命名空间,用于后面的读写操作
using namespace std;
serial::Serial ser; //声明串口对象
unsigned char buf[1];                      //定义字符串长度
unsigned char data[512];//
unsigned int dn=0;
unsigned int i=0,j=0;

  double pitch=0, roll=0, yaw=0;
  double ax = 0.0;
  double ay = 0.0;
  double az = 0.0;
  double tsx = 0.0;
  double tsy = 0.0;
  double tsz = 0.0;
  double tvx = 0.0;
  double tvy = 0.0;
  double tvz = 0.0;

  Vectordouble oawV;
  Quaternion worldQ; //[w,x,y,z]
  Vectordouble aV;//[x,y,z]
  Vectordouble gV;//[x,y,z]
  Vectordouble gVo;//[x,y,z]
  Vectordouble realV;


  void countGravity(Quaternion worldQ){
    gV.x=2.0*(worldQ.x*worldQ.z-worldQ.w*worldQ.y);
    gV.y=2.0*(worldQ.w*worldQ.x+worldQ.y*worldQ.z);
    gV.z=worldQ.w*worldQ.w-worldQ.x*worldQ.x-worldQ.y*worldQ.y+worldQ.z*worldQ.z;
  }

  void countRealAccel(short int awx, short int awy, short int awz){

    realV.x=((double)awx)-(gV.x)*4096.0;
    realV.y=((double)awy)-(gV.y)*4096.0;
    realV.z=((double)awz)-(gV.z)*4096.0;
    gVo.x = gV.x;
    gVo.y = gV.y;
    gVo.z = gV.z;
    oawV.x=(double)awx;
    oawV.y=(double)awy;
    oawV.z=(double)awz;
  };

  double gravity[3]={0.0,0.0,0.0};
  double linear_acceleration[3]={0.0,0.0,0.0};

  void onSensorChanged(double realx,double realy,double realz){
    // 在本例中,alpha 由 t / (t + dT)计算得来,
    // 其中 t 是低通滤波器的时间常数,dT 是事件报送频率
    float alpha = 0.8;
    // 用低通滤波器分离出重力加速度
    gravity[0]  = alpha * gravity[0] + (1 - alpha) * realx;
    gravity[1]  = alpha * gravity[1] + (1 - alpha) * realy;
    gravity[2]  = alpha * gravity[2] + (1 - alpha) * realz;
    // 用高通滤波器剔除重力干扰
    linear_acceleration[0] = realx - gravity[0];
    linear_acceleration[1] = realy - gravity[1];
    linear_acceleration[2] = realz - gravity[2];
    aV.x=linear_acceleration[0];
    aV.y=linear_acceleration[1];
    aV.z=linear_acceleration[2];

  }


  double acc2v(short int aw){
    return double (((double) aw)/4096.0)*9.8;
  }
  double acc2v(double aw){
    return double ((aw)/4096.0)*9.8;
  }



  ros::Time last_time;
  unsigned int startN=100;
  tf::Quaternion lastQ;

  void pulishMSG( short int awx, short int awy, short int awz,float yy,float pp,float rr,float qw,float qx,float qy,float qz,tf::TransformBroadcaster odom_broadcaster,ros::Publisher odom_pub){
    ros::Time current_time= ros::Time::now();
    double dt=(current_time.toSec()-last_time.toSec());


    last_time=current_time;

    worldQ.w=double(qw);
    worldQ.x=double(qx);
    worldQ.y=double(qy);
    worldQ.z=double(qz);
    worldQ.normalize();

    countGravity(worldQ);
    countRealAccel(awx, awy,awz);


    //ROS_INFO("awx=%d awy=%d awz=%d ",awx,awy,awz);
    //ROS_INFO("realx=%lf realy=%lf realz=%lf ",realV.x,realV.y,realV.z);
    onSensorChanged( realV.x, realV.y, realV.z);
    //onSensorChanged( double(awx), double(awy), double(awz));
    //ROS_INFO("linearx=%lf lineary=%lf linearz=%lf ",linear_acceleration[0],linear_acceleration[1],linear_acceleration[2]);

    if(startN==0){
      aV.rotate(&worldQ);
      ax=acc2v(aV.x);
      ay=acc2v(aV.y);
      az=acc2v(aV.z);


      odataX[datan].a=((datan==0)?0.0:(odataX[datan-1].a+dt));
      odataY[datan].a=odataX[datan].a;
      odataZ[datan].a=odataX[datan].a;
      odataX[datan].b=ax;
      odataY[datan].b=ay;
      odataZ[datan].b=az;
      datan+=1;
      if(datan==DATA_LENGTH){
        //
        ROS_INFO("----------------");
        for(datan=0;datan posi=count();
        ROS_INFO("posix=%lf posiy=%lf posiz=%lf ",result[0],result[1],result[2]);
        //tsx+= result[0];
        //tsy+= result[1];
        //tsz+= result[2];
        //tsx+= vel_avrg_result[0]*DATA_LENGTH*dt;
        //tsy+= vel_avrg_result[1]*DATA_LENGTH*dt;
        //tsz+= vel_avrg_result[2]*DATA_LENGTH*dt;
        //ROS_INFO("vx=%lf vy=%lf vz=%lf ",vel_avrg_result[0],vel_avrg_result[1],vel_avrg_result[2]);

      }
      //
      ax=KalmanFilter(&klmx, ax);
      ay=KalmanFilter(&klmy, ay);
      az=KalmanFilter(&klmz, az);

      tvx +=ax*dt;
      tvy +=ay*dt;
      tvz +=az*dt;

    }else{
      startN--;
    }


    //tsx= tvx;
    //tsy= tvy;
    //tsz= tvz;
    tsx+= tvx*dt;
    tsy+= tvy*dt;
    tsz+= tvz*dt;

    if(tsx*tsx+tsy*tsy+tsz*tsz>3*3){
      tsx= 0.0;
      tsy= 0.0;
      tsz= 0.0;
    }
    tvx*=0.9;
    tvy*=0.9;
    tvz*=0.9;
    /*ax*=0.9;
    ay*=0.9;
    az*=0.9;
    */


    //tf::Quaternion Q=tf::createQuaternionFromRPY(0.0,0.0,0.0);//	( qx,      qy,      qz,      qw     ) ;
    //Q.setEulerZYX(0,0,3.1415926/180);
    //Q.x=double(nqx);
    //Q.y=double(nqy);
    //Q.z=double(nqz);
    //Q.w=double(nqw);
    geometry_msgs::Quaternion odom_quat= tf::createQuaternionMsgFromRollPitchYaw(0, 0, 0);

    odom_quat.x=worldQ.x;//Q.getX();
    odom_quat.y=worldQ.y;//Q.getY();
    odom_quat.z=worldQ.z;//Q.getZ();
    odom_quat.w=worldQ.w;//Q.getW();


    //first, we'll publish the transform over tf
    geometry_msgs::TransformStamped odom_trans;
    odom_trans.header.stamp = current_time;
    odom_trans.header.frame_id = "odom";
    odom_trans.child_frame_id = "base_link";

    odom_trans.transform.translation.x = tsx*10;
    odom_trans.transform.translation.y = tsy*10;
    odom_trans.transform.translation.z = tsz*10;
    odom_trans.transform.rotation = odom_quat;

    //send the transform
    odom_broadcaster.sendTransform(odom_trans);

    //next, we'll publish the odometry message over ROS
    nav_msgs::Odometry odom;
    odom.header.stamp = current_time;
    odom.header.frame_id = "odom";

    //set the position
    odom.pose.pose.position.x = tsx*10;
    odom.pose.pose.position.y = tsy*10;
    odom.pose.pose.position.z = tsz*10;//odom_trans.transform.translation.z;
    odom.pose.pose.orientation = odom_quat;

    //set the velocity
    odom.child_frame_id = "base_link";
    odom.twist.twist.linear.x = tvx;
    odom.twist.twist.linear.y = tvy;
    odom.twist.twist.linear.z = tvz;
    odom.twist.twist.angular.z = 0.0;

    //publish the message
    odom_pub.publish(odom);
  }
int main(int argc, char** argv){
  ros::init(argc, argv, "mpu6050_teapotPacket");

  ros::NodeHandle n;
  ros::Publisher odom_pub;
  tf::TransformBroadcaster odom_broadcaster;
  odom_pub = n.advertise("odom", 1);

  Init_KalmanInfo(&klmx,0.5,0.1);
  Init_KalmanInfo(&klmy,0.5,0.1);
  Init_KalmanInfo(&klmz,0.5,0.1);


  io_service iosev;
  serial_port sp(iosev, "/dev/ttyUSB0");         //定义传输的串口
  sp.set_option(serial_port::baud_rate(115200));
  sp.set_option(serial_port::flow_control());
  sp.set_option(serial_port::parity());
  sp.set_option(serial_port::stop_bits());
  sp.set_option(serial_port::character_size(8));
  iosev.run();

  ros::Rate r(200.0);
  last_time=ros::Time::now();
  lastQ=tf::createQuaternionFromRPY(0.0,0.0,0.0);
  while(n.ok()){



    while(1){

      try
      {
        read (sp,buffer(buf));
        data[dn]=buf[0];
        dn++;

        if(dn>=64){break;}
        //ROS_INFO("%d", buf[0]);//打印接受到的字符串
      }catch (boost::system::system_error e){
          ROS_ERROR_STREAM("read err ");
          break;
      }
    }
    //ROS_INFO("read");
    float qw,qx,qy,qz;
    float yy,pp,rr;
    short int  awx,awy,awz;
    unsigned char *pwx,*pwy,*pwz;

    unsigned char * pw,*px,*py,*pz;
    unsigned char * pyy,*ppp,*prr;
    unsigned char flag=0;
    //xieyi
    //{'$',l,x,x,y,y,z,z,w,w,0,0,'\r','\n'}
        for(i=0;i<(dn-1);){
          if((data[i])=='$'){
            unsigned char len=data[i+1];
            if((i+len)>dn)break;//data length is not ok
            if((data[i+len-2]!='\r')||(data[i+len-1]!='\n')){
              i++;
              continue;//package error
            };
            //
            //ROS_INFO("d0=%d",'$');
            if(len==26){

                pw=(unsigned char*)&qw;
                px=(unsigned char*)&qx;
                py=(unsigned char*)&qy;
                pz=(unsigned char*)&qz;
                *pw=data[i+2];
                *(pw+1)=data[i+3];
                *(pw+2)=data[i+4];
                *(pw+3)=data[i+5];
                *px=data[i+6];
                *(px+1)=data[i+7];
                *(px+2)=data[i+8];
                *(px+3)=data[i+9];
                *py=data[i+10];
                *(py+1)=data[i+11];
                *(py+2)=data[i+12];
                *(py+3)=data[i+13];
                *pz=data[i+14];
                *(pz+1)=data[i+15];
                *(pz+2)=data[i+16];
                *(pz+3)=data[i+17];

                pwx=(unsigned char*)&awx;
                pwy=(unsigned char*)&awy;
                pwz=(unsigned char*)&awz;
                *pwx=data[i+18];
                *(pwx+1)=data[i+19];
                *pwy=data[i+20];
                *(pwy+1)=data[i+21];
                *pwz=data[i+22];
                *(pwz+1)=data[i+23];
                flag=1;
                i+=25;
             }
            if(len==16){


                pyy=(unsigned char*)&yy;
                ppp=(unsigned char*)&pp;
                prr=(unsigned char*)&rr;

                *pyy=data[i+2];
                *(pyy+1)=data[i+3];
                *(pyy+2)=data[i+4];
                *(pyy+3)=data[i+5];
                *ppp=data[i+6];
                *(ppp+1)=data[i+7];
                *(ppp+2)=data[i+8];
                *(ppp+3)=data[i+9];
                *prr=data[i+10];
                *(prr+1)=data[i+11];
                *(prr+2)=data[i+12];
                *(prr+3)=data[i+13];

                flag=1;
                i+=15;

            }
            if(len==20){

                pw=(unsigned char*)&qw;
                px=(unsigned char*)&qx;
                py=(unsigned char*)&qy;
                pz=(unsigned char*)&qz;
                *pw=data[i+2];
                *(pw+1)=data[i+3];
                *(pw+2)=data[i+4];
                *(pw+3)=data[i+5];
                *px=data[i+6];
                *(px+1)=data[i+7];
                *(px+2)=data[i+8];
                *(px+3)=data[i+9];
                *py=data[i+10];
                *(py+1)=data[i+11];
                *(py+2)=data[i+12];
                *(py+3)=data[i+13];
                *pz=data[i+14];
                *(pz+1)=data[i+15];
                *(pz+2)=data[i+16];
                *(pz+3)=data[i+17];
                flag=1;
                i+=19;
             }
            }else{
              //wait
              break;
            }



          i+=1;
        }
        //move to 0
        //if(i>0){
        for(j=0;i


你可能感兴趣的:(算法,arduino,ros)