51小四轴制作之飞行姿态与PWM

四轴飞行器飞行的原理就是通过改变四个电机转速改变飞行器当前的飞行状态,而飞行器在空间中具有六个状态:垂直运动、俯仰运动、横滚运动、偏航运动。要实现这些飞行状态就需要对四轴飞行器每个电机的转速进行调整,这里的调整就用到了PWM(脉冲宽度调制)。

  • 飞行姿态

这里参考了这篇博客,讲的很详细
https://blog.csdn.net/qq_25005909/article/details/76512369

由于在飞行时如果螺旋桨同向转动,四轴飞行器会受到转动力矩的作用不利于我们控制飞行器,所以采用了两对相反的螺旋桨并且电机反向转动,这样可以平衡力矩,达到稳定飞行。
也就是图中1和3是正向螺旋桨逆时针运动,2和4是反向螺旋桨顺时针运动。
在这里插入图片描述
1.垂直运动:所有电机同时提高相同的转速将飞行器上升。
2.俯仰运动:控制其中两个电机转速,也就是1的转速提高而3的转速减少,这样飞行器会向x轴方向仰起并且向x轴运动,如果要想后仰起移动只需要1的转速减少3的转速升高即可。
3.横滚运动:和俯仰运动类似,只是改变的是2和4电机,向侧方向翻转并且移动。
4.偏航运动:通过反扭力实现四轴飞行器的旋转,之前通过旋翼的转向的配置抵消了力矩,而现在要实现四轴飞行器方向的偏转需要通过力矩产生一个扭力,也就是需要其中两个同向电机转速减少,另外两个电机转速提高,比如1和3转速增加、2和4转速减少即可发生偏航运动。
5.前后运动
要想实现飞行器在水平面内前后、左右的运动,必须在水平面内对飞行器施加一定的力。在图e中,增加电机3转速,使拉力增大,相应减小电机1转速,使拉力减小,同时保持其它两个电机转速不变,反扭矩仍然要保持平衡。按图b的理论,飞行器首先发生一定程度的倾斜,从而使旋翼拉力产生水平分量,因此可以实现飞行器的前飞运动。向后飞行与向前飞行正好相反。当然在图b图c中,飞行器在产生俯仰、翻滚运动的同时也会产生沿x、y轴的水平运动。
6.侧向运动
在图f中,由于结构对称,所以侧向飞行的工作原理与前后运动完全一样。 总得来说就是控制四个电机的速度了。然后相应的提高速度和减慢速度就可以让四轴动起来了。

  • PWM

PWM波输出模块,首先下手PWM模块是因为这个模块直接控制电机的运转,再配合无线传输就可以简单地控制四轴飞行器,这样就可以在完成硬件后第一时间检测硬件功能是否正常,在最开始将可能故障排查就能使后续地工作更加顺畅。
PWM波是通过控制占空比,即高电平在一个周期内所占的比例,来控制电机的转速的。那我就要做一个函数,输入4个值控制4个电机的转速,而这4个值就是分别控制四个PWM输出口输出占空比的。而要控制占空比也就是要求在一个周期内高电平所占的比例,那就需要计算占空比。虽然理解了占空比,但是计算以及在程序中体现稍显麻烦。

  • PWM的概念及如何控制转速
    PWM即是宽度脉冲调制,是一种微处理器形成数字信号控制模拟电路的技术,具体就是产生一个方波,为什么要用这个PWM来控制转速呢。首先控制转速可以调节电流的大小,但这样不容易由单片机控制,但是可以用另一种方法来达到调速的作用,给电机工作一会停一会,就像我们骑自行车可以用比较小的力气一直地蹬,也可以每隔一会猛踩一会然后让自行车自己滑动,两种方法实际的平均速度都是一样的。所以这个PWM控制电机转速也就是后者,PWM信号传给电子调速器,而这个信号就是一种方波,就是一段高位低位交替的波形,当这个信号传给电调用于控制时,高位被称为高电平,低位被称为低电平,当处在高电平时电机会转动而低电平时电机不工作,由于间隙很短,这样就控制了电机的转速。所以这里引入了一个概念叫做“占空比”,就是指在一个脉冲循环内,通电时间相对于总时间所占的比例,通过调节这个占空比就能调节转速,这就是单片机控制电机转速的方式。
    在这里插入图片描述

  • PWM占空比计算
    8位的PWM的话,每个周期里要分为256个小脉冲,占空比就是这256个脉冲里的高电平占这个整个256个电平的比例
    8位PWM的周期 = 计数脉冲周期×256
    8位PWM的频率 = 计数脉冲频率/256
    8位PWM的脉宽时间(高电平时间)= 计数脉冲周期×(256-CCAPnL)
    8位PWM的占空比 = 脉宽时间/PWM周期 = (1- CCAPnL/256) ×100%
    单片机中计数器和定时器采用的是脉冲计数,脉冲就是低电平转变为高电平的这个过程,也就是上升沿,而计时器是记录机器内部的脉冲个数再换算成时间,对于51单片机来说一个计数脉冲周期就是1us,也就是一个机器周期。8位PWM的周期就是计时器记录256次脉冲的时间,占空比就是在这个周期内记录的脉冲个数除以总的脉冲数256。

  • PWM在单片机程序中的体现
    在STC15W4K32S4中PWM输出模块自带两个内部15位计时器,T1、T2,这两个个计时器也就是定时器,可以通过编程设定时间实现定时。

    而在程序中PWM占空比的控制即是通过调整波形翻转的间隔达到的,这个时间间隔就由这两个定时器来控制,T1控制低电平翻转成高电平的时间节点,T2控制高电平翻转成低电平的时间节点。

    总的流程:系统内部时钟计时,然后两个定时器定时,当内部时钟的值与T1设定的值相等时,由低电平翻转成高电平,接下来持续输出高电平波形;当内部时钟的值达到T2设定的值时,由高电平翻转成低电平。当内部时钟计完一个周期后再将内部时钟重置继续输出这个波形。

    作用:通过设定翻转的时间节点调整波形处于高电平的时间,也就是控制了一个周期内的脉冲宽度,也就是控制了占空比。所以叫做脉冲宽度调制PWM。

  • 相应代码分析
    PWM模块主要分为两个函数,一个是PWM模块的初始化,基本上是搬过来的,所有的寄存器设置方式在数据手册上都有,这里比较关键的操作是设置每个PWM输出口内部时钟T1和T2的定时时间。在初始化时定义好T2的数值,这个T2定时的长度就相当于一个周期的长短。像是这里定义的是1001,一个周期就相当于1ms。
    另一个则是改变4个PWM输出口输出的PWM波形,改变T1的定时时间,就相应地改变了高电平的时间也就是脉冲的宽度。
    联系公式,不难看出,T2-T1的时间即是高电平的时间,而一个周期即为1ms,占空比就是(T2-T1)/T2。

void PWM_INIT()
{
	int i=1;
	//所有I/O口全设为准双向,弱上拉模式
	P0M0=0x00;
	P0M1=0x00;
	P1M0=0x00;
	P1M1=0x00;
	P2M0=0x00;
	P2M1=0x00;
	P3M0=0x00;
	P3M1=0x00;
	P4M0=0x00;
	P4M1=0x00;
	P5M0=0x00;
	P5M1=0x00;
	P6M0=0x00;
	P6M1=0x00;
	P7M0=0x00;
	P7M1=0x00;
	/*设置需要使用的PWM输出口为强推挽模式
	用到的PWM包含的端口都在为P2和P3所以
	只需要将这两个端口设置即可
	*/
	P2M0=0x0e;
	P2M1=0x00;
	P3M0=0x80;
	P3M1=0x00;
	
    //PWM控制寄存器
	P_SW2=0x80;    //最高位置1才能访问和PWM相关的特殊寄存器

	//PWM配置寄存器
  PWMCFG=0xb0;    //7位    6位                5位    4位    3位    2位    1位    0位
	                //置0  1-计数器归零触发ADC C7INI  C6INI  C5INI  C4INI  C3INI  C2INI
	                //     0-归零时不触发ADC       (值为1时上电高电平,为0低电平)
    //PWM时钟选择寄存器
	PWMCKS=0x10;    //7位6位5位    4位             3位    2位    1位    0位
	                //   置0    0-系统时钟分频          分频参数设定
	                //          1-定时器2溢出       时钟=系统时钟/([3:0]+1)
    //PWM中断标志寄存器
	PWMIF=0x00;     //7位    6位                5位    4位    3位    2位    1位    0位
                  //置0  计数器归零中断标志            相应PWM端口中断标志
    //PWM外部异常控制寄存器
	PWMFDCR=0x00;   //7位    6位       5位                4位
	                //置0    置0 外部异常检测开关  外部异常时0-无反应 1-高阻状态
	                //3位             2位                 1位                0位
                  //PWM异常中断  比较器与异常的关系   P2.4与异常的关系  PWM异常标志
    //PWM计数器
    PWMCH=0x03;     //15位寄存器,决定PWM周期,数值为1-32767,单位:脉冲时钟
    PWMCL=0xe9;

// 以下为每个PWM输出口单独设置
	PWM2CR=0x00;    //7位6位5位4位   3位      2位       1位        0位
	                //    置0      输出切换 中断开关 T2中断开关 T1中断开关
	PWM3CR=0x00;
	PWM4CR=0x00;
	PWM5CR=0x00;

	PWM2T1H=0x03;          //15位寄存器第一次翻转计数  第一次翻转是指从低电平翻转到高电平的计时
	PWM2T1L=0xe8;
	PWM2T2H=0x03;          //15位寄存器第二次翻转计数  第二次翻转是指从高电平翻转到低电平的计时
	PWM2T2L=0xe9;          //第二次翻转应比精度等级要高,否则会工作不正常,比如精度1000,第二次翻转就必须小于1000
/*
	PWM占空比的控制即是通过调整波形翻转的间隔达到的,这个时间间隔由两个定时器来控制,T1控制低电平翻转成高电平的时间
	节点,T2控制高电平翻转成低电平的时间节点。
	总的流程:系统内部时钟计时,然后两个定时器定时,当内部时钟的值与T1设定的值相等时,由低电平翻转成高电平,接下来持续
	输出高电平波形;当内部时钟的值达到T2设定的值时,由高电平翻转成低电平。当内部时钟计完一个周期后再将内部时钟重置继续
	输出这个波形。
	作用:通过设定翻转的时间节点调整波形处于高电平的时间,也就是控制了一个周期内的脉冲宽度,也就是控制了占空比。所以叫做
	脉冲宽度调制PWM。
*/
	PWM3T1H=0x03;
	PWM3T1L=0xe8;
	PWM3T2H=0x03;
	PWM3T2L=0xe9;

	PWM4T1H=0x03;
  PWM4T1L=0xe8;
	PWM4T2H=0x03;
	PWM4T2L=0xe9;

	PWM5T1H=0x03;
	PWM5T1L=0xe8;
	PWM5T2H=0x03;
	PWM5T2L=0xe9;
//以上为每个PWM输出口单独设置

  PWMCR=0x8f;     //7位          6位                5位 4位 3位 2位 1位 0位     10001111
	                //PWM开关 计数归零中断开关   相应I/O为GPIO模式(0)或PWM模式(1)

}


/*
这个函数是用来给T1定时器设定数值的,由每个定时器具有15位,
因为上面设定的T2值为1001(相当于在T2设定的时间结束),所
以我们的一个周期就是计时器计到1000。
设定了T1的数值,就是设定了开始转变为高电平的时间,T2-T1的
时间即是高电平的宽度。
本函数输入的4个值取值范围为0-1000 1000电机停,0转速最高,
*/
void PWM(int p1,int p2,int p3,int p4)
{
    PWM2T1H = p1 >> 8;
    PWM2T1L = p1;

    PWM3T1H = p2 >> 8;
    PWM3T1L = p2;

    PWM4T1H = p3 >> 8;
    PWM4T1L = p3;

    PWM5T1H = p4 >> 8;
    PWM5T1L = p4;
}```

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
今天本来也没做好起飞的准备,不过感觉老是在屋里调有些东西是观察不到的,因此就冒险去户外飞了一下。果然。。。。。。坠机了,原因是其中一个非自紧螺旋桨的螺丝松了,稍后上图,之前也松过一次,没处理好,这次得到教训了。这一摔就是400块钱没了,维修也得1到2个星期。 目前的功能: 1.开启传感器低通滤波98Hz,滤掉电机震动对加速度计和陀螺仪的影响。 2.磁力计现场校准,代码直接完成,不需要PC干预。换个地方飞不用再带个电脑做校准了。 3.陀螺仪零偏自校准 4.加速度计零偏和灵敏度校准 4.代码时间片管理,姿态融合500Hz,PID控制200Hz 5.位置式PID控制,控制参数采用kp,Ti,Td,从今天飞行状况来看,此功能日后需大力改进 6.固定航向模式。日后加入可控航向。 7.串口在线调试,支持在线参数保存和读取,采用GD32F103内部Flash来保存参数,不用外扩存储芯片,也方便调试PID参数和磁力计校准。 8.飞行模式:x模式 自己设计的飞控板第二版,兼容F10x/F2xx/F4xx系列MCU,正面:外扩4个PWMin外接遥控接收机,4个PWMout外接motor,4个PWM备用,1个DCMI摄像头接口,1个USART1接蓝牙模块,1个SPI可接SPI nand。外接TF卡用于存储视频 整机:两个白色轴中间是机头,右边白色轴上是之前做的蓝牙模块,整机标配:450机架,980kv电机,好盈20A电调,11.1V-3S动力电池,7通道接收机,锂电池低压报警器,桨1047 PID分两种位置式和增量式,我采用的是位置式,将Ki和Kd用Ti和Td的形式来表达,并带入到式2-3中,ek=角度的期望-传感器输出的角度,所用的PID三个参数是:Kp、Ti、Td。 公式如图所示: 四轴PID控制的目的就是将接收到的遥控的控制信号(一般有油门THR、升降舵ELE(对应pitch)、副翼Ail(对应roll)、方向舵RUD(对应yaw))与飞控板本身计算得出pitch、roll、yaw做比较,分别得出它们之间的误差值,然后将Kp、Ti、Td与这个误差值结合得出PID输出(PID_pitch、PID_roll或者PID_yaw),再将这三个PID输出与油门结合在一起算出送到每一个电调的PWM数值,从而控制每一个电机的转动。
以下是一个基于STM32的四轴飞行器向前飞行的简单示例代码。请注意,这只是一个基本的示例,实际的飞行器控制代码需要根据具体的硬件和飞行控制算法进行相应的调整和扩展。 ```C #include "stm32f4xx.h" // 定义电机控制的引脚 #define MOTOR1_PIN GPIO_PIN_0 #define MOTOR1_PORT GPIOA #define MOTOR2_PIN GPIO_PIN_1 #define MOTOR2_PORT GPIOA #define MOTOR3_PIN GPIO_PIN_2 #define MOTOR3_PORT GPIOA #define MOTOR4_PIN GPIO_PIN_3 #define MOTOR4_PORT GPIOA // 定义PWM相关参数 #define PWM_PERIOD 1000 // PWM周期 #define MOTOR_MIN_SPEED 100 // 电机最低速度 #define MOTOR_MAX_SPEED 1000 // 电机最高速度 // 初始化PWM输出 void PWM_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; TIM_HandleTypeDef htim; // 使能GPIO和TIM时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_TIM2_CLK_ENABLE(); // 配置GPIO引脚为复用功能 GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF1_TIM2; GPIO_InitStruct.Pin = MOTOR1_PIN; HAL_GPIO_Init(MOTOR1_PORT, &GPIO_InitStruct); GPIO_InitStruct.Pin = MOTOR2_PIN; HAL_GPIO_Init(MOTOR2_PORT, &GPIO_InitStruct); GPIO_InitStruct.Pin = MOTOR3_PIN; HAL_GPIO_Init(MOTOR3_PORT, &GPIO_InitStruct); GPIO_InitStruct.Pin = MOTOR4_PIN; HAL_GPIO_Init(MOTOR4_PORT, &GPIO_InitStruct); // 配置TIM基本参数 htim.Instance = TIM2; htim.Init.Prescaler = (SystemCoreClock / PWM_PERIOD) - 1; htim.Init.CounterMode = TIM_COUNTERMODE_UP; htim.Init.Period = PWM_PERIOD - 1; htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim); // 配置PWM输出通道 TIM_OC_InitTypeDef sConfigOC; sConfigOC.OCMode = TIM_OCMODE_PWM1; sConfigOC.Pulse = MOTOR_MIN_SPEED; sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC, TIM_CHANNEL_2); HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC, TIM_CHANNEL_3); HAL_TIM_PWM_ConfigChannel(&htim, &sConfigOC, TIM_CHANNEL_4); // 开启PWM输出 HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_2); HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_3); HAL_TIM_PWM_Start(&htim, TIM_CHANNEL_4); } // 控制四轴飞行器向前飞行 void FlyForward(void) { // 增加前进方向电机的速度,减小后退方向电机的速度 __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_1, MOTOR_MAX_SPEED); __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_4, MOTOR_MAX_SPEED); __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_2, MOTOR_MIN_SPEED); __HAL_TIM_SET_COMPARE(&htim, TIM_CHANNEL_3, MOTOR_MIN_SPEED); } int main(void) { // 初始化系统 HAL_Init(); // 初始化PWM输出 PWM_Init(); // 向前飞行 FlyForward(); while (1) { // 在这里可以添加其他飞行控制代码 // ... } } ``` 请注意,这只是一个简单的示例代码,实际的四轴飞行器控制代码需要根据具体的硬件和飞行控制算法进行相应的调整和扩展。同时,飞行器的飞行涉及到安全问题,请确保在适当的环境和条件下进行测试。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值