ソフトドリフトに関する調査(調査方法詳細)
〜マリオカート8デラックス版〜

著者: whoami
公開日: 2021年3月14日

目次

  1. はじめに
  2. 調査方法概要
  3. 必要機材
  4. セットアップ方法
  5. プログラム実行方法
  6. 調査例
  7. まとめ

はじめに

このページではソフトドリフトの入力方法について調査を行うにあたり利用した調査方法の概要、必要な機材、セットアップ方法、プログラム実行方法について説明します。機材の準備は少し手間で、実際に動作させるためにはLinuxの知識をある程度必要としますが、whoamiの調査環境をそのまま再現できます。

注意
細かな環境の違いにより再現できない可能性もあります。また、ここで紹介した方法だけが唯一の方法というわけではなく、これ以外の方法でも同様の実験は可能でしょう。

調査方法概要

コントローラのアナログスティックを正確に倒すのは基本的に不可能だと思います。また正確に調べられたとしてもコントローラの種類や個体差によって出力データに差異が生じることが考えられます。そこで、コントローラとSwitch本体の間でやりとりされているデータを直接利用することにしました。あまり手間をかけたくないということで、USB接続でプロキシ動作するものがないか検索したところ、USBProxyFacedancerが見つかりました。今回はUSBProxyに変更を加えてUSBコントローラとSwitchの間でデータ変換を行い正確なアナログスティックの値をSwitchに出力するようなwhoami版USBProxyを作成して利用しました。

Facedancerについて
FacedancerにはSwitchのプロコンを模擬するデモプログラムが添付されています。GreatFET Oneとデモプログラムを用いることでSwitchからプロコンだと認識されることまでは確認しました。それ以上の確認は行っていませんが、Facedancerを利用することで操作タイミングもより正確に制御されたコントローラ出力を行うことが可能かもしれません。

ここで実現するシステムは以下の図のようにコントローラから送信されたデータをwhoami版USBProxyが受信し、必要に応じてそのデータを変換しSwitchに送信します。これにより、正確に制御されたコントローラ出力を実現します。

必要機材

今回は以下の機器を準備し利用しました。PCはブロードバンドルータからIPアドレスを割り当てられてインターネット接続が可能であるものとします。

機器説明写真
BeagleBone BlackARM Cortex-A8プロセッサを搭載したシングルボードコンピュータです。whoami版USBProxyを動作させてホリパッドとSwitchの間でデータの変換を行います。
Nintendo SwitchとドックBeagleBone BlackとUSB接続を行うのでドックを利用します。もちろんディスプレイも準備します。ここで紹介する実験を行うだけであればインターネット接続は不要です。
PCMicroSDカードへの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 SwitchBeagleBone Blackに接続してUSBProxyに制御データを送信します。ここではブルーのホリパッドを利用しますが、標準色(ブラック)での動作実績もあります。
USBケーブル(Type A - Mini Type B)BeagleBone BlackとSwitchのドックへの接続に利用します。電源だけではなく信号もちゃんと送ることができるケーブルが必要です。
ネットワークケーブルBeagleBone Blackのネットワーク接続に利用します。
ブロードバンドルータBeagleBone BlackとPCのネットワーク接続に利用します。DHCPサーバとして動作しローカルエリアネットワーク内の機器のIPアドレス割り当て行います。また、NAT機能によりローカルエリアネットワークの機器からインターネットへの接続を実現します。もちろん、ブロードバンドルータを利用しない方法もありますがここでは説明しません。
注意
USB接続のコントローラとしてホリパッドを利用しました。ホリパッド以外で動作するかは分かりません。とりあえずホリパッド ミニでも試してみたのですが残念ながら動作しませんでした。またホリパッドであっても仕様変更等により動作しない可能性もあります。

whoami版USBProxyを利用して実験を行う際の接続は以下の通りになります。

セットアップ方法

ここではwhoami版USBProxyのセットアップ方法について説明します。行う作業は以下の2つです。

  1. MicroSDカードにOSイメージをコピー
  2. whoami版USBProxyのインストール

作業はBeagleBone BlackとPC(Linux)で行います。また、最初はPCでの作業となるためBeagleBone Blackの電源は接続しないでおきます。

1. MicroSDカードにOSイメージをコピー

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: 
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: 
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コマンドは少し時間(数分程度)がかかりますので、コマンド終了までのんびり待ちます。

sudoコマンド
上記の例ではumountddコマンドの実行にsudoコマンドを利用しています。sudoは一時的にスーパーユーザー権限でコマンドを実行するためによく利用されるコマンドです。以下の説明でも必要に応じてsudoコマンドを利用しています。
Raspberry Pi Imager
Raspberry Pi ImagerRaspberry Pi用のOSのディスクイメージをMicroSDカードに書き込むためのツールですが、任意のディスクイメージを書き込む機能も備えています。

2. USBProxyのセットアップ

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"になります。

BeagleBone Blackリモートログイン情報
ホスト名arm.local
ユーザIDdebian
パスワードtemppwd
user@pc:~$ ssh debian@arm.local
debian@arm.local's password: 
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$ 
BeagleBone Blackの名前解決
ここで利用するBeagleBone Blackの名前はarm.localですが、この名前からIPアドレスへの変換にはmDNSという仕組みを利用しています。最近のOSはmDNSを標準でサポートしているのが一般的ですが、もしもmDNSをサポートしていない場合には名前解決ができません。その場合には別の方法でBeagleBone BlackのIPアドレスを確認し、そのIPアドレスを用いてリモートログインする必要があります。

プログラム実行方法

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: 

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にする。
-AAボタンを押した状態にする。
-BBボタンを押した状態にする。
-XXボタンを押した状態にする。
-YYボタンを押した状態にする。
-LLボタンを押した状態にする。
-RRボタンを押した状態にする。
-ZLZLボタンを押した状態にする。
-ZRZRボタンを押した状態にする。
-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: 
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: 
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: 
debian@arm:~$ cat /run/input.txt
cat: /run/input.txt: No such file or directory
debian@arm:~/USBProxy/src$ 
BeagleBone Blackを終了させるには
BeagleBone Blackは電源ケーブルを接続するだけで起動しますが、正常終了させるためにはshutdownコマンド等を利用する必要があります。以下のようにshutdownコマンドを実行すると、終了作業が実行され最終的にBeagleBone Black上の4つのUSER LEDSが全て消灯します。
debian@arm:~/USBProxy/src$ sudo shutdown -h now
[sudo] password for debian: 

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: 
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: 
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: 
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
ポケモンでのタマゴ孵化
ソフトドリフトに関する調査に戻る