一文读懂舵机工作原理并运用(附代码)
杂谈
自己拿到这一模块是也挺迷茫的,后来看了一些资料,也渐渐积累了些自己的理解,很多博文并没有将舵机讲明白,至少你待把PWM与角度如何换算讲清楚吧,所以笔者写这篇博文供大家学习掌握。
如果你拿到一个舵机,该咋办?莫慌,往下看
第一步先要区分这个舵机是数字舵机还是模拟舵机。
以为两者的控制方式有些许不同,模拟舵机需要给它不停的发送PWM信号,才能让它保持在规定的位置或者让它按照某个速度转动,数字舵机则只需要发送一次PWM信号就能保持在规定的某个位置。
换句话说,模拟舵机想要它转到某一位置,程序上就要放在while等循环中,数字舵机只要给一次PWM值就能以一定速度转到某一位置。
第二步是看清自己的需要
大多数舵机都是180度的舵机,顾名思义就是旋转的范围就是0-180度,这类舵机是控制舵机转到某一角度的。
而有的舵机是360度的舵机,这类舵机则是而一个PWM信号,舵机会以一个特定的速度转动,类似与电机。但与电机不同的是,360舵机是闭环控制,速度控制稳定。
第三步是了解舵机的内部结构
舵机内部长啥样?不如自己拆一个来的直接。
主要是有一个电机、角度传感器,驱动电路、传动齿轮组成,四者形成一个闭环系统,实现角度(或者称作位置)的精准控制(见下图)。这些有些了解就好,不必深究。
第四步是弄清舵机的工作原理
这一步很是关键!!!
首先舵机是用PWM波来驱动的,有PWM信号大哥的地方,就有周期和占空比两个小弟跟着。
接下来以数字舵机为例,毕竟用的最多。
舵机的控制原理就是向控制端(就是信号线,一般是黄色或者白色)输入一个PWM值,舵机就会转到某一个角度,所以,给定的PWM值与角度是对应关系。
那么,如何确定这个关系就是关键所在!
既然是输出一路PWM波,那么就需要先确定PWM的频率(一般为50HZ),进而就确定了PWM的输出周期(一般为20ms)。对于这点不清楚的可以见我以前的博文。PWM相关要点
一般舵机都会给出下面几个参数:
高电平0.5-2.5ms对应0-180度。(2.5%<占空比<12.5%)
也就是这张图
如何确定呢?来个公式
设高电平时间为t,那对应的角度angle=(t-0.5)*180/(2.5-0.5),(0.5<=t<=2.5)。这应该很好理解了。
举例如下:高电平t=0.5ms,带入公式,angle=0度。
第五步掌握PWM输出舵机的定时器配置
假如使用的系统主频为72M,得到50HZ的PWM,则有下面一个公式
50=72000 000/(arr+1)/(psc+1)
设arr=9999,则psc=143,写程序时输出比较配置好这两个参数,从而确定计时器计一个数时间为0.002ms,0.002*(arr+1)=20ms,刚好是PWM波的周期。
接下来要确定舵机转动角度与PWM值之间的关系。
一般我们直接使用TIM_SetCompare1(TIM1,PWM);这个函数修改输出的PWM值,也就是直接写值到CCR寄存器。
根据上图公式,我们就确定了PWM值的范围[250,1250]对应舵机[0,180]。
第六步编写驱动程序
void TIM2_PWM_Init(u16 arr, u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure; //定义一个引脚初始化的结构体
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue; //定义一个定时中断的结构体
TIM_OCInitTypeDef TIM_OCInitTypeStrue; //定义一个PWM输出的结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能GPIOA时钟,在STM32中使用IO口前都要使能对应时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能通用定时器2时钟,A0引脚对应TIM2CHN1
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;//引脚0
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //复用推挽输出模式,定时器功能为A0引脚复用功能
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; //定义该引脚输出速度为50MHZ
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化引脚GPIOA0
TIM_TimeBaseInitStrue.TIM_Period=arr; //计数模式为向上计数时,定时器从0开始计数,计数超过到arr时触发定时中断服务函数
TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //预分频系数,决定每一个计数的时长
TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //计数模式:向上计数
TIM_TimeBaseInitStrue.TIM_ClockDivision=0; //一般不使用,默认TIM_CKD_DIV1
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStrue); //根据TIM_TimeBaseInitStrue的参数初始化定时器TIM2
TIM_OCInitTypeStrue.TIM_OCMode=TIM_OCMode_PWM1; //PWM模式1,当定时器计数小于TIM_Pulse时,定时器对应IO输出有效电平
TIM_OCInitTypeStrue.TIM_OCPolarity=TIM_OCNPolarity_High; //输出有效电平为高电平
TIM_OCInitTypeStrue.TIM_OutputState=TIM_OutputState_Enable; //使能PWM输出
TIM_OCInitTypeStrue.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OC1Init(TIM2, &TIM_OCInitTypeStrue); //根TIM_OCInitTypeStrue参数初始化定时器2通道1
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Disable); //CH1预装载使能
TIM_ARRPreloadConfig(TIM2, ENABLE); //CH1预装载使能
TIM_Cmd(TIM2, ENABLE); //使能定时器TIM2
}
//main文件调用方式
int main(void)
{
delay_init();
TIM2_PWM_Init(9999, 143); //TIM2_Int_Init(u16 arr, u16 psc),初始化定时器TIM2
u16 PWM=750;
u8 Direction=1;
while(1)
{
delay_ms(100);
if(Direction)PWM=PWM+50;
else PWM=PWM-50;
if (PWM>1250) Direction=0; //PWM值1250代表舵机位置接近180度
if (PWM<250) Direction=1; //PWM值250代表舵机位置接近0度
TIM_SetCompare1(TIM2, PWM); //设置待装入捕获比较寄存器的脉冲值,相当于不断设置TIM_Pulse
}
}
到此,舵机基本的控制方式就应该掌握了。
注意事项:舵机可别直接接在32等核心板上,容易烧,需要外部供电,只要把信号线接到对应PWM输出引脚上就可以。
有帮助的不妨点个赞,哈哈。
更多推荐
所有评论(0)