Files
LaserTracing/Module/Imu/Imu.c
T
2026-04-23 14:02:03 +08:00

299 lines
7.7 KiB
C

/************************************************************************************************
* 程序版本:V3.0
* 程序日期:2022-11-3
* 程序作者:
************************************************************************************************/
#include "Imu.h"
#include "main.h"
#define Kp_New 0.9f //互补滤波当前数据的权重
#define Kp_Old 0.1f //互补滤波历史数据的权重
#define Acc_Gain 0.0001220f //加速度变成G (初始化加速度满量程-+4g LSBa = 2*4/65535.0)
#define Gyro_Gain 0.0609756f //角速度变成度 (初始化陀螺仪满量程+-2000 LSBg = 2*2000/65535.0)
#define Gyro_Gr 0.0010641f //角速度变成弧度(3.1415/180 * LSBg)
//kp=ki=0 就是完全相信陀螺仪
#define Kp 1.5f // proportional gain governs rate of convergence to accelerometer/magnetometer
//比例增益控制加速度计,磁力计的收敛速率
#define Ki 0.005f // integral gain governs rate of convergence of gyroscope biases
//积分增益控制陀螺偏差的收敛速度
#define halfT 0.005f // half the sample period 采样周期的一半
static volatile float q0 = 1, q1 = 0, q2 = 0, q3 = 0; // quaternion elements representing the estimated orientation
static volatile float exInt = 0, eyInt = 0, ezInt = 0; // scaled integral error
/*
static float MedianValue(float *value_buf, unsigned int size)
{
unsigned int i,j;
float temp;
//排序采用冒泡法
for (j=0;j<=size;j++){
for (i=0;i<=size-j;i++){
if (value_buf[i] > value_buf[i+1]){
temp = value_buf[i];
value_buf[i] = value_buf[i+1];
value_buf[i+1] = temp;
}
}
}
return value_buf[(size-1)/2];
}
*/
static float MedianValue(float *value_buf, unsigned int size)
{
unsigned int i;
float temp = 0;
for (i=0; i<size; i++)
temp += value_buf[i];
return temp/size;
}
static float Acc_Filter_X(float in_data)
{
static float value_buf[Imu_AccFilterSize] = {0};
static unsigned char cnt = 0;
value_buf[cnt] = in_data;
cnt++;
if (cnt>=Imu_AccFilterSize)cnt=0;
return MedianValue(value_buf, Imu_AccFilterSize);
}
static float Acc_Filter_Y(float in_data)
{
static float value_buf[Imu_AccFilterSize] = {0};
static unsigned char cnt = 0;
value_buf[cnt] = in_data;
cnt++;
if (cnt>=Imu_AccFilterSize)cnt=0;
return MedianValue(value_buf, Imu_AccFilterSize);
}
static float Acc_Filter_Z(float in_data)
{
static float value_buf[Imu_AccFilterSize] = {0};
static unsigned char cnt = 0;
value_buf[cnt] = in_data;
cnt++;
if (cnt>=Imu_AccFilterSize)cnt=0;
return MedianValue(value_buf, Imu_AccFilterSize);
}
static float Mag_Filter_X(float in_data)
{
static float value_buf[Imu_MagFilterSize] = {0};
static unsigned char cnt = 0;
value_buf[cnt] = in_data;
cnt++;
if (cnt>=Imu_MagFilterSize)cnt=0;
return MedianValue(value_buf, Imu_MagFilterSize);
}
static float Mag_Filter_Y(float in_data)
{
static float value_buf[Imu_MagFilterSize] = {0};
static unsigned char cnt = 0;
value_buf[cnt] = in_data;
cnt++;
if (cnt>=Imu_MagFilterSize)cnt=0;
return MedianValue(value_buf, Imu_MagFilterSize);
}
static float Mag_Filter_Z(float in_data)
{
static float value_buf[Imu_MagFilterSize] = {0};
static unsigned char cnt = 0;
value_buf[cnt] = in_data;
cnt++;
if (cnt>=Imu_MagFilterSize)cnt=0;
return MedianValue(value_buf, Imu_MagFilterSize);
}
static float Gyro_Filter_X(float in_data)
{
static float value_buf[Imu_GyroFilterSize] = {0};
static unsigned char cnt = 0;
value_buf[cnt] = in_data;
cnt++;
if (cnt>=Imu_GyroFilterSize)cnt=0;
return MedianValue(value_buf, Imu_GyroFilterSize);
}
static float Gyro_Filter_Y(float in_data)
{
static float value_buf[Imu_GyroFilterSize] = {0};
static unsigned char cnt = 0;
value_buf[cnt] = in_data;
cnt++;
if (cnt>=Imu_GyroFilterSize)cnt=0;
return MedianValue(value_buf, Imu_GyroFilterSize);
}
static float Gyro_Filter_Z(float in_data)
{
static float value_buf[Imu_GyroFilterSize] = {0};
static unsigned char cnt = 0;
value_buf[cnt] = in_data;
cnt++;
if (cnt>=Imu_GyroFilterSize)cnt=0;
return MedianValue(value_buf, Imu_GyroFilterSize);
}
static float invSqrt(float x) {
float halfx = 0.5f * x;
float y = x;
long i = *(long*)&y;
i = 0x5f3759df - (i>>1);
y = *(float*)&i;
y = y * (1.5f - (halfx * y * y));
return y;
}
static void IMUupdate(float gx, float gy, float gz, float ax, float ay, float az)
{
float vx, vy, vz;
float ex, ey, ez;
float norm;
float q0q0 = q0*q0;
float q0q1 = q0*q1;
float q0q2 = q0*q2;
float q0q3 = q0*q3;
float q1q1 = q1*q1;
float q1q2 = q1*q2;
float q1q3 = q1*q3;
float q2q2 = q2*q2;
float q2q3 = q2*q3;
float q3q3 = q3*q3;
if(ax*ay*az==0)
return;
//加速度计<测量>的重力加速度向量(机体坐标系)
norm = invSqrt(ax*ax + ay*ay + az*az);
ax = ax * norm;
ay = ay * norm;
az = az * norm;
// printf("ax=%0.2f ay=%0.2f az=%0.2f\r\n",ax,ay,az);
//陀螺仪积分<估计>重力向量(机体坐标系)
vx = 2*(q1q3 - q0q2); //矩阵(3,1)项
vy = 2*(q0q1 + q2q3); //矩阵(3,2)项
vz = q0q0 - q1q1 - q2q2 + q3q3 ; //矩阵(3,3)项
//向量叉乘所得的值
ex = (ay*vz - az*vy);
ey = (az*vx - ax*vz);
ez = (ax*vy - ay*vx);
//用上面求出误差进行积分
exInt = exInt + ex * Ki;
eyInt = eyInt + ey * Ki;
ezInt = ezInt + ez * Ki;
//将误差PI后补偿到陀螺仪
gx = gx + Kp*ex + exInt;
gy = gy + Kp*ey + eyInt;
gz = gz + Kp*ez + ezInt;//这里的gz由于没有观测者进行矫正会产生漂移,表现出来的就是积分自增或自减
//四元素的微分方程
q0 = q0 + (-q1*gx - q2*gy - q3*gz)*halfT;
q1 = q1 + (q0*gx + q2*gz - q3*gy)*halfT;
q2 = q2 + (q0*gy - q1*gz + q3*gx)*halfT;
q3 = q3 + (q0*gz + q1*gy - q2*gx)*halfT;
//单位化四元数
norm = invSqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
q0 = q0 * norm;
q1 = q1 * norm;
q2 = q2 * norm;
q3 = q3 * norm;
// 矩阵表达式
// matrix[0] = q0q0 + q1q1 - q2q2 - q3q3; // 11
// matrix[1] = 2.f * (q1q2 + q0q3); // 12
// matrix[2] = 2.f * (q1q3 - q0q2); // 13
// matrix[3] = 2.f * (q1q2 - q0q3); // 21
// matrix[4] = q0q0 - q1q1 + q2q2 - q3q3; // 22
// matrix[5] = 2.f * (q2q3 + q0q1); // 23
// matrix[6] = 2.f * (q1q3 + q0q2); // 31
// matrix[7] = 2.f * (q2q3 - q0q1); // 32
// matrix[8] = q0q0 - q1q1 - q2q2 + q3q3; // 33
//下一步是四元数转换成欧拉角(Z->Y->X)
}
#define ALPHA 0.01
void IMU_Update(float *gy,float *acc, float *mag, RadDp Rad, DegDp Deg)
{
static volatile double Phi,Theta, Psi, Gz2, By2, Bz2, Bx3;
volatile float Gyr[XYZ], Acc[XYZ], Mag[XYZ];
Gyr[X] = gy[X];
Gyr[Y] = gy[Y];
Gyr[Z] = gy[Z];
Acc[X] = acc[X];
Acc[Y] = acc[Y];
Acc[Z] = acc[Z];
Mag[X] = -mag[X];
Mag[Y] = -mag[Y];
Mag[Z] = -mag[Z];
// IMUupdate(Gyr[X], Gyr[Y], Gyr[Z], Acc[X], Acc[Y], Acc[Z]);
// Phi = -atan2(2.f * q0*q1 + 2.f * q2*q3, 1 - 2.f * q1*q1 - 2.f * q2*q2);
// Theta = -asin(2.f * (q0*q2 - q1*q3));
// volatile float xh = Mag[0]*cos(Theta) + Mag[1]*sin(Phi)*sin(Theta) + Mag[2]*cos(Phi)*sin(Theta);
// volatile float yh = Mag[1]*cos(Phi) - Mag[2]*sin(Phi);
// Psi = atan2(yh, xh);
Phi = atan2(Acc[Y], (Acc[Z] + Acc[X] * ALPHA));
//Phi = atan2(Acc[Y], Acc[Z]);
Gz2 = Acc[Y] * sin(Phi) + Acc[Z] * cos(Phi);
Theta = atan(-Acc[X] / Gz2);
By2 = Mag[Z] * sin(Phi) - Mag[Y] * cos(Phi);
Bz2 = Mag[Y] * sin(Phi) + Mag[Z] * cos(Phi);
Bx3 = Mag[X] * cos(Theta) + Bz2 * sin(Theta);
Psi = atan2(By2, Bx3);
Rad->roll = Phi;
Rad->pitch = Theta;
Rad->yaw = Psi;
Deg->roll = Rad->roll * RAD_TO_DEG;
Deg->pitch = Rad->pitch * RAD_TO_DEG;
Deg->yaw = Rad->yaw * RAD_TO_DEG;
}