1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RP2040 を使ったキーボード入力対応ミニアケコンの自作

1
Last updated at Posted at 2025-12-08

記事の内容

PCに外部キーボードデバイスとして認識されるアーケードタイプのコントローラーの制作方法のついて記載します。
例として方向キーとEnterキー入力のできる仕様になります。
image.png

制作の動機

Unity などのゲームエンジンでシンプルなゲーム(移動と単一アクション程度)を制作する際、ゲームコントローラーの入力設定を行うのが手間に感じることがあります。
また、ビルド後に他の PC でもコントローラーなしですぐ動作させたいという理由から、キーボード入力として扱えるコントローラーがあると便利だと思い、制作しました。

作成するもの

レバーとボタンを1つずつ取り付けたコントローラー。
4img.JPG

使用したもの

  • Mac Book Pro
    開発に使用します。

  • Arduino IDE
    スケッチの作成とマイコンへの書き込みに使用します。

  • Seeed XIAO RP2040
    マイコンとして使用し、キーボードデバイスとして振る舞うスケッチを書き込みます。
    https://akizukidenshi.com/catalog/g/g116132/
    同じ RP2040 デバイス(例:Raspberry Pi Pico など)でも代用可能ですが、XIAO は小型で取り付けやすいという利点があります。

  • ボタン、レバー等のスイッチ系の電子パーツ
    入力インタフェースとして使用します。
    1img.JPG

  • 3Dプリンター
    コントローラーの筐体作成に使用します。
    ケースであればあんでも良いので詳細は割愛します。

工程

スケッチの用意

Arduino IDEでスケッチを作成します。
ライブラリにTinyUSBを使用します。
ライブラリマネージャーから「Adafruit TinyUSB Library」を追加してください。


#include "Adafruit_TinyUSB.h"

uint8_t const desc_hid_report[] = {
    TUD_HID_REPORT_DESC_KEYBOARD()
};
Adafruit_USBD_HID usb_hid;

//------------- Input Pins -------------//
uint8_t pins[] = { D3, D4, D5, D6, D7 };

uint8_t pincount = sizeof(pins) / sizeof(pins[0]);

uint8_t hidcode[] = {HID_KEY_ARROW_UP, HID_KEY_ARROW_DOWN, HID_KEY_ARROW_RIGHT, HID_KEY_ARROW_LEFT, HID_KEY_ENTER };

#if defined(ARDUINO_SAMD_CIRCUITPLAYGROUND_EXPRESS) || defined(ARDUINO_NRF52840_CIRCUITPLAY) || defined(ARDUINO_FUNHOUSE_ESP32S2)
bool activeState = true;
#else
bool activeState = false;
#endif

void setup() {
  if (!TinyUSBDevice.isInitialized()) {
    TinyUSBDevice.begin(0);
  }

  // Setup HID
  usb_hid.setBootProtocol(HID_ITF_PROTOCOL_KEYBOARD);
  usb_hid.setPollInterval(2);
  usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report));
  usb_hid.setStringDescriptor("TinyUSB Keyboard");
  usb_hid.setReportCallback(NULL, hid_report_callback);

  usb_hid.begin();

  if (TinyUSBDevice.mounted()) {
    TinyUSBDevice.detach();
    delay(10);
    TinyUSBDevice.attach();
  }

  for (uint8_t i = 0; i < pincount; i++) {
    pinMode(pins[i], activeState ? INPUT_PULLDOWN : INPUT_PULLUP);
  }
}

void process_hid() {
  static bool keyPressedPreviously = false;

  uint8_t count = 0;
  uint8_t keycode[6] = {0};

  // scan normal key and send report
  for (uint8_t i = 0; i < pincount; i++) {
    if (activeState == digitalRead(pins[i])) {
      // if pin is active (low), add its hid code to key report
      keycode[count++] = hidcode[i];
      // 6 is max keycode per report
      if (count == 6) break;
    }
  }

  if (TinyUSBDevice.suspended() && count) {
    TinyUSBDevice.remoteWakeup();
  }

  if (!usb_hid.ready()) return;

  if (count) {
    uint8_t const report_id = 0;
    uint8_t const modifier = 0;

    keyPressedPreviously = true;
    usb_hid.keyboardReport(report_id, modifier, keycode);
  } else {
    if (keyPressedPreviously) {
      keyPressedPreviously = false;
      usb_hid.keyboardRelease(0);
    }
  }
}

void loop() {
  #ifdef TINYUSB_NEED_POLLING_TASK
  TinyUSBDevice.task();
  #endif

  if (!TinyUSBDevice.mounted()) {
    return;
  }
  static uint32_t ms = 0;
  if (millis() - ms > 2) {
    ms = millis();
    process_hid();
  }
}

// Output report callback for LED indicator such as Caplocks
void hid_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
  (void) report_id;
  (void) bufsize;
  if (report_type != HID_REPORT_TYPE_OUTPUT) return;
  uint8_t ledIndicator = buffer[0];

}

以下の部分で、スイッチを接続するピン番号を指定します。

//------------- Input Pins -------------//
uint8_t pins[] = { D3, D4, D5, D6, D7 };

以下の部分で、各ピンに対応するキーコードを指定します。

uint8_t hidcode[] = {HID_KEY_ARROW_UP, HID_KEY_ARROW_DOWN, HID_KEY_ARROW_RIGHT, HID_KEY_ARROW_LEFT, HID_KEY_ENTER };

XIAOをPCに繋ぎ、スケッチを書き込みます。
書き込み後、キーボードデバイスとして認識されるようになります。

パーツの結線

スケッチで指定したデジタル入力ピンと GND にスイッチパーツを結線します。
キーを押すと方向キーと Enter キーが入力され、長押しした場合は連続入力が行われます。
2img.JPG

キーを入力すると方向キーとEnterキーの入力ができます。
長押しすると連続入力になります。

パーツの組み込み

用意したケースにレバー・ボタン・XIAO を取り付けます。
IMG_2933.jpg

完成

4img.JPG
3img.JPG

すべて組み上げれば完成です。
XIAO を採用すると USB-C でそのまま接続でき、USB-C to C ケーブルで動作する点も地味に便利です。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?