2015年全国大学生电子设计竞赛多旋翼自主飞行器(C题)2015年8月15日摘要本文对四旋翼碟形飞行器进行了初步的研究和设计。
首先,对飞行器各旋翼的电机选择做了论证,分析了实际升力效率与PWM的关系并选择了此样机的最优工作频率,并重点对飞行器进行了硬件和软件的设计。
本飞行器采用瑞萨R5F100LEA单片机为主控制器,通过四元数算法处理传感器MPU6000采集机身平衡信息并进行闭环的PID控制来保持机身的平衡。
整个控制系统包括电源模块、传感器检测模块、电机调速模块、飞行控制模块及微处理器模块等。
角度传感器和角速率传感模块为整个系统提供飞行器当前姿态和角速率信号,构成飞行器的增稳系统。
本系统经过飞行测试,可以达到设计要求。
关键字:R5F100LEA单片机、传感器、PWM、PID控制。
目录1系统方案 (1)1.1电机的论证与选择 (1)1.2红外对管检测传感器的论证与选择 (1)1.3电机驱动方案的论证与选择 (2)2系统控制理论分析 (2)2.1控制方式 (2)2.2 PID模糊控制算法 (2)3控制系统硬件与软件设计 (4)3.1系统硬件电路设计 (4)3.1.1系统总体框图 (4)3.1.2 飞行控制电路原理图 (4)3.1.3电机驱动模块子系统 (5)3.1.4电源 (5)3.1.5简易电子示高模块电路原理图 (6)3.2系统软件设计 (6)3.2.1程序功能描述与设计思路 (6)3.2.2程序流程图 (6)4测试条件与测试结果 (7)4.1 测试条件与仪器 (7)4.2 测试结果及分析 (7)4.2.1测试结果(数据) (7)4.2.2测试分析与结论 (8)附录1:电路图原理 (9)附录2:源程序 (10)1系统方案本系统主要由电源模块、电机调速控制模块、飞行控制模块、传感器模块组成,下面分别论证这几个模块的选择。
1.1电机的论证与选择四旋翼无人飞行器是通过控制四个不同无刷直流电机的转速,达到控制四旋翼无人飞行器的飞行姿态和位置,与传统直升机通过控制舵机来改变螺旋桨的桨距角,达到控制直升机的目的不同。
在电机的选型上,主要有直流有刷电机和直流无刷电机两种。
方案一:直流有刷电机是当前普遍使用的一种直流电机,它的驱动电路简单、控制方法成熟,但是直流有刷电机使用电刷进行换向,换向时电刷与线圈触电存在机械接触,电机长时间高速转动使极易因磨损导致电气接触不良等问题,而且有刷电机效率低、力矩小、重量大,不适合对功率重量比敏感的电动小型飞行器。
方案二:直流无刷电机能量密度高、力矩大、重量轻,采用非接触式的电子换向方法,消除了电刷磨损,较好地解决了直流有刷电机的缺点,适用于对功率重量比敏感的用途,同时增强了电机的可靠性。
综合以上两种方案,选择方案二。
1.2红外对管检测传感器的论证与选择探测地面黑线的基本原理是:光线照射到路面并反射,由于黑线和白色地面对光的反射系数不同,所以可以根据接收到的反射光强弱来判断黑线。
可实现的方案有:方案一:采用普通发光二极管及光敏电阻组成的发射接收方案。
该方案在实际使用时,容易受到外界光源的干扰,有时甚至检测不到。
主要是因为可见光的反射效果跟地表的平坦程度、地表材料的反射情况均对检测效果产生直接影响。
虽然可采取超高高度发光二极管降低一定的干扰,但这又增加额外的功率损耗。
方案二:红外避障传感器E18-D80NK。
这是一种集发射与接收于一体的光电传感器,发射光经过调制后发出,接收头对反射光进行解调输出,有效的避免了可见光的干扰。
透镜的使用,也使得这款传感器最远可以检测80厘米距离。
检测障碍物的距离可以根据要求通过尾部的电位器旋钮进行调节。
并且具有探测距离远、受可见光干扰小、价格便宜、易于装配、使用方便等特点。
综合以上两种方案,选择方案二。
1.3电机驱动方案的论证与选择方案一: 采用继电器对电动机的开或关进行控制,通过开关的切换对小车的速度进行调整。
这个方案的优点是电路较为简单,缺点是继电器的响应时间慢、机械结构易损坏、寿命较短、可靠性不高。
方案二: 采用电阻网络或数字电位器调整电动机的分压,从而达到调速的目的。
但是电阻网络只能实现有级调速,而数字电阻的元器件价格比较昂贵。
更主要的问题在于一般电动机的电阻很小,但电流很大;分压不仅会降低效率,而且实现很困难。
方案三:采用全桥驱动PWM电路。
这种驱动的优点是使管子工作在占空比可调的开关状态,提高使用效率实现电机转速的微调。
并且保证了可以简单的方式实现方向控制。
基于上述三种方案,应选择方案三比较合适。
2系统控制理论分析2.1控制方式本次比赛的难点在于如何使飞行器在空中较好的实现平衡控制,然后使其进行巡线飞行和降落。
题中所研究的四旋翼结构属于X型分布,即螺旋桨M1和M4与M2和M3关于X轴对称,螺旋桨M1和M3与M2和M4关于Y轴对称如图1所示。
对于四旋翼的模型简单的数学物理建模。
通过陀螺仪返回的六个数据进行四元数拟合处理得到空间欧拉角。
然后返回给系统进行闭环PID控制。
图1 螺旋桨分布示意图2.2 PID模糊控制算法PID是工业控制上的一种控制算法,在工程实际中,应用最为广泛的调节器控制规律为比例、积分、微分控制,简称PID控制,又称PID调节。
PID控制器问世至今已有近70年历史,它以其结构简单、稳定性好、工作可靠、调整方便而成为工业控制的主要技术之一。
当被控对象的结构和参数不能完全掌握,或得不到精确的数学模型时,控制理论的其它技术难以采用时,系统控制器的结构和参数必须依靠经验和现场调试来确定,这时应用PID控制技术最为方便。
PID控制算法原理如图2所示。
图2 PID计算方式经过测算和推导,我们得出了PID的计算公式为:进入PID调节子程序时,首先需要根据系统给定值和采样值计算偏差。
另外,在系统进入稳态后,偏差是很小的。
当控制过程进入这种状态后,就进入了系统设定的一个允许带里。
本设计中的算法设计与流程图如图3所示。
图3 PID调节子程序流程图3控制系统硬件与软件设计3.1系统硬件电路设计3.1.1系统总体框图系统总体框图如图4所示。
图4 系统总体框图3.1.2 飞行控制电路原理图飞行控制模块是控制系统的核心部分。
它在每个控制周期内实时处理传感器采集的数据和飞行器的姿态信息,完成PID控制的算法,得到四旋翼飞行器的姿态和位置信息,计算出控制量,转化为相应的控制信号经驱动电路后驱动四个电机工作,保持四旋翼飞行器稳定飞行。
电路图如图5所示。
图5飞控系统电路3.1.3电机驱动模块子系统四电机驱动模块根据中心控制模块指令驱动各个电机到达指定转速,将电机的速度通过测速反馈装置反馈给飞行姿态控制模块,控制无刷直流电机闭环控制转速,从而控制飞行状态,达到预期位置和姿态。
通过电子调速器给电机提供电流,使之改变电机的转速快慢。
本系统中设计的电机驱动电路如图6所示。
图6电机驱动电路原理图3.1.4电源电源由一块11.1V 2200ma的锂电池(重量约为166克)供电,在由电调降压给系统中的各个模块供5v电压并给电机提供电流,这样可满足可满足各个小系统的电源要求。
3.1.5简易电子示高模块电路原理图简易电子示高装置是根据光敏二极管对激光束光强的持续接收,可以控制光敏二极管模块输出低电平,一旦激光束对光敏二极管照射的中断,即可使光敏二极管部分电路呈现高电平。
进而触发光电门,促使发光二极管和蜂鸣器工作,起到报警作用。
基本框图如图7所示。
图7 报警触发模块基本框图3.2系统软件设计3.2.1程序功能描述与设计思路根据题目要求软件部分主要实现传感检测和PWM输出的更改。
(1)传感检测功能:设置高度和角度的输出信号类型。
(2)PWM输出:根据检测的数据,通过PID算法更改PWM的输出。
3.2.2程序流程图本系统以瑞萨MCU为核心,采用C语言对单片机进行编程。
主程序主要起导向和决策的作用,系统的控制总流程图如图所示。
系统包括延时子程序,电机转速控制子程序,检测子程序,副翼子程序。
系统控制的总流程图如图8所示。
部分程序清单见附录2。
图8 主流程图4测试条件与测试结果4.1 测试条件与仪器测试条件:检查多次,仿真电路和硬件电路必须与系统原理图完全相同,并且检查无误,硬件电路保证无虚焊。
测试仪器:高精度的数字毫伏表,数字示波器,数字万用表。
4.2 测试结果及分析4.2.1测试结果(数据)表2 测试功能、测试工具及实现的情况表经测试,系统可以满足基本要求和部分发挥部分,并具有稳定前行的特点。
4.2.2测试分析与结论根据上述测试数据,各个点的理论误差与实际误差比较,由此可以得出以下结论:1、实际与理论差距太大,高度受电压影响太大,通过运用红外对管调节四轴高度,2、通过微调PID参数使四轴起飞平衡,3、通过调节加速度计可使四轴按要求飞行,减小误差综上所述,基本可以达到预期目标,说明我们的硬件和软件的设计基本趋于合理,达到要求。
附录1:电路图原理附录2:源程序/************************************************************************************* *********************************** DISCLAIMER* This software is supplied by Renesas Electronics Corporation and is only* intended for use with Renesas products. No other uses are authorized. This* software is owned by Renesas Electronics Corporation and is protected under* all applicable laws, including copyright laws./************************************************************************************* **********************************Includes************************************************************************************** *********************************/#include "r_cg_macrodriver.h"#include "r_cg_cgc.h"#include "r_cg_port.h"#include "r_cg_timer.h"/* Start user code for include. Do not edit comment generated here */uint16_t n,m,a;//#define CH1 1000//#define CH2 0//#define CH3 1000//#define CH4 1000/********CH1 Roll ***************//********CH2 Pitch ***************//********CH3 Throttl ***************//********CH4 Yaw ***************//********CH5 Constant-level ***************//* End user code. Do not edit comment generated here */#include "r_cg_userdefine.h"/************************************************************************************* **********************************Global variables and functions************************************************************************************** *********************************//* Start user code for global. Do not edit comment generated here */void Delay_1ms(unsigned int K); //一毫秒基准延时函数void modle2 (void); //模式二:围绕矩形从A点到B点再到Avoid modle3 (void); //模式三:投放小铁片到B点在返回A点void modle4 (void); //模式四:从A点到B点拾取小铁片返回A点void modle5 (void); //模式五:原地旋转/* End user code. Do not edit comment generated here */void R_MAIN_UserInit(void); //初始化函数/************************************************************************************* *********************************** Function Name: main* Description : This function implements main function.* Arguments : None* Return Value : None************************************************************************************** *********************************/void main(void){R_MAIN_UserInit();/* Start user code. Do not edit comment generated here */while(1){if (P5.2 == 1){Delay_1ms(20);if(P5.2 == 1)a = 1;}else if (P5.3 == 1){Delay_1ms(20);if(P5.3 == 1)a = 2;}else if(P5.4 == 1){Delay_1ms(20);if(P5.4 == 1)a = 3;}else if (P5.5 == 1){if(P5.5 == 1)a = 4;}else if (P1.3 == 1){Delay_1ms(20);if(P1.3 == 1)a = 5;}switch(a){case 1: modle1(); break;case 2: modle2(); break;case 3: modle3(); break;case 4: modle4(); break;case 5: modle5(); break;default: break;}a=0;}/* End user code. Do not edit comment generated here */}/************************************************************************************* *********************************** Function Name: R_MAIN_UserInit* Description : This function adds user code before implementing main function.* Arguments : None* Return Value : None************************************************************************************** *********************************/void R_MAIN_UserInit(void){/* Start user code. Do not edit comment generated here */EI();/* End user code. Do not edit comment generated here */}/* Start user code for adding. Do not edit comment generated here */void modle1(void){R_TAU0_Channel0_Start();P5.1=0;Delay_1ms(2000);P5.1=1;TDR01=0X0BBF; // UnlockTDR02=0X0BAF;TDR03=0X07D5;TDR04=0X0FAA;Delay_1ms(5000);TDR01=0X0B9F; // FlyTDR02=0X0BAF;TDR04=0X0BAF;for(n=0;n<760;n++) //zhixian{TDR03+=0X0001;Delay_1ms(3);}for(m=0;m<34;m++){if(P1.4==0){for(n=0;n<4;n++){TDR03+=0X0001;Delay_1ms(4);}TDR02=0X0B2F;Delay_1ms(100);}else{TDR02=0X0B2F;Delay_1ms(100);}}TDR02=0X0C3F;Delay_1ms(200);for(n=0;n<760;n++) //landed{TDR02=0X0BAF;Delay_1ms(3);}TDR01=0X0BAF; //LockTDR02=0X0BAF;TDR03=0X07D5;TDR04=0X07D5;Delay_1ms(5000);P5.1=0;Delay_1ms(2000);P5.1=1;R_TAU0_Channel0_Stop();}void modle2(void){R_TAU0_Channel0_Start();TDR01=0X0BAF; // UnlockTDR02=0X0BAF;TDR03=0X07D5;TDR04=0X0FAA;Delay_1ms(5000);TDR01=0X0BBF; // FlyTDR02=0X0BAF;TDR04=0X0BAF;for(n=0;n<760;n++){TDR03+=0X0001;Delay_1ms(2);}TDR02=0X0B9F;TDR01=0X0C4F; // right flyDelay_1ms(1500);TDR01=0X0A92;Delay_1ms(400);TDR01=0X0B6C;for(m=0;m<18;m++) // advanc fly{if(P1.4==0){for(n=0;n<3;n++){Delay_1ms(4);}TDR02=0X0B2F;Delay_1ms(200);}else{TDR02=0X0B2F;Delay_1ms(200);}}TDR02=0X0CFF;Delay_1ms(400);TDR02=0X0C28; //lift flyTDR01=0X0B29;Delay_1ms(2000);TDR01=0X0CEF;Delay_1ms(300);TDR01=0X0B4F;for(m=0;m<18;m++) // retreat fly {if(P1.4==0){for(n=0;n<3;n++){TDR03+=0X0001;Delay_1ms(4);}TDR02=0X0BFF;Delay_1ms(200);}else{TDR02=0X0BFF;Delay_1ms(200);}}TDR02=0X0A9F;Delay_1ms(500);for(n=0;n<700;n++) //landed{TDR01=0X0BAF;TDR02=0X0BAF;Delay_1ms(3);}TDR01=0X0BAF; //LockTDR02=0X0BAF;TDR03=0X07D5;TDR04=0X07D5;Delay_1ms(5000);R_TAU0_Channel0_Stop();}/****************************************************************************** void modle3(void){************************************************************************* }******************************************************************************//****************************************************************************** void modle4(void){************************************************************************* }******************************************************************************/void modle5(void){R_TAU0_Channel0_Start();TDR01=0X0BBF; // UnlockTDR02=0X0BAF;TDR03=0X07D5;TDR04=0X0FAA;Delay_1ms(5000);TDR01=0X0BBE; // FlyTDR02=0X0BAF;TDR04=0X0BAF;for(n=0;n<780;n++){TDR03+=0X0001;Delay_1ms(3);}TDR04=0X0E8F; //XUANTINGDelay_1ms(5000);for(n=0;n<770;n++) //landed{TDR02=0X0BAF;TDR03-= 0X0001;Delay_1ms(7);}TDR01=0X0BAF; //LockTDR02=0X0BAF;TDR03=0X07D5;TDR04=0X07D5;Delay_1ms(5000);R_TAU0_Channel0_Stop();}void Delay_1ms(unsigned int K)//{unsigned char i,j;for(;K>0;K--){for(j=14; j>0; j--)for(i=250; i>0; i--);for(i=4; i>0; i--);}}/* End user code. Do not edit comment generated here */。