平衡车代码阅读,学习mpu6050滤波

编程入门 行业动态 更新时间:2024-10-09 23:13:13

平衡车<a href=https://www.elefans.com/category/jswz/34/1771412.html style=代码阅读,学习mpu6050滤波"/>

平衡车代码阅读,学习mpu6050滤波

 

 

 mpu6050.c

#include "MPU6050.h"
#include "IOI2C.h"
#include "usart.h"/**************************************************************************
作者:平衡小车之家
我的淘宝小店:/
**************************************************************************/
#define PRINT_ACCEL     (0x01)
#define PRINT_GYRO      (0x02)
#define PRINT_QUAT      (0x04)
#define ACCEL_ON        (0x01)
#define GYRO_ON         (0x02)
#define MOTION          (0)
#define NO_MOTION       (1)
#define DEFAULT_MPU_HZ  (200)
#define FLASH_SIZE      (512)
#define FLASH_MEM_START ((void*)0x1800)
#define q30  1073741824.0f
short gyro[3], accel[3], sensors;
float Pitch,Roll; 
float q0=1.0f,q1=0.0f,q2=0.0f,q3=0.0f;
static signed char gyro_orientation[9] = {-1, 0, 0,0,-1, 0,0, 0, 1};static  unsigned short inv_row_2_scale(const signed char *row)
{unsigned short b;if (row[0] > 0)b = 0;else if (row[0] < 0)b = 4;else if (row[1] > 0)b = 1;else if (row[1] < 0)b = 5;else if (row[2] > 0)b = 2;else if (row[2] < 0)b = 6;elseb = 7;      // errorreturn b;
}static  unsigned short inv_orientation_matrix_to_scalar(const signed char *mtx)
{unsigned short scalar;scalar = inv_row_2_scale(mtx);scalar |= inv_row_2_scale(mtx + 3) << 3;scalar |= inv_row_2_scale(mtx + 6) << 6;return scalar;
}static void run_self_test(void)
{int result;long gyro[3], accel[3];result = mpu_run_self_test(gyro, accel);if (result == 0x7) {/* Test passed. We can trust the gyro data here, so let's push it down* to the DMP.*/float sens;unsigned short accel_sens;mpu_get_gyro_sens(&sens);gyro[0] = (long)(gyro[0] * sens);gyro[1] = (long)(gyro[1] * sens);gyro[2] = (long)(gyro[2] * sens);dmp_set_gyro_bias(gyro);mpu_get_accel_sens(&accel_sens);accel[0] *= accel_sens;accel[1] *= accel_sens;accel[2] *= accel_sens;dmp_set_accel_bias(accel);printf("setting bias succesfully ......\r\n");}
}uint8_t buffer[14];int16_t  MPU6050_FIFO[6][11];
int16_t Gx_offset=0,Gy_offset=0,Gz_offset=0;/**************************实现函数********************************************
*函数原型:		void  MPU6050_newValues(int16_t ax,int16_t ay,int16_t az,int16_t gx,int16_t gy,int16_t gz)
*功  能:	    将新的ADC数据更新到 FIFO数组,进行滤波处理
*******************************************************************************/void  MPU6050_newValues(int16_t ax,int16_t ay,int16_t az,int16_t gx,int16_t gy,int16_t gz)
{
unsigned char i ;
int32_t sum=0;
for(i=1;i<10;i++){	//FIFO 操作
MPU6050_FIFO[0][i-1]=MPU6050_FIFO[0][i];
MPU6050_FIFO[1][i-1]=MPU6050_FIFO[1][i];
MPU6050_FIFO[2][i-1]=MPU6050_FIFO[2][i];
MPU6050_FIFO[3][i-1]=MPU6050_FIFO[3][i];
MPU6050_FIFO[4][i-1]=MPU6050_FIFO[4][i];
MPU6050_FIFO[5][i-1]=MPU6050_FIFO[5][i];
}
MPU6050_FIFO[0][9]=ax;//将新的数据放置到 数据的最后面
MPU6050_FIFO[1][9]=ay;
MPU6050_FIFO[2][9]=az;
MPU6050_FIFO[3][9]=gx;
MPU6050_FIFO[4][9]=gy;
MPU6050_FIFO[5][9]=gz;sum=0;
for(i=0;i<10;i++){	//求当前数组的合,再取平均值sum+=MPU6050_FIFO[0][i];
}
MPU6050_FIFO[0][10]=sum/10;sum=0;
for(i=0;i<10;i++){sum+=MPU6050_FIFO[1][i];
}
MPU6050_FIFO[1][10]=sum/10;sum=0;
for(i=0;i<10;i++){sum+=MPU6050_FIFO[2][i];
}
MPU6050_FIFO[2][10]=sum/10;sum=0;
for(i=0;i<10;i++){sum+=MPU6050_FIFO[3][i];
}
MPU6050_FIFO[3][10]=sum/10;sum=0;
for(i=0;i<10;i++){sum+=MPU6050_FIFO[4][i];
}
MPU6050_FIFO[4][10]=sum/10;sum=0;
for(i=0;i<10;i++){sum+=MPU6050_FIFO[5][i];
}
MPU6050_FIFO[5][10]=sum/10;
}/**************************实现函数********************************************
*函数原型:		void MPU6050_setClockSource(uint8_t source)
*功  能:	    设置  MPU6050 的时钟源* CLK_SEL | Clock Source* --------+--------------------------------------* 0       | Internal oscillator* 1       | PLL with X Gyro reference* 2       | PLL with Y Gyro reference* 3       | PLL with Z Gyro reference* 4       | PLL with external 32.768kHz reference* 5       | PLL with external 19.2MHz reference* 6       | Reserved* 7       | Stops the clock and keeps the timing generator in reset
*******************************************************************************/
void MPU6050_setClockSource(uint8_t source){IICwriteBits(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_CLKSEL_BIT, MPU6050_PWR1_CLKSEL_LENGTH, source);}/** Set full-scale gyroscope range.* @param range New full-scale gyroscope range value* @see getFullScaleRange()* @see MPU6050_GYRO_FS_250* @see MPU6050_RA_GYRO_CONFIG* @see MPU6050_GCONFIG_FS_SEL_BIT* @see MPU6050_GCONFIG_FS_SEL_LENGTH*/
void MPU6050_setFullScaleGyroRange(uint8_t range) {IICwriteBits(devAddr, MPU6050_RA_GYRO_CONFIG, MPU6050_GCONFIG_FS_SEL_BIT, MPU6050_GCONFIG_FS_SEL_LENGTH, range);
}/**************************实现函数********************************************
*函数原型:		void MPU6050_setFullScaleAccelRange(uint8_t range)
*功  能:	    设置  MPU6050 加速度计的最大量程
*******************************************************************************/
void MPU6050_setFullScaleAccelRange(uint8_t range) {IICwriteBits(devAddr, MPU6050_RA_ACCEL_CONFIG, MPU6050_ACONFIG_AFS_SEL_BIT, MPU6050_ACONFIG_AFS_SEL_LENGTH, range);
}/**************************实现函数********************************************
*函数原型:		void MPU6050_setSleepEnabled(uint8_t enabled)
*功  能:	    设置  MPU6050 是否进入睡眠模式enabled =1   睡觉enabled =0   工作
*******************************************************************************/
void MPU6050_setSleepEnabled(uint8_t enabled) {IICwriteBit(devAddr, MPU6050_RA_PWR_MGMT_1, MPU6050_PWR1_SLEEP_BIT, enabled);
}/**************************实现函数********************************************
*函数原型:		uint8_t MPU6050_getDeviceID(void)
*功  能:	    读取  MPU6050 WHO_AM_I 标识	 将返回 0x68
*******************************************************************************/
uint8_t MPU6050_getDeviceID(void) {IICreadBytes(devAddr, MPU6050_RA_WHO_AM_I, 1, buffer);return buffer[0];
}/**************************实现函数********************************************
*函数原型:		uint8_t MPU6050_testConnection(void)
*功  能:	    检测MPU6050 是否已经连接
*******************************************************************************/
uint8_t MPU6050_testConnection(void) {if(MPU6050_getDeviceID() == 0x68)  //0b01101000;return 1;else return 0;
}/**************************实现函数********************************************
*函数原型:		void MPU6050_setI2CMasterModeEnabled(uint8_t enabled)
*功  能:	    设置 MPU6050 是否为AUX I2C线的主机
*******************************************************************************/
void MPU6050_setI2CMasterModeEnabled(uint8_t enabled) {IICwriteBit(devAddr, MPU6050_RA_USER_CTRL, MPU6050_USERCTRL_I2C_MST_EN_BIT, enabled);
}/**************************实现函数********************************************
*函数原型:		void MPU6050_setI2CBypassEnabled(uint8_t enabled)
*功  能:	    设置 MPU6050 是否为AUX I2C线的主机
*******************************************************************************/
void MPU6050_setI2CBypassEnabled(uint8_t enabled) {IICwriteBit(devAddr, MPU6050_RA_INT_PIN_CFG, MPU6050_INTCFG_I2C_BYPASS_EN_BIT, enabled);
}/**************************实现函数********************************************
*函数原型:		void MPU6050_initialize(void)
*功  能:	    初始化 	MPU6050 以进入可用状态。
*******************************************************************************/
void MPU6050_initialize(void) {MPU6050_setClockSource(MPU6050_CLOCK_PLL_YGYRO); //设置时钟MPU6050_setFullScaleGyroRange(MPU6050_GYRO_FS_2000);//陀螺仪最大量程 +-1000度每秒MPU6050_setFullScaleAccelRange(MPU6050_ACCEL_FS_2);	//加速度度最大量程 +-2GMPU6050_setSleepEnabled(0); //进入工作状态MPU6050_setI2CMasterModeEnabled(0);	 //不让MPU6050 控制AUXI2CMPU6050_setI2CBypassEnabled(0);	 //主控制器的I2C与	MPU6050的AUXI2C	直通。控制器可以直接访问HMC5883L
}/**************************************************************************
函数功能:MPU6050内置DMP的初始化
入口参数:无
返回  值:无
作    者:平衡小车之家
**************************************************************************/
void DMP_Init(void)
{ u8 temp[1]={0};i2cRead(0x68,0x75,1,temp);Flag_Show=1;printf("mpu_set_sensor complete ......\r\n");if(temp[0]!=0x68)NVIC_SystemReset();if(!mpu_init()){if(!mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL))printf("mpu_set_sensor complete ......\r\n");if(!mpu_configure_fifo(INV_XYZ_GYRO | INV_XYZ_ACCEL))printf("mpu_configure_fifo complete ......\r\n");if(!mpu_set_sample_rate(DEFAULT_MPU_HZ))printf("mpu_set_sample_rate complete ......\r\n");if(!dmp_load_motion_driver_firmware())printf("dmp_load_motion_driver_firmware complete ......\r\n");if(!dmp_set_orientation(inv_orientation_matrix_to_scalar(gyro_orientation)))printf("dmp_set_orientation complete ......\r\n");if(!dmp_enable_feature(DMP_FEATURE_6X_LP_QUAT | DMP_FEATURE_TAP |DMP_FEATURE_ANDROID_ORIENT | DMP_FEATURE_SEND_RAW_ACCEL | DMP_FEATURE_SEND_CAL_GYRO |DMP_FEATURE_GYRO_CAL))printf("dmp_enable_feature complete ......\r\n");if(!dmp_set_fifo_rate(DEFAULT_MPU_HZ))printf("dmp_set_fifo_rate complete ......\r\n");run_self_test();if(!mpu_set_dmp_state(1))printf("mpu_set_dmp_state complete ......\r\n");}Flag_Show=0;
}
/**************************************************************************
函数功能:读取MPU6050内置DMP的姿态信息
入口参数:无
返回  值:无
作    者:平衡小车之家
**************************************************************************/
void Read_DMP(void)
{	unsigned long sensor_timestamp;unsigned char more;long quat[4];dmp_read_fifo(gyro, accel, quat, &sensor_timestamp, &sensors, &more);		if (sensors & INV_WXYZ_QUAT ){    q0=quat[0] / q30;q1=quat[1] / q30;q2=quat[2] / q30;q3=quat[3] / q30;Pitch = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; 	Roll = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll}}
/**************************************************************************
函数功能:读取MPU6050内置温度传感器数据
入口参数:无
返回  值:摄氏温度
作    者:平衡小车之家
**************************************************************************/
int Read_Temperature(void)
{	   float Temp;Temp=(I2C_ReadOneByte(devAddr,MPU6050_RA_TEMP_OUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_TEMP_OUT_L);if(Temp>32768) Temp-=65536;Temp=(36.53+Temp/340)*10;return (int)Temp;
}
//------------------End of File----------------------------

control.c 

#include "control.h"	
#include "filter.h"	/**************************************************************************
作者:平衡小车之家
我的淘宝小店:/
**************************************************************************/
int Balance_Pwm,Velocity_Pwm,Turn_Pwm;
u8 Flag_Target;
int Voltage_Temp,Voltage_Count,Voltage_All;
/**************************************************************************
函数功能:所有的控制代码都在这里面5ms定时中断由MPU6050的INT引脚触发严格保证采样和数据处理的时间同步				 
**************************************************************************/
int EXTI9_5_IRQHandler(void) 
{    if(PBin(5)==0)		{   EXTI->PR=1<<5;                                                      //清除LINE5上的中断标志位   Flag_Target=!Flag_Target;if(delay_flag==1){if(++delay_50==10)	 delay_50=0,delay_flag=0;                     //给主函数提供精准延时}if(Flag_Target==1)                                                  //5ms读取一次陀螺仪和加速度计的值,更高的采样频率可以改善卡尔曼滤波和互补滤波的效果{Get_Angle(Way_Angle);                                               //===更新姿态		Voltage_Temp=Get_battery_volt();		                                //=====读取电池电压		Voltage_Count++;                                                    //=====平均值计数器Voltage_All+=Voltage_Temp;                                          //=====多次采样累积if(Voltage_Count==100) Voltage=Voltage_All/100,Voltage_All=0,Voltage_Count=0;//=====求平均值		return 0;	                                               }                                                                   //10ms控制一次,为了保证M法测速的时间基准,首先读取编码器数据Encoder_Left=-Read_Encoder(2);                                      //===读取编码器的值,因为两个电机的旋转了180度的,所以对其中一个取反,保证输出极性一致Encoder_Right=Read_Encoder(4);                                      //===读取编码器的值Get_Angle(Way_Angle);                                               //===更新姿态	Read_Distane();                                                     //读取超声波测量得到的距离if(Bi_zhang==0)Led_Flash(100);                                      //===LED闪烁;常规模式 1s改变一次指示灯的状态	if(Bi_zhang==1)Led_Flash(0);                                        //===LED闪烁;避障模式 指示灯常亮	Key();                                                              //===扫描按键状态 单击双击可以改变小车运行状态Balance_Pwm =balance(Angle_Balance,Gyro_Balance);                   //===平衡PID控制	Velocity_Pwm=velocity(Encoder_Left,Encoder_Right);                  //===速度环PID控制	 记住,速度反馈是正反馈,就是小车快的时候要慢下来就需要再跑快一点Turn_Pwm    =turn(Encoder_Left,Encoder_Right,Gyro_Turn);            //===转向环PID控制     Moto1=Balance_Pwm+Velocity_Pwm-Turn_Pwm;                            //===计算左轮电机最终PWMMoto2=Balance_Pwm+Velocity_Pwm+Turn_Pwm;                            //===计算右轮电机最终PWMXianfu_Pwm();                                                       //===PWM限幅if(Pick_Up(Acceleration_Z,Angle_Balance,Encoder_Left,Encoder_Right))//===检查是否小车被那起Flag_Stop=1;	                                                      //===如果被拿起就关闭电机if(Put_Down(Angle_Balance,Encoder_Left,Encoder_Right))              //===检查是否小车被放下Flag_Stop=0;	                                                      //===如果被放下就启动电机if(Turn_Off(Angle_Balance,Voltage)==0)                              //===如果不存在异常Set_Pwm(Moto1,Moto2);                                               //===赋值给PWM寄存器  }       	return 0;	  
} /**************************************************************************
函数功能:直立PD控制
入口参数:角度、角速度
返回  值:直立控制PWM
作    者:平衡小车之家
**************************************************************************/
int balance(float Angle,float Gyro)
{  float Bias;int balance;Bias=Angle-ZHONGZHI;       //===求出平衡的角度中值 和机械相关balance=Balance_Kp*Bias+Gyro*Balance_Kd;   //===计算平衡控制的电机PWM  PD控制   kp是P系数 kd是D系数 return balance;
}/**************************************************************************
函数功能:速度PI控制 修改前进后退遥控速度,请修Target_Velocity,比如,改成60就比较慢了
入口参数:左轮编码器、右轮编码器
返回  值:速度控制PWM
作    者:平衡小车之家
**************************************************************************/
int velocity(int encoder_left,int encoder_right)
{  static float Velocity,Encoder_Least,Encoder,Movement;static float Encoder_Integral,Target_Velocity=90;//=============遥控前进后退部分=======================// if(1==Flag_Qian)    	Movement=-Target_Velocity;	      //===前进标志位置1 else if(1==Flag_Hou)	Movement=Target_Velocity;         //===后退标志位置1else  Movement=0;	if(Bi_zhang==1&&Distance<500&&Flag_Left!=1&&Flag_Right!=1)        //避障标志位置1且非遥控转弯的时候,进入避障模式Movement=Target_Velocity;//=============速度PI控制器=======================//	Encoder_Least =(Encoder_Left+Encoder_Right)-0;                    //===获取最新速度偏差==测量速度(左右编码器之和)-目标速度(此处为零) Encoder *= 0.7;		                                                //===一阶低通滤波器       Encoder += Encoder_Least*0.3;	                                    //===一阶低通滤波器    Encoder_Integral +=Encoder;                                       //===积分出位移 积分时间:10msEncoder_Integral=Encoder_Integral-Movement;                       //===接收遥控器数据,控制前进后退if(Encoder_Integral>11000)  	Encoder_Integral=11000;             //===积分限幅if(Encoder_Integral<-11000)	Encoder_Integral=-11000;              //===积分限幅	Velocity=Encoder*Velocity_Kp+Encoder_Integral*Velocity_Ki;                          //===速度控制	if(Turn_Off(Angle_Balance,Voltage)==1||Flag_Stop==1)   Encoder_Integral=0;      //===电机关闭后清除积分return Velocity;
}/**************************************************************************
函数功能:转向控制  修改转向速度,请修改Turn_Amplitude即可
入口参数:左轮编码器、右轮编码器、Z轴陀螺仪
返回  值:转向控制PWM
作    者:平衡小车之家
**************************************************************************/
int turn(int encoder_left,int encoder_right,float gyro)//转向控制
{static float Turn_Target,Turn,Encoder_temp,Turn_Convert=0.7,Turn_Count,Kp=42,Kd=0;float Turn_Amplitude=50/Flag_sudu;    //=============遥控左右旋转部分=======================//if(1==Flag_Left||1==Flag_Right)                      //这一部分主要是根据旋转前的速度调整速度的起始速度,增加小车的适应性{if(++Turn_Count==1)Encoder_temp=myabs(encoder_left+encoder_right);Turn_Convert=50/Encoder_temp;if(Turn_Convert<0.4)Turn_Convert=0.4;if(Turn_Convert>1)Turn_Convert=1;}	else{Turn_Convert=0.7;Turn_Count=0;Encoder_temp=0;}		if(1==Flag_Left)	           Turn_Target-=Turn_Convert;        //===接收转向遥控数据else if(1==Flag_Right)	     Turn_Target+=Turn_Convert;        //===接收转向遥控数据else Turn_Target=0;                                            //===接收转向遥控数据if(Turn_Target>Turn_Amplitude)  Turn_Target=Turn_Amplitude;    //===转向速度限幅if(Turn_Target<-Turn_Amplitude) Turn_Target=-Turn_Amplitude;   //===转向速度限幅if(Flag_Qian==1||Flag_Hou==1)  Kd=0.4;                         //===接收转向遥控数据直立行走的时候增加陀螺仪就纠正    else Kd=0.27;                                          //=============转向PD控制器=======================//Turn=Turn_Target*Kp+gyro*Kd;                 //===结合Z轴陀螺仪进行PD控制return Turn;
}
/**************************************************************************
函数功能:赋值给PWM寄存器
入口参数:左轮PWM、右轮PWM
返回  值:无
**************************************************************************/
void Set_Pwm(int moto1,int moto2)
{int siqu=400;if(moto1>0)			AIN2=1,			AIN1=0;else 	          AIN2=0,			AIN1=1;PWMA=myabs(moto1)+siqu;if(moto2>0)	BIN1=0,			BIN2=1;else        BIN1=1,			BIN2=0;PWMB=myabs(moto2)+siqu;	
}/**************************************************************************
函数功能:限制PWM赋值 
入口参数:无
返回  值:无
**************************************************************************/
void Xianfu_Pwm(void)
{	int Amplitude=6900;    //===PWM满幅是7200 限制在6900if(Flag_Qian==1)  Moto1-=DIFFERENCE;  //DIFFERENCE是一个衡量平衡小车电机和机械安装差异的一个变量。直接作用于输出,让小车具有更好的一致性。if(Flag_Hou==1)  Moto2-=DIFFERENCE;  //DIFFERENCE是一个衡量平衡小车电机和机械安装差异的一个变量。直接作用于输出,让小车具有更好的一致性。if(Moto1<-Amplitude) Moto1=-Amplitude;	if(Moto1>Amplitude)  Moto1=Amplitude;	if(Moto2<-Amplitude) Moto2=-Amplitude;	if(Moto2>Amplitude)  Moto2=Amplitude;		}
/**************************************************************************
函数功能:按键修改小车运行状态 
入口参数:无
返回  值:无
**************************************************************************/
void Key(void)
{	u8 tmp,tmp2;tmp=click_N_Double(50); if(tmp==1)Flag_Stop=!Flag_Stop;//单击控制小车的启停if(tmp==2)Flag_Show=!Flag_Show;//双击控制小车的显示状态tmp2=Long_Press();                   if(tmp2==1) Bi_zhang=!Bi_zhang;		//长按控制小车是否进入超声波避障模式 
}/**************************************************************************
函数功能:异常关闭电机
入口参数:倾角和电压
返回  值:1:异常  0:正常
**************************************************************************/
u8 Turn_Off(float angle, int voltage)
{u8 temp;if(angle<-40||angle>40||1==Flag_Stop||voltage<1110)//电池电压低于11.1V关闭电机{	                                                 //===倾角大于40度关闭电机temp=1;                                            //===Flag_Stop置1关闭电机AIN1=0;                                            AIN2=0;BIN1=0;BIN2=0;}elsetemp=0;return temp;			
}/**************************************************************************
函数功能:获取角度 三种算法经过我们的调校,都非常理想 
入口参数:获取角度的算法 1:DMP  2:卡尔曼 3:互补滤波
返回  值:无
**************************************************************************/
void Get_Angle(u8 way)
{ float Accel_Y,Accel_X,Accel_Z,Gyro_Y,Gyro_Z;Temperature=Read_Temperature();      //===读取MPU6050内置温度传感器数据,近似表示主板温度。	if(way==1)                           //===DMP的读取在数据采集中断提醒的时候,严格遵循时序要求{	Read_DMP();                      //===读取加速度、角速度、倾角Angle_Balance=Pitch;             //===更新平衡倾角Gyro_Balance=gyro[1];            //===更新平衡角速度Gyro_Turn=gyro[2];               //===更新转向角速度Acceleration_Z=accel[2];         //===更新Z轴加速度计}			else{Gyro_Y=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_YOUT_L);    //读取Y轴陀螺仪Gyro_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_GYRO_ZOUT_L);    //读取Z轴陀螺仪Accel_X=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_XOUT_L); //读取X轴加速度计Accel_Z=(I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_H)<<8)+I2C_ReadOneByte(devAddr,MPU6050_RA_ACCEL_ZOUT_L); //读取Z轴加速度计if(Gyro_Y>32768)  Gyro_Y-=65536;                       //数据类型转换  也可通过short强制类型转换if(Gyro_Z>32768)  Gyro_Z-=65536;                       //数据类型转换if(Accel_X>32768) Accel_X-=65536;                      //数据类型转换if(Accel_Z>32768) Accel_Z-=65536;                      //数据类型转换Gyro_Balance=-Gyro_Y;                                  //更新平衡角速度Accel_Y=atan2(Accel_X,Accel_Z)*180/PI;                 //计算倾角	Gyro_Y=Gyro_Y/16.4;                                    //陀螺仪量程转换	if(Way_Angle==2)		  	Kalman_Filter(Accel_Y,-Gyro_Y);//卡尔曼滤波	else if(Way_Angle==3)   Yijielvbo(Accel_Y,-Gyro_Y);    //互补滤波Angle_Balance=angle;                                   //更新平衡倾角Gyro_Turn=Gyro_Z;                                      //更新转向角速度Acceleration_Z=Accel_Z;                                //===更新Z轴加速度计	}
}
/**************************************************************************
函数功能:绝对值函数
入口参数:int
返回  值:unsigned int
**************************************************************************/
int myabs(int a)
{ 		   int temp;if(a<0)  temp=-a;  else temp=a;return temp;
}
/**************************************************************************
函数功能:检测小车是否被拿起
入口参数:int
返回  值:unsigned int
**************************************************************************/
int Pick_Up(float Acceleration,float Angle,int encoder_left,int encoder_right)
{ 		   static u16 flag,count0,count1,count2;if(flag==0)                                                                   //第一步{if(myabs(encoder_left)+myabs(encoder_right)<30)                         //条件1,小车接近静止count0++;else count0=0;		if(count0>10)				flag=1,count0=0; } if(flag==1)                                                                  //进入第二步{if(++count1>200)       count1=0,flag=0;                                 //超时不再等待2000msif(Acceleration>26000&&(Angle>(-20+ZHONGZHI))&&(Angle<(20+ZHONGZHI)))   //条件2,小车是在0度附近被拿起flag=2; } if(flag==2)                                                                  //第三步{if(++count2>100)       count2=0,flag=0;                                   //超时不再等待1000msif(myabs(encoder_left+encoder_right)>150)                                 //条件3,小车的轮胎因为正反馈达到最大的转速   {flag=0;                                                                                     return 1;                                                               //检测到小车被拿起}}return 0;
}
/**************************************************************************
函数功能:检测小车是否被放下
入口参数:int
返回  值:unsigned int
**************************************************************************/
int Put_Down(float Angle,int encoder_left,int encoder_right)
{ 		   static u16 flag,count;	 if(Flag_Stop==0)                           //防止误检      return 0;	                 if(flag==0)                                               {if(Angle>(-10+ZHONGZHI)&&Angle<(10+ZHONGZHI)&&encoder_left==0&&encoder_right==0)         //条件1,小车是在0度附近的flag=1; } if(flag==1)                                               {if(++count>50)                                          //超时不再等待 500ms{count=0;flag=0;}if(encoder_left<-3&&encoder_right<-3&&encoder_left>-30&&encoder_right>-30)                //条件2,小车的轮胎在未上电的时候被人为转动  {flag=0;flag=0;return 1;                                             //检测到小车被放下}}return 0;
}

filter.c

#include "filter.h"/**************************************************************************
作者:平衡小车之家
我的淘宝小店:/
**************************************************************************/
float K1 =0.02; 
float angle, angle_dot; 	
float Q_angle=0.001;// 过程噪声的协方差
float Q_gyro=0.003;//0.003 过程噪声的协方差 过程噪声的协方差为一个一行两列矩阵
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;	 //输出值(后验估计)的微分=角速度
}/**************************************************************************
函数功能:一阶互补滤波
入口参数:加速度、角速度
返回  值:无
**************************************************************************/
void Yijielvbo(float angle_m, float gyro_m)
{angle = K1 * angle_m+ (1-K1) * (angle + gyro_m * 0.005);
}

show.c

#include "show.h"/**************************************************************************
作者:平衡小车之家
我的淘宝小店:/
**************************************************************************/
unsigned char i;          //计数变量
unsigned char Send_Count; //串口需要发送的数据个数
float Vol;
/**************************************************************************
函数功能:OLED显示
入口参数:无
返回  值:无
**************************************************************************/
void oled_show(void)
{//=============第一行显示小车模式=======================//	if(Way_Angle==1)	OLED_ShowString(0,0,"DMP");else if(Way_Angle==2)	OLED_ShowString(0,0,"Kalman");else if(Way_Angle==3)	OLED_ShowString(0,0,"Hubu");if(Bi_zhang==1)	OLED_ShowString(60,0,"Bizhang");else             OLED_ShowString(60,0,"Putong");//=============第二行显示温度和距离===============//	OLED_ShowNumber(0,10,Temperature/10,2,12);OLED_ShowNumber(23,10,Temperature%10,1,12);OLED_ShowString(13,10,".");OLED_ShowString(35,10,"`C");OLED_ShowNumber(70,10,(u16)Distance,5,12);OLED_ShowString(105,10,"mm");//=============第三行显示编码器1=======================//	OLED_ShowString(00,20,"EncoLEFT");if( Encoder_Left<0)		OLED_ShowString(80,20,"-"),OLED_ShowNumber(95,20,-Encoder_Left,3,12);else                 	OLED_ShowString(80,20,"+"),OLED_ShowNumber(95,20, Encoder_Left,3,12);//=============第四行显示编码器2=======================//		OLED_ShowString(00,30,"EncoRIGHT");if(Encoder_Right<0)		  OLED_ShowString(80,30,"-"),OLED_ShowNumber(95,30,-Encoder_Right,3,12);else               		OLED_ShowString(80,30,"+"),OLED_ShowNumber(95,30,Encoder_Right,3,12);	//=============第五行显示电压=======================//OLED_ShowString(00,40,"Volta");OLED_ShowString(58,40,".");OLED_ShowString(80,40,"V");OLED_ShowNumber(45,40,Voltage/100,2,12);OLED_ShowNumber(68,40,Voltage%100,2,12);if(Voltage%100<10) 	OLED_ShowNumber(62,40,0,2,12);//=============第六行显示角度=======================//OLED_ShowString(0,50,"Angle");if(Angle_Balance<0)		OLED_ShowNumber(45,50,Angle_Balance+360,3,12);else					        OLED_ShowNumber(45,50,Angle_Balance,3,12);//=============刷新=======================//OLED_Refresh_Gram();	}
/**************************************************************************
函数功能:向APP发送数据
入口参数:无
返回  值:无
作    者:平衡小车之家
**************************************************************************/
void APP_Show(void)
{    static u8 flag;int app_2,app_3,app_4;app_4=(Voltage-1110)*2/3;		if(app_4<0)app_4=0;if(app_4>100)app_4=100;   //对电压数据进行处理app_3=Encoder_Right/1.3; if(app_3<0)app_3=-app_3;			                   //对编码器数据就行数据处理便于图形化app_2=Encoder_Left/1.3;  if(app_2<0)app_2=-app_2;flag=!flag;if(PID_Send==1)//发送PID参数{printf("{C%d:%d:%d:%d:%d:%d:%d:%d:%d}$",(int)(Balance_Kp*100),(int)(Balance_Kd*100),(int)(Velocity_Kp*100),(int)(Velocity_Ki*100),0,0,0,0,0);//打印到APP上面	PID_Send=0;	}	else	if(flag==0)// printf("{A%d:%d:%d:%d}$",(u8)app_2,(u8)app_3,app_4,(int)Angle_Balance); //打印到APP上面elseprintf("{B%d:%d:%d:%d}$",(int)Angle_Balance,Distance,Encoder_Left,Encoder_Right);//打印到APP上面 显示波形
}
/**************************************************************************
函数功能:虚拟示波器往上位机发送数据 关闭显示屏
入口参数:无
返回  值:无
作    者:平衡小车之家
**************************************************************************/
void DataScope(void)
{   Vol=(float)Voltage/100;DataScope_Get_Channel_Data( Angle_Balance, 1 );       //显示角度 单位:度(°)DataScope_Get_Channel_Data( Distance/10, 2 );         //显示超声波测量的距离 单位:CM DataScope_Get_Channel_Data( Vol, 3 );                 //显示电池电压 单位:V
//		DataScope_Get_Channel_Data( 0 , 4 );   
//		DataScope_Get_Channel_Data(0, 5 ); //用您要显示的数据替换0就行了
//		DataScope_Get_Channel_Data(0 , 6 );//用您要显示的数据替换0就行了
//		DataScope_Get_Channel_Data(0, 7 );
//		DataScope_Get_Channel_Data( 0, 8 ); 
//		DataScope_Get_Channel_Data(0, 9 );  
//		DataScope_Get_Channel_Data( 0 , 10);Send_Count = DataScope_Data_Generate(3);for( i = 0 ; i < Send_Count; i++) {while((USART1->SR&0X40)==0);  USART1->DR = DataScope_OutPut_Buffer[i]; }
}

DateScope_DP.c

 
#include "DataScope_DP.h"/**************************************************************************
作者:平衡小车之家 
淘宝店铺:/
**************************************************************************/
unsigned char DataScope_OutPut_Buffer[42] = {0};	   //串口发送缓冲区//函数说明:将单精度浮点数据转成4字节数据并存入指定地址 
//附加说明:用户无需直接操作此函数 
//target:目标单精度数据
//buf:待写入数组
//beg:指定从数组第几个元素开始写入
//函数无返回 
void Float2Byte(float *target,unsigned char *buf,unsigned char beg)
{unsigned char *point;point = (unsigned char*)target;	  //得到float的地址buf[beg]   = point[0];buf[beg+1] = point[1];buf[beg+2] = point[2];buf[beg+3] = point[3];
}//函数说明:将待发送通道的单精度浮点数据写入发送缓冲区
//Data:通道数据
//Channel:选择通道(1-10)
//函数无返回 
void DataScope_Get_Channel_Data(float Data,unsigned char Channel)
{if ( (Channel > 10) || (Channel == 0) ) return;  //通道个数大于10或等于0,直接跳出,不执行函数else{switch (Channel){case 1:  Float2Byte(&Data,DataScope_OutPut_Buffer,1); break;case 2:  Float2Byte(&Data,DataScope_OutPut_Buffer,5); break;case 3:  Float2Byte(&Data,DataScope_OutPut_Buffer,9); break;case 4:  Float2Byte(&Data,DataScope_OutPut_Buffer,13); break;case 5:  Float2Byte(&Data,DataScope_OutPut_Buffer,17); break;case 6:  Float2Byte(&Data,DataScope_OutPut_Buffer,21); break;case 7:  Float2Byte(&Data,DataScope_OutPut_Buffer,25); break;case 8:  Float2Byte(&Data,DataScope_OutPut_Buffer,29); break;case 9:  Float2Byte(&Data,DataScope_OutPut_Buffer,33); break;case 10: Float2Byte(&Data,DataScope_OutPut_Buffer,37); break;}}	 
}//函数说明:生成 DataScopeV1.0 能正确识别的帧格式
//Channel_Number,需要发送的通道个数
//返回发送缓冲区数据个数
//返回0表示帧格式生成失败 
unsigned char DataScope_Data_Generate(unsigned char Channel_Number)
{if ( (Channel_Number > 10) || (Channel_Number == 0) ) { return 0; }  //通道个数大于10或等于0,直接跳出,不执行函数else{	DataScope_OutPut_Buffer[0] = '$';  //帧头switch(Channel_Number)   { case 1:   DataScope_OutPut_Buffer[5]  =  5; return  6;  case 2:   DataScope_OutPut_Buffer[9]  =  9; return 10;case 3:   DataScope_OutPut_Buffer[13] = 13; return 14; case 4:   DataScope_OutPut_Buffer[17] = 17; return 18;case 5:   DataScope_OutPut_Buffer[21] = 21; return 22;  case 6:   DataScope_OutPut_Buffer[25] = 25; return 26;case 7:   DataScope_OutPut_Buffer[29] = 29; return 30; case 8:   DataScope_OutPut_Buffer[33] = 33; return 34; case 9:   DataScope_OutPut_Buffer[37] = 37; return 38;case 10:  DataScope_OutPut_Buffer[41] = 41; return 42; }	 }return 0;
}

 

更多推荐

平衡车代码阅读,学习mpu6050滤波

本文发布于:2024-02-07 08:08:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1754492.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:代码

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!