このページではソフトドリフトの入力方法について調査を行うにあたり利用した調査方法の概要、必要な機材、セットアップ方法、プログラム実行方法について説明します。機材の準備は少し手間で、実際に動作させるためにはLinuxの知識をある程度必要としますが、whoamiの調査環境をそのまま再現できます。
コントローラのアナログスティックを正確に倒すのは基本的に不可能だと思います。また正確に調べられたとしてもコントローラの種類や個体差によって出力データに差異が生じることが考えられます。そこで、コントローラとSwitch本体の間でやりとりされているデータを直接利用することにしました。あまり手間をかけたくないということで、USB接続でプロキシ動作するものがないか検索したところ、USBProxyやFacedancerが見つかりました。今回はUSBProxyに変更を加えてUSBコントローラとSwitchの間でデータ変換を行い正確なアナログスティックの値をSwitchに出力するようなwhoami版USBProxyを作成して利用しました。
ここで実現するシステムは以下の図のようにコントローラから送信されたデータをwhoami版USBProxyが受信し、必要に応じてそのデータを変換しSwitchに送信します。これにより、正確に制御されたコントローラ出力を実現します。
今回は以下の機器を準備し利用しました。PCはブロードバンドルータからIPアドレスを割り当てられてインターネット接続が可能であるものとします。
機器 | 説明 | 写真 |
BeagleBone Black | ARM Cortex-A8プロセッサを搭載したシングルボードコンピュータです。whoami版USBProxyを動作させてホリパッドとSwitchの間でデータの変換を行います。 | |
Nintendo Switchとドック | BeagleBone BlackとUSB接続を行うのでドックを利用します。もちろんディスプレイも準備します。ここで紹介する実験を行うだけであればインターネット接続は不要です。 | |
PC | MicroSDカードへのOSインストールやBeagleBone Blackの遠隔操作に利用します。MicroSDカードへのディスクイメージの書き込みやsshでのリモートログインが可能であればWindowsやMacでも問題ありませんが、ここではLinux(Ubuntu 20.04など)を利用するものとして説明します。またブロードバンドルータを介してインターネットに接続できるものとします。もしもMicroSDカードを直接利用できない場合には別途紹介しているMicroSDカード対応のUSBアダプタなども準備しておきます。 | |
MicroSDカード (1GB以上) | BeagleBone Black向けのOSをインストールして利用します。 | |
MicroSDカードの変換アダプタ USB接続のSDカードアダプタ | PCにMicroSDカードのスロットが存在しない場合に必要に応じて利用します。 | |
ホリパッド for Nintendo Switch | BeagleBone Blackに接続してUSBProxyに制御データを送信します。ここではブルーのホリパッドを利用しますが、標準色(ブラック)での動作実績もあります。 | |
USBケーブル(Type A - Mini Type B) | BeagleBone BlackとSwitchのドックへの接続に利用します。電源だけではなく信号もちゃんと送ることができるケーブルが必要です。 | |
ネットワークケーブル | BeagleBone Blackのネットワーク接続に利用します。 | |
ブロードバンドルータ | BeagleBone BlackとPCのネットワーク接続に利用します。DHCPサーバとして動作しローカルエリアネットワーク内の機器のIPアドレス割り当て行います。また、NAT機能によりローカルエリアネットワークの機器からインターネットへの接続を実現します。もちろん、ブロードバンドルータを利用しない方法もありますがここでは説明しません。 |
whoami版USBProxyを利用して実験を行う際の接続は以下の通りになります。
ここではwhoami版USBProxyのセットアップ方法について説明します。行う作業は以下の2つです。
作業はBeagleBone BlackとPC(Linux)で行います。また、最初はPCでの作業となるためBeagleBone Blackの電源は接続しないでおきます。
PCを利用してUSBProxyのリリースページからOSイメージ(Debian-USBProxy.img.xz)をダウンロードします。ファイルは~/Downloadsにダウンロードしたものとします。xz形式で圧縮されているのでunxz
コマンド等で展開しておきます。
user@pc:~$ cd Downloads
user@pc:~/Downlods$ ls -l Debian-USBProxy.img.xz
-rw-rw-r-- 1 user user 283780956 Mar 5 21:16 Debian-USBProxy.img.xz
user@pc:~/Downlods$ unxz Debian-USBProxy.img.xz
user@pc:~/Downlods$ ls -l Debian-USBProxy.img
-rw-rw-r-- 1 user user 902823936 Mar 5 21:16 Debian-USBProxy.img
user@pc:~/Downlods$
書き込みを行うMicroSDカードをPCのスロットに挿入します。PC本体にMicroSDカードスロットが存在しない場合にはMicroSDカード接続対応USBアダプタ等を利用します。MicroSDカードを挿入すると/devの下に新たにデバイスファイルが生成されるはずです。ここで追加されたデバイスの名前は覚えておきます。また、もしもMicroSDカードがマウントされてしまった場合にはアンマウントしておきます。
以下の例ではMicroSDカードを挿入したことで/dev/sdbと/dev/sdb1が追加されたことが分かります。また、/dev/sdb1が/media/user/SDCARDとしてマウントされたのでアンマウントをしておきます。
user@pc:~/Downloads$ ls /dev/sd*
/dev/sda /dev/sda1 /dev/sda2
-- ここでMircoSDカードをPCに挿入 --
user@pc:~/Downloads$ ls /dev/sd*
/dev/sda /dev/sda1 /dev/sda2 /dev/sdb /dev/sdb1
user@pc:~/Downloads$ df
Filesystem 1K-blocks Used Available Use% Mounted on
udev 15875040 0 15875040 0% /dev
tmpfs 3180048 2484 3177564 1% /run
/dev/sda2 479550128 225710984 229409576 50% /
tmpfs 15900228 0 15900228 0% /dev/shm
tmpfs 5120 4 5116 1% /run/lock
tmpfs 15900228 0 15900228 0% /sys/fs/cgroup
/dev/sda1 523248 6196 517052 2% /boot/efi
tmpfs 3180044 36 3180008 1% /run/user/1000
/dev/sdb1 723292 645680 23860 97% /media/user/SDCARD
user@pc:~/Downloads$ sudo umount /media/user/SDCARD
[sudo] password for debian: temppwd
user@pc:~/Downloads$
dd
コマンドを利用して先程ダウンロードして展開したディスクイメージをMicroSDカードに書き込みます。上記の例ではMicroSDカードを挿入した時に追加されたファイルである/dev/sdbがMicroSDカードを表すファイルとなります。このファイル名は環境によって異なる可能性があります。以下のようにddコマンドを実行する際には/dev/sdbを適切なファイル名に置き換えて十分注意して実行してください!間違ったファイル名を指定すると他のHDDやSSDのデータが完全に失われる可能性があります!この作業に自信がないようであればRaspberry Pi ImagerのようなGUIツールを利用することをおすすめします。
user@pc:~/Downloads$ sudo dd if=Debian-USBProxy.img of=/dev/sdb bs=1M
[sudo] password for debian: temppwd
861+0 records in
861+0 records out
902823936 bytes (903 MB, 861 MiB) copied, 240.869s, 3.7 MB/s
user@pc:~/Downloads$
dd
コマンドは少し時間(数分程度)がかかりますので、コマンド終了までのんびり待ちます。
umount
やdd
コマンドの実行にsudo
コマンドを利用しています。sudo
は一時的にスーパーユーザー権限でコマンドを実行するためによく利用されるコマンドです。以下の説明でも必要に応じてsudo
コマンドを利用しています。
BeagleBone Blackが電源に接続していないことを確認します。OSイメージをコピーしたMicroSDカードをPCから取り出しBeagleBone BlackのMicroSDカードスロットに挿入します。BeagleBone Blackとブロードバンドルータをネットワークケーブルで接続します。最後にUSBケーブルをSwitchのドックに接続することで電源を入れます。しばらくするとBeagleBone Blackが正常に起動し、PCからBeagleBone Blackにリモートログインできるようになります。リモートログインにはSSHプロトコル対応のアプリケーションが必要です。ここではssh
コマンドを利用します。その時に利用するBeagleBone Blackのホスト名は"arm.local"、ユーザIDは"debian"、パスワードは"temppwd"になります。
ホスト名 | arm.local |
ユーザID | debian |
パスワード | temppwd |
user@pc:~$ ssh debian@arm.local
debian@arm.local's password: temppwd
Linux arm 3.12.0-bone8 #1 SMP Mon Nov 18 18:49:58 EST 2013 armv7l
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
debian@arm:~$
以下のような作業を行い、インストール済みのUSBProxyをwhoami版USBProxyに置き換えます。
debian@arm:~$ mv USBProxy USBProxy.orig
debian@arm:~$ git clone https://github.com/v-whoami-v/USBProxy
Cloning into 'USBProxy'...
remote: Enumerating objects: 4320, done.
remote: Total 4320 (delta 0), reused 0 (delta 0), pack-reused 4320
Receiving objects: 100% (4320/4320), 1.42 MiB | 1.27 MiB/s, done.
Resolving deltas: 100% (3089/3089), done.
debian@arm:~$ cd USBProxy/src
debian@arm:~/USBProxy/src$ make
make -C lib
make[1]: Entering directory '/home/debian/USBProxy/src/lib'
-- 省略 --
debian@arm:~/USBProxy/src$
これでwhoami版USBProxyの実行ファイルが生成されました。whoami版USBProxyにはUSBProxy本体の他にサポートプログラムを含んでいます。これらのプログラムはswitchpadディレクトリの下に置いてあります。以下のようにmake
コマンドを実行することでサポートプログラムの実行ファイルを生成します。
debian@arm:~/USBProxy/src$ cd ../switchpad
debian@arm:~/USBProxy/switchpad$ make
cc geninput.c -o geninput
cc gen_outer.c -o gen_outer
cc gen_left.c -o gen_left
cc gen_left_soft.c -o gen_left_soft
cc gen_right.c -o gen_right
cc gen_right_soft.c -o gen_right_soft
chmod +x gen_drift.sh
chmod +x genrules_softdrift_left.sh
chmod +x genrules_softdrift_right.sh
chmod +x genrules_softdrift.sh
debian@arm:~/USBProxy/switchpad$
whoami版USBProxyを実行する前に忘れずにホリパッドをBeagleBone Blackに接続します。
whoami版USBProxyの実行ファイルはusb-mitm
です。whoami版USBProxyとして実行するには引数として"-S"を指定します。
debian@arm:~/USBProxy/switchpad$ cd ../src
debian@arm:~/USBProxy/src$ sudo ./usb-mitm -S
[sudo] password for debian: temppwd
BeagleBone Blackに接続したコントローラがSwitch内で正常に動作することを確認します。whoami版USBProxyの動作は完璧ではないため、時々データロスが連続して発生し思った通りに動作しないことがありますのでご注意ください。
またwhoami版USBProxyはCtrl-C(コントロールキーを押しながらCキーを押す)で終了します。whoami版USBProxyを終了せずに後述する/run/rules.txtや/run/input.txtを書き換えたい場合には、PCで複数のターミナルウィンドウを開くなどして別途ログインしてください。
whoami版USBProxyを用いることでUSBコントローラのデータを変換してSwitchに転送できますが以下の2つの変換方法があります。
これら2つの変換方法について説明します。
/run/rules.txtに左スティックの座標変換ルールを記述します。複数行記述することで複数の変換ルールを記述できます。変換ルールのフォーマットは以下の通りです。
入力X座標,入力Y座標,出力X座標,出力Y座標
例えば真左である(0,128)付近のコントローラからの入力を斜め入力(0,3)に変換してSwitchに出力するルールは以下のようになります。ルールに記述されていない入力座標についてはコントローラからの出力をそのまま利用します。また、whoami版USBProxyにはもう少し現実的な/run/rules.txtのサンプルファイルが添付されています。
0,127,0,3
0,128,0,3
0,129,0,3
1,127,0,3
1,128,0,3
1,129,0,3
/run/rules.txtはusb-mitm
開始時にロードされて利用されますが、コントローラの"+"ボタンを押すことでリロードすることもできます。
Switchに送信するコントロールデータ(16進数)を/run/input.txtに記述することでコントローラが出力したデータ全体を置き換えることができます。whoami版USBProxyに付属しているgeninput
を利用することで簡単に/run/input.txtを生成できますのでファイルの内容については省略します。geninput
コマンドの引数は以下の通りです。
-leftx NUM | 左スティックのX軸の値をNUMにする。 |
-lefty NUM | 左スティックのY軸の値をNUMにする。 |
-rightx NUM | 右スティックのX軸の値をNUMにする。 |
-righty NUM | 右スティックのY軸の値をNUMにする。 |
-A | Aボタンを押した状態にする。 |
-B | Bボタンを押した状態にする。 |
-X | Xボタンを押した状態にする。 |
-Y | Yボタンを押した状態にする。 |
-L | Lボタンを押した状態にする。 |
-R | Rボタンを押した状態にする。 |
-ZL | ZLボタンを押した状態にする。 |
-ZR | ZRボタンを押した状態にする。 |
-CAP | キャプチャーボタンを押した状態にする。 |
-HOME | ホームボタンを押した状態にする。 |
-rm | /run/input.txtを削除する |
例えばアナログスティックを左入力(0,128)しBボタンを押しているという出力を生成するには以下のようにgeninput
を実行します。ここではUSBProxyを実行した状態で別の作業を行うため、PCで新たなターミナルウィンドウを開いてBeagleBone Blackにリモートログインしています。
user@pc:~$ ssh debian@arm.local
debian@arm.local's password: temppwd
Linux arm 3.12.0-bone8 #1 SMP Mon Nov 18 18:49:58 EST 2013 armv7l
The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.
Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
debian@arm:~$ cd USBProxy/switchpad
debian@arm:~/USBProxy/switchpad$ sudo ./geninput -leftx 0 -lefty 128 -B
[sudo] password for debian: temppwd
02 00 0f 00 80 80 80 00
debian@arm:~$ cat /run/input.txt
02 00 0f 00 80 80 80 00debian@arm:~/USBProxy/switchpad$
完全置き換えを終了するには以下のようにgeninput
を実行するなどして/run/input.txtを削除します。
debian@arm:~/USBProxy/src$ sudo ./geninput -rm
[sudo] password for debian: temppwd
debian@arm:~$ cat /run/input.txt
cat: /run/input.txt: No such file or directory
debian@arm:~/USBProxy/src$
shutdown
コマンド等を利用する必要があります。以下のようにshutdown
コマンドを実行すると、終了作業が実行され最終的にBeagleBone Black上の4つのUSER LEDSが全て消灯します。
debian@arm:~/USBProxy/src$ sudo shutdown -h now
[sudo] password for debian: temppwd
Broadcast message from root@arm (pts/0) (Wed Mar 10 10:39:51 2021):
The system is going down for system halt NOW!
debian@arm:~$ Connection to arm.local closed by remote host.
Connection to arm.local closed.
user@pc:~$
電源ケーブル(SwitchとBeagleBone Blackを接続しているUSBケーブル)を取り外すことで強制終了もできます。強制終了した場合でもMicroSDカードのファイルシステムが破損することはないと思いますが、直前に編集したファイル等の内容が破損するかもしれないのでご注意ください。また、/runディレクトリはメモリ上に作成されるファイルシステムをマウントして利用しているため終了時に内部のファイルは全て削除されます。
それではwhoami版USBProxyを利用して実際にアナログスティックの出力値とソフトドリフトの関係を少し調べてみましょう。
まずはソフトドリフト境界の一つを確認してみましょう。
ブーストカウンタが5増加するようになる座標は全てソフトドリフトの境界角度の座標(左方向(0,3)、右方向(255,4))に変換されるように/run/rules.txtを生成します。以下のコマンドで/run/rules.txtを生成できます。
debian@arm:~/USBProxy/switchpad$ sudo rm /run/rules.txt
[sudo] password for debian: temppwd
debian@arm:~/USBProxy/switchpad$ sudo touch /run/rules.txt
debian@arm:~/USBProxy/switchpad$ sudo chmod 666 /run/rules.txt
debian@arm:~/USBProxy/switchpad$ ./genrules_softdrift.sh 0,3 255,4 > /run/rules.txt
debian@arm:~/USBProxy/switchpad$
次にコントローラの"+"ボタンを押して設定ファイルをリロードします。この状態でSwitchの設定から"コントローラーとセンサー > スティックの補正"を開いて左スティックを押し込みます。左や右にスティックを倒してみると強制的に45度付近の座標に変換されているのが分かると思います。この状態でマリオカート8デラックスでプレイしてみると斜め入力の限界角度まで倒した時の車体の動作の感覚がなんとなく分かると思います。
次に以下のようにブーストカウンタが5増加するようになる座標は全てソフトドリフトの範囲外となる座標(左方向(0,2)、右方向(255,3))に変換されるように/run/rules.txtを生成します。これによりブーストカウンタが5増加するドリフトができなくなります。
debian@arm:~/USBProxy/switchpad$ sudo rm /run/rules.txt
[sudo] password for debian: temppwd
debian@arm:~/USBProxy/switchpad$ sudo touch /run/rules.txt
debian@arm:~/USBProxy/switchpad$ sudo chmod 666 /run/rules.txt
debian@arm:~/USBProxy/switchpad$ ./genrules_softdrift.sh 0,2 255,3 > /run/rules.txt
debian@arm:~/USBProxy/switchpad$
再びコントローラの"+"ボタンを押して設定ファイルをリロードします。この設定ではドリフト中に曲がる量は先程の設定とほとんど同じにもかかわらず、なかなかミニターボ発動可能状態にならないということが実感できると思います。
今回行った実験ではアナログスティックの座標が(0,3)や(255,4)の時のドリフトではブーストカウンタが早く溜まるけど、(0,2)や(255,3)の時はなかなか溜まらないということを確認しました。このようにコントローラがSwitchに出力するアナログスティックの座標をいろいろと変換して実行してみることで、各座標でのブーストカウンタの溜まる時間の変化や車体の曲がり方の変化を確認することができます。
次にコントロールの自動実行を試してみます。
高精度な操作タイミングでの自動実行はできないので細かな調査には利用できませんが、精度を気にせずに同じ処理を何度も繰り返す場合に利用できます。基本的には先に説明したgeninput
コマンドをタイミングよく実行するスクリプトを書いて実行すれば実現できます。ということでサンプルとしてgen_drift.sh
というスクリプトを作ってみたのでそれを使ってみます。gen_drift.sh
の中身は以下の通りです。
#!/bin/sh
./geninput -A
sleep $1
./geninput -A -leftx $3 -lefty $4 -ZR
sleep $2
./geninput -rm
例えば、走り始めて1秒後に座標(0,3)の左ドリフトを開始しその10秒後に停止する、という自動制御は以下のような引数でgen_drift.sh
を実行することで実現できます。
debian@arm:~/USBProxy/switchpad$ sudo ./gen_drift.sh 1 10 0 3
[sudo] password for debian: temppwd
04 00 0f 80 80 80 80 00
84 00 0f 00 03 80 80 00
debian@arm:~/USBProxy/switchpad$
壁にぶつかるなど停止することがないように注意する必要がありますが、このコマンドの引数を少しずつ変化させながら何度も実験を行うことでブーストカウンタの増加量が5となる座標の範囲を調べていくことができます。ミニターボが発動可能状態となるまでの実際の時間は別途キャプチャボード等でプレイ動画を録画しておき、ドリフト中のフレーム数を数えることで調べることができます。
このページではソフトドリフトの斜め入力境界角度の調査を行うのに利用したシステムの構築方法と利用方法について説明しました。 このシステムではUSBコントローラから出力されたアナログスティック値を厳密な値に変換するためにBeagleBone Blackとwhoami版USBProxyを利用しました。 データロスや遅延等が発生するため常用するには適しませんが設定ファイルに記述した通りの厳密なコントローラ出力を実現することが可能となっています。 また、マリオカート8デラックスのソフトドリフトの調査に利用するために構築したシステムですが、その他の用途にも利用できるかもしれません。
稚拙な説明で分かりにくい部分が多々あると思いますが、このページで書かれている内容が少しでもお役に立てば幸いです!
#!/bin/sh
while :; do
./geninput -leftx 0 -lefty 0 -rightx 255; sleep 0.2
./geninput -leftx 128 -lefty 0 -rightx 255; sleep 0.2
./geninput -leftx 255 -lefty 0 -rightx 255; sleep 0.2
./geninput -leftx 255 -lefty 128 -rightx 255; sleep 0.2
./geninput -leftx 255 -lefty 255 -rightx 255; sleep 0.2
./geninput -leftx 128 -lefty 255 -rightx 255; sleep 0.2
./geninput -leftx 0 -lefty 255 -rightx 255; sleep 0.2
./geninput -leftx 0 -lefty 128 -rightx 255; sleep 0.2
done