先分享几个小四轴无人机项目
新唐M452飞控开源项目,虽然完全开源但是还不够成熟,PID调节感觉还有些问题
助你轻松DIY四轴飞行器——新唐M452飞控套件评测 - 电路城
MWC 飞控,采用arduino编程,方案比较成熟,对创客教育很友好,以后做scratch也方便,但是成本比较高
MWC(1) Multiwii 飞控程序初学者概要_明年暑假升初中的博客-CSDN博客_mwc飞控
Crazepony 采用STM32成本比较低,方案也比较成熟,下面的方案基本上是基于Crazepony修改的
Crazepony四轴飞行器
此项目定位是低成本,只作为玩具或课堂教学使用,下面是正题
主控和Crazepony相同,STM32程序大框架可以直接使用;
去掉了电子罗盘,电子罗盘作用主要体现在yaw角,实测温漂一分钟也只有几度,在可接受范围;
RF使用国产芯片,仅需一块多,性能相比NRF24L01并不差;
去掉CP2102,作为玩具是不需要的,如果作为学习可以考虑留串口接口,使用CH340做电平转换,留下的串口接口也方便以后外置蓝牙、WiFi等模块;
STM32的最小系统一般包括:复位电路,外部时钟电路,启动模式选择电路,电源退偶电路等
复位
查阅意法半导的官方手册可以知道,STM32系列单片机都是低电平复位。于是采用如图的主流复位电路作为主控的复位电路。
外部时钟
外部时钟我们采用的是8M无源晶振。单片机内部做倍频,系统时钟最高可达到72M。
启动模式
STM32的启动模式分为三种,可以下面的表格给出:
电源退偶
不仅是主控最小系统需要对电源退偶,所有的数字电路和模拟电路共存的系统,都需要对电源退偶。电源退偶,说直接一点就是将电源上的噪声电压引入到地平面,让电源电压保持在一个稳定的值,这样系统才可能稳定工作。怎么做呢?用一个大电容并联一个小电容。
我们都知道,电容对频率越高的信号,呈现低阻特性,对直流呈现高阻特性。那么电源上的噪声对地平面而言,就是一个交流信号,交流信号就能通过电容到达地平面,而电源是一个直流,电容对他呈现出无限大的阻力,无法通过。这样,我们用示波器就可以看到,加了退偶电容的电源会比没加退偶电容的电源,波形要稳定得多。
市面上所有的航模动力电池,都是3.7V的标称值,比此电压高的电池,都是几个3.7V的电池串联起来的。
没错,电源就只有一个稳压,没有升压,充电有外置充电线,成本和重量进一步减少,但是稳压到3.3V是不行的,关键就是稳压到2.8V,往下往上都有可能造成不稳定,这样即使四个空心杯转起来也不会造成死机。
采用的是最常用的MPU6050陀螺仪加速度计一体芯片,对小四轴来说,它的精度和性能绰绰有余了,气压计FBM320用于定高,实际可以不使用。
每个场效应管接一个大电阻下拉,目的是为了防止在单片机没接手电机的控制权时,电机由于PWM信号不稳定开始猛转。接一个下拉电阻,保证了场管输入信号要么是高,要么是低,没有不确定的第三种状态。那么电机也只有两种状态,要么转,要么不转。主控输出的是PWM波形,用于控制场效应管的关闭和导通,从而控制电机的转动速度。
相比Crazepony的NRF24L01,XN297价格低很多
作为小孩子使用的无人机,LED当然少不了,除了一个电源指示灯,还有四个灯分别代表四个马达,甚至可以在飞行中做个流水灯效果 。
项目的遥控器使用的是JJ的一款遥控器,价格不到十块钱,但是通讯协议未知,拿到样品之后,用逻辑分析仪解析通讯协议,具体方法《一个无线遥控通讯协议破解实例》,拿下了这个遥控器。
遥控器的RF芯片是SPI通讯,当时做的时候截了两张图
取出通讯协议如下,连同配置方式也一起取出来
20 0C //使能CRC
21 00 //信号设置 增强型
22 01 // Enable Pipe0
23 03 // address witdth is 5 bytes
24 00 //信号设置 增强型
25 00 //初始化时的频率通道DEFAULT_CHANNEL
26 3F //发射功率 通信速率
28 00 //传输状态寄存器
29 00 //数据读取寄存器
31 0F //数据宽度PAYLOAD_WIDTH
3C 00 //DYNPD配置
3D 20 //FEATURE配置 byte模式
50 73
39 01 //载波通讯设置Dem_cal_data
3A 45 21 EF 2C 5A 50 //载波通讯设置RF_cal2_data
3B 0B DF 02 //载波通讯设置Dem_cal2_data
3E F6 37 5D //载波通讯设置RF_cal_data
3F 0A 6D 67 9C 46 //载波通讯设置BB_cal_data
2A 00 00 00 00 00 //ID设置TX_ADDRESS_DEF
30 00 00 00 00 00 //ID设置TX_ADDRESS_DEF
FD 0020 8C //不使能IC,设置为发送端
27 70 //置位状态
E1 00 // CLEAR TXFIFO
20 8E //设置为发送端
A0 A4 72 53 41 0B 11 3C 49 1B 31 86 BB C9 AE 4F //数据发送07 FF //置位状态
27 FF //置位状态
E1 00 // CLEAR TXFIFO07 2E //置位状态
27 2E //置位状态
E1 00 // CLEAR TXFIFO
A0 A4 72 53 41 0B 11 3C 49 1B 31 86 BB C9 AE 00
|包头| | ID地址 | | 通道 | |
A0 00 72 53 41 0B 11 3C 49 1B 31 86 BB C9 AE 0030 72 53 41 0B 11 //ID设置TX_ADDRESS_DEF
07 2E //置位状态
27 2E //置位状态
25 3C //使用的频率通道DEFAULT_CHANNEL
E1 00 // CLEAR TXFIFO
A0 A5 F7 00 00 7E 03 7D FA 7C 0E 7E 0D C9 AE 20
\A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0D C9 AE 1607 2E //置位状态
27 2E //置位状态
25 49 //使用的频率通道DEFAULT_CHANNEL
E1 00 // CLEAR TXFIFO
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0D C9 AE 1607 2E //置位状态
27 2E //置位状态
25 1B //使用的频率通道DEFAULT_CHANNEL
E1 00 // CLEAR TXFIFO
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0D C9 AE 1607 2E //置位状态
27 2E //置位状态
25 31 //使用的频率通道DEFAULT_CHANNEL
E1 00 // CLEAR TXFIFO
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0D C9 AE 16A0 A5 F7 00 00 7E 03 7D FA 7C 03 7E 0D C9 AE 15
A0 A5 F7 00 00 7E 03 7D FA 7C 03 7E 08 C9 AE 10
A0 A5 F7 00 00 7E 03 7D FA 7C 03 7E 0B C9 AE 13
A0 A5 F7 00 00 7E 03 7D FA 7C 03 7E 0C C9 AE 14
A0 A5 F7 00 00 7E 03 7D FA 7C 10 7E 0E C9 AE 23
A0 A5 F7 00 00 7E 03 7D FA 7C 0A 7E 0E C9 AE 1D
A0 A5 F7 00 00 7E 03 7D FA 7C 07 7E 0E C9 AE 1A
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0D C9 AE 16A0 A5 F7 00 00 7E 03 7D FA 7F FC 7E 0D C9 AE 11 //油门 31744->7C00 +1023 2^15=32767->7FFF
 ̄ ̄ ̄
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7F FE C9 AE 08
A0 A5 F7 00 00 7E 03 7D FA 7C 03 7C 00 C9 AE 06 //油门左右31744->7C00 +512 32256->7E00 +1023 32767->7FFF
 ̄ ̄ ̄
A0 A5 F7 00 00 7C 00 7D F9 7C 03 7E 0E C9 AE 10
A0 A5 F7 00 00 7F FE 7D F9 7C 03 7E 0E C9 AE 11 //方向左右 31744->7C00 +512 32256->7E00 +1023 32767->7FFF
 ̄ ̄ ̄
A0 A5 F7 00 00 7E 03 7F FC 7C 04 7E 0E C9 AE 1B
A0 A5 F7 00 00 7E 03 7C 00 7C 04 7E 0E C9 AE 1C //方向上下 31744->7C00 +512 32256->7E00 +1023 32767->7FFF
 ̄ ̄ ̄
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0E C9 AE 17
A0 A5 F7 00 00 7E 38 7F FC 7C 04 7E 0E C9 AE 50 //方向按键
 ̄
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0E C9 AE 17
A0 A5 F7 01 00 7E 03 7D FA 7C 04 7E 0D C9 AE 17 //油门按键
 ̄
以下按键非点动
//A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0E C9 AE 17
A0 A5 FA 00 00 7E 03 7D FA 7C 04 7E 0E C9 AE 1A //k1 灵敏度
//A0 A5 FA 00 00 7E 03 7D FA 7C 03 7E 0E C9 AE 19
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0E C9 AE 17 //k2 灵敏度
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0E C9 AE 17
A0 A5 F7 00 00 7E 03 91 FA 7C 04 7E 0E C9 AE 2B //k3 前
 ̄ ̄ ̄  ̄
A0 A5 F7 00 00 7E 03 7D FA 7C 04 7E 0E C9 AE 17
A0 A5 F7 00 00 7E 03 69 FA 7C 04 7E 0E C9 AE 03 //k4 后
 ̄ ̄ ̄  ̄
A0 A5 FA 00 00 7E 03 7D FA 7C 04 7E 0E C9 AE 1A
A0 A5 FA 00 00 66 03 7D FA 7C 03 7E 0E C9 AE 01 //k5 左
 ̄ ̄ ̄  ̄
A0 A5 F7 00 00 AE 03 7D FA 7C 03 7E 0E C9 AE 46
A0 A5 F7 00 00 CA 03 7D FA 7C 04 7E 0E C9 AE 63 //k6 右
遥控器在配对上采用先ID 0广播,再发送遥控器ID进行配对,在后面编写的时候也使用相同方式。
软件流程如下图所示:
主控使用的是STM32芯片,没有上实时操作系统,依靠中断嵌套来完成整体功能。程序核心就是通过定时器,在主循环中通过不断查询判断各个条件,这样就产生了几个大小不一样的时间段,我们根据需要就可以完成以多大的频率扫描一次遥控器指令、多久更新一次传感器数据、多久更新一次控制等等飞控需要实现的功能,尽可能的利用主控的资源。
进入主函数之后就是STM32处理器及各个部分的初始化。
接下来就是进入主循环while(1)
之中了,主循环也就是整个程序功能实现的关键,程序进入这里面就循环在里面运行了,当然中断会打断去运行中断服务程序运行完之后再回到这里运行。
主循环体中首先有if(loop100HzCnt >= 10){}
这个结构,其中loop100HzCnt这个变量是在TIM4中断服务程序中累加的,1ms累加一次,也就是说定时每10ms就去完成一次其中的工作。
那么100Hz需要做一次的工作是什么呢?读取mpu6050数据,气压计数据并进行整合。因为采用软解姿态,读取的数据为加速度计和陀螺仪的AD值,将数据进行标定、滤波、校正后通过四元素融合得到三轴欧拉角度。如下图。
加速度传感器采集数据容易失真,造成姿态解算出来的欧拉角错误,只用角度单环情况下,使系统很难稳定运行,因此可以加入角速度作为内环,角速度由陀螺仪采集数据输出,采集值一般不存在受外界影响情况,抗干扰能力强,并且角速度变化灵敏,当受外界干扰时回复迅速增强了系统的鲁棒性。
采用双闭环PID控制,如下图所示。
角度作为外环,角速度作为内环,进行姿态双环PID控制。角度环的输出值作为角速度环的输入建立自稳系统。
在if(loop50HzFlag){}
进入50Hz(20ms执行一次)循环。loop50HzFlag
标志位是在TIM4中断中每20ms置位一次的,这里解析了收到的遥控器无线发送过来的指令,结合当前的姿态计算更新这些控数据给核心控制算法输出控制飞控,我们就可以控制飞控前进后退,上升下降等等操作了。如下图。
同样的思路if(loop10HzFlag){}
也就是以10Hz的频率去执行下面功能。在这里可以通过蓝牙向我们的手机APP传送一些飞控的姿态信息,然后查询飞控的电量没有足够的话就让飞控降落下来,查询高度啊超出可控范围也把飞控降下来,查询是否和遥控器失联啊,失联就降下飞控等等安全飞行的控制。如下图
最后就是if(pcCmdFlag)这个了,这是一个与上位机调试有关的东西,主循环查询这个标志位,标志位是由上位机发送过来的指令置位的,它主要是处理pc机发送过来的指令,PID参数读取,修改等等。
RF接收由ucRF_DumpRxData函数处理,在100Hz循环中
其他的也继承了crazepony的起飞降落粘滞性、油门曲线。
定高资料可参考crazepony,原程序已实现定高可以直接使用。
姿态算法也保留crazepony的算法,上位机也可以直接使用。
程序有了接下来就是调PID,所谓的PID。P是比例系数。说通俗点就是知道误差后用怎样的程度去减小误差。此值越大系统误差越小。 I 是积分时间。是对误差的累加时间。此值越小。累加越快,积分作用越大。系统误差越小。 D 是微分时间。是提高系统的响应。用来稳定系统的。可以放在反馈和误差的通道里。这样3种同时作用。就可以实现闭环反馈控制。消除误差。
具体方法是:先整定内环PID,再整定外环P。
内环P:从小到大,拉动四轴越来越困难,越来越感觉到四轴在抵抗你的拉动;到比较大的数值时,四轴自己会高频震动,肉眼可见,此时拉扯它,它会快速的振荡几下,过几秒钟后稳定;继续增大,不用加人为干扰,自己发散翻机。
特别注意:只有内环P的时候,四轴会缓慢的往一个方向下掉,这属于正常现象。这就是系统角速度静差。
内环I:前述PID原理可以看出,积分只是用来消除静差,因此积分项系数个人觉得没必要弄的很大,因为这样做会降低系统稳定性。从小到大,四轴会定在一个位置不动,不再往下掉;继续增加I的值,四轴会不稳定,拉扯一下会自己发散。
特别注意:增加I的值,四轴的定角度能力很强,拉动他比较困难,似乎像是在钉钉子一样,但是一旦有强干扰,它就会发散。这是由于积分项太大,拉动一下积分速度快,给 的补偿非常大,因此很难拉动,给人一种很稳定的错觉。
内环D:这里的微分项D为标准的PID原理下的微分项,即本次误差-上次误差。在角速度环中的微分就是角加速度,原本四轴的震动就比较强烈,引起陀螺的值变化较大,此时做微分就更容易引入噪声。因此一般在这里可以适当做一些滑动滤波或者IIR滤波。从小到大,飞机的性能没有多大改变,只是回中的时候更加平稳;继续增加D的值,可以肉眼看到四轴在平衡位置高频震动(或者听到电机发出滋滋的声音)。前述已经说明D项属于辅助性项,因此如果机架的震动较大,D项可以忽略不加。
外环P:当内环PID全部整定完成后,飞机已经可以稳定在某一位置而不动了。此时内环P,从小到大,可以明显看到飞机从倾斜位置慢慢回中,用手拉扯它然后放手,它会慢速回中,达到平衡位置;继续增大P的值,用遥控器给不同的角度给定,可以看到飞机跟踪的速度和响应越来越快;继续增加P的值,飞机变得十分敏感,机动性能越来越强,有发散的趋势。
这部分可以参考《四轴PID讲解_recode123的博客-CSDN博客》
还有文章
玩无人机必备!PID调节经验_eagle11235的博客-CSDN博客_无人机pid控制
X型小四轴双闭环PID调节_dmffrank的博客-CSDN博客
以及crazepony的调试方法
飞行器平衡调试 | Crazepony开源四轴飞行器
但是调试方法其实不固定,合适的PID也不只有一组,只要最后能稳定就是最好的。
虽然硬件低成本,但是软件很丰富,定位教学的话scratch必不可少,crazepony的基础上,增加了使用串口的方式与scratch通讯部分,与市场上无线通讯不同,可以不使用遥控器直接电脑控制无人机,甚至可以当做开发板来使用,在主程序中PD_CONTROL可以选择使用crazepony上位机或scratch。
软件框架中,添加ProgramData文件,和arduino一样,串口传输程序且不会BootLoader抹掉,但是也不一样,这里的BootLoader是无人机程序,是一个完整的飞控,scratch软件中,可以直接在积木块选择运行scratch还是运行预制的飞控,而运行scratch的时候,飞控的保护仍然处于运行状态,保护无人机和用户。
scratch发送的程序存储在EEPROM中,关机后重启仍然保留,在scratch中,你设置可以规划无人机路线,实现全自动飞行。
最后大概统计一下,硬件成本包括遥控器、电机等全部总价能做到25以内,支持悬停、翻滚、微调、无头模式等,软件支持crazepony上位机或scratch3.0,项目的硬件PCB、STM32程序等已全部完成。
此项目只有我一个人做,难免出现错误,欢迎评论指正,也可以加我QQ一起交流进步,CSDN不能上传无人机项目资源,需要可以加我QQ。