2022年12月12日月曜日

ESP32を受信機にしてXboxのコントローラーをI2C経由で使えるライブラリを作った


背景

ESP32というマイコンにはbluetooth機能が付いているため、Xbox SeriesXのコントローラーと通信できます。
しかしながら、ESP32で利用可能な信号線の数は20本弱とそれほど多くなく、多機能な装置を作ろうとすると信号線が足りなくなります。
また、ESP32のBLE機能は開発中なためか、ESP32をリセットしないと読み込みが進まない不具合が時々発生します。

上記の課題を解決するために、ESP32をコントローラーの受信機にしてI2C通信でコントローラーの情報を配信するライブラリを作ってみました。

ControllerAsI2c_asukiaaa

需要があると思うので使い方を紹介します。

使ったもの

  • ESP32開発ボード
    grove端子が付いていて接続が楽だったのでM5Stack basicを利用しました。
    atom liteも小型でおすすめです。
  • Xbox SeriesXのコントローラー

    上記amazonなどの販売店の他に、xbox design labで好みの色の組み合わせで注文も可能です。
  • 親機となるマイコン
    今回はLeonardoを使いました。
    ピンが多いマイコンを使いたいという最初の趣旨からは外れていますが、計算力がそれほど多くないマイコンでも使える例としてleonardoにしています。
  • ESP32と親機を繋ぐ部品
    Groveケーブル、変換コネクタ、ブレッドボード、ジャンパワイヤなどを利用しました
  • プログラムを書き込むPC
    Arduino IDEやplatformioで書き込めます。
    Arduino IDEを使う場合はesp32arduinoの設定を行ってください。
    詳細設定にurlを設定してからボードマネージャ経由でインストールするのが最も手順が少ないと思います。
    platformioを使う場合はボード設定の書き換えで済むので、事前準備は不要です。

ライブラリを設定

Arduino IDEの場合

ライブラリマネージャからControllerAsI2c_asukiaaaをインストールしてください。

platformioの場合

platformio.iniのlib_depsにControllerAsI2c_asukiaaaを追加してください。
lib_deps = ControllerAsI2c_asukiaaa
このライブラリは記事を公開する数時間前に登録したので、上記の書き方で利用可能になるまでに1週間ほどかかると思います。
すぐに試したい場合は下記のようにリポジトリを指定すると使えます。
lib_deps = https://github.com/asukiaaa/arduino-ControllerAsI2c.git

受信機となるESP32にプログラムを書き込み

受信機プログラムがこちらです。

examples/slave_target/esp32/wireless-xbox-series-x/wireless-xbox-series-x.ino

ESP32に書き込むとXbox SereisXのコントローラーとペアリング可能な装置として動きます。ファイルを開くか作るかして、ESP32に書き込んでください。

特定のXboxのコントローラーにだけ接続させたい場合は、XBOX_CONTROLLER_ADDRESSで対象となるコントローラーのアドレスを指定してください。
ファイルの最初の方に書き方の例をコメントアウトしています。
// #define XBOX_CONTROLLER_ADDRESS "aa:bb:cc:dd:ee:ff"

Arduino IDEの場合

ファイル -> スケッチ例 ->ControllerAsI2c_asukiaaa -> slave_target -> esp32 -> wireless-xbox-series-x で開けます。


platformioの場合

src/main.cppの1行目に「#include <Arduino.h>」を記述した上でサンプルプログラムをコピーしてください。

動作確認


プログラムを書き込んだらシリアルモニタを115200bpsで開くとログを見れます。

ESP32とxboxのコントローラーを初めて接続する場合は、Xboxのコントローラーの側面のペアリングボタンを長押しして、コントローラーをペアリング待ち状態にしてください。

繋がると下記のようにConnected to xxというログが出ます。
load:0x40080400,len:3608
entry 0x400805f0
Name: , Address: 44:16:22:5e:b2:d4, appearance: 964, manufacturer data: 060000, serviceUUID: 0x1812, txPower: 20
Name: , Address: 48:a3:05:10:bd:11, manufacturer data: 4c001006411ed6c35e13, txPower: 12
lld_pdu_get_tx_flush_nb HCI packet count mismatch (1, 2)
lld_pdu_get_tx_flush_nb HCI packet count mismatch (1, 2)
lld_pdu_get_tx_flush_nb HCI packet count mismatch (1, 2)
Connected to 44:16:22:5e:b2:d4

既知の不具合として「lld_pdu_get_tx_flush_nb HCI packet count mismatch (1, 2)」が発生してなかなか繋がらない場合があります。
数回接続に失敗したらリセットさせているのですが、それでも繋がらない(見つからなくてリセットするまで行かない)場合があります。
居るはずなのに数十秒以上繋がらない場合はESP32をリセットしてみてください。

一度繋がると再接続時は繋がりやすくなります。
ペアリング出来たら、xboxのコントローラーをペアリングモードにしなくても電源ボタン(xboxマーク)を押してコントローラーを起動させれば、ESP32と繋がります。

I2C利用元となるプログラムを書き込み

受信機となったESP32をI2C端末として利用したい装置にプログラムを書き込みます。
記事公開時点で用意しているサンプルは2種類です。

情報をシリアル出力するもの
examples/master_controller/basic_read_write/basic_read_write.ino

コントローラーのABXYボタンの2つが同時押しされたときにモーターを振動させるもの
examples/master_controller/xbox_vibration/xbox_vibration.ino

先ほどと同様にArduino IDEならファイル -> スケッチ例 -> ControllerAsI2c_asukiaaa から辿れます。
platformioの場合は、先頭に「#nclude <Arduino.h>」を記述した後にペーストして使ってください。

動作確認


プログラムを書き込み、I2CケーブルをESP32に接続した状態でシリアルモニタで様子を見ます。
ここで表示するのは情報をシリアル出力するプログラムのログです。

I2Cケーブルが接続されていない状態だと、読み込み結果(stateRead)が異常(0でない)情報が表示されます。
readAtは読み取り処理が行われたマイコン内部時間(millisの戻り値)です。
stateRead 2
readAt 14514

I2Cケーブルが正しく接続されESP32と通信できた場合は、stateReadは0となります。
下記のログはconnectionStateが0でない、ESP32とxboxのコントローラーが通信出来てない状態を表しています。
tateRead 0
readAt 94415
controllerType 1
receiverType 1 connectionState 3 communicationCount 70

xboxのコントローラーと無線接続できた状態のログは、各ボタンやレバーの状態を表示します。
stateRead 0
readAt 171603
controllerType 1
receiverType 1 connectionState 0 communicationCount 176 buttonsDirL 0 0 0 0 buttonsDirR 0 0 0 0 joyLHori 0.00 joyLVert -0.00 joyRHori 0.00 joyRVert -0.00 buttonsL[0] 0.00 buttonsL[1] 0.00 buttonsL[2] 0.00 buttonsR[0] 0.00 buttonsR[1] 0.00 buttonsR[2] 0.00 buttonsCenter 0 0 0 0
ジョイスティックは左下が-1、右上が1、レバーは最大が1としています。

ProMicroでI2C通信を通してxboxのコントローラーの情報を読めました。

終わり

ESP32をxboxのコントローラーの受信機として動かせました。
この仕組みを利用すれば、無線機能が付いてないマイコンもxboxのコントローラーで無線制御できます。

参考

ControllerAsI2c_asukiaaa

0 件のコメント :