目次
はじめに
ロータリーエンコーダーというデバイスをご存じでしょうか?
ロータリーエンコーダーは、回転方向や回転角度を検出するためのデバイスです。
ロボット制御など回転体の状態を精度よく取得したい場面でひろく使われています。
リンク
回転センサ比較
ロータリーエンコーダとは別に回転入力を検出するデバイスとしてポテンショメータがあります。
それぞれの特徴と用途を比較します。
基本的な違い
特徴 | ロータリーエンコーダ | ポテンショメータ |
作動原理 | 回転をパルス信号(デジタル)に変換 | 回転角に応じて抵抗値を変化させ、アナログ信号を出力 |
回転可能範囲 | 制限なし(無限回転可能) | 制限あり(通常、270°や360°) |
出力形式 | デジタル信号(パルス) | アナログ信号 |
方向検出 | 時計回り(CW)、反時計回り(CCW)の方向検出が可能 | 回転方向の情報は取得不可 |
精度 | パルス数に依存。高分解能が可能 | 回転角に応じた連続値(ADCビット数に依存) |
位置保持 | 電源オフ時に位置情報は保持されない(初期化が必要) | 抵抗値として物理的に保持 |
寿命 | 機械的寿命が長く、摩耗が少ない | 摩擦や接触部の摩耗により寿命が短い場合がある |
応答速度 | 高回転の検出に適している | 高回転には不向き |
動作原理(詳細)
ロータリーエンコーダーは、回転運動をデジタル信号に変換します。以下のように動作します
パルス信号の生成
- 内部には光学ディスクや磁気ディスク、接触式の接点があります。
- 回転することでクロック(CLK)とデータ(DT)の2つのパルス信号が生成されます。
方向検出
- クロック信号とデータ信号の位相差を比較することで、時計回り(CW)か反時計回り(CCW)を判定します。
回転量の計測
パルス数をカウントすることで、回転角度や回転量を測定できます。
選択基準
ロータリーエンコーダーを選択した方が良い場合
無限回転や方向検出が必要な用途
- ロボットの回転制御
- メニュー選択やモーターの回転数検出
- 回転運動を高精度で測定したい場合
ポテンショメータを選択した方が良い場合
範囲内での連続的な位置調整が必要な用途
- ボリューム調整
- 光の輝度や音量の調整
- シンプルで低コストなアナログ入力が必要な場合
配線
OLEDも合わせて配線します
RaspberryPi Pico | ロータリーエンコーダ |
VSYS(39番) | VCC |
GND(38番) | GND |
GP0(19番) | DT |
GP1(20番) | CLK |
GP2(番) | SW |
ロータリーエンコーダを回すとディスプレイの絵が動く
まずは以下をrotary.pyとしてpicoにアップロード
from machine import Pin
from utime import sleep
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)
self.last_status = new_status
except RuntimeError:
pass
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)
main.pyは以下です
from rotary import Rotary
import utime as time
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import framebuf
WIDTH = 128
HEIGHT = 64
buffer = bytearray(b'\x00\x00\x00\x00\x01\xf0\x0f\x00\x06\x860\xb0\x04\x01@\x10\x04\x01\x000\x02\x10\x89 \x02\x05\xd2 \x01\x03\xe0@\x01\x87\xe0\x80\x10~?\x00\x00\x88\x11\x80\x01\x18\x08@\x02><@\x02a\xc3@C\xc1\x81\xe0\x05\x80\x90\x91\x08\x80\x80\x98\x08\x81\xc0\x88\t\x83\xe1\x98)\xe4\x1f\x98\x07\xf8\x0e0\x068\x0c \x02\x18\x080\x02\x88\x08 \x03\x0e0A\x01\x8f\xf8\x80\x00|\x1f\x00\x008\x0c\x00\x00\x0c0\x02\x00\x03\xe0\x00\x00\x00\x80\x00\x01\x00\x00\x04')
fb = framebuf.FrameBuffer(buffer, 32, 32, framebuf.MONO_HLSB)
i2c = I2C(0, scl=Pin(17), sda=Pin(16),freq=200000)
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c)
# clear screen
oled.fill(0)
oled.blit(fb, 64, 32)
oled.show()
time.sleep(1)
oled.fill(0)
rotary = Rotary(0, 1, 2)
val = 0
def rotary_changed(change):
global val
if change == Rotary.ROT_CW:
val += 10
oled.blit(fb, val, 32)
oled.show()
time.sleep(0.2)
oled.fill(0)
print(val)
elif change == Rotary.ROT_CCW:
val -= 10
oled.blit(fb, val, 32)
oled.show()
time.sleep(0.2)
oled.fill(0)
print(val)
elif change == Rotary.SW_PRESS:
val += 20
oled.blit(fb, 64, val)
oled.show()
time.sleep(0.2)
oled.fill(0)
elif change == Rotary.SW_RELEASE:
val -= 20
oled.blit(fb, 64, val)
oled.show()
time.sleep(0.2)
oled.fill(0)
rotary.add_handler(rotary_changed)
while True:
time.sleep(0.1)
リンク
コメント