旋转编码器|从零开始认识各种传感器
1. 什么是旋转编码器?
旋转编码器是一种能够将旋转位置变化转换为数字信号输出的装置,被广泛应用于机械设备、自动化控制、测量仪表等领域。它是电位计的现代数字等效产品,比电位计功能更广泛。 电位计只能旋转大约3/4的圆, 旋转编码器可以旋转多圈,适合用来感知位置角度的连续变化,比如汽车中控的旋转按钮。
图1 旋转编码器应用于汽车中控旋钮
2. 旋转编码器是如何工作的
旋转编码器的工作原理是利用光电传感器或磁电传感器,采集旋转盘的位移信息,将其转化成数字信号输出。根据信号的数量和类型,可以实现不同分辨率和不同输出形式的旋转编码器。其中,绝对式旋转编码器能够直接输出每个位置的绝对值,而增量式旋转编码器则只能输出相对位移和方向变化。 在编码器内部有一个开有槽孔的金属盘,它有一个接地管脚C链接到地。 还有两个金属探针a和b。当转动旋钮时,根据转动方向的不同,探针A和B会先后接触到地,产生的脉冲信号会有90度的相位差,形成一种正交编码。
图2 旋转编码器结构
通过检测信号A状态改变时,B信号的值,就可以确定旋转的方向:
1. 当A的状态改变时,如果B不等于A,则表示顺时针旋转。
2. 当A的状态改变时,如果B等于A,则表示逆时针旋转。
图3 旋转编码器工作原理
3. 常见的旋转编码器的种类
旋转编码器可分为绝对型(absolute)编码器及增量型(incremental)编码器两种。增量型编码器也称作相对型编码器(relative encoder),利用检测脉冲的方式来计算转速及位置,可输出有关旋转轴运动的信号,一般会由其他设备或电路进一步转换为速度、距离、每分钟转速或位置的信号。而绝对型编码器可以精确输出旋转轴相对于初始状态的位置,可视为一种角度传感器。
3.1 绝对型编码器
绝对编码器是能输出角度绝对值的一种编码器。绝对编码器的码盘与增量编码器有很大的不同,他的码盘上面每个角度都记录了不同的编码,唯一对应于当前转动位置。它的一大优点就是不怕断电,断电后由于编码的唯一性,上电后依然可以读取当前准确的位置。
图4 绝对型旋转编码器
对于需要多于一圈的角度记录,可以在码盘转轴上外加齿轮来进行多圈记录,类似钟表的机械原理。
图5 多圈记录旋转编码器
3.2 增量型编码器
增量型编码器,也称作相对编码器,他的码盘编码是均匀分布的。它是通过从初始位置开始转动后记录的脉冲数量确定当前转动位置。增量型编码器的信号可以很方便的转换为运动相关的速度等信号,且成本较低,其是最广为使用的编码器。但是它的原理也决定了它无法在断电时储存当前位置。
图6 增量型编码器原理
3.3 两种旋转编码器的比较
图7 旋转编码器的特性比较
从两种旋转编码器的比较表格可以看出,两者最大的区别就是是否具有断电记忆系统当前位置的功能。由于绝对旋转编码器的每个角度的编码是唯一的,它可以做到在断电重启时记住当前系统位置,使得它适用于需要高精度和即时位置信息的应用,如机器人手臂的位置、自动化工厂传送带的位置等等。而增量式编码器由于结构简单,价格便宜,是应用更为广泛的编码器。
4. 旋转编码器演示
最后,我们来演示如何使用配备显示屏的树莓派读取并显示旋转编码器的数据。实验中使用的是一款增量式旋转编码器,转动旋柱,可以看到屏幕显示转动角度增加,反方向转动,则显示转动角度减小,过零点后变成负值。
图8 树莓派读取旋转编码器展示
完整代码如下:
main.py
from breakout_colourlcd240x240 import BreakoutColourLCD240x240
from machine import ADC, Pin, Timer, PWM
from utime import sleep
import time, math,array
#------------------------------------------------------------------
from rotary import Rotary
rotary = Rotary(20,21,22)
val = 0
def rotary_changed(change):
global val
if change == Rotary.ROT_CW:
val = val + 1
print(val)
elif change == Rotary.ROT_CCW:
val = val - 1
print(val)
rotary.add_handler(rotary_changed)
#显示屏
width = BreakoutColourLCD240x240.WIDTH
height = BreakoutColourLCD240x240.HEIGHT
display_buffer = bytearray(width * height*2)
display = BreakoutColourLCD240x240(display_buffer)
#-------------------------------------------------------------------
#屏幕基本图形绘制
def display_init():
display.set_pen(0,255,0)
display.rectangle(58,30,13,160)
display.circle(64,190,6)
display.set_pen(255,0,0)
display.text("current", 150, 20, 194, 2)
display.text("step", 150, 35, 194, 2)
display.update()
for i in range(6):
display.set_pen(0,200,0)
display.pixel_span(80,27 + i*30,10)
display.text(str(50 - i *10), 100, 20+i*30, 194, 2)
display.set_pen(0,0,220)
if i < 5:
for j in range(4):
display.pixel_span(80,33 + j*6 + i * 30,5)
display.update()
display.update()
def main():
color = [0,255,0] #温度计颜色
timer1 = Timer()
#基本图形绘制
display_init()
#timer1初始化,以5Hz刷新温度计绘制yvis0z
timer1.init(freq=5,mode=Timer.PERIODIC, callback=lambda t:display_change(round(val,1), color))
while True:
sleep(0.1 )
main()
rotary.py
import machine
import utime as time
from machine import Pin
import micropython
class Rotary:
ROT_CW = 1
ROT_CCW = 2
SW_PRESS = 4
SW_RELEASE = 8
def __init__(self,dt,clk,sw):
self.dt_pin = Pin(dt, Pin.IN)
self.clk_pin = Pin(clk, Pin.IN)
self.sw_pin = Pin(sw, Pin.IN)
self.last_status = (self.dt_pin.value() << 1) | self.clk_pin.value()
self.dt_pin.irq(handler=self.rotary_change, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING )
self.clk_pin.irq(handler=self.rotary_change, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING )
self.sw_pin.irq(handler=self.switch_detect, trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING )
self.handlers = []
self.last_button_status = self.sw_pin.value()
def rotary_change(self, pin):
new_status = (self.dt_pin.value() << 1) | self.clk_pin.value()
if new_status == self.last_status:
return
transition = (self.last_status << 2) | new_status
try:
if transition == 0b1110:
micropython.schedule(self.call_handlers, Rotary.ROT_CW)
elif transition == 0b1101:
micropython.schedule(self.call_handlers, Rotary.ROT_CCW)
except:
pass
self.last_status = new_status
def switch_detect(self,pin):
if self.last_button_status == self.sw_pin.value():
return
self.last_button_status = self.sw_pin.value()
if self.sw_pin.value():
micropython.schedule(self.call_handlers, Rotary.SW_RELEASE)
else:
micropython.schedule(self.call_handlers, Rotary.SW_PRESS)
def add_handler(self, handler):
self.handlers.append(handler)
def call_handlers(self, type):
for handler in self.handlers:
handler(type)