这是我写的程序, 车越晃越厉害,最后倒地!! 求大神知道 ,求参考程序!!!!!
#include
#include
#include
#include
#include
#include
#define SMPLRT_DIV 0x19
#define CONFIG 0x1A
#define GYRO_CONFIG 0x1B
#define ACCEL_CONFIG 0x1C
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define PWR_MGMT_1 0x6B
#define WHO_AM_I 0x75
#define SlaveAddress 0xD0
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
***it in1=P1^1;
***it in2=P1^2;
***it in3=P1^5;
***it in4=P1^6;
***it SCL=P2^7;
***it SDA=P2^6;
void delay(unsigned int k);
void InitMPU6050();
void Delay5us();
void I2C_Start();
void I2C_Stop();
void I2C_SendACK(bit ack);
bit I2C_RecvACK();
void I2C_SendByte(uchar dat);
uchar I2C_RecvByte();
void I2C_ReadPage();
void I2C_WritePage();
int GetData(uchar REG_Address);
int PWM(int a,int b);
void PWM_calculate( void);
int temp;
uchar Single_ReadI2C(uchar REG_Address);
float Adjust_up1,Adjust_up2;
unsigned int PWM_Duty1,PWM_Duty2;
//******角度参数************
float Gyro_y; //Y轴陀螺仪数据暂存
float Angle_gy; //由角速度计算的倾斜角度
float Accel_x; //X轴加速度值暂存
float Angle_ax; //由加速度计算的倾斜角度
float Angle; //小车最终倾斜角度
float Angle1;
uchar value; //角度正负极性标记
//******卡尔曼参数************
float code Q_angle=0.001;
float code Q_gyro=0.003;
float code R_angle=0.5;
float code dt=0.01; //dt为kalman滤波器采样时间;
char code C_0 = 1;
float xdata Q_bias, Angle_err;
float xdata PCt_0, PCt_1, E;
float xdata K_0, K_1, t_0, t_1;
float xdata Pdot[4] ={0,0,0,0};
float xdata PP[2][2] = { { 1, 0 },{ 0, 1 } };
void Single_WriteI2C(uchar REG_Address,uchar REG_data);
//*********************************************************
// 卡尔曼滤波
//*********************************************************
//在程序中利用Angle+=(Gyro - Q_bias) * dt计算出陀螺仪积分出的角度,其中Q_bias是陀螺仪偏差。
//此时利用陀螺仪积分求出的Angle相当于系统的估计值,得到系统的观测方程;而加速度计检测的角
//度Accel相当于系统中的测量值,得到系统状态方程。
//程序中Q_angle和Q_gyro分别表示系统对加速度计及陀螺仪的信任度。
//根据Pdot = A*P + P*A' + Q_angle计算出先验估计协方差的微分,
//用于将当前估计值进行线性化处理。其中A为雅克比矩阵。
//随后计算系统预测角度的协方差矩阵P。计算估计值Accel与预测值Angle间的误差Angle_err。
//计算卡尔曼增益K_0,K_1,K_0用于最优估计值,K_1用于计算最优估计值的偏差并更新协方差矩阵P。
//通过卡尔曼增益计算出最优估计值Angle及预测值偏差Q_bias,此时得到最优角度值Angle及角速度值。
//Kalman滤波,20MHz的处理时间约0.77ms;
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; //后验估计
Gyro_y = Gyro - Q_bias; //输出值(后验估计)的微分=角速度
}
//*******************************
//*******卡尔曼融合**************
//*******************************
Angle_Calcu(void)
{
//------加速度--------------------------
//范围为2g时,换算关系:16384 LSB/g
//角度较小时,x=sinx得到角度(弧度), deg = rad*180/3.14
//因为x>=sinx,故乘以1.3适当放大
Accel_x = GetData(ACCEL_XOUT_H); //读取X轴加速度
if(Accel_x>0) value=1;
else value=0;
Angle_ax = (Accel_x - 1100) /16384; //去除零点偏移,计算得到角度(弧度)
Angle_ax = Angle_ax*1.2*180/3.14; //弧度转换为度,
//-------角速度-------------------------
//范围为2000deg/s时,换算关系:16.4 LSB/(deg/s)
Gyro_y = GetData(GYRO_YOUT_H); //静止时角速度Y轴输出为-30左右
Gyro_y = -(Gyro_y + 30)/16.4; //去除零点偏移,计算角速度值,负号为方向处理
Angle_gy = Angle_gy + Gyro_y*0.01; //角速度积分得到倾斜角度.
//-------卡尔曼滤波融合-----------------------
Kalman_Filter(Angle_ax,Gyro_y); //卡尔曼滤波计算倾角
/*-------互补滤波-----------------------*/
//补偿原理是取当前倾角和加速度获得倾角差值进行放大,然后与
//陀螺仪角速度叠加后再积分,从而使倾角最跟踪为加速度获得的角度
//0.5为放大倍数,可调节补偿度;0.01为系统周期10ms
Angle = Angle + (((Angle_ax-Angle)*0.5 + Gyro_y)*0.01);
}
int PWM(int a,int b)
{
CCAP0H=(65536-a)/256;
CCAP0L=(65536-a)%256;
CCAPM0=0x42; //PCA模块0工作在8位PWM模式
CCAP1H=(65536-b)/256;
CCAP1L=(65536-b)%256;
CCAPM1=0x42;
CR=1; //启动PCA定时器
}
void PWM_calculate( void)
{
// Adjust_up1 =Gyro_y*2;
Adjust_up1=0;
Adjust_up2 = Angle*200;
if( Angle>0) //加速度向前
{
in1=0;
in2=1;
in3=0;
in4=1;
if(Gyro_y>0)
{
PWM_Duty1 =(int)Adjust_up2 -(int)Adjust_up1;
}
if(Gyro_y<=0)
{
PWM_Duty1 =(int)Adjust_up1 + (int)Adjust_up2;
}
}
else if(Angle<0)//加速度向后
{
in1=1;
in2=0;
in3=1;
in4=0;
if(Gyro_y<=0)
{
PWM_Duty1 =0 - (int)Adjust_up2 - (int)Adjust_up1;
}
if(Gyro_y>0)
{
PWM_Duty1 =0 - (int)Adjust_up2 + (int)Adjust_up1;
}
}
}
void delay(unsigned int k)
{
unsigned int i,j;
for(i=0;i
{
for(j=0;j<121;j++);
}
}
void Delay5us()
{
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();
}
void I2C_Start()
{
SDA = 1;
SCL = 1;
Delay5us();
SDA = 0;
Delay5us();
SCL = 0;
}
void I2C_Stop()
{
SDA = 0;
SCL = 1;
Delay5us();
SDA = 1;
Delay5us();
}
void I2C_SendACK(bit ack)
{
SDA = ack;
SCL = 1;
Delay5us();
SCL = 0;
Delay5us();
}
bit I2C_RecvACK()
{
SCL = 1;
Delay5us();
CY = SDA;
SCL = 0;
Delay5us();
return CY;
}
void I2C_SendByte(uchar dat)
{
uchar i;
for (i=0; i<8; i++)
{
dat <<= 1;
SDA = CY;
SCL = 1;
Delay5us();
SCL = 0;
Delay5us();
}
I2C_RecvACK();
}
uchar I2C_RecvByte()
{
uchar i;
uchar dat = 0;
SDA = 1;
for (i=0; i<8; i++)
{
dat <<= 1;
SCL = 1;
Delay5us();
dat |= SDA;
SCL = 0;
Delay5us();
}
return dat;
}
void Single_WriteI2C(uchar REG_Address,uchar REG_data)
{
I2C_Start();
I2C_SendByte(SlaveAddress);
I2C_SendByte(REG_Address);
I2C_SendByte(REG_data);
I2C_Stop();
}
uchar Single_ReadI2C(uchar REG_Address)
{
uchar REG_data;
I2C_Start();
I2C_SendByte(SlaveAddress);
I2C_SendByte(REG_Address);
I2C_Start();
I2C_SendByte(SlaveAddress+1);
REG_data=I2C_RecvByte();
I2C_SendACK(1);
I2C_Stop();
return REG_data;
}
void InitMPU6050()
{
Single_WriteI2C(PWR_MGMT_1, 0x00);
Single_WriteI2C(SMPLRT_DIV, 0x07);
Single_WriteI2C(CONFIG, 0x06);
Single_WriteI2C(GYRO_CONFIG, 0x18);
Single_WriteI2C(ACCEL_CONFIG, 0x01);
}
int GetData(uchar REG_Address)
{
char H,L;
H=Single_ReadI2C(REG_Address);
L=Single_ReadI2C(REG_Address+1);
return (H<<8)+L;
}
void main()
{
CCON=0x00; //初始化PCA控制寄存器
CMOD=0x02;
CL=0x00;
CH=0x00;
InitMPU6050();
delay(150);
while(1)
{
Angle_Calcu();
PWM_calculate();
PWM(PWM_Duty1+38000,PWM_Duty1+38000);
// PWM(37000,37000);
}
}
|