Nintendo Switchでロボットを操作する
こんにちは。京大機械研の岩です。先日Nintendo Switchを買い、マイコンと通信してロボットを動かせるようにしてみたので記事にしておきます。
きっかけ
キャチロボバトルコンテスト第13回大会に出場するにあたり、Nintendo Switchをロボットのコントローラとして使えないか試してみることにしました。
早速Nintendo Switchのゲーム開発環境について調べてみますが、ネットの情報によるとどうやら経験のある開発者しか申請を通してもらえないなどの情報があり、ソフト屋さんではない私は直接の開発は諦めることにしました。
そこで出会ったのが「プチコン4」というゲームソフトです。
これはNintendo Switch内でプログラミングができる製品で、オリジナルのゲームを作ったり遊んだりできます。プログラムはBASIC言語で記述します。
このソフトを活用して”無理やり”外部のマイコンと通信し、ロボットを操作することにしました。
構成
プチコン4でUI制御とジョイコン情報の取得を行い、取得したデータを音声通信でヘッドホン出力からマイコンに流し込みます。これを元にロボットを操作します。
UI制御とジョイコン情報の取得
プチコン4側のプログラムです。
ボタンを長方形で描画し、タッチ座標を比較判定して、押されたボタンのIDを取得します。 ボタンの同時押しを非対応とすることでデータ量を減らしています。 ジョイスティックは中央+8方向のみとし、さらにデータ量を減らしています。
音声通信のプロトコル
0から9までの数値データを周波数変調し、音を鳴らす/止めるを繰り返すことで連続してデータを送信します。データの終了/開始点を明確にするため、データの末尾にストップビットを追加しています。 データを0から9までとしたのは周波数領域上でデータを密にしすぎるとマイコンでデータを受け取る時に隣同士の数値が間違って受け取られるためです。受信側アルゴリズムの工夫次第ではもっと詰められるとは思いますが。
プチコン4で音声通信
一桁ずつ音声信号に変調して出力します。基本的に各音階に1つの数字を0から9まで割り当てていますが、EとFやBとCなど近い周波数の音どうしは避けて変調しています。 プチコン4ではタイマー割り込みが使えず、また遅延命令がWAIT(1/60sec単位)しか使えないため、1/60secを単位として通信を行います。前述のプロトコルだと10進数で1桁のデータを送信するのに2/60secかかるので、通信速度は驚異の100bpsとなります。遅延を抑えるためにはデータ量の削減が必須です。
受信側
トランジスタで音声波形の正の部分だけを増幅し、マイコンで読みやすいパルスに変えます。抵抗値は適当に手元にあった10kにしました。
TP1の波形です。
TP2の波形です。
回路さえできればあとはマイコン側で復調するだけです。割り込みでパルスの幅を測って比較し、ボタンIDとジョイスティック方向IDを得ます。
動作の様子
受信したデータをターミナルに吐いてみます。
Switchとラズピコで通信できた! pic.twitter.com/ZseGIJiHV7
— 岩 (@iwamechatronics) 2023年7月24日
音声信号は可聴領域なのでイヤホンプラグを外すと特徴的な通信音が出ます。
黎明期のインターネット? pic.twitter.com/smhxHXJaXP
— 岩 (@iwamechatronics) 2023年7月21日
課題点
今回実装した方法だと通信が遅く最大遅延が150msも出てしまいます。もっと速くSwitchからデータを送る方法を模索しないといけませんね。
画像による転送やステレオ音声を使った並列化など手段はまだまだありそうです。
追記
通信方式を見直して送信周期を15ms程度にまで改善することができたので、追記しておきます。
プチコン4側のプログラムです。PCMSTREAMという任意波形を生成できる関数を使って通信します。
L出力にクロック信号、R出力にデータ信号を流し、同期通信を行います。
波形は以下の通りです。SPIもどきと言ったところでしょうか。
Switchの音声出力にはDCカット回路が入っているようなので、電圧の時間平均が0になるように波形が少々変則的になっています。
データ信号の生成部です。8bit幅のデータ×5を1bitずつ処理してPCMSTREAMする波形配列を作っています。
実際の通信波形です。上がデータ、下がクロックです。PCMSTREAMの性能上かなり歪んだ方形波になっています。
受信側は前回同様トランジスタで検波、増幅し、マイコンで信号を受け取ります。
クロックの立ち上がりエッジでデータのHIGH/LOWを読み込み、1bitずつ復調します。
プログラムは省略します。
これでなんとか実用できそうな通信が実現できました。