无名飞控

无名飞控Time.c文件

由于无名飞控主要核心:传感器滤波、姿态解算、惯导、控制等代码在TIME.c里面运行,所以先来分析这个文件。

打开文件第一个函数:

void Timer4_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//结构体变量,这个结构体的成员是定时器的配置寄存器,如果将定时器的基址强制转换为这个结构体指针就可以依靠这个指针操作寄存器
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//使能或者失能APB1外设时钟
TIM_DeInit(TIM4);//将外设TIM4寄存器重设为缺省值
TIM_TimeBaseStructure.TIM_Period=4000;//TIM_Period设置了在下一个更新事件装入活动的自动重装载寄存器周期的值。它的取值必须在0x0000和0xFFFF之间。
TIM_TimeBaseStructure.TIM_Prescaler= (72 - 1);//设置了用来作为TIM4时钟频率除数的预分频值。它的取值必须在0x0000和0xFFFF之间
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;//设置了时钟分割
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//TIM向上计数模式
TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);//1us*1000=1ms
TIM_ClearFlag(TIM4, TIM_FLAG_Update);
TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);
TIM_Cmd(TIM4, ENABLE);
}
其中:


IM_ClearFlag(TIM4, TIM_FLAG_Update);// 清除TIM4的待处理标志位

TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE);// 使能或者失能指定的TIM中断, TIM中断源

TIM_Cmd(TIM4, ENABLE);// 使能或者失能TIMx外设


这个函数是初始化TIM4时钟,时钟开始运行后应发中断,从而运行姿态结算和控制代码。

//定义变量赋值

uint8 US_100_Start=0,US_100_Finished=1,US_100_Sampling_Cnt=0,US_100_Retry_Cnt=0;
uint8 ADNS3080_Cnt=0;
uint8 HC_SR04_Cnt=0;
Testime Time4_Delta;//结构体
uint16_t High_Okay_flag=0;
其中
typedef struct
{
  float Last_Time;
  float Now_Time;
  float Time_Delta;
  uint16 Time_Delta_INT;单位ms
}Testime;

 接下来判断中断是否发生

if(TIM_GetITStatus(TIM4,TIM_IT_Update)!=RESET )//检查指定的TIM4中断发生与否
 {    假如中断发生
     Test_Period(&Time4_Delta);//系统调度时间测试器
     NRF24L01_RC();//遥控器查询接收,非中端方式
 /*************加速度计、陀螺仪数字量采集***********/
     GET_MPU_DATA();//1.4ms
其中首先调用了Test_Period来得到现在的时间,上次中断发生时间,时间间隔

void Test_Period(Testime *Time_Lab)
{
   Time_Lab->Last_Time=Time_Lab->Now_Time;
   Time_Lab->Now_Time=(10000*TIME_ISR_CNT
                      +TIM2->CNT/2)/1000.0;单位ms
   Time_Lab->Time_Delta=Time_Lab->Now_Time-Time_Lab->Last_Time;
   Time_Lab->Time_Delta_INT=(uint16)(Time_Lab->Time_Delta);
}

这个函数是有TIME_ISR_CNT,这个量是从TIM2中来,这个量主要是记录现在已经工作了多少0.01S,TIM2->CNT/2是现在又经过了多少微秒,可以从TIM2中看出一点端倪:

void TIM2_Configuration_Cnt(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
    TIM_DeInit(TIM2);
    //TIM_TimeBaseStructure.TIM_Period = 60000;//30ms
    //TIM_TimeBaseStructure.TIM_Period = 20000;//10ms
    TIM_TimeBaseStructure.TIM_Period = 20000;//0.01s,系统运行1S,会计数2000000次,这里数20000即引发中断

    TIM_TimeBaseStructure.TIM_Prescaler = 36-1; //36M/36/2=0.5us,分频36M,
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;系统时钟72M
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    TIM_ClearFlag(TIM2, TIM_FLAG_Update);
    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
    TIM_Cmd(TIM2, ENABLE);
}


先不管NRF24L01_RC函数,是 nRF24L01的驱动函数,如果使用自己的接收机的话,这里应该用不着。

nRF24L01是由NORDIC生产的工作在2.4GHz~2.5GHz的ISM 频段的单片无线收发器芯片

进入 GET_MPU_DATA()得到mpu的数据

定义:

void GET_MPU_DATA(void)
{
  //GET_ACC_DATA();
  IMU_Filter();
  GET_GYRO_DATA();
  
}

首先IMU_Filter函数

float X_Origion,Y_Origion,Z_Origion;
void IMU_Filter(void)/*得到加速度数据,并进行低通滤波*/
{
	uint8_t axis;   
        imu.accelRaw[0] = GetData(ACCEL_XOUT_H);//imu结构体
        imu.accelRaw[1] = GetData(ACCEL_YOUT_H);
        imu.accelRaw[2] = GetData(ACCEL_ZOUT_H);
        Acce_Correct_Filter();//对imu.accelRaw进行低通滤波得到数组Acce_Correct
             
        X_Origion=K[0]*(imu.accelRaw[0])-B[0];//经过椭球校正后的三轴加速度量//初值均为0;
        Y_Origion=K[1]*(imu.accelRaw[1])-B[1];
        Z_Origion=K[2]*(imu.accelRaw[2])-B[2];
        /*typedef struct
 {
 float Position[Axis_Num];//位置估计量
 float Speed[Axis_Num];//速度估计量
 float Acceleration[Axis_Num];//加速度估计量
 float Pos_History[Axis_Num][Num];//历史惯导位置
 float Vel_History[Axis_Num][Num];//历史惯导速度
 float Acce_Bias[Axis_Num];//惯导加速度漂移量估计量
 }SINS;
  FilterBefore_NamelessQuad是一个SINS结构体  *///我注释的
        FilterBefore_NamelessQuad.Acceleration[_YAW]=
                      -Sin_Roll* X_Origion
                        + Sin_Pitch *Cos_Roll *Y_Origion
                           + Cos_Pitch * Cos_Roll *Z_Origion;
        FilterBefore_NamelessQuad.Acceleration[_PITCH]=
                   Cos_Yaw* Cos_Roll * X_Origion
                        +(Sin_Pitch*Sin_Roll*Cos_Yaw-Cos_Pitch * Sin_Yaw) * Y_Origion
                          +(Sin_Pitch * Sin_Yaw+Cos_Pitch * Sin_Roll * Cos_Yaw) * Z_Origion;  
        FilterBefore_NamelessQuad.Acceleration[_ROLL]=
                   Sin_Yaw* Cos_Roll * X_Origion
                        +(Sin_Pitch * Sin_Roll * Sin_Yaw +Cos_Pitch * Cos_Yaw) * Y_Origion 
                          + (Cos_Pitch * Sin_Roll * Sin_Yaw - Sin_Pitch * Cos_Yaw) * Z_Origion;  
        
        
        FilterBefore_NamelessQuad.Acceleration[_YAW]*=AcceGravity/AcceMax;
        FilterBefore_NamelessQuad.Acceleration[_YAW]-=AcceGravity;
        FilterBefore_NamelessQuad.Acceleration[_YAW]*=100;//加速度cm/s^2
        FilterBefore_NamelessQuad.Acceleration[_PITCH]*=AcceGravity/AcceMax;
        FilterBefore_NamelessQuad.Acceleration[_PITCH]*=100;//加速度cm/s^2
        FilterBefore_NamelessQuad.Acceleration[_ROLL]*=AcceGravity/AcceMax;
        FilterBefore_NamelessQuad.Acceleration[_ROLL]*=100;//加速度cm/s^2

     
        Acce_Control_Filter();//加速度滤波,用于惯导、加速度控制反馈量再次滤波     
        
	/* 加速度计Butterworth滤波 */
	/* 获取最新x(n) */
	    accButter[0].input[2] =Int_Sort(X_Origion);
        accButter[1].input[2] =Int_Sort(Y_Origion);
        accButter[2].input[2] =Int_Sort(Z_Origion);
	/* Butterworth滤波 */
	for (axis = 0; axis < 3; axis++)
	{
	accButter[axis].output[2] =
                 Int_Sort(b_acc[0] * accButter[axis].input[2] 
                  + b_acc[1] * accButter[axis].input[1] 
                    + b_acc[2] * accButter[axis].input[0] 
                      - a_acc[1] * accButter[axis].output[1] 
                        - a_acc[2] * accButter[axis].output[0]);
		imu.accelFilter[axis] = accButter[axis].output[2];
	}	
	for (axis = 0; axis < 3; axis++)
	{
		/* x(n) 序列保存 */
		accButter[axis].input[0] = accButter[axis].input[1];
		accButter[axis].input[1] = accButter[axis].input[2];
		/* y(n) 序列保存 */
		accButter[axis].output[0] = accButter[axis].output[1];
		accButter[axis].output[1] = accButter[axis].output[2];
	}  
       X_g_av=imu.accelFilter[0];
       Y_g_av=imu.accelFilter[1];
       Z_g_av=imu.accelFilter[2];   
}
对于  imu 是一个 _IMU_Tag 类型的结构体, _IMU_Tag imu;
typedef struct 
{
	float accelRaw[3];	// 加速度计原始数据
	float gyroRaw[3];     // 陀螺仪原始数据
	float accelFilter[3];	// 加速度计滤波后数据
	float gyroFilter[3];	// 陀螺仪滤波后数据
}_IMU_Tag;
接着是gitdata函数,将原始数据赋值给一个16位无符号整形的数
int16_t GetData(uint8_t REG_Address)
{
	uint8_t Hd,Ld;
	Hd=Single_ReadI2C(0xD0,REG_Address);
	Ld=Single_ReadI2C(0xD0,REG_Address+1);
	return (Hd<<8)+Ld; 
}

取完数据后,回到IMU_Filter进入

 Acce_Correct_Filter();butterworth滤波,对imu.accelRaw进行滤波赋值给Acce_Correct

void Acce_Correct_Filter()
{
   Acce_Correct[0]=Int_Sort(LPButterworth(imu.accelRaw[0],
                    &Butter_Buffer_Correct[0],&Butter_1HZ_Parameter_Acce));
   Acce_Correct[1]=Int_Sort(LPButterworth(imu.accelRaw[1]
                    ,&Butter_Buffer_Correct[1],&Butter_1HZ_Parameter_Acce));
   Acce_Correct[2]=Int_Sort(LPButterworth(imu.accelRaw[2]
                    ,&Butter_Buffer_Correct[2],&Butter_1HZ_Parameter_Acce)); 
}

对于Acce_Correct有定义 int16_t Acce_Correct[3]={0};//用于矫正加速度量,截至频率很低

对于int_Sort有定义 #define Int_Sort    (int16_t)

对于LPButterworth,其参数有:

Butter_BufferData Butter_Buffer_Correct[3];

Butter_Parameter Butter_1HZ_Parameter_Acce={

  //250hz---1hz      

  1,   -1.822694925196,    0.837181651256,

  0.003621681514929,0.007243363029857, 0.003621681514929

};  

从名字上推应该是低通Butterworth滤波器定义 


float LPButterworth(float curr_input,Butter_BufferData *Buffer,Butter_Parameter *Parameter)
{   
    /* 加速度计Butterworth滤波 */
	/* 获取最新x(n) */
        static int LPB_Cnt=0;
        Buffer->Input_Butter[2]=curr_input;
        if(LPB_Cnt>=100)
        {
	/* Butterworth滤波 */
        Buffer->Output_Butter[2]=
         Parameter->b[0] * Buffer->Input_Butter[2] 
        +Parameter->b[1] * Buffer->Input_Butter[1]
	+Parameter->b[2] * Buffer->Input_Butter[0] 
        -Parameter->a[1] * Buffer->Output_Butter[1] 
        -Parameter->a[2] * Buffer->Output_Butter[0];
        }
        else
        {
          Buffer->Output_Butter[2]=Buffer->Input_Butter[2];
          LPB_Cnt++;
        }
	/* x(n) 序列保存 */
        Buffer->Input_Butter[0]=Buffer->Input_Butter[1];
        Buffer->Input_Butter[1]=Buffer->Input_Butter[2];
	/* y(n) 序列保存 */
        Buffer->Output_Butter[0]=Buffer->Output_Butter[1];
        Buffer->Output_Butter[1]=Buffer->Output_Butter[2];
        
        
        return Buffer->Output_Butter[2];
}

对imu.accelRaw[i]进行滤波,之后赋给 Acce_Correct[i]

经校正后给I_Origion

        X_Origion=K[0]*(imu.accelRaw[0])-B[0];//经过椭球校正后的三轴加速度量//初值均为0;
        Y_Origion=K[1]*(imu.accelRaw[1])-B[1];
        Z_Origion=K[2]*(imu.accelRaw[2])-B[2];

{ floatK[3]={1.0,1.0,1.0};//标度误差

float B[3]={0,0,0};//零位误差}

坐标系转换,将加速度有地理系转到机体系

FilterBefore_NamelessQuad.Acceleration[_YAW]=
                      -Sin_Roll* X_Origion
                        + Sin_Pitch *Cos_Roll *Y_Origion
                           + Cos_Pitch * Cos_Roll *Z_Origion;
        FilterBefore_NamelessQuad.Acceleration[_PITCH]=
                   Cos_Yaw* Cos_Roll * X_Origion
                        +(Sin_Pitch*Sin_Roll*Cos_Yaw-Cos_Pitch * Sin_Yaw) * Y_Origion
                          +(Sin_Pitch * Sin_Yaw+Cos_Pitch * Sin_Roll * Cos_Yaw) * Z_Origion;  
        FilterBefore_NamelessQuad.Acceleration[_ROLL]=
                   Sin_Yaw* Cos_Roll * X_Origion
                        +(Sin_Pitch * Sin_Roll * Sin_Yaw +Cos_Pitch * Cos_Yaw) * Y_Origion 
                          + (Cos_Pitch * Sin_Roll * Sin_Yaw - Sin_Pitch * Cos_Yaw) * Z_Origion;  

 FilterBefore_NamelessQuad是一个SINS结构体  
  
{
 float Position[Axis_Num];//位置估计量
 float Speed[Axis_Num];//速度估计量
 float Acceleration[Axis_Num];//加速度估计量
 float Pos_History[Axis_Num][Num];//历史惯导位置
 float Vel_History[Axis_Num][Num];//历史惯导速度
 float Acce_Bias[Axis_Num];//惯导加速度漂移量估计量
 }SINS;

继续回到IMU_Filter

FilterBefore_NamelessQuad.Acceleration[_YAW]*=AcceGravity/AcceMax;
        FilterBefore_NamelessQuad.Acceleration[_YAW]-=AcceGravity;
        FilterBefore_NamelessQuad.Acceleration[_YAW]*=100;//加速度cm/s^2
        FilterBefore_NamelessQuad.Acceleration[_PITCH]*=AcceGravity/AcceMax;
        FilterBefore_NamelessQuad.Acceleration[_PITCH]*=100;//加速度cm/s^2
        FilterBefore_NamelessQuad.Acceleration[_ROLL]*=AcceGravity/AcceMax;
        FilterBefore_NamelessQuad.Acceleration[_ROLL]*=100;//加速度cm/s^2//

//把加速度量化处理,也是乘以一个量程

接下来又有:(好像并没有什么卵用)

Acce_Control_Filter();//加速度滤波,用于惯导、加速度控制反馈量再次滤波,对imu.accelRaw[i]进行滤波,之后赋给 Acce_Correct[i]

又有:再次butterworth滤波,对纠正后的数据进行滤波,滤波后数据赋值给I_g_av

         /* 加速度计Butterworth滤波 */

         /* 获取最新x(n) */

         accButter[0].input[2]=Int_Sort(X_Origion);

        accButter[1].input[2]=Int_Sort(Y_Origion);

        accButter[2].input[2]=Int_Sort(Z_Origion);

         /* Butterworth滤波 */

         for (axis = 0; axis < 3; axis++)

         {

         accButter[axis].output[2] =

                 Int_Sort(b_acc[0] *accButter[axis].input[2]

                  + b_acc[1] *accButter[axis].input[1]

                    + b_acc[2] *accButter[axis].input[0]

                      - a_acc[1] *accButter[axis].output[1]

                        - a_acc[2] *accButter[axis].output[0]);

                   imu.accelFilter[axis] =accButter[axis].output[2];

         }       

         for (axis = 0; axis < 3; axis++)

         {

                   /* x(n) 序列保存 */

                   accButter[axis].input[0] =accButter[axis].input[1];

                   accButter[axis].input[1] =accButter[axis].input[2];

                   /* y(n) 序列保存 */

                   accButter[axis].output[0] =accButter[axis].output[1];

                   accButter[axis].output[1] =accButter[axis].output[2];

         } 

       X_g_av=imu.accelFilter[0];

       Y_g_av=imu.accelFilter[1];

       Z_g_av=imu.accelFilter[2];  

}

其中,accButter是一个结构体

struct _ButterWorth2d_Acc_Tag accButter[3] = 
{
	/* input[3] output[3] */
	{0, 0, 0, 0, 0, 0},		// X-axis
	{0, 0, 0, 0, 0, 0},		// Y-axis
	{0, 0, 0, 0, 0, 0},		// Z-axis
};

加速度的数据经过两次滤波,一次是1赫兹的,然后纠偏,转换到机体系,再滤波,这次滤波是15赫兹(程序注释是这样具体什么样再看看)

至此也就得到了加速度数据要取陀螺仪数据

回到GET_MPU_DATA,进入GET_GYRO_DATA();

void GET_GYRO_DATA(void)//角速度低通滤波后用于姿态解算
{
	X_w  = GetData(GYRO_XOUT_H)-X_w_off;
	Y_w  = GetData(GYRO_YOUT_H)-Y_w_off;
	Z_w  = GetData(GYRO_ZOUT_H)-Z_w_off;
        X_w_av=GYRO_LPF(X_w,
                        &Gyro_BufferData[0],
                        &Gyro_Parameter   
                        );
        Y_w_av=GYRO_LPF(Y_w,
                        &Gyro_BufferData[1],
                        &Gyro_Parameter   
                        );
        Z_w_av=GYRO_LPF(Z_w,
                        &Gyro_BufferData[2],
                        &Gyro_Parameter   
                        );  
}

其中:float  X_w_off =0,Y_w_off =0,Z_w_off =0;

和加速度处理类似,将原始数据赋值给一个16位无符号整形的数,减去偏差,然后滤波

对于GYRO_LPF:

float GYRO_LPF(float curr_inputer,
               Butter_BufferData *Buffer,
               Butter_Parameter *Parameter)
{
        /* 加速度计Butterworth滤波 */
	/* 获取最新x(n) */
        Buffer->Input_Butter[2]=curr_inputer;
	/* Butterworth滤波 */
        Buffer->Output_Butter[2]=
         Parameter->b[0] * Buffer->Input_Butter[2] 
        +Parameter->b[1] * Buffer->Input_Butter[1]
	+Parameter->b[2] * Buffer->Input_Butter[0] 
        -Parameter->a[1] * Buffer->Output_Butter[1] 
        -Parameter->a[2] * Buffer->Output_Butter[0];
	/* x(n) 序列保存 */
        Buffer->Input_Butter[0]=Buffer->Input_Butter[1];
        Buffer->Input_Butter[1]=Buffer->Input_Butter[2];
	/* y(n) 序列保存 */
        Buffer->Output_Butter[0]=Buffer->Output_Butter[1];
        Buffer->Output_Butter[1]=Buffer->Output_Butter[2];
        return (Buffer->Output_Butter[2]);
}
其中:Butter_Parameter Gyro_Parameter={
  1,   -1.475480443593,   0.5869195080612,
  0.02785976611714,  0.05571953223427,  0.02785976611714,
};  

Butter_BufferData Gyro_BufferData[3];

就此得到加速度计和陀螺仪数据,也就得到了mpu所有数据

下面回到void TIM4_IRQHandler(void)

根据飞控介绍,飞控使用气压计spl06_01,磁力计IST8310

则应该进入

SPL06_001_StateMachine();
 Get_Mag_IST8310();

磁力计和气压计

#elsedef IMU_BOARD_NC686
      SPL06_001_StateMachine();
      Get_Mag_IST8310();

具体定义

先进入SPL06_001_StateMachine,表面上无输入无输出,但是

uint8 SPL06_001_Offset_Okay=0;
uint8 SPL06_001_Finished=0;
float SPL06_001_Filter_P,SPL06_001_Filter_high;
unsigned int SPL06_001_Cnt=0;
void SPL06_001_StateMachine(void)
{
  user_spl0601_get();
  if(SPL06_001_Cnt<=50)  SPL06_001_Cnt++;
  if(SPL06_001_Cnt==49)
  {
    SPL06_001_Offset_Okay=1;
    High_Okay_flag=1;
    SPL06_001_Offset=pressure;
  }
    
  if(SPL06_001_Offset_Okay==1)//初始气压零点设置完毕
  {
    SPL06_001_Filter_P=pressure;      
    SPL06_001_Filter_high=Get_Altitude_SPL06_001(SPL06_001_Filter_P);
  }

但是它有调用了user_spl0601_get,顾名思义就是得到spl0601的数据,具体什么数据,接着看。

float temperature;
float pressure;
float user_spl0601_get()
{
  static uint16_t spl06_cnt=0;
  spl06_cnt++;
  if(spl06_cnt==1)
  {
  spl0601_get_raw_temp();
  temperature = spl0601_get_temperature();
  }
  else
  {
    spl0601_get_raw_pressure();
    pressure = spl0601_get_pressure();
    spl06_cnt=0;
  }
  return 0;
}
有两句语句

static uint16_t spl06_cnt=0;
 spl06_cnt++;

这两句把spl06_cnt变成1,于是if(spl06_cnt==1)就成立,每次判断都成立,
判断成立就有:

spl0601_get_raw_temp();
 temperature = spl0601_get_temperature();

又调用函数spl0601_get_raw_temp

/*****************************************************************************
 函 数 名  : spl0601_get_raw_temp
 功能描述  : 获取温度的原始值,并转换成32Bits整数
 输入参数  : void  
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 
 
 修改历史      :
  1.日    期   : 2015年11月30日
    作    者   : WL
    修改内容   : 新生成函数

*****************************************************************************/
void spl0601_get_raw_temp(void)
{
    uint8 h[3] = {0}; 
    h[0] = spl0601_read(HW_ADR, 0x03);
    h[1] = spl0601_read(HW_ADR, 0x04);
    h[2] = spl0601_read(HW_ADR, 0x05);
    p_spl0601->i32rawTemperature = (int32)h[0]<<16 | (int32)h[1]<<8 | (int32)h[2];
    p_spl0601->i32rawTemperature= (p_spl0601->i32rawTemperature&0x800000) ? (0xFF000000|p_spl0601->i32rawTemperature) : p_spl0601->i32rawTemperature;
}
然后


/*****************************************************************************
 函 数 名  : spl0601_get_temperature
 功能描述  : 在获取原始值的基础上,返回浮点校准后的温度值
 输入参数  : void  
 输出参数  : 无
 返 回 值  : 
 调用函数  : 
 被调函数  : 
 
 修改历史      :
  1.日    期   : 2015年11月30日
    作    者   : WL
    修改内容   : 新生成函数

*****************************************************************************/
float spl0601_get_temperature(void)
{
    float fTCompensate;
    float fTsc;

    fTsc = p_spl0601->i32rawTemperature / (float)p_spl0601->i32kT;
    fTCompensate =  p_spl0601->calib_param.c0 * 0.5 + p_spl0601->calib_param.c1 * fTsc;
    return fTCompensate;
}

总之就此得到了温度,这是气压计啊,为什么得到温度?不应该是压力吗?

接着看 user_spl0601_get结束,下面进入

if(SPL06_001_Cnt<=50)  SPL06_001_Cnt++;
  if(SPL06_001_Cnt==49)
  {
    SPL06_001_Offset_Okay=1;
    High_Okay_flag=1;
    SPL06_001_Offset=pressure;
  }
    
  if(SPL06_001_Offset_Okay==1)//初始气压零点设置完毕
  {
    SPL06_001_Filter_P=pressure;      
    SPL06_001_Filter_high=Get_Altitude_SPL06_001(SPL06_001_Filter_P);
  }
   
}
也就是说SPL06_001_Cnt累加50次后进入到if(SPL06_001_Cnt==49)的判断,取高度




先不管

看看磁力计

Get_Mag_IST8310得到磁力计数据



IST8310 Mag_IST8310;
void Get_Mag_IST8310(void)
{
  static uint16_t IST8310_Sample_Cnt=0;
  float MagTemp[3]={0};
  IST8310_Sample_Cnt++;
  if(IST8310_Sample_Cnt==1)
  {  
  Single_WriteI2C(IST8310_SLAVE_ADDRESS,IST8310_REG_CNTRL1,0x01);//Single Measurement Mode
  }
  else if(IST8310_Sample_Cnt==3)//至少间隔6ms,此处为8ms
  {
    Mag_IST8310.Buf[0]=Single_ReadI2C(IST8310_SLAVE_ADDRESS,0x03);//OUT_X_L_A
    Mag_IST8310.Buf[1]=Single_ReadI2C(IST8310_SLAVE_ADDRESS,0x04);//OUT_X_H_A
    Mag_IST8310.Buf[2]=Single_ReadI2C(IST8310_SLAVE_ADDRESS,0x05);//OUT_Y_L_A
    Mag_IST8310.Buf[3]=Single_ReadI2C(IST8310_SLAVE_ADDRESS,0x06);//OUT_Y_H_A
    Mag_IST8310.Buf[4]=Single_ReadI2C(IST8310_SLAVE_ADDRESS,0x07);//OUT_Z_L_A
    Mag_IST8310.Buf[5]=Single_ReadI2C(IST8310_SLAVE_ADDRESS,0x08);//OUT_Z_H_A
    /*****************合成三轴磁力计数据******************/
    Mag_IST8310.Mag_Data[0]=(Mag_IST8310.Buf[1]<<8)|Mag_IST8310.Buf[0];
    Mag_IST8310.Mag_Data[1]=(Mag_IST8310.Buf[3]<<8)|Mag_IST8310.Buf[2];
    Mag_IST8310.Mag_Data[2]=(Mag_IST8310.Buf[5]<<8)|Mag_IST8310.Buf[4];
    IST8310_Sample_Cnt=0;
  }
#ifdef MAG_REVERSE_SIDE//重新映射磁力计三轴数据
   Mag_IST8310.x = Mag_IST8310.Mag_Data[0];
   Mag_IST8310.y = -Mag_IST8310.Mag_Data[1];
   Mag_IST8310.z = Mag_IST8310.Mag_Data[2];
#else 
   Mag_IST8310.x = Mag_IST8310.Mag_Data[0];
   Mag_IST8310.y = Mag_IST8310.Mag_Data[1];
   Mag_IST8310.z = Mag_IST8310.Mag_Data[2];
#endif
   DataMag.x=Mag_IST8310.x;
   DataMag.y=Mag_IST8310.y;
   DataMag.z=Mag_IST8310.z;
        
   MagTemp[0]=Mag_IST8310.x-Mag_Offset[0];
   MagTemp[1]=Mag_IST8310.y-Mag_Offset[1];
   MagTemp[2]=Mag_IST8310.z-Mag_Offset[2];
   
   
   /************磁力计倾角补偿*****************/
   Mag_IST8310.thx = MagTemp[0] * Cos_Roll+ MagTemp[2] * Sin_Roll;
   Mag_IST8310.thy = MagTemp[0] * Sin_Pitch*Sin_Roll    
                    +MagTemp[1] * Cos_Pitch
                    -MagTemp[2] * Cos_Roll*Sin_Pitch;
   /***********反正切得到磁力计观测角度*********/
   Mag_IST8310.Angle_Mag=atan2(Mag_IST8310.thx,Mag_IST8310.thy)*57.296;
}
磁力计倾角补偿为什么?










  • 10
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
开源飞控:支持气压计、超声波定高、户外GPS定点、定速巡航,部分视频链接如下: 无名飞控暴力测试 无名飞控江边定点(长时间) 无名飞控定高作死测试 无名飞控加速度计6面校准与融合简单讲解 无名飞控源码整体框架介绍初步 无名飞控解(上)锁与遥控器简单设置 无名科创自研飞控平台,经过武汉科技大学连续四届研究生师兄们参考国内外主流飞控(APM、Pixhawk、Autoquad、MWC、CC3D、无穷开、ANO、Light等)的算法与整体框架的进行深入学习基础上,经过软、硬件的精心设计,继承与发展,目前飞控整体功能相对完善,主要功能有:姿态自稳、超声波、气压计定高,户外GPS定点,GPS模式下定速巡航等功能,涵盖飞控学习主要核心算法: 1、四旋翼的传感器滤波(针对传感器不同使用情况:姿态解算、惯导、控制、传感器矫正等)分别采用窗口滑动滤波、不同截止频率的巴特沃斯数字低通滤波器);2、姿态解算(互补滤波、梯度下降法等);3、惯性导航(经典回路反馈法即APM三阶段互补滤波,单观测器的卡尔曼滤波,双观测量的卡尔曼滤波,观测传感器延时修正处理等); 4、控制算法(经典PID控制、前馈控制、自抗扰控制ADRC)等。 无名科创团队的发展: 多旋翼飞行器飞行控制系统(简称飞控)是我们团队历届主研项目,团队13年即开始第一代飞控的研究,从最开始的小四轴,到后来的多旋翼飞控,经历N个版本改进,经历无数次断桨、射桨、炸机,一步一步完善与改进,整合除了目前我们这款对外开源的飞控。团队历来贡献者均就职于无人机公司做算法相关工作。目前我们的飞控更加完善,更加稳定,更加适合学习,主要核心代码自写率达到百分之90以上,代码基本上是逐行注释,整个飞控框架清晰明了,模块化封装规范,方便大家学习与二次开发。由于作者目前仍然在校,主研项目仍为飞控,个人时间比较多,可和大家一同交流学习。我们的服务宗旨是:打造国内功能最多、性能最好、成本最低、可玩性最强的开源飞控学习平台。帮助大家以最小的代价、最大的获得感、最快的速度学习飞控相关算法,顺利完成进阶逆袭!!! 团队主要成员CSDN开源技术博客汇总 ,充分展现我们开源共享、共同进步的创客精神,不废话了,直接上图: 部分技术博客截图: 无名科创开源飞控:独家首创10轴IMU组合:MPU6050(加速度计、陀螺仪)+IST8310(DJI同款磁力计)+SPL06-001(歌尔高精度气压计、媲美MS5611),MCU:STM32F103RCT6,这是一款强大的飞控,主频72Mhz,flash 256K,板载10 Axis传感器,3轴陀螺,3轴加速度,3轴磁罗盘,高精度气压计。适合新手学习无刷飞控,更适合玩家做多种拓展和二次开发,飞控预留多个串口,可外接各种附加设备,已实现超声波定高、气压计定高、GPS定点等功能,代码完全开源。 无名科创开源飞控学习平台: 1、飞控板与IMU分离式设计 2、采用3D打印的IMU气压防护罩 3、软件调试支持主流IAR、Keil两款编译器 4、支持多家上位机与地面站,方便调试
### 回答1: 无名创新飞控开源地面站(ngroundstation)是一种先进的无人机地面控制系统。它具备开源的特点,意味着用户可以自由地根据自身需求进行定制和修改。这使得它成为无人机领域的创新工具,给用户提供了更大的灵活性和个性化的选择。 ngroundstation采用了先进的飞控技术,可以实时监控和控制无人机的飞行。它的主要功能包括飞行数据显示、任务规划、航线设置、自动驾驶模式、图像传输、视频回放等。用户可以通过简洁直观的界面对无人机进行灵活的操作和监控。 ngroundstation支持多种无人机型号,并且可以与各种传感器和设备进行无缝集成,从而实现更丰富的功能和更高的性能。它还提供了多种通信方式,包括无线网络、蓝牙和串口,以满足不同用户的需求。 ngroundstation还拥有高度可扩展的特性,用户可以通过添加插件、编写脚本等方式对其进行功能扩展。这使得系统可以适用于各种应用场景,如航拍摄影、植保、应急救援等。 总之,无名创新飞控开源地面站(ngroundstation)是一款先进的无人机地面控制系统,具备开源、灵活、可定制等特点。它的出现为无人机领域的发展带来了更大的创新空间,同时也满足了用户个性化需求的不断增长。 ### 回答2: 无名创新飞控开源地面站ngroundstation是一款使用开源技术开发的先进飞行控制系统。ngroundstation旨在提供一个可靠、灵活、易于使用的地面控制站,以便操作者可以实时监控和控制无人机的飞行。 该地面站具有许多强大的功能。首先,它能够实时显示无人机的飞行状态和位置信息,包括高度、速度、航向等。操作者可以通过地图界面追踪无人机的实时位置,并随时调整飞行路径和目标。 ngroundstation还具有智能导航功能,可以预先设置航点和航线,让无人机在没有人为干预的情况下按照设定的轨迹进行飞行。这对于航拍摄影和地理勘测等任务非常有用,可以确保飞行的准确性和稳定性。 此外,地面站还提供了数据记录和回放功能,可以记录和回放无人机的飞行数据和图像,以便进一步分析和研究。操作者可以通过回放功能来审查无人机的飞行过程,了解操作过程中的任何潜在问题。 ngroundstation还具有强大的远程控制功能。操作者可以通过地面站远程操控无人机的起飞、降落、航向调整等操作,无需实际接触无人机。这是一项非常重要的功能,可以保证操作者的安全,并且方便地进行任务规划和控制。 总之,ngroundstation是一款优秀的无人机地面控制站软件,通过其先进的功能和易用的操作界面,操作者可以实时监控和控制无人机的飞行,同时提供了数据记录和回放功能,方便进一步分析和研究。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值