mpu6050卡尔曼滤波得到的数据不能使平衡小车平衡,dmp库的可以,波型显示卡尔曼有延迟怎么解决
void task_control_car(void *pvParameters)
{
BaseType_t err = pdFALSE;
while (1)
{
if (SemMpuIntr != NULL)
{
err = xSemaphoreTake(SemMpuIntr, portMAX_DELAY); // 获取信号量
if (err == pdTRUE) // 获取信号量成功
{
//===读取编码器的值,因为两个电机的旋转了180度的,所以对其中一个取反
Encoder_A = Read_Encoder(2); // 减1是因为编码器的固定误差
Encoder_B = Read_Encoder(3);
// 获取小车的平衡角度
Car_Read_Angle();
// 读取传感器数据
// mpu_dmp_get_data(&pitch, &roll, &yaw);
// MPU_Get_Gyroscope(&gyrox, &gyroy, &gyroz);
// Car_Angle_Balance= roll * 10;
// Balance_Pwm = Car_Balance(Car_Angle_Balance, gyrox);
// Car_Angle_Balance= angle * 10;
// Car_Angle_Balance= Car_Angle_Balance * 10;
Balance_Pwm = Car_Balance(Car_Angle_Balance, Gyro_Balance);
Velocity_Pwm = Car_Velocity(Encoder_A, Encoder_B);
if (1 == Flag_Left || 1 == Flag_Right)
Turn_Pwm = Car_Turn(Encoder_A, Encoder_B, Gyro_Turn); //===转向环PID控制
else
Turn_Pwm = -0.4 * Gyro_Turn;
PWMA = Balance_Pwm + Velocity_Pwm;// + Turn_Pwm
PWMB = Balance_Pwm + Velocity_Pwm;// - Turn_Pwm
// 角度太大时小车会倒下,停止电机
if (Car_Angle_Balance >= 400 || Car_Angle_Balance <= -400)
{
PWMA = PWMB = 0;
Flag_Qian = Flag_Hou = Flag_Left = Flag_Right = 0;
Encoder = Encoder_Integral = 0;
}
Set_Pwm(PWMA, -PWMB); // pwm更新
}
}
else if (err == pdFALSE)
{
printf("%s, %d, SemMpuIntr is NULL\r\n", __FILE__, __LINE__);
vTaskDelay(10); // 延时10ms,也就是10个时钟节拍
}
}
}
/********************************************
函数功能:获取角度
*********************************************/
void Car_Read_Angle(void)
{
short Acce[3]; // 加速度计缓存
short Gryo[3]; // 陀螺仪缓存
float Gyro_X, Gyro_Z; // X轴和Z轴角速度
float Accel_Y, Accel_Z; // Y轴和Z轴加速度
MPU_Get_Gyroscope(&Gryo[0], &Gryo[1], &Gryo[2]);
MPU_Get_Accelerometer(&Acce[0], &Acce[1], &Acce[2]);
// 数据转换(修改为X轴相关参数)
Gyro_X = (float)Gryo[0]; // 改为读取X轴陀螺仪数据
Gyro_Z = (float)Gryo[2];
Accel_Y = (float)Acce[1]; // 改为读取Y轴加速度数据
Accel_Z = (float)Acce[2];
// 数据类型转换(2's complement)
if (Gyro_X > 32768) Gyro_X -= 65536;
if (Gyro_Z > 32768) Gyro_Z -= 65536;
if (Accel_Y > 32768) Accel_Y -= 65536;
if (Accel_Z > 32768) Accel_Z -= 65536;
Gyro_X = -Gyro_X; // 根据传感器安装方向调整符号
// 更新参数(偏移量需要重新校准)
Gyro_Balance = Gyro_X ;// - 7.5 X轴角速度偏移校准值(示例值,需实测调整)
Gyro_Turn = Gyro_Z ; //- 16 Z轴偏移保持不变
// 计算绕X轴的倾斜角度(Roll)
// 当传感器绕X轴旋转时,使用Y和Z轴加速度计算角度
Angle_Balance = atan2(Accel_Y, Accel_Z) * 180 / 3.14;//pitch角
// 量程转换(保持16.4 LSB/(deg/s)不变)
Car_Gyro_Balance = Gyro_X / 16.4; // X轴角速度
// 卡尔曼滤波
// angle = Kalman_Filter(Angle_Balance, Car_Gyro_Balance);
Kalman_Filter(Angle_Balance, Car_Gyro_Balance);//roll轴
Car_Angle_Balance= angle * 10; // 更新最终角度
}
/*
********************************************************************************************************
文件名:Filter.c
功 能:滤波算法
*********************************************************************************************************
*/
#include "Filter.h"
// 卡尔曼滤波参数
float K1 = 0.02;
float angle, angle_dot;
float Q_angle = 0.001; // 过程噪声的协方差
float Q_gyro = 0.003; // 0.03 过程噪声的协方差 过程噪声的协方差为一个一行两列矩阵
float R_angle = 0.5; // 测量噪声的协方差 既测量偏差
float dt = 0.005; //
char C_0 = 1;
float Q_bias, Angle_err;
float PCt_0, PCt_1, E;
float K_0, K_1, t_0, t_1;
float Pdot[4] = {0, 0, 0, 0};
float PP[2][2] = {{1, 0}, {0, 1}};
// 简易卡尔曼滤波
// 加速度、角速度
void Kalman_Filter(float Accel, float Gyro)
{
angle += (Gyro - Q_bias) * dt; // 先验估计
Pdot[0] = Q_angle - PP[0][1] - PP[1][0]; // Pk-先验估计误差协方差的微分
Pdot[1] = -PP[1][1];
Pdot[2] = -PP[1][1];
Pdot[3] = Q_gyro;
PP[0][0] += Pdot[0] * dt; // Pk-先验估计误差协方差微分的积分
PP[0][1] += Pdot[1] * dt; // =先验估计误差协方差
PP[1][0] += Pdot[2] * dt;
PP[1][1] += Pdot[3] * dt;
Angle_err = Accel - angle; // zk-先验估计
PCt_0 = C_0 * PP[0][0];
PCt_1 = C_0 * PP[1][0];
E = R_angle + C_0 * PCt_0;
K_0 = PCt_0 / E;
K_1 = PCt_1 / E;
t_0 = PCt_0;
t_1 = C_0 * PP[0][1];
PP[0][0] -= K_0 * t_0; // 后验估计误差协方差
PP[0][1] -= K_0 * t_1;
PP[1][0] -= K_1 * t_0;
PP[1][1] -= K_1 * t_1;
angle += K_0 * Angle_err; // 后验估计
Q_bias += K_1 * Angle_err; // 后验估计
angle_dot = Gyro - Q_bias; // 输出值(后验估计)的微分=角速度
}