toio playground (toio javascript libraryを使ってみた)

これはSony Interactive Entertainment Inc.の [toio](https://toio.io)の [toioの技術仕様](https://toio.github.io/toio-spec/) と [javascript library](https://github.com/toio/toio.js) が公開されたのを受けて、[トイオ・コレクション](https://toio.io/titles/toio-collection.html) 付属のプレイマットを使った経路設定、編集、経路追従するプログラムを作成してみた記事です。



## はじめに

### toio（トイオ）とは

 toioについては[toioとは](https://toio.io/about.html)のページを、toioのコンセプトは[開発者インタビュー](https://toio.io/interview.html)で何を実現したかったのか熱く語られていますのでご参照ください。

### toioのjavascriptライブラリについて

このtoioのロボットであるtoioコアキューブはBluetoothでtoioコンソールと通信して動くようにできています。
先日公開されたtoio javascriptライブラリを入れることでNode.jsからコアキューブを直接制御することが可能になりました。

## toio playground

本記事のtoio playgroundはtoio javacriptライブラリを使ってNode.jsで動作するwebアプリケーションです。

toioのプレイマットに対応するweb画面上のplayground（下の画面）にコースを描き、Runすることでtoioコアキューブがプレイマットの上で同じ軌跡を描くというものです。

![playground](https://raw.githubusercontent.com/mnakada/toio-playground/images/toio-playground.jpg)



## 動作環境

- macOS 10.14(Mojave)で確認

  他の環境は未確認

- Node.js  Ver.10.15.3で確認 

  Ver.8以降なら多分OK



## 使い方

以下、MacOS環境です。

ターミナルを起動し、適当な場所にgit cloneします。

```
> git clone https://github.com/mnakada/toio-playground.git
> cd toioplayground
> npm i
> npm run build
> npm run local
```

これでlocalにweb serverがport 10010で起動します。

ブラウザで [http://localhost:10010](http://localhost:10010) を開くとplaygroundが開きます。



次にトイオ・コレクション付属のプレイマットと充電済みのコアキューブを用意します。

コアキューブの電源を入れるとターミナルに

```
Toio Linked!
```

と表示されます。（されない場合、MacOSのBlueTooth接続が可能な状態かどうか確認してください）



ここからの使い方は一度、下のビデオを参照ください。

[![](https://img.youtube.com/vi/fi6TMiUDdPI/0.jpg)]( https://youtu.be/fi6TMiUDdPI)



コアキューブをプレイマットの適当な位置に置きキューブの後ろ寄り（toioと側面に書かれているのと反対側）を上から押すことで底面の機能ボタンを押します。

webのplayground画面では機能ボタンが押されたマット上の位置と同じ場所にポイントが置かれていくので、プレイマット上で適当に場所をずらしながらキューブを使ってポイントを置いていってください。

置かれたポイントをつなぐようにベジェ曲線が引かれていきます。



playground上のポイントとポイントから生えているハンドルを使って曲線を操作することができます。

また、ポイント間の曲線にマウスカーソルを合わせて１秒間グラブ（マウスの左ボタンを長押し）することでポイントを追加できます。

ポイントにマウスカーソルを合わせて'delete'キーを押すことでポイントを削除することもできます。



経路の曲線ができたら、プレイマット上にコアキューブを置いてplaygroundの右上の `Run` ボタンを押すと経路曲線の入り口から出口までコアキューブが走ります。

`Export file` で経路曲線を.tpfファイルにExportします。
ファイルをplaygroundにDrag&Dropするか `Import file` で保存した.tpfファイルの経路データをImportすることができます。

playgroundの経路を消去するには `Clear` を押してください。



現状、コアキューブの電源が落ちたり、Bluetoothが切れたりした場合にはnode.jsのプログラムを再起動しないとコアキューブの再linkができません。

反応が無くなったら、ターミナルのnode.jsのプログラムをCtrl-Cで一旦止めて再度実行してください。



## プログラムについて

[GitHub mnakada/toio-playground](https://github.com/mnakada/toio-playground)に置いてあります。

簡単にプログラムの構造を説明します。

npm run localを実行するとnode backend/ToioPlayground.jsが起動されます。
ToioPlayground.jsはconfig.jsonファイルを読み込んで、backend/WebService.jsを呼び出します。
ここでWebServerを起動し、backend/ToioConnect.jsを起動します。

ToioConnect.jsはtoioのコアキューブの制御ライブラリを初期化し、コアキューブの座標情報をWebServiceに投げたり、Runした時のシーケンスを実行するプログラムになります。

ToioConnect.jsの中のMoveTarget()がコアキューブを自身の位置とtargetで与えられる目標位置から左右のタイヤの速度を計算して動かす部分になります。ここを色々と書き換えることでコアキューブが目標の経路にどれだけ追従するかをチューニングすることができます。

MoveTarget()は100ms後の目標位置を与えられ、目標との距離と角度差を計算して左右のタイヤの速度を設定します。このときspeedは距離に応じたコアキューブ自体の移動速度、dvは曲がるための左右のタイヤの移動速度との差分速度です。（速度の単位はタイヤの回転速度でx4.3rpm）

kはそのままだとカーブの収束が遅いので目標までの距離が遠い場合は早く収束しやすいようにかけている係数で、log10を使っているのは適当な係数のカーブを作るためで特に意味はありません。

MoveTarget()自体は100ms後のターゲットにむけて100msかけて移動するためのコードですが、100ms毎に呼び出すと動作がギクシャクすることになるので10ms周期で呼び出され、その度に100ms後の目標に向けて計算しています。

```javascript
  MoveTarget(target) {
    if(!this.cubePosition) return false;
    const distance = Math.hypot(target.x - this.cubePosition.x, target.y - this.cubePosition.y);
    if((this.runState !== 2) && (distance < 5)) {
      this.cube.move(0, 0, 0); // stop
      return false;
    }
    let realAngle = Math.atan2(target.y - this.cubePosition.y, target.x - this.cubePosition.x) * 180 / Math.PI - this.cubePosition.angle;
    realAngle %= 360;
    if(realAngle < -180) realAngle += 360;
    if(realAngle > 180) realAngle -= 360;

    let speed = distance + 10;
    if(speed > 100) speed = 100;
    const limit = speed;
    const k = Math.log10(distance); // slope factor
    let dv = realAngle * 0.4124 * k; // 13.3 * Math.PI / 180 * 100 * 60 / (430 * 12.5 * Math.PI * 0.1) / 2
    if(dv > limit) dv = limit;
    const lspeed = speed + dv;
    const rspeed = speed - dv;
    this.cube.move(lspeed, rspeed, 100);
    return true;
  }
```



frontend側でwebの画面を作っているのは、source/vueにあるvue.jsのプログラムです。

webpackでbundle fileにまとめられているのでbuild後の状態からはわかりにくいですが、source/index.htmlからsource/js/ToioPlayground.jsが呼ばれています。vue.jsの表示は以下の通りです。

​	TopMenu.vue : メニューを含めた画面全体

​	Trajectory.vue : コアキューブの通った軌跡を表現している赤い点のレイヤー

​	TopView.vue : BezierCurveEditor.vueのwrapperレイヤー

​	BezierCurveEditor.vue : ベジェ曲線、開始、終了点とハンドルを描画しているレイヤー

これらのレイヤーでbackendから投げられてくるコアキューブの座標情報を表現しています。

また、SVGのベジェ曲線へのGUIを表現しているのはBezierCurveEditor.vueですが、ポイントやハンドルの操作をデータに反映しているのはsource/js/GraphData.jsになります。



## おわりに

toioのjavascriptライブラリを使って簡単なwebアプリケーションを作ってみました。

目標へ移動するための左右のタイヤの速度を計算するところを色々試しているとコアキューブがあちこち走り回ったり、ぐるぐると回り始めてしまったりと楽しいことがたくさん起こります。

コースに綺麗に沿って急ターンも小回りで回れるのを探索するのは楽しいので是非書き換えて工夫してみてください。