1.为什么要电机测速
电机应用在很多的控制领域,控制领域多数是控制精度高的闭环控制,比如应用广泛的PID,在闭环系统内中电机是作为执行器,要实现闭环控制的话,需要我们的系统有反馈回路,反馈回路中需要有测量元件,来实现电机的闭环控制,所以编码器作为一种测量元件,广泛的应用于电机的速度测量,实现电机的闭环控制。
2.编码器是什么呢?
编码器encoder,将信号(比特流)或数据进行编制,转换为可以通讯、传输和存储的信号形式的设备,可以将角位移(码盘实现)或者直线位移(码尺)转化为电信号。编码器的类型有很多种,例如根据检测原理,可分为光学式、磁式、感应式和电容式。根据内部机械结构的运动方式,可分为线性编码器和旋转编码器。根据其刻度实现方法及信号输出形式,又可分为增量式、绝对式以及混合式三种。对于这些编码器的相关原理和区别网上有很多介绍,在这就不多说了,本文主要针对于霍尔编码器的原理及测速实现进行讲解(个人的总结吧,有不对的地方多多指教)。
3.霍尔编码器
在学习如何实现编码器测速之前,先了解以下概念:
减速比:一般直流电机会带减速箱,因为P=FV,我们希望输出大的扭矩的话,就需要减速,如果减速比是1:30,那么这就意味着我们电机外的转轴(连接负载那一端)转一圈,电机内的转子转了30圈。
编码器的线数:我们以上面那个示意图为例子我们电机内转子旋转一圈,那么霍尔元件就会输出多少个脉冲,这个脉冲的个数(一般来说是一个上升沿和下降沿),在上图自动编码器的减速电机是增量式的11线。
带霍尔编码器的直流电机,转到一周,在减速比为1:30,线数为11的情况下,A B两相分别输出数目相同的1*30*11的脉冲数,我们可以根据一定时间内脉冲数计算出电机的瞬时速度,在这我觉得可以这样逻辑,在一定时间内的脉冲数就是电机的位移。
4.测速原理
我们的编码器可以输出脉冲,那么如何来测速呢?
1.我们可以通过多少钱的输入捕获或者使用GPIO的外部中断来检测脉冲信号的边沿变化,实现对脉冲的计数,但是这样一方面会有毛刺的影响,另一方面我们会比较频繁的进入中断,但是进入中断后只是简单的计数是比较浪费软件资源的。
2.由于测速的需求,以STM32为例子,高级定时器的TIM1 TIM8和通用定时器的TIM2到TIM5有输入捕获的编码器接口功能。可以对脉冲计数,并且带滤波功能。如图是正反转的时候,A B两相的脉冲信号。这个时候的定时器就当做计数器的功能,输入的时钟就是这A B两相的脉冲,当然可以选择三种模式,模式的配置在STM32中是 TIM_EncoderInterfaceConfig(TIM3,TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);这个东西,当我们选择TIM_EncoderMode_TI1时候即A B两项都计数。
脉冲信号的两项先后关系是表示旋转方向,脉冲的个数表示转过的角度,在这里简单的说一下为什么要用正交信号,这个就可以类比于我们人走路一样,前脚后脚前进,后脚前脚后退,表示方向,如上图,A B两相的电平是交替的跳变的,如果一相的电平在没有发送变化的情况下。另一相的电平发生了反复的电平变化就是出现了噪声,也就是一只腿不动,另一只推前后踢肯定是不正常的,另外A B相的信号我们都可以对其计次,使得分辨率更高。结合下图是讲到编码器的时候都会出现的一张图。
我们选择在TI1、TI2都计数的情况,当TI1FP1出现上升沿,对应的TI2电平为高,即对应我们表格的反转A相上升沿,B相高电平,此事应该是向下计数。正转的时候计数器向上计数,反转的时候计数器向下计数。
5.编程设计
我们在定时器的程序设计中,经常会有ARR自动重装、PSC预分屏器,在编码器模式下,ARR的值就是脉冲计数的最大量程,由于编码器模式下的时钟是外部的脉冲,如果我们的预分频系数是二的情况下,电机一圈产生100脉冲,但是只可以记录到50个。
在程序设计中第一需要一个定时器进行时间的定时,第二就是需要另一个定时器的编码器模式实现脉冲的计数。
我们怎么来计算转速呢?是通过一段时间内产生的脉冲数,来除以一圈内的脉冲数,这样得到的就是在一段时间内的圈数,再把这个圈数除以这段时间,不就得到了转速了吗。
以下是结合一些大佬的程序和文章的总结:
通过一个定时器TIM5实现0.05秒的定时,该定时器的中断服务函数就是来读取另一个定时器TIM3在这一段时间内产生的脉冲个数。
在TIM3定时器中,我们配置它为编码器模式,定义count得到的脉冲数 current-count在每次0.05秒时CNT里面的值。
u32 Read_Encoder(void)
{
u32 Count; //一段时间内的脉冲个数
u16 Current_Count; //在0.05秒时的CNT值
u16 Enc_Timer_Overflow_one; //定时器溢出值
Enc_Timer_Overflow_one=Encoder_Timer_Overflow;
Current_Count = TIM_GetCounter(TIM3);
Encoder_Timer_Overflow=0; //清0方便下次计算
Count = (u32)(Current_Count - Previous_Count + (Enc_Timer_Overflow_one) * (4*ENCODER_PPR)); //我们选用四倍频ARR的值就是
Previous_Count = Current_Count;
return(Count);
}
那么一段时间内产生的脉冲数我们放到TIM5的中断服务函数中。
在0.05秒内,产生的脉冲数目为:A=次数*ARR+(当前的CNT值-上一次的CNT值)
电机转动一圈的产生的脉冲数:B=(线数*4)/PSC.
那么在一段时间内转过的圈数为:A/B
转速为每秒内转过的圈数:A/B/time
void TIM5_IRQHandler(void)
{
if(TIM_GetITStatus(TIM5,TIM_IT_Update)==SET)
{
encode=Read_Encoder(); //脉冲个数
printf("编码器脉冲个数%d\r\n",encode);
speed=encode/390.0f/4.0f/0.05f;
printf("转速%f\r\n",speed);
}
TIM_ClearITPendingBit(TIM5,TIM_IT_Update);
}
但是在实际的工程中,我们是需要对正转、反转都需要检测的,可以通过TIM的控制寄存器的第四位来判断
计算正反转中一共产生的脉冲数目,利用设置标志位来识别正反转。
u32 Read_Encoder(void)
{
u32 Count;
u16 Current_Count;
u16 Enc_Timer_Overflow_one;
Enc_Timer_Overflow_one=Encoder_Timer_Overflow;
Current_Count = TIM_GetCounter(TIM3);
Encoder_Timer_Overflow=0;
if((TIM3->CR1&0x0010) == 0x0010)
{
flag=1; //Reversal flag
Count = (u32)((Enc_Timer_Overflow_one)*(4*ENCODER_PPR) +(Previous_Count-Current_Count));
}
else
{
flag =0; //Forward sign
Count = (u32)(Current_Count - Previous_Count + (Enc_Timer_Overflow_one) * (4*ENCODER_PPR));
}
Previous_Count = Current_Count;
return(Count);
}