当前位置:   article > 正文

MPU6050 卡尔曼滤波算法 四元数欧拉姿态解算 STM32 CubeMX HAL库 MDKkeil5 零基础移植_mpu6050卡尔曼滤波姿态解算

mpu6050卡尔曼滤波姿态解算

1.在 cubemx 开启 IIC 并设置好对应的 IIC 引脚

2.generate code 生成代码

(记得生成单个 c. h.文件)!!!!!!

3.复制以下的全部代码 新建分别保存放到 Inc Src 文件夹

每个字都是有用的!!!!!!

请全部复制!!!!!!!!!

每个字都是有用的!!!!!!

请全部复制!!!!!!!!

MPU6050.h

这是.h 文件中存放的内容

定义了结构体用于存放粗数据和处理后的数据 

使用时我们只需要关心 MPU6050_t 这个结构体类型

  1. /*
  2.  * mpu6050.h
  3.  *
  4.  *  Created on: Nov 13, 2019
  5.  *      Author: Bulanov Konstantin
  6.  */
  7. #ifndef INC_GY521_H_
  8. #define INC_GY521_H_
  9. #endif /* INC_GY521_H_ */
  10. #include <stdint.h>
  11. #include "i2c.h"
  12. // MPU6050 structure
  13. typedef struct
  14. {
  15.     int16_t Accel_X_RAW;
  16.     int16_t Accel_Y_RAW;
  17.     int16_t Accel_Z_RAW;
  18.     double Ax;
  19.     double Ay;
  20.     double Az;
  21.     int16_t Gyro_X_RAW;
  22.     int16_t Gyro_Y_RAW;
  23.     int16_t Gyro_Z_RAW;
  24.     double Gx;
  25.     double Gy;
  26.     double Gz;
  27.     float Temperature;
  28.     double KalmanAngleX;
  29.     double KalmanAngleY;
  30. } MPU6050_t;
  31. // Kalman structure
  32. typedef struct
  33. {
  34.     double Q_angle;
  35.     double Q_bias;
  36.     double R_measure;
  37.     double angle;
  38.     double bias;
  39.     double P[2][2];
  40. } Kalman_t;
  41. uint8_t MPU6050_Init(I2C_HandleTypeDef *I2Cx);
  42. void MPU6050_Read_Accel(I2C_HandleTypeDef *I2Cx, MPU6050_t *DataStruct);
  43. void MPU6050_Read_Gyro(I2C_HandleTypeDef *I2Cx, MPU6050_t *DataStruct);
  44. void MPU6050_Read_Temp(I2C_HandleTypeDef *I2Cx, MPU6050_t *DataStruct);
  45. void MPU6050_Read_All(I2C_HandleTypeDef *I2Cx, MPU6050_t *DataStruct);
  46. double Kalman_getAngle(Kalman_t *Kalman, double newAngle, double newRate, double dt);

MPU6050.c

这其中包含了数据处理的函数

每个字都是有用的!!!!!!

请全部复制!!!!!!!!

每个字都是有用的!!!!!

请全部复制!!!!!!!!

关于DEFINE 这关乎数据的读取 请全部复制!!!!!!

  1. /*
  2. * mpu6050.c
  3. *
  4. * Created on: Nov 13, 2019
  5. * Author: Bulanov Konstantin
  6. *
  7. * Contact information
  8. * -------------------
  9. */
  10. #include <math.h>
  11. #include "mpu6050.h"
  12. #define RAD_TO_DEG 57.295779513082320876798154814105
  13. #define WHO_AM_I_REG 0x75
  14. #define PWR_MGMT_1_REG 0x6B
  15. #define SMPLRT_DIV_REG 0x19
  16. #define ACCEL_CONFIG_REG 0x1C
  17. #define ACCEL_XOUT_H_REG 0x3B
  18. #define TEMP_OUT_H_REG 0x41
  19. #define GYRO_CONFIG_REG 0x1B
  20. #define GYRO_XOUT_H_REG 0x43
  21. // Setup MPU6050
  22. #define MPU6050_ADDR 0xD0
  23. const uint16_t i2c_timeout = 100;
  24. const double Accel_Z_corrector = 14418.0;
  25. uint32_t timer;
  26. Kalman_t KalmanX = {
  27. .Q_angle = 0.001f,
  28. .Q_bias = 0.003f,
  29. .R_measure = 0.03f};
  30. Kalman_t KalmanY = {
  31. .Q_angle = 0.001f,
  32. .Q_bias = 0.003f,
  33. .R_measure = 0.03f,
  34. };
  35. uint8_t MPU6050_Init(I2C_HandleTypeDef *I2Cx)
  36. {
  37. uint8_t check;
  38. uint8_t Data;
  39. // check device ID WHO_AM_I
  40. HAL_I2C_Mem_Read(I2Cx, MPU6050_ADDR, WHO_AM_I_REG, 1, &check, 1, i2c_timeout);
  41. if (check == 104) // 0x68 will be returned by the sensor if everything goes well
  42. {
  43. // power management register 0X6B we should write all 0's to wake the sensor up
  44. Data = 0;
  45. HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, PWR_MGMT_1_REG, 1, &Data, 1, i2c_timeout);
  46. // Set DATA RATE of 1KHz by writing SMPLRT_DIV register
  47. Data = 0x07;
  48. HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, SMPLRT_DIV_REG, 1, &Data, 1, i2c_timeout);
  49. // Set accelerometer configuration in ACCEL_CONFIG Register
  50. // XA_ST=0,YA_ST=0,ZA_ST=0, FS_SEL=0 -> ? 2g
  51. Data = 0x00;
  52. HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, ACCEL_CONFIG_REG, 1, &Data, 1, i2c_timeout);
  53. // Set Gyroscopic configuration in GYRO_CONFIG Register
  54. // XG_ST=0,YG_ST=0,ZG_ST=0, FS_SEL=0 -> ? 250 ?/s
  55. Data = 0x00;
  56. HAL_I2C_Mem_Write(I2Cx, MPU6050_ADDR, GYRO_CONFIG_REG, 1, &Data, 1, i2c_timeout);
  57. return 0;
  58. }
  59. return 1;
  60. }
  61. void MPU6050_Read_Accel(I2C_HandleTypeDef *I2Cx, MPU6050_t *DataStruct)
  62. {
  63. uint8_t Rec_Data[6];
  64. // Read 6 BYTES of data starting from ACCEL_XOUT_H register
  65. HAL_I2C_Mem_Read(I2Cx, MPU6050_ADDR, ACCEL_XOUT_H_REG, 1, Rec_Data, 6, i2c_timeout);
  66. DataStruct->Accel_X_RAW = (int16_t)(Rec_Data[0] << 8 | Rec_Data[1]);
  67. DataStruct->Accel_Y_RAW = (int16_t)(Rec_Data[2] << 8 | Rec_Data[3]);
  68. DataStruct->Accel_Z_RAW = (int16_t)(Rec_Data[4] << 8 | Rec_Data[5]);
  69. /*** convert the RAW values into acceleration in 'g'
  70. we have to divide according to the Full scale value set in FS_SEL
  71. I have configured FS_SEL = 0. So I am dividing by 16384.0
  72. for more details check ACCEL_CONFIG Register ****/
  73. DataStruct->Ax = DataStruct->Accel_X_RAW / 16384.0;
  74. DataStruct->Ay = DataStruct->Accel_Y_RAW / 16384.0;
  75. DataStruct->Az = DataStruct->Accel_Z_RAW / Accel_Z_corrector;
  76. }
  77. void MPU6050_Read_Gyro(I2C_HandleTypeDef *I2Cx, MPU6050_t *DataStruct)
  78. {
  79. uint8_t Rec_Data[6];
  80. // Read 6 BYTES of data starting from GYRO_XOUT_H register
  81. HAL_I2C_Mem_Read(I2Cx, MPU6050_ADDR, GYRO_XOUT_H_REG, 1, Rec_Data, 6, i2c_timeout);
  82. DataStruct->Gyro_X_RAW = (int16_t)(Rec_Data[0] << 8 | Rec_Data[1]);
  83. DataStruct->Gyro_Y_RAW = (int16_t)(Rec_Data[2] << 8 | Rec_Data[3]);
  84. DataStruct->Gyro_Z_RAW = (int16_t)(Rec_Data[4] << 8 | Rec_Data[5]);
  85. /*** convert the RAW values into dps (?/s)
  86. we have to divide according to the Full scale value set in FS_SEL
  87. I have configured FS_SEL = 0. So I am dividing by 131.0
  88. for more details check GYRO_CONFIG Register ****/
  89. DataStruct->Gx = DataStruct->Gyro_X_RAW / 131.0;
  90. DataStruct->Gy = DataStruct->Gyro_Y_RAW / 131.0;
  91. DataStruct->Gz = DataStruct->Gyro_Z_RAW / 131.0;
  92. }
  93. void MPU6050_Read_Temp(I2C_HandleTypeDef *I2Cx, MPU6050_t *DataStruct)
  94. {
  95. uint8_t Rec_Data[2];
  96. int16_t temp;
  97. // Read 2 BYTES of data starting from TEMP_OUT_H_REG register
  98. HAL_I2C_Mem_Read(I2Cx, MPU6050_ADDR, TEMP_OUT_H_REG, 1, Rec_Data, 2, i2c_timeout);
  99. temp = (int16_t)(Rec_Data[0] << 8 | Rec_Data[1]);
  100. DataStruct->Temperature = (float)((int16_t)temp / (float)340.0 + (float)36.53);
  101. }
  102. void MPU6050_Read_All(I2C_HandleTypeDef *I2Cx, MPU6050_t *DataStruct)
  103. {
  104. uint8_t Rec_Data[14];
  105. int16_t temp;
  106. // Read 14 BYTES of data starting from ACCEL_XOUT_H register
  107. HAL_I2C_Mem_Read(I2Cx, MPU6050_ADDR, ACCEL_XOUT_H_REG, 1, Rec_Data, 14, i2c_timeout);
  108. DataStruct->Accel_X_RAW = (int16_t)(Rec_Data[0] << 8 | Rec_Data[1]);
  109. DataStruct->Accel_Y_RAW = (int16_t)(Rec_Data[2] << 8 | Rec_Data[3]);
  110. DataStruct->Accel_Z_RAW = (int16_t)(Rec_Data[4] << 8 | Rec_Data[5]);
  111. temp = (int16_t)(Rec_Data[6] << 8 | Rec_Data[7]);
  112. DataStruct->Gyro_X_RAW = (int16_t)(Rec_Data[8] << 8 | Rec_Data[9]);
  113. DataStruct->Gyro_Y_RAW = (int16_t)(Rec_Data[10] << 8 | Rec_Data[11]);
  114. DataStruct->Gyro_Z_RAW = (int16_t)(Rec_Data[12] << 8 | Rec_Data[13]);
  115. DataStruct->Ax = DataStruct->Accel_X_RAW / 16384.0;
  116. DataStruct->Ay = DataStruct->Accel_Y_RAW / 16384.0;
  117. DataStruct->Az = DataStruct->Accel_Z_RAW / Accel_Z_corrector;
  118. DataStruct->Temperature = (float)((int16_t)temp / (float)340.0 + (float)36.53);
  119. DataStruct->Gx = DataStruct->Gyro_X_RAW / 131.0;
  120. DataStruct->Gy = DataStruct->Gyro_Y_RAW / 131.0;
  121. DataStruct->Gz = DataStruct->Gyro_Z_RAW / 131.0;
  122. // Kalman angle solve
  123. double dt = (double)(HAL_GetTick() - timer) / 1000;
  124. timer = HAL_GetTick();
  125. double roll;
  126. double roll_sqrt = sqrt(
  127. DataStruct->Accel_X_RAW * DataStruct->Accel_X_RAW + DataStruct->Accel_Z_RAW * DataStruct->Accel_Z_RAW);
  128. if (roll_sqrt != 0.0)
  129. {
  130. roll = atan(DataStruct->Accel_Y_RAW / roll_sqrt) * RAD_TO_DEG;
  131. }
  132. else
  133. {
  134. roll = 0.0;
  135. }
  136. double pitch = atan2(-DataStruct->Accel_X_RAW, DataStruct->Accel_Z_RAW) * RAD_TO_DEG;
  137. if ((pitch < -90 && DataStruct->KalmanAngleY > 90) || (pitch > 90 && DataStruct->KalmanAngleY < -90))
  138. {
  139. KalmanY.angle = pitch;
  140. DataStruct->KalmanAngleY = pitch;
  141. }
  142. else
  143. {
  144. DataStruct->KalmanAngleY = Kalman_getAngle(&KalmanY, pitch, DataStruct->Gy, dt);
  145. }
  146. if (fabs(DataStruct->KalmanAngleY) > 90)
  147. DataStruct->Gx = -DataStruct->Gx;
  148. DataStruct->KalmanAngleX = Kalman_getAngle(&KalmanX, roll, DataStruct->Gx, dt);
  149. }
  150. double Kalman_getAngle(Kalman_t *Kalman, double newAngle, double newRate, double dt)
  151. {
  152. double rate = newRate - Kalman->bias;
  153. Kalman->angle += dt * rate;
  154. Kalman->P[0][0] += dt * (dt * Kalman->P[1][1] - Kalman->P[0][1] - Kalman->P[1][0] + Kalman->Q_angle);
  155. Kalman->P[0][1] -= dt * Kalman->P[1][1];
  156. Kalman->P[1][0] -= dt * Kalman->P[1][1];
  157. Kalman->P[1][1] += Kalman->Q_bias * dt;
  158. double S = Kalman->P[0][0] + Kalman->R_measure;
  159. double K[2];
  160. K[0] = Kalman->P[0][0] / S;
  161. K[1] = Kalman->P[1][0] / S;
  162. double y = newAngle - Kalman->angle;
  163. Kalman->angle += K[0] * y;
  164. Kalman->bias += K[1] * y;
  165. double P00_temp = Kalman->P[0][0];
  166. double P01_temp = Kalman->P[0][1];
  167. Kalman->P[0][0] -= K[0] * P00_temp;
  168. Kalman->P[0][1] -= K[0] * P01_temp;
  169. Kalman->P[1][0] -= K[1] * P00_temp;
  170. Kalman->P[1][1] -= K[1] * P01_temp;
  171. return Kalman->angle;
  172. };

 5. 移植完毕代码之后

重要的是怎么去使用

(在使用之前请确保 编译时 上述文件是包含在程序中的!!!!)

我们需要创建一个全局变量 用于存放数据

这一步非常重要!!!!!!

请不要忘记创建变量!!!!

请不要忘记创建变量!!!!

请不要忘记创建变量!!!!

请按下面步骤操作

这一步也是至关重要!!!!

请放在进入while(1)死循环之前 

请放在进入while(1)死循环之前 

请放在进入while(1)死循环之前 

这一步是用于确保初始化的正确

这之后就是while(1)死循环里的操作了 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/460645
推荐阅读
相关标签
  

闽ICP备14008679号