最原始版匿名四轴无人机代码注释

基于STM32平台

#include "CONTROL.h"
#include "BSP.H"
#include "UART2.h"
#include "IMU.h"
#include "MPU6050.h"
#include "MOTO.h"
PID PID_ROL,PID_PIT,PID_YAW;
u8 ARMED = 0;
u16 moto1=0,moto2=0,moto3=0,moto4=0;

float Get_MxMi(float num,float max,float min)//将num限制在min与max之间
{
   
    if(num>max)
        return max;
    else if(num<min)
        return min;
    else
        return num;
}         //解算出来的自我姿态,根据此得出自稳所需改变角度  //遥控发来的所需要改变的角度以进行倾斜的飞行,进行前进后退或转向 
          //Q_ANGLE.X ,         Q_ANGLE.Y,     Q_ANGLE.Z, //RC_Target_ROL, RC_Target_PIT, RC_Target_YAW
void CONTROL(float rol_now, float pit_now, float yaw_now,   float rol_tar, float pit_tar, float yaw_tar)
{
   

    vs16 throttle;
    vs16 yaw_d;
    float rol = rol_tar + rol_now;//将所有要改变的值加起来
    float pit = pit_tar + pit_now;
    float yaw = yaw_tar + yaw_now;

    throttle = Rc_Get.THROTTLE - 1000;//油门,代表电机的转速
    if(throttle<0)  throttle=0;//消除实际操作误差

    PID_ROL.IMAX = throttle/2;  //积分项限幅=throttle的1/2,为什么和throttle有关?
    Get_MxMi(PID_ROL.IMAX,1000,0);//并将积分项限幅限制在0-1000之间
    PID_PIT.IMAX = PID_ROL.IMAX;


    /****************************  P比例调节   ***********************************/

    PID_ROL.pout = PID_ROL.P * rol;
    PID_PIT.pout = PID_PIT.P * pit;
    PID_YAW.pout = PID_YAW.P * yaw;

    /****************************  I积分调节   **********************************/

    if(rol_tar*rol_tar<0.1 && pit_tar*pit_tar<0.1 && rol_now*rol_now<30 && pit_now*pit_now<30 && throttle>300)
    {
   //target遥控几乎未动,now当前比较接近水平,油门很大

        PID_ROL.iout += PID_ROL.I * rol;  
        PID_PIT.iout += PID_PIT.I * pit;                                 //积分项容易超调
        PID_ROL.iout = Get_MxMi(PID_ROL.iout,PID_ROL.IMAX,-PID_ROL.IMAX);//积分项限制在积分项限幅内
        PID_PIT.iout = Get_MxMi(PID_PIT.iout,PID_PIT.IMAX,-PID_PIT.IMAX);//防止大角度积累造成积分超调
    }
    else if(throttle<200)//油门很小不需要积分调节,为什么?
    {
   
        PID_ROL.iout = 0;
        PID_PIT.iout = 0;
    }

  /***************************  D微分调节  ***********************************/ 

    PID_ROL.dout = PID_ROL.D * MPU6050_GYRO_LAST.X;//,飞机头朝X正方向,ROL绕X轴转
    PID_PIT.dout = PID_PIT.D * MPU6050_GYRO_LAST.Y;//6050测得角速度,角度的微分就是角速度

    if(1480>Rc_Get.YAW || Rc_Get.YAW>1520)//YAW的微分调节,1500是什么也不改变的零点值
    {
            //自己飘的YAW值       //遥控所需要的改变量,*10提高权重,加快响应
        yaw_d = MPU6050_GYRO_LAST.Z + (Rc_Get.YAW-1500)*10;
        GYRO_I.Z = 0;//假设遥控不动的情况下YAW不可能自己飘,没有地磁作参考直接置零算了              
    }   //在IMU的preparedata()中GYRO_I.Z += MPU6050_GYRO_LAST.Z*Gyro_G*0.001;//0.001为dt
                              //GYRO_I.Z相当于绕Z轴(即yaw)旋转的总角度
        //在IMU的 IMUupdata ()中Q_ANGLE.Z = GYRO_I.Z
    else //为什么要分两种情况//遥控的左转右转功能不要了
    yaw_d = MPU6050_GYRO_LAST.Z;//很小的遥控改变量就不要了
    PID_YAW.dout = PID_YAW.D * yaw_d;

    /**************************************************************************************/


    PID_ROL.OUT = PID_ROL.pout + PID_ROL.iout + PID_ROL.dout;//最终的输出量
    PID_PIT.OUT = PID_PIT.pout + PID_PIT.iout + PID_PIT.dout;
    PID_YAW.OUT = PID_YAW.pout + PID_YAW.iout + PID_YAW.dout;

    if(throttle>200)//                                - +                           + +
    {
               //两正两负,调整roll的话PID_ROL.OUT要 - +,调整pit的话PID_PIT.OUT 要 - -
        moto3= throttle - PID_ROL.OUT - PID_PIT.OUT + PID_YAW.OUT;//赋给电机值
        moto1= throttle + PID_ROL.OUT - PID_PIT.OUT - PID_YAW.OUT;//加减号一定两正两负,电机对称
        moto2 = throttle + PID_ROL.OUT + PID_PIT.OUT + PID_YAW.OUT;//要改,先注释掉其他三个
        moto4= throttle - PID_ROL.OUT + PID_PIT.OUT - PID_YAW.OUT;
    }
    else//定义电机的死区,避免误操作
    {
   
        moto1 = 0;
        moto2 = 0;
        moto3 = 0;
        moto4 = 0;
    }
    if(ARMED)   {
   PCout(13)=0;Moto_PwmRflash(moto1,moto2,moto3,moto4);}//使能电机
    else            {
   PCout(13)=1;Moto_PwmRflash(0,0,0,0);}
}

#include "imu.h"
#include "MPU6050.h"
#include "math.h"

#define RtA         57.324841               //弧度到角度
#define AtR     0.0174533               //度到角度
#define Acc_G   0.0011963               //加速度变成G
#define Gyro_G  0.0610351               //角速度变成度   此参数对应陀螺2000度每秒
#define Gyro_Gr 0.0010653               //角速度变成弧度   此参数对应陀螺2000度每秒
#define FILTER_NUM 20

S_INT16_XYZ ACC_AVG;            //平均值滤波后的ACC
S_FLOAT_XYZ GYRO_I;             //陀螺仪积分
S_FLOAT_XYZ EXP_ANGLE;      //期望角度
S_FLOAT_XYZ DIF_ANGLE;      //期望角度与实际角度差
S_FLOAT_XYZ Q_ANGLE;            //四元数计算出的角度

int16_t ACC_X_BUF[FILTER_NUM],ACC_Y_BUF[FILTER_NUM],ACC_Z_BUF[FILTER_NUM];  //加速度滑动窗口滤波数组
//filter是滤波的意思
void Prepare_Data(void)
{
   
    static uint8_t filter_cnt=0;
    int32_t temp1=0,temp2=0,temp3=0;
    uint8_t i;

    MPU6050_Read();
    MPU6050_Dataanl();

    ACC_X_BUF[filter_cnt] = MPU6050_ACC_LAST.X;//更新滑动窗口数组
    ACC_Y_BUF[filter_cnt] = MPU6050_ACC_LAST.Y;
    ACC_Z_BUF[filter_cnt] = MPU6050_ACC_LAST.Z;
    for(i=0;i<FILTER_NUM;i++)
    {
   
        temp1 += ACC_X_BUF[i];
        temp2 += ACC_Y_BUF[i];
        temp3 += ACC_Z_BUF[i];
    }
    ACC_AVG.X = temp1 / FILTER_NUM;
    ACC_AVG.Y = temp2 / FILTER_NUM;
    ACC_AVG.Z = temp3 / FILTER_NUM;
    filter_cnt++;
    if(filter_cnt==FILTER_NUM)  filter_cnt=0;

    //GYRO_I.X += MPU6050_GYRO_LAST.X*Gyro_G*0.001;//0.001是时间间隔,两次prepare的执行周期
    //GYRO_I.Y += MPU6050_GYRO_LAST.Y*Gyro_G*0.001;//这里已经使用四元数进行结算,因此不用直接累加
    GYRO_I.Z += MPU6050_GYRO_LAST.Z*Gyro_G*0.001;
}

void Get_Attitude(void)
{
   
    IMUupdate(MPU6050_GYRO_LAST.X*Gyro_Gr,
                        MPU6050_GYRO_LAST.Y*Gyro_Gr,
                        MPU6050_GYRO_LAST.Z*Gyro_Gr,
                        ACC_AVG.X,ACC_AVG.Y,ACC_AVG.Z); //*0.0174转成弧度=π%180
}

#define Kp 10.0f                        // proportional gain governs rate of convergence to accelerometer/magnetometer
#define Ki 0.008f                          // integral gain governs rate of convergence of gyroscope biases
#define halfT 0.001f                   // half the sample period采样周期的一半

float q0 = 1, q1 = 0, q2 = 0, q3 = 0;    // quaternion elements representing the estimated orientation
float exInt = 0, eyInt = 0, ezInt = 0;    // scaled integral error
void IMUupdate(float gx, float gy, float gz, float ax, float ay, float az)
{
   
  float norm;
//  float hx, hy, hz, bx, bz;
  float vx, vy, vz;// wx, wy, wz;
  float ex, ey, ez;

  // 先把这些用得到的值算好
  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 = sqrt(ax*ax + ay*ay + az*az);       //acc数据归一化
  ax = ax /norm;
  ay = ay / norm;
  az = az / norm;

  // estimated direction of gravity and flux (v and w)              估计重力方向和流量/变迁
  vx = 2*(q1q3 - q0q2);                                             //四元素中xyz的表示
  vy = 2*(q0q1 + q2q3);
  vz = q0q0 - q1q1 - q2q2 + q3q3 ;

  // error is sum of cross product between reference direction of fields and direction measured by sensors
  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;

  // adjusted gyroscope measurements
  gx = gx + Kp*ex + exInt;                                              //将误差PI后补偿到陀螺仪,即补偿零点漂移
  gy = gy + Kp*ey + eyInt;
  gz = gz + Kp*ez + ezInt;                                          //这里的gz由于没有观测者进行矫正会产生漂移,表现出来的就是积分自增或自减

  // integrate quaternion rate and normalise                           //四元素的微分方程
  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;

  // normalise quaternion
  norm = sqrt(q0*q0 + q1*q1 + q2*q2 + q3*q3);
  q0 = q0 / norm;
  q1 = q1 / norm;
  q2 = q2 / norm;
  q3 = q3 / norm;

  Q_ANGLE.Z = GYRO_I.Z;//atan2(2 * q1 * q2 + 2 * q0 * q3, -2 * q2*q2 - 2 * q3* q3 + 1)* 57.3; // yaw
  Q_ANGLE.Y = asin(-2 * q1 * q3 + 2 * q0* q2)* 57.3; // pitch
  Q_ANGLE.X = atan2(2 * q2 * q3 + 2 * q0 * q1, -2 * q1 * q1 - 2 * q2* q2 + 1)* 57.3; // roll
}

#include "MOTO.h"

int16_t MOTO1_PWM = 0;
int16_t MOTO2_PWM = 0;
int16_t MOTO3_PWM = 0;
int16_t MOTO4_PWM = 0;

void Moto_PwmRflash(int16_t MOTO1_PWM,int16_t MOTO2_PWM,int16_t MOTO3_PWM,int16_t MOTO4_PWM)
{
          
    if(MOTO1_PWM>Moto_PwmMax)   MOTO1_PWM = Moto_PwmMax;
    if(MOTO2_PWM>Moto_PwmMax)   MOTO2_PWM = Moto_PwmMax;
    if(MOTO3_PWM>Moto_PwmMax)   MOTO3_PWM = Moto_PwmMax;
    if(MOTO4_PWM>Moto_PwmMax)   MOTO4_PWM = Moto_PwmMax;
    if(MOTO1_PWM<0) MOTO1_PWM = 0;
    if(MOTO2_PWM<0) MOTO2_PWM = 0;
    if(MOTO3_PWM<0) MOTO3_PWM = 0;
    if(MOTO4_PWM<0) MOTO4_PWM = 0;

    TIM4->CCR1 =MOTO1_PWM;
    TIM4->CCR2 = MOTO2_PWM;
    TIM4->CCR3 = MOTO3_PWM;
    TIM4->CCR4 = MOTO4_PWM;
}

void Tim4_init(void)
{
   
    TIM_TimeBaseInitTypeDef     TIM_TimeBaseStructure;
    TIM_OCInitTypeDef               TIM_OCInitStructure;
    uint16_t PrescalerValue = 0;
    /* -----------------------------------------------------------------------
    TIM3 Configuration(配置): generate 4 PWM signals with 4 different duty cycles(占空比):
    The TIM3CLK frequency(频率) is set to SystemCoreClock (Hz), to get TIM3 counter
    clock at 24 MHz the Prescaler is computed(计算) as following:
    - Prescaler = (TIM3CLK / TIM3 counter clock) - 1
    SystemCoreClock is set to 72 MHz for Low-density(密度), Medium-density, High-density
    and Connectivity(连通性) line devices and to 24 MHz for Low-Density Value line and
    Medium-Density Value line devices

    The TIM3 is running at 36 KHz: TIM3 Frequency = TIM3 counter clock/(ARR + 1)
    = 24 MHz / 1000 = 24 KHz
    TIM3 Channel1 duty cycle = (TIM3_CCR1/ TIM3_ARR)* 100 = 50%
    TIM3 Channel2 duty cycle = (TIM3_CCR2/ TIM3_ARR)* 100 = 37.5%
    TIM3 Channel3 duty cycle = (TIM3_CCR3/ TIM3_ARR)* 100 = 25%
    TIM3 Channel4 duty cycle = (TIM3_CCR4/ TIM3_ARR)* 100 = 12.5%
    ----------------------------------------------------------------------- */
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);//TIM3和TIM4同在APB1时钟下
    /* Compute the prescaler value */
    PrescalerValue = (uint16_t) (SystemCoreClock / 24000000) - 1;
    /* Time base configuration */
    TIM_TimeBaseStructure.TIM_Period = 999;     //计数上线  ,CNT=999时中断计数器并结束一个周期,进行下一个从零开始的周期
    TIM_TimeBaseStructure.TIM_Prescaler = PrescalerValue;   //pwm时钟分频 72MHz多大分频分成24MHz
    TIM_TimeBaseStructure.TIM_ClockDivision = 0;    
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     //向上计数
    TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

    /* PWM1 Mode configuration: Channel */
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//CNT<CCR1时为有效电平
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 0;//初始占空比为0
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//低电平有效
    TIM_OC1Init(TIM4, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);
    TIM_OC2Init(TIM4, &TIM_OCInitStructure);
    TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);
    TIM_OC3Init(TIM4, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);
    TIM_OC4Init(TIM4, &TIM_OCInitStructure);
    TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);
    TIM_ARRPreloadConfig(TIM4, ENABLE);
    TIM_Cmd(TIM4, ENABLE);
}


void Moto_Init(void)
{
   
    GPIO_InitTypeDef GPIO_InitStructure;
    //使能电机用的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); 
    //设置电机使用到得管脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 ; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    Tim4_init();    
}

#include "MPU6050.h"
#include "Tim.h"

u8                      mpu6050_buffer[14];                 //iic读取后存放数据
S_INT16_XYZ     GYRO_OFFSET,ACC_OFFSET;         //零漂
u8                      GYRO_OFFSET_OK = 1;
u8                      ACC_OFFSET_OK = 1;
S_INT16_XYZ     MPU6050_ACC_LAS
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值