プログラミング素人のはてなブログ

プログラミングも電気回路も専門外の技術屋の末端が勉強したことや作品をアウトプットするブログ。コードに間違いなど見つけられたら、気軽にコメントください。 C#、Python3、ラズパイなど。

Arduinoでロータリーエンコーダを使ってみた

ロータリーエンコーダなるものを試してみた

ロータリーエンコーダとは回転数や角度、回転速度等を電気信号を用いて測定できるものです。
f:id:s51517765:20211225205435p:plain
オシロスコープのレンジ調整つまみなどに使われていて、可変抵抗と似ていますがどちらの方向にも無限に回すことが出来ます。
f:id:s51517765:20211225205557j:plain
ロータリーエンコーダの仕組みは2つの信号をが位相がずれて出力されることで、一回転を4分割することでその位相を検出します。
位相を4分解で取得することで回転数や角度、回転速度等を検出することが出来ます。

今回は、いらなくなったマウスのホイール部分からロータリーエンコーダを取り出してArduinoで読み取ってみました。
あらかじめ分解前にその出力をオシロスコープで観測することで、A/B出力、電源、GNDを確認しました。
f:id:s51517765:20211225210003j:plain
f:id:s51517765:20211225210027p:plain

これを基板上に再構成しました。
f:id:s51517765:20211225210431p:plain
f:id:s51517765:20211225221930p:plain
オシロスコープでは出力がうまく取れてもArduinoではうまく出力が取れなくて、A/B出力を両方ともプルダウンすることでうまくいきました。
オシロスコープArduinoの入力インピーダンスの違いによる差だと思います。

Arduinoでロータリーエンコーダの位相を取得するには、2つのdigital入力のHigh or Lowの組み合わせで4つの状態(state)を検出します。

a = digitalRead(pinA); 
b = digitalRead(pinB);

int get_state(int a, int b) {
  int state;
  if (a == 1 && b == 0)state = 1;
  else if (a == 1 && b == 1)state = 2;
  else if (a == 0 && b == 1)state = 3;
  else state = 0;

  return state;
}

これが正回転か逆回転かは、前の状態(state)をprevとして保存しておいて現在の状態と比較します。
これによってカウントを動かしていきます。
状態は4つなので、正回転であれば0→1 or 1→2 or 2→3 or 3→4 or 4→0となります(vice versa)。
ただし、どちらがどちら回転かはやってみないとわからないのでここでいう正・逆はとくに拘ることでもないです。

if (prev == state + 1 || prev == state - 3)count += 1;
else if (prev == state - 1 || prev == state + 3)count -= 1;

これで、回転数等を測ることはできますが、せっかくなので見える化してみます。
LEDを5つ表示灯としてつけてみました。
ちなみに4つであれば、ロータリーエンコーダの4つの状態にLEDを当てはめると簡単にできてしまいますのであえて5つにし、countを5で割った”余り”でLEDを制御します。

まとめ

マウスから取り出したロータリーエンコーダをArduinoで使ってみました。

const int pinA = 2;
const int pinB = 3;
int a, b, state, prev;
const int LED0 = A0;
const int LED1 = A1;
const int LED2 = A2;
const int LED3 = A3;
const int LED4 = A4;

void setup() {
  pinMode(pinA, INPUT);
  pinMode(pinB, INPUT);
  pinMode(LED0, OUTPUT);
  pinMode(LED1, OUTPUT);
  pinMode(LED2, OUTPUT);
  pinMode(LED3, OUTPUT);
  pinMode(LED4, OUTPUT);
  Serial.begin(9600);
}

void LED(unsigned int count) {
  switch (count % 5) {
    case 0:
      digitalWrite(LED0, HIGH);
      digitalWrite(LED1, LOW);
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, LOW);
      digitalWrite(LED4, LOW);
      break;
    case 1:
      digitalWrite(LED0, LOW);
      digitalWrite(LED1, HIGH);
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, LOW);
      digitalWrite(LED4, LOW);
      break;
    case 2:
      digitalWrite(LED0, LOW);
      digitalWrite(LED1, LOW);
      digitalWrite(LED2, HIGH);
      digitalWrite(LED3, LOW);
      digitalWrite(LED4, LOW);
      break;
    case 3:
      digitalWrite(LED0, LOW);
      digitalWrite(LED1, LOW);
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, HIGH);
      digitalWrite(LED4, LOW);
      break;
    case 4:
      digitalWrite(LED0, LOW);
      digitalWrite(LED1, LOW);
      digitalWrite(LED2, LOW);
      digitalWrite(LED3, LOW);
      digitalWrite(LED4, HIGH);
      break;
  }
}

int get_state(int a, int b) {
  int state;
  if (a == 1 && b == 0)state = 1;
  else if (a == 1 && b == 1)state = 2;
  else if (a == 0 && b == 1)state = 3;
  else state = 0;

  Serial.print(a);
  Serial.print(",");
  Serial.print(b);
  Serial.print(",");
  Serial.println(state);

  return state;
}

unsigned int count = 1 << 14;
void loop() {
  a = digitalRead(pinA);
  b = digitalRead(pinB);
  state = get_state(a, b);

  if (prev == state + 1 || prev == state - 3)count += 1;
  else if (prev == state - 1 || prev == state + 3)count -= 1;

  //Serial.println(count);

  LED(count );
  prev = state;
}

P.S.

実は、最初これとは異なるマウスから取ったロータリーエンコーダを動かそうと試したのですが結局仕組みがよくわかりませんでした。
f:id:s51517765:20211225212359p:plain
こちらはLEDのアノード・カソードと回転するスリット、エンコーダの電源とA/B出力?と思われるピンが3本あるのですがまた違う方式のようです。