【ESP32】ローターリーエンコーダーで無線ゲームコントローラーを作る方法

マイコン/Arduino

今回もロータリーエンコーダーネタです。

つい先日まで勘違いしていたのですが、ESP32では全てのピンが入力割り込みにつかえるようです。そこで、今回は遠慮なくピン入力割り込みを使用してロータリーエンコーダーを読み取ります。

また、前回はゲームコントローラーと言いながらボリュームコントローラーの例だったので、今回こそゲームコントローラーです。

これまでの方法の問題点

前回紹介した、別スレッドをロータリーエンコーダーの監視に割り当てる方法では、割り込み間隔の制限があります。このため、分解能が高いエンコーダーを使ったり、高速で回転させたりした場合に大量の取りこぼしが発生するという問題がありました。今回はこれを改善します。

考え方

今回の考え方はロータリーエンコーダーの正攻法です。
A相の立ち上がり(もしくは立下り)エッジを検出したら、そのときのB相の状態を確認し、0ならC.W.、それ以外ならC.C.W.としています。これが一番素直ですね。

配線図

ロータリーエンコーダーのA相とB相をESP32の16番と17番に接続しています。どこのピンでも問題ないので、下記図とは異なるピン番号に接続した場合はプログラムソースは適宜読み替えてください。

ESP32とロータリーエンコーダーの接続

スケッチ例

#include <Arduino.h>
#include <BleGamepad.h>

#define numOfButtons 1
#define numOfButtons 1
#define enableX true
#define enableY true
#define enableZ false
#define enableRZ false
#define enableRX false
#define enableRY false
#define enableSlider1 false
#define enableSlider2 false
BleGamepad bleGamepad("hundleController");

//ロータリーエンコーダー設定
#define PinEnc1A 16
#define PinEnc1B 17
volatile int Counter1 = 0;
int ar=0;

void ROTALY() {
  if(digitalRead(PinEnc1A)==0)
  {
    if(digitalRead(PinEnc1B)==0)
    {
      Counter1++;
    }
    else
    {
      Counter1--;
    }
  }
}

void setup(){
  //入力ピン設定
  pinMode(PinEnc1A, INPUT_PULLUP);
  pinMode(PinEnc1B, INPUT_PULLUP);

  //ロータリーエンコーダー割り込み設定
  attachInterrupt(PinEnc1A, ROTALY, FALLING);

  //ゲームパッド設定
  BleGamepadConfiguration bleGamepadConfig;
  bleGamepadConfig.setControllerType(CONTROLLER_TYPE_GAMEPAD);
  bleGamepadConfig.setWhichAxes(enableX, enableY, enableZ, enableRX, enableRY, enableRZ, enableSlider1, enableSlider2);
  bleGamepadConfig.setButtonCount(numOfButtons);
  bleGamepadConfig.setAxesMin(-32767);
  bleGamepadConfig.setAxesMax(32767);
  bleGamepad.begin(&bleGamepadConfig);
}

void loop(){
  if (bleGamepad.isConnected()){
    if (Counter1 > 0) {
      if(ar>(-32666))
      {
        ar-=30;
        bleGamepad.setAxes(ar);
        Counter1--;
      }
    else{
      Counter1=0;
    }
  }
  else if (Counter1 < 0){
    if(ar<32666){
      ar+=30;
      bleGamepad.setAxes(ar);
      Counter1++;
    }
    else{
      Counter1=0;
    }
  }
}
else{
  Counter1=0;
  delay(1);
  }
}

うまくいかない場合

一番はまるのが、Windowsの[USBゲームコントローラーのセットアップ]のウィンドウでデバイスが認識されないことだと思います。ProMicroでもESP32でも遭遇しています。

Windowsの設定アプリには表示されませんが、この状態でもゲーム上からは大抵見えて使えます。

このときは47行目の

 bleGamepadConfig.setControllerType(CONTROLLER_TYPE_GAMEPAD);

bleGamepadConfig.setControllerType(CONTROLLER_TYPE_MULTI_AXIS);
bleGamepadConfig.setControllerType(CONTROLLER_TYPE_JOYSTICK);

などのようにしてみてください。これらの違いはよくわかりませんが、ここを変更しただけで認識されることが多いです。また、一度あるデバイスとしてWindowsのレジストリに登録されてしまうとファームを書き換えてもデバイスの種類や名前が反映されないことがあるので、この場合は下の記事にあるようにレジストリの該当する部分をいったん削除してみることをお勧めします。

Arduinoでゲームコントローラーのデバイス名を設定する
Arduinoでゲームコントローラーを作るときのデバイス名設定方法とはまりやすいポイントを説明します。

まとめ

今回の方法で、プログラムソースは格段にシンプルでかつ、確実な読み取りが行えるようになりました。(今までの方法がイマイチだっただけという話も…)

次回は高級なロータリーエンコーダーを使って格安のETS2用のハンコンの作り方を紹介します。

コメント