电子元器件william hill官网
直播中

blAckGe

3年用户 44经验值
擅长:电源/新能源 控制/MCU
私信 关注

mpu6050数据处理

mpu6050向arduino传输数据,matlab通过串口再读取传感器数据。由于每次启动传感器会重新校准,导致每次传感器测得同一姿态、同一位置x y两个方向角的初始值都不一样,这就造成很大的麻烦:比如说,我测小车的底盘倾角有无变化,每次测初始值都不一样,那就没办法测了。不知道各位高人有什么解决思路,办法。
这个是arduino的代码

  1. //连线方法
  2. //MPU-UNO
  3. //VCC-VCC
  4. //GND-GND
  5. //SCL-A5
  6. //SDA-A4
  7. //INT-2 (Optional)

  8. #include
  9. #include
  10. #include

  11. float fRad2Deg = 57.295779513f; //将弧度转为角度的乘数
  12. const int MPU = 0x68; //MPU-6050的I2C地址
  13. const int nValCnt = 7; //一次读取寄存器的数量

  14. const int nCalibTimes = 1000; //校准时读数的次数
  15. int calibData[nValCnt]; //校准数据

  16. unsigned long nLastTime = 0; //上一次读数的时间
  17. float fLastRoll = 0.0f; //上一次滤波得到的Roll角
  18. float fLastPitch = 0.0f; //上一次滤波得到的Pitch角
  19. Kalman kalmanRoll; //Roll角滤波器
  20. Kalman kalmanPitch; //Pitch角滤波器

  21. void setup() {
  22.   Serial.begin(9600); //初始化串口,指定波特率
  23.   Wire.begin(); //初始化Wire库
  24.   WriteMPUReg(0x6B, 0); //启动MPU6050设备

  25.   Calibration(); //执行校准
  26.   nLastTime = micros(); //记录当前时间
  27. }

  28. void loop() {
  29.   int readouts[nValCnt];
  30.   ReadAccGyr(readouts); //读出测量值
  31.   
  32.   float realVals[7];
  33.   Rectify(readouts, realVals); //根据校准的偏移量进行纠正

  34.   //计算加速度向量的模长,均以g为单位
  35.   float fNorm = sqrt(realVals[0] * realVals[0] + realVals[1] * realVals[1] + realVals[2] * realVals[2]);
  36.   float fRoll = GetRoll(realVals, fNorm); //计算Roll角
  37.   if (realVals[1] > 0) {
  38.     fRoll = -fRoll;
  39.   }
  40.   float fPitch = GetPitch(realVals, fNorm); //计算Pitch角
  41.   if (realVals[0] < 0) {
  42.     fPitch = -fPitch;
  43.   }

  44.   //计算两次测量的时间间隔dt,以秒为单位
  45.   unsigned long nCurTime = micros();
  46.   float dt = (double)(nCurTime - nLastTime) / 1000000.0;
  47.   //对Roll角和Pitch角进行卡尔曼滤波
  48.   float fNewRoll = kalmanRoll.getAngle(fRoll, realVals[4], dt);
  49.   float fNewPitch = kalmanPitch.getAngle(fPitch, realVals[5], dt);
  50.   //跟据滤波值计算角度速
  51.   float fRollRate = (fNewRoll - fLastRoll) / dt;
  52.   float fPitchRate = (fNewPitch - fLastPitch) / dt;

  53. //更新Roll角和Pitch角
  54.   fLastRoll = fNewRoll;
  55.   fLastPitch = fNewPitch;
  56.   //更新本次测的时间
  57.   nLastTime = nCurTime;

  58.   //向串口打印输出Roll角和Pitch角,运行时在Arduino的串口监视器中查看
  59.   //Serial.print("Roll:");
  60.   Serial.println(fNewRoll); //Serial.print('(');
  61.   //Serial.print(fRollRate); //Serial.print("),tPitch:");
  62.   Serial.println(fNewPitch); //Serial.print('(');
  63.   //Serial.print(fPitchRate); //Serial.print(")n");
  64.   delay(100);
  65. }

  66. //向MPU6050写入一个字节的数据
  67. //指定寄存器地址与一个字节的值
  68. void WriteMPUReg(int nReg, unsigned char nVal) {
  69.   Wire.beginTransmission(MPU);
  70.   Wire.write(nReg);
  71.   Wire.write(nVal);
  72.   Wire.endTransmission(true);
  73. }

  74. //从MPU6050读出一个字节的数据
  75. //指定寄存器地址,返回读出的值
  76. unsigned char ReadMPUReg(int nReg) {
  77.   Wire.beginTransmission(MPU);
  78.   Wire.write(nReg);
  79.   Wire.requestFrom(MPU, 1, true);
  80.   Wire.endTransmission(true);
  81.   return Wire.read();
  82. }

  83. //从MPU6050读出加速度计三个分量、温度和三个角速度计
  84. //保存在指定的数组中
  85. void ReadAccGyr(int *pVals) {
  86.   Wire.beginTransmission(MPU);
  87.   Wire.write(0x3B);
  88.   Wire.requestFrom(MPU, nValCnt * 2, true);
  89.   Wire.endTransmission(true);
  90.   for (long i = 0; i < nValCnt; ++i) {
  91.     pVals[i] = Wire.read() << 8 | Wire.read();
  92.   }
  93. }

  94. //对大量读数进行统计,校准平均偏移量
  95. void Calibration()
  96. {
  97.   float valSums[7] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0};
  98.   //先求和
  99.   for (int i = 0; i < nCalibTimes; ++i) {
  100.     int mpuVals[nValCnt];
  101.     ReadAccGyr(mpuVals);
  102.     for (int j = 0; j < nValCnt; ++j) {
  103.       valSums[j] += mpuVals[j];
  104.     }
  105.   }
  106.   //再求平均
  107.   for (int i = 0; i < nValCnt; ++i) {
  108.     calibData[i] = int(valSums[i] / nCalibTimes);
  109.   }
  110.   calibData[2] += 16384; //设芯片Z轴竖直向下,设定静态工作点。
  111. }

  112. //算得Roll角。算法见文档。
  113. float GetRoll(float *pRealVals, float fNorm) {
  114.   float fNormXZ = sqrt(pRealVals[0] * pRealVals[0] + pRealVals[2] * pRealVals[2]);
  115.   float fCos = fNormXZ / fNorm;
  116.   return acos(fCos) * fRad2Deg;
  117. }

  118. //算得Pitch角。算法见文档。
  119. float GetPitch(float *pRealVals, float fNorm) {
  120.   float fNormYZ = sqrt(pRealVals[1] * pRealVals[1] + pRealVals[2] * pRealVals[2]);
  121.   float fCos = fNormYZ / fNorm;
  122.   return acos(fCos) * fRad2Deg;
  123. }

  124. //对读数进行纠正,消除偏移,并转换为物理量。公式见文档。
  125. void Rectify(int *pReadout, float *pRealVals) {
  126.   for (int i = 0; i < 3; ++i) {
  127.     pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 16384.0f;
  128.   }
  129.   pRealVals[3] = pReadout[3] / 340.0f + 36.53;
  130.   for (int i = 4; i < 7; ++i) {
  131.     pRealVals[i] = (float)(pReadout[i] - calibData[i]) / 131.0f;
  132.   }
  133. }
这个是matlab的代码
  1. clc;clear;
  2. if~isempty(instrfind)
  3.     fclose(instrfind);
  4.     delete(instrfind);
  5. end
  6. global s;
  7. s=  serial('COM5');
  8. set(s,'BaudRate',9600);
  9. fopen(s);
  10. t=1;T=500;
  11. A=1;
  12. amount=0;
  13. while(t
  14.     a=str2double(fgetl(s));
  15.     figure(1);
  16.     A=[A,a];
  17.     plot(A);
  18.     grid;
  19.     t=t+1;
  20.     drawnow limitrate;
  21. end
  22. X_Pitch=A(1:2:end);
  23. Y_Roll=A(2:2:end);
  24. figure(2);
  25. plot(X_Pitch);
  26. figure(3);
  27. plot(Y_Roll);


已退回7积分

回帖(3)

chenwei6991627

2021-8-5 11:47:47
那把初始值去掉呢
1 举报
  • blAckGe: 能力实在有限,代码不知何从下手,望指教

blAckGe

2021-8-6 09:36:25
如果想实现始终以地面为基准,像手机水平仪那样,那改进思路应该是怎样的呢
举报

mm2mm2

2021-8-12 14:00:38
有点难看懂啊,学习
举报

更多回帖

发帖
×
20
完善资料,
赚取积分