toioで12台使ってダンスさせたハナシ

こんな感じのコンテンツを作った時の話です。
[![Image from Gyazo](https://i.gyazo.com/a3b3d6b4a4c94ddb1f7f28cc3bb12898.gif)](https://gyazo.com/a3b3d6b4a4c94ddb1f7f28cc3bb12898)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ついに完成しました！ユニティちゃんとtoioが音楽に合わせて踊ります！超気合入った作品なので是非見てください！<br><br>・ビートに合わせて踊る<br>・限界の１２台接続<br>・ぶつかりそうでぶつからない<br><br>続き→ <a href="https://t.co/pmuPGYne8Y">https://t.co/pmuPGYne8Y</a> <a href="https://twitter.com/hashtag/toio?src=hash&amp;ref_src=twsrc%5Etfw">#toio</a> <a href="https://twitter.com/hashtag/Unity?src=hash&amp;ref_src=twsrc%5Etfw">#Unity</a> <a href="https://twitter.com/hashtag/%E3%83%AD%E3%83%9C%E3%82%84%E3%82%8D?src=hash&amp;ref_src=twsrc%5Etfw">#ロボやろ</a> <a href="https://t.co/KnejK3uvMy">pic.twitter.com/KnejK3uvMy</a></p>&mdash; 伊藤周@オーナカ (@warapuri) <a href="https://twitter.com/warapuri/status/1333019634652483585?ref_src=twsrc%5Etfw">November 29, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

フル動画 → [Unity-Chan AR Concert with toio dancers](https://youtu.be/V0K3u6ffla8)

## アイディア出し

最初[「ロボットやろうぜ！- toio & Unity 作品動画コンテスト」](https://toio.io/blog/detail/20200930-2.html)の話を聞いた時考えたのが、以下のアイディアでした。

- 多数台のロボットでダンスしたら面白いんでは？
- それも音楽のビートに合わせてやったらアガるんでは？
- 後半、↓な感じに動かしたらさらにアガるんでは？
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">明後日から東京藝大卒業作品展が始まります！<br><br>僕の展示会場はロビー階の第３展示室です。<br>毎日作品横にいる予定なので、近くに来た際にはぜひ足を運んでみてください！<br><br>第67回　美術学部/大学院美術研究科　卒業・修了作品展<br>1月28日(月)〜2月3日(日)9:30〜17:30まで<br>※最終日は9:30〜12:00まで <a href="https://t.co/2SKOq40XWZ">pic.twitter.com/2SKOq40XWZ</a></p>&mdash; Shun Onozawa (@jugbounce) <a href="https://twitter.com/jugbounce/status/1089124842996027394?ref_src=twsrc%5Etfw">January 26, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

特に３つ目が是非やりたかったんですねー（それが後に地獄をみることになるんですが...）

で最大何台繋がるか？というのが疑問だったのですが、toioのUnity SDK開発されているモリカトロンさんが直々にやっているのを参考にしたところ

https://tech.morikatron.ai/entry/2020/04/23/150000

> iPhone 11でトライしたところ、無事に12台の鬼ごっこが、スムーズに動くようになりました。

と書いてあったので、勝手に

「つまり、iPhone11で12台なら、iPhone12なら12台以上もいけるんでは！？いや、きっと余裕だろう！」

と脳内翻訳して、とりあえず16台買ってみました。
ところが１６台toioもなかなかなくて、結局ソニーストアで大量に注文することになりました。

で届くまでシミュレーションでUnityエディタ上でガシガシ作っていったんです。

## 音楽にロボットを合わせるために

ビートに合わせるんだったら、以前買ったこれが役に立つだろうということで、

RhythmTool
https://assetstore.unity.com/packages/tools/audio/rhythmtool-15679?locale=ja-JP
[![Image from Gyazo](https://i.gyazo.com/e4f743051325372fe56c843d5f6973d7.gif)](https://gyazo.com/e4f743051325372fe56c843d5f6973d7)
これ、すごいんですよ。ビートのタイミングを勝手に検出してくれるので、音ゲーとかが簡単に作れるというもの。これを使ってビートのタイミングで動かすと言うことを考えたのです。

要はビートの瞬間に動かす→少し進んだら止める→待機→再びビートが来たら動かす

ということをすればダンスしている風に見えるんじゃないかと。

実際に作ったところ、なんか北朝鮮マスゲーム風になってきたけど、まあそれはそれで良いかなという感じ。

## レールに沿って動かす

マスゲーム的にするんであれば、いろんな形に動いたら良いんじゃないか、ということで以下のスプラインアセットを使いました。

Curvy Spline
https://assetstore.unity.com/packages/tools/utilities/curvy-splines-7038?locale=ja-JP
![今回使ったパス](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72960/a1e8953b-34c6-d114-2161-72dabd482d7c.png)
これ、使ってよかったです。後から「あーあそこやっぱりもう少し移動をこうしたいな」思った時に、手軽にスプラインを修正するだけで済むので大変便利でした。
あと、スプライン曲線自体をPrefabにしておくだけで、その形状を使った他の箇所も連動してくれるので、変更の手間が最小限で済みました。

## 状態遷移を扱う

で、ですね。

toio Unity SDKを見ていくと、SDKの思想が
「マネージャーが全てを統括する」
という感じのC言語的な感じを受けたのです（個人的感想です）。
12台のtoioを制御するのも１つのマネージャークラスがそれを制御する、と。

いやー、それはキツいんじゃないかな、と感じたわけです。今回はそれぞれ一つ一つが自律しながら、協調するという複雑なことをやらせたいわけです。

今回は状態遷移を扱うわけだから、やはりtoio1台に対して一つの状態遷移を扱えないと手に負えないだろうと。なおかつ全体を統括する状態遷移も必要だと。

そこでやはり状態遷移はコーディングするんではなくて、ビジュアルスクリプトでやっていきたいわけです。

なぜ状態遷移はコーディングするのではなくビジュアルスクリプトしたいのか、というと

- 状態遷移は時が経つにつれて変異するので、コーディングでは見通しが悪い
- ビジュアルスクリプトは現在の状態が「見て」わかるので、デバッグしやすい
- 容易に修正できてビルドする必要がない

で、以前使っていたarborを使う選択肢もあったのですが、

arbor 3
https://assetstore.unity.com/packages/tools/visual-scripting/arbor-3-fsm-bt-graph-editor-112239?locale=ja-JP

今回は、ちょうどUnityがBoltを買収したということで、Bolt無料になったということで
Bolt
https://assetstore.unity.com/packages/tools/visual-scripting/bolt-163802?locale=ja-JP
![今回使った状態遷移図](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72960/182a4643-98a4-07fc-02a8-29258bfc2e26.png)
これを機会にBoltを本気で使ってみようということにしました。

## 実機で確認したらトラブル続出
それで、ようやく16台のtoioが到着したわけなのですが、実際にやってみると、まーいろんなトラブルが起こるわけです。

### トラブル1: Boltでエラーが出て実機で動かない

さあこれでiPhone用にビルドして動かしてみるかーと、実機で動かそうとしたところ以下のエラーが出ました。

```
ExecutionEngineException: Attempting to call method XXX for which no ahead of time (AOT) code was generated.
```

こういう時は落ち着いて、エラー文をコピーしてググるのが一番ですね。
以下のサイトに書いてました。

【Unity】Boltで作ったゲームでAOTのエラーが出るときの対処
https://ekulabo.com/bolt-aot-pre-build

つまり、BoltをiPhoneで使う場合は「Tools > Bolt > AOT Pre-Build」を事前にしておけよ、ということでした。
Pre-Buildしてみて、再度ビルド＆インストールしたところ正常に繋がる動作が始まりました！

### トラブル2: 16台は繋がらなかった
まず16台繋がらない。
それ以前に12台も繋がらない。繋がるのは8台だけでした。

「おかしい…　ちょっと試した時は確実に12台繋がったのに、後でやったら8台以上行かない…。そんなバカな話があるだろうか？」

いよいよおかしいので、iPhoneのBluetoothを再起動させたら、12台までは繋がるようになりました。
というわけで、
__多数台繋げれられない場合は、iPhoneのBluetoothを再起動__
を守りましょう。
あと、
__toioがiPhoneに繋がるのは12台まで__
ということが確定されました(2020/11/29現在)。まあ今後SDKの改善修正が入ったりすればできるかもしれませんが...。

### トラブル3: シミュレーションと実機とで動きが違う
1台2台で動かしている時はまあそんなに気にならないのですが、12台で動かしているとなんか動きがカクカクするのです。そうなると肝心の後半の連携した動きがうまくいかないのです。完全に連携した動きじゃないと必ずぶつかってしまうのです。
[![Image from Gyazo](https://i.gyazo.com/a71059b76d72374800632b7f021bb006.gif)](https://gyazo.com/a71059b76d72374800632b7f021bb006)

### トラブル4: いきなりBluetooth通信が切れる
トラブル3と合わせて問題となったのが、いきなり通信が切れてしまうのです。エラーメッセージは出ているのですが詳しい内容まではわかりません。

以下のドキュメントを見てみると、どうやら Move2Targetに代表されるClosed-Loopメソッド は通信量が多いようです。

https://github.com/morikatron/toio-sdk-for-unity/blob/develop/docs/usage_cubehandle.md#25-closed-loop-メソッド

通信料が多いことでトラブル3と4が起こっているのではないかと予想しました。

## 通信量をいかに下げるか

Closed-Loopメソッドは呼び続けるから通信量が多くなるようです。
一方、One-Shotメソッドというのは一回だけ呼ぶので、通信料が減るようです。

しかし、ではOne-Shotメソッドに全て変更すればOK、というわけにはいかないのです。
One-Shotメソッドはその名の通り呼びっぱなしなので、最終的な到着地が指定できません。

つまり

`A地点に行け`

とClosed-Loopメソッドで指定できたのに、

`右にX度回転して、前に10ぐらい進んで`

というようにOne-Shotメソッドで指定するわけです。
（ちなみに距離の指定も謎の単位系で、「10cm」とかで指定できない）

これでは細かい多数台連携などできるわけがありません。

ではどうしたか。

正確を要する場面はClosed-Loopメソッドで、とりあえず適当で良い場面はOne-Shotメソッドでという混合で行うことにしました。（具体的に書くと、直線でガーっと行く場面では必ず指定の場所へ行って欲しいのでClosed-Loopメソッドで到達地点を指定し、その後回転して次のスタートラインに着くまではOne-Shotメソッドでなんとかたどり着かせる）

そして、Closed-Loopメソッドも極力連続で呼ばないように非同期で分散して呼ぶようにしました。

つまり、全体的に通信量を下げたわけです。

それでようやくちゃんと動くようになりました。

[![Image from Gyazo](https://i.gyazo.com/9398652fe5c53b71636f15c600b8dd66.gif)](https://gyazo.com/9398652fe5c53b71636f15c600b8dd66)

## 作業を終えて

ロボット制御は今回初めてで確かに難しかったのですが、とっても楽しかったです！やっぱり実体のモノを動かすというのは面白いですね！

是非皆さんもtoioを買ってUnityで遊んでみてはいかがでしょうか。