Toioで遊んでみる (1)

# Toioがやってきた！

発表時から気になっていたToio (https://toio.io/ )を入手した。アメリカでは売っておらず、Amazon Japanのglobal shippingにも対応しておらず、結局国際転送サービスのお世話になった。これは絶対に楽しいに決まってるやつや！
<img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465152/9a5e5849-726b-9b5f-4590-306f54d17a1e.jpeg"/> <img width="400" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/465152/e21405d5-3da7-a4a6-ae07-b5a64d3c0434.jpeg">

こいつ、動くぞ！
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">めだま生物 <a href="https://t.co/q8XXH1bQ9d">https://t.co/q8XXH1bQ9d</a></p>&mdash; Tomoto S. Washio (@tomoto335) <a href="https://twitter.com/tomoto335/status/1152037186687995904?ref_src=twsrc%5Etfw">2019年7月19日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 遊んでみよう！

製品としての遊び方も丁寧に作られていて非常にハイクオリティなのだが、ここではもちろんハッカー流の遊び方の話である。

Toioのキューブは仕様書 (https://toio.github.io/toio-spec/ )が公開されていて、これに従ってBLEでキューブを制御できる。このキューブの特筆すべき点は、**マット上に印刷された特殊なパターンとキューブに仕込まれたカメラにより、キューブの座標と姿勢を正確に把握できる**ということである。普通この手のロボットを正確な座標に向けて動かそうと思ったら、天井にカメラを付けて画像処理と組み合わせたり、かなりハードル高いのである。Toioならわりと簡単にこんな「一人サッカーロボット」とかできてしまう。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="en" dir="ltr">Toio project: Self-soccer Robot <a href="https://t.co/6gtgWZiquy">https://t.co/6gtgWZiquy</a></p>&mdash; Tomoto S. Washio (@tomoto335) <a href="https://twitter.com/tomoto335/status/1152037014537043968?ref_src=twsrc%5Etfw">2019年7月19日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

なお、キューブ操作用のライブラリは誰かが既に作っているかもしれないが、それに乗るだけでは「一番おいしいところを持ってかれる」ようなものなので自分で書く。車輪の再発明ﾄﾞﾝﾄｺｰｲ(ﾟ∀ﾟ)!!

## ソースコード

ここにどんどん放り込んでいくのでよろしく: https://github.com/tomoto/tomotoio

* 言語: Python 3.6
* OS: Linux (BLE通信にbluepyを使用しているので)
* ハード: Raspberry Pi 4 + Raspbian Stretchを使用。Windows 10上のVMwareではBLEが不安定で意図通り動かず。
* Python 3.6の仮想環境作って`pip install -e .`すれば使えるはず。

## キューブのスキャン

このへん: https://github.com/tomoto/tomotoio/blob/master/tomotoio/scanner.py

接続先キューブのMACアドレスはあらかじめスキャンしてファイルに書いておく。どうせ持ってるキューブは固定なので、root権限が必要なスキャン操作を毎回走らせるのはnonsenseという考え。スキャン処理自体はbluepyの基本機能だけででき、何の変哲もない。

## サンプルたち

この中にある: https://github.com/tomoto/tomotoio/tree/master/examples

簡単な順に紹介:
* `simple.py` 接続と切断だけの最小のサンプル。
* `soundeffects.py` プリセットの効果音を順番に再生する。
* `notifications.py` 位置・ボタン・動き情報のNotificationをコンソールにだらだら出力
* `rotate.py` キューブ#2の方向にキューブ#1を向ける。(めだま生物のキビキビ版)
* `symmetric.py` キューブ#2の点対称の位置にキューブ#1を移動する。
* `circle.py` キューブ#2を中心にキューブ#1を周回させる。
* `soccer.py` 上で紹介した一人サッカー。

なお `utils.py`にあるのはお決まりの初期化処理。接続時にキューブに光と音で「番号、いち！に！」と言わせるのはここ。

## 基盤機能

### キューブ操作

このへん: https://github.com/tomoto/tomotoio/blob/master/tomotoio/cube.py

インスタンスの入手は、このへん https://github.com/tomoto/tomotoio/blob/master/tomotoio/factory.py の関数にMACアドレスを指定して行う。以下のような操作ができる。

* `cube.xxx.get()` 属性値(toioID, motion, button, battery)の取得
* `cube.xxx.enableNotification()` Notificationの有効化(属性値が変化すると `cube.xxx.addListener()` で登録した関数が呼ばれる)
* `cube.setXxx()` モーター、音、光などの設定
* `cube.release()` 接続切断

「指定座標に移動」のような処理はこれだけではまだ難しいので、次回以降扱う。

### BLE通信

このへん: https://github.com/tomoto/tomotoio/blob/master/tomotoio/blepeer.py

見ての通り、bluepyの薄いラッパ。Notificationの処理は下記のようにちょっとめんどうなのでここに隠蔽する。
1. subscribeスレッドを上げて`waitForNotifications`呼び出しを回す
2. `writeCharacteristics`が`waitForNotifications`と被らないよう、write要求はスレッド間キューをかましてsubscribeスレッドの側で処理する

### BLEメッセージのエンコードとデコード

このへん: https://github.com/tomoto/tomotoio/blob/master/tomotoio/messages.py

仕様書をひたすら写経しただけ。エンコード前・デコード後のデータの入れ物は https://github.com/tomoto/tomotoio/blob/master/tomotoio/data.py で定義。

# 次回

[指定座標への移動などのナビゲーションの話、上で紹介した一人サッカーの話](https://qiita.com/tomoto335/items/eb6b814b5ebc08b0e82a)でもしてみよう。