微波EDA网,见证研发工程师的成长!
首页 > 研发问答 > 嵌入式设计讨论 > MCU和单片机设计讨论 > 一起DIY四轴飞行器

一起DIY四轴飞行器

时间:10-02 整理:3721RD 点击:
网上看到一个四轴飞行器的视频深深吸引了我,然而我是一个Kinetis的忠实粉丝,就想尝试一下用Kinetis MK10去做一个四轴飞行器!
期间因为很多事情,让这个项目断断续续,但是很高兴我能坚持下来。
当然,尽管现在也还未能成功起飞,但是最起码,有了新的进展,在这里,我分享一下我的Kinetis四轴心得。
也算是我自己的一个学习记录吧。
首先是main函数:

  1.     int main(void)
  2.     {
  3.         uint32_t i;
  4.         uint8_t ret;
  5.         uint32_t counter = 0;
  6.         imu_float_euler_angle_t angle;
  7.         SYSTICK_DelayInit(); //Init Delay
  8.         UART_QuickInit(UART1_RX_PC03_TX_PC04, 115200);  //Init UART and printf
  9.         GPIO_QuickInit(HW_GPIOA, 1 , kGPIO_Mode_OPP);   //Init LED
  10.         //Blink LED to indicate system is running
  11.         for(i = 0; i < 10; i++)
  12.         {
  13.             GPIO_ToggleBit(HW_GPIOA, 1);
  14.             DelayMs(50);
  15.         }
  16.         //init sensor
  17.         ret = InitSensor();
  18.         if(ret)
  19.         {
  20.             printf("Sensor init failed! code:%d\r\n", ret);
  21.         }
  22.         // install imu interface function
  23.         imu_io_install(&IMU_IOInstallStruct1);
  24.         // install trans uart for send data
  25.         trans_io_install(&TRANS_IOInstallStruct1);
  26.       
  27.         trans_user_data_t send_data;
  28.         while(1)
  29.         {
  30.             imu_get_euler_angle(&angle);
  31.     //              通过串口将姿态的数据发送出去,串口速度为115200               
  32.     //        printf("%05d %05d %05d\r", (int16_t)angle.imu_pitch, (int16_t)angle.imu_roll, (int16_t)angle.imu_yaw);
  33.             
  34.                             //以下函数用于发送数据帧,传输飞控需要的数据帧
  35.             send_data.trans_pitch = (int16_t)angle.imu_pitch*100;
  36.             send_data.trans_roll = (int16_t)angle.imu_roll*100;
  37.             send_data.trans_yaw = (int16_t)angle.imu_yaw*10;
  38.             trans_send_pactket(send_data);  //发送一帧数据
  39.                             //结束
  40.             //blink the LED
  41.             counter++;
  42.             counter %= 10;
  43.             if(!counter)
  44.             {
  45.                 GPIO_ToggleBit(HW_GPIOA, 1);   //LED运行灯闪烁
  46.             }
  47.         }
  48.     }

复制代码

main函数就是飞控一开始执行的代码,主要的一些外设的初始化工作。比如IIC啦,UART啦,SPI啦等等。
InitSensor();其实就是MPU6050   hmc5883 的初始化函数。代码如下:

  1.     uint8_t InitSensor(void)
  2.     {
  3.         static int init = 0;
  4.         uint8_t ret = 0;
  5.         if(!init)
  6.         {
  7.             ret += mpu6050_init(&mpu6050_device1, IMU_TEST_I2C_MAP, "mpu6050", 96000);
  8.             ret += hmc5883_init(&hmc_device, IMU_TEST_I2C_MAP, "hmc5883", 96000);
  9.          //   ret += bmp180_init(&bmp180_device1, IMU_TEST_I2C_MAP, "bmp180", 96000);
  10.             init = 1;
  11.         }
  12.         if(ret)
  13.         {
  14.             return ret;
  15.         }
  16.         return 0;
  17.     }

复制代码

然后在while(1)里,就是最重要的姿态解算函数了。
imu_get_euler_angle(&angle);就是姿态解算函数,并把得到的结果保存到angle变量里。
代码如下:

  1.     uint32_t imu_get_euler_angle(imu_float_euler_angle_t * angle)
  2.     {
  3.         uint8_t err = 0;
  4.         int16_t ax,ay,az,gx,gy,gz,mx,my,mz;
  5.         imu_raw_data_t raw_data;
  6.     //    imu_raw_data_t filter_data;
  7.         imu_float_data_t float_data;
  8.         err += gpIOInstallStruct->imu_get_accel(&ax, &ay, &az);
  9.         err += gpIOInstallStruct->imu_get_gyro(&gx, &gy, &gz);
  10.         err += gpIOInstallStruct->imu_get_mag(&mx, &my, &mz);
  11.         if(err >0)
  12.         {
  13.           return 1;
  14.         }
  15.         raw_data.ax = ax;
  16.         raw_data.ay = ay;
  17.         raw_data.az = az;
  18.         raw_data.gx = gx;
  19.         raw_data.gy = gy;
  20.         raw_data.gz = gz;
  21.         raw_data.mx = mx;
  22.         raw_data.my = my;
  23.         raw_data.mz = mz;
  24.     #if 0
  25.         //I need rawdata I give you filtered data
  26.         imu_sliding_filter(raw_data, &filter_data);
  27.     #endif
  28.         // I need filtered data I give you float data
  29.         imu_format_data(raw_data, &float_data);
  30.         //I need float data I give you euler angles
  31.         updateAHRS( float_data.gx * Gyro_Gr,
  32.                     float_data.gy * Gyro_Gr,
  33.                     float_data.gz * Gyro_Gr,
  34.                     float_data.ax,
  35.                     float_data.ay,
  36.                     float_data.az,
  37.                     float_data.mx,
  38.                     float_data.my,
  39.                     float_data.mz,
  40.                     angle);
  41.         return 0;
  42.     }

复制代码

得到飞控的姿态,就可以做很多事情了。
在四轴飞行器里,我们需要使用姿态来做PID控制
常用的是单级PID算法,高级的就是串级PID。
我在尝试使用串级PID
串级PID的代码如下:

  1.     //飞行器姿态外环控制
  2.     void ANO_FlyControl::Attitude_Outter_Loop(void)
  3.     {
  4.             int32_t        errorAngle[2];
  5.             Vector3f Gyro_ADC;
  6.             
  7.             //计算角度误差值
  8.             errorAngle[ROLL] = constrain_int32((rc.Command[ROLL] * 2) , -((int)FLYANGLE_MAX), +FLYANGLE_MAX) - imu.angle.x * 10;
  9.             errorAngle[PITCH] = constrain_int32((rc.Command[PITCH] * 2) , -((int)FLYANGLE_MAX), +FLYANGLE_MAX) - imu.angle.y * 10;
  10.             
  11.             //获取角速度
  12.             Gyro_ADC = mpu6050.Get_Gyro() / 4;
  13.             
  14.             //得到外环PID输出
  15.             RateError[ROLL] = pid[PIDLEVEL].get_p(errorAngle[ROLL]) - Gyro_ADC.x;
  16.             RateError[PITCH] = pid[PIDLEVEL].get_p(errorAngle[PITCH]) - Gyro_ADC.y;
  17.             RateError[YAW] = ((int32_t)(yawRate) * rc.Command[YAW]) / 32 - Gyro_ADC.z;               
  18.     }

复制代码

  1.     //飞行器姿态内环控制
  2.     void ANO_FlyControl::Attitude_Inner_Loop(void)
  3.     {
  4.             int32_t PIDTerm[3];
  5.             
  6.             for(u8 i=0; i<3;i++)
  7.             {
  8.                     //当油门低于检查值时积分清零,重新积分  
  9.                     if ((rc.rawData[THROTTLE]) < RC_MINCHECK)        
  10.                             pid[i].reset_I();
  11.                   
  12.                     //得到内环PID输出
  13.                     PIDTerm[i] = pid[i].get_pid(RateError[i], PID_INNER_LOOP_TIME);
  14.             }
  15.             
  16.             PIDTerm[YAW] = -constrain_int32(PIDTerm[YAW], -300 - abs(rc.Command[YAW]), +300 + abs(rc.Command[YAW]));        
  17.                   
  18.             //PID输出转为电机控制量
  19.             motor.writeMotor(rc.Command[THROTTLE], PIDTerm[ROLL], PIDTerm[PITCH], PIDTerm[YAW]);
  20.     }        

复制代码

分为外环控制 和 内环控制两部分。
PID算法完成,当然是输出给PWM控制电机了。
代码如下:

  1. //四轴X模式
  2.         motorPWM[0] = throttle - pidTermRoll + pidTermPitch - pidTermYaw; //后右
  3.         motorPWM[1] = throttle - pidTermRoll - pidTermPitch + pidTermYaw; //前右
  4.         motorPWM[2] = throttle + pidTermRoll + pidTermPitch + pidTermYaw; //后左
  5.         motorPWM[3] = throttle + pidTermRoll - pidTermPitch - pidTermYaw; //前左

复制代码

这样,一个基本能飞的四轴飞控系统就差不多完成了。

实物图:




小编好厉害,继续加油!

不错 哦,大师级别哦。

好啊    我想学学  做一个玩玩

一直想做四轴,但没经验,要多多学习呀!

记号学习学习。

牛逼!

好,,好,,好,,好

不错 哦,看看学习一下。

好啊    我想学学  做一个玩玩

谢谢小编分享,好好学习

小编好厉害,有电路图吗参考

很牛逼啊,真心感谢小编这么大公无私的奉献出来啦 哈哈

想试着做 慢慢学习

谢谢小编分享。

谢谢小编分享。

推荐,谢谢分享

收藏了,谢谢分享。

非常厉害的小编

学习了,可惜没原理图。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top