目录
一、种类介绍
编码器主要分为光电编码器和磁编码器(霍尔编码器)。
1、光电编码器
通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。码盘可以包含AB相,相位差相差90度。
2.霍尔编码器
通过磁电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。电动机旋转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在一定相位差的方波信号。
3.优缺点
优缺点: 光电编码器相对于霍尔编码器来说,多数在恶劣环境下无法使用,而且体积也比较大。此外,光电编码器精度不高,主要是由于码盘(光栅)无法划分的太细。但是,在磁场环境下,光电编码器不受磁场的影响。如果磁场不是很强的话,霍尔编码器可以采用磁屏蔽的方法(顺磁性材料:铁、坡莫合金。抗磁材料:热解石墨)。
二、测速方法
根据脉冲计数来测量转速的方法有以下三种:
(1)在规定时间内测量所产生的脉冲个数来获得被测速度,称为M法测速;
(2)测量相邻两个脉冲的时间来测量速度,称为T法测速;
(3)同时测量检测时间和在此时间内脉冲发生器发出的脉冲个数来测量速度,称为M/T法测速。
1.M法( 高速测量准确)
优点:固定采样周期测量,实现起来简单易行。在高速测量时,有较好的速度平稳性及较高的测量精度。
缺点:在低速时会出现速度波动幅度大,平稳性差,且随着采样频率的提高,所测得的低速范围会变窄,测速精度随之下降等问题。
设脉冲发生器每转一圈发出的脉冲数为P,且在规定的时间Tg(s)内,测得的脉冲数为m1,则电机每分钟转数:nm=60*m1/(P*Ta)(r/min)
技术指标:
a、分辨率:Q=60*(m1+1)/(P*Tg)-60*m1/(P*Tg)=60/(P*Tg)
b、测量精度:在极端情况下会产生正负1个转速脉冲的检测误差,相对误差为1/m1
c、检测时间:T=PQ
2.T法(低速测量准确)
测量相邻两个脉冲的时间间隔来确定被测速度的方法。用一已知频率为f。的高频时钟频率向一计时器发送脉冲数,此计时器由测速脉冲的两个相邻脉冲控制其起始和终止。若计数器的读数为m2,则电机每分钟的转数为nm=60*f./(P*m2)(r/min)
式中:fc--时钟脉冲频率
m2--计数器对时钟脉冲频率f的脉冲计数值技术指标:
a、分辨率:Q=60*fc/(P*m2)-60*fc/((P*(m2+1))=n2..*P/(60*f-+n…*P)。在极端的情况下,时间的检测会产生正负1个高频脉冲周期。因此下法在被测转速
较低时,才有较高的测量精度。
b、测量精度:时钟脉冲m,计数时,总有1个脉冲的误差,由此造成的相对误差为1/mz
c、检测时间:T等于测速脉冲周期,即T=60/(P*nm)
d、时钟脉冲中f,的确定:f.愈高,分辨率愈高,测速精度愈高;但f,过高,又会使m,过大,使计数器字长加长,影响运算速度。确定方法是:根据最低转速nm min和计
算机字长设计出最大计数m2 max。f=nm min*p*m2 max/60
3. M/T法
为了兼顾高速与低速,实际使用中常常是 M 法和 T 法结合使用,称为 M/T 法测速。
M法、T法结合的 M/T 测速法:低速时测周期、高速时测频率。
四、判断正反转
针对具有AB两相的编码器。 只需要看QEP_A和QEP_B。AB具有90度的相位差,通过判断两者上升沿或者下降沿的关系即可。
假设QEP_A触发为高电平,QEP_B为低电平时为正转,反之为反转。
五、代码
编码器返回的数据是一组正交信号,由于Arduino和ESP32都没有正交解码功能,所以要想实现正交解码功能的话就需要用两个io口来同时判断当前是属于状态。
配置对应的io口,一个编码器需要两个io口,一个用来检测外部跳边沿中断,另一个来判断方向。
一个脉冲信号周期完成4次跳变。精度提高
1时刻:TI2为低电平,TI1上升沿跳变,计数器向上计数;
2时刻:TI1为高电平,TI2上升沿跳变,计数器仍然向上计数;
3时刻:TI2为高电平,TI1下降沿跳变,计数器仍然向上计数;
4时刻:TI1为低电平,TI2下降沿跳变,计数器仍然向上计数。
M法测速
#include<Ticker.h>
#define PI 3.1415926
/***************** 定时中断参数 *****************/
Ticker timer1; // 中断函数
int interrupt_time = 10; // 中断时间
int timer_flag=0; //定时器标志;
/***************** 编码器引脚及参数 *****************/
uint8_t R1 = 18, R2=19; // 右轮编码器引脚
uint8_t L1 = 26, L2=25; // 左轮编码器引脚 左右轮区分是以锂电池为底部区分
volatile long Rcounter1=0, Rcounter2=0; // 右轮脉冲计数 该变量用于存储编码器的值,所以用类型修饰符volatile;
volatile long Lcounter1=0, Lcounter2=0; // 左轮脉冲计数 该变量用于存储编码器的值,所以用类型修饰符volatile;
// void right_counter_encoder1(); // 右轮1 计数脉冲数
// void right_counter_encoder2(); // 右轮2 计数脉冲数
// void left_counter_encoder1(); // 左轮1 计数脉冲数
// void left_counter_encoder2(); // 左轮2 计数脉冲数
void setup()
{
Serial.begin(115200);
/***************** 编码器初始化 *****************/
pinMode(L1, INPUT); pinMode(L2, INPUT);
pinMode(R1, INPUT); pinMode(R2, INPUT);
attachInterrupt(R1, right_counter_encoder1, RISING);//设置编码器R1相位上升沿中断
attachInterrupt(R2, right_counter_encoder2, RISING);//设置编码器R2相位上升沿中断
attachInterrupt(L1, left_counter_encoder1, RISING);//设置编码器L1相位上升沿中断
attachInterrupt(L2, left_counter_encoder2, RISING);//设置编码器L2相位上升沿中断
/***************** 定时中断 *****************/
timer1.attach_ms(interrupt_time, timerIsr); // 打开定时器中断
interrupts(); //打开外部中断
}
void loop()
{
if(timer_flag==1)
{ //判断是否发生定时器中断,这里是 interrupt_time ms发生一次
timer_flag=0; //清除标记
}
}
//定时器中断处理函数,其功能主要为了输出编码器得到的数据
void timerIsr(){
timer_flag=1; //定时时间达到标志
readEncoder(); // 编码器
}
//编码器输出 mm
void readEncoder(){
float L = Lcounter1/7/238*2*PI; // 编码器旋转的角度(rad)编码器旋转一圈7个脉冲,减速比为238,
float R = Rcounter1/7/238*2*PI; // 右轮
Serial.print("左轮旋转的角度为: "); Serial.println(L);
//数值清零,重新计数
Rcounter1 = 0; Rcounter2 = 0;
Lcounter1 = 0; Lcounter2 = 0;
}
// 编码器计数
void right_counter_encoder1(){ //右轮计数
Rcounter1++;
}
void right_counter_encoder2(){
Rcounter2++;
}
void left_counter_encoder1(){ // //左轮计数
Lcounter1++;
}
void left_counter_encoder2(){
Lcounter2++;
}
验证
———————————————
本文为学习笔记
原文链接:https://blog.csdn.net/ksjz123/article/details/108825534
https://blog.csdn.net/weixin_45829708/article/details/122374287