toio を Mac + Python で制御できるライブラリつくった

# はじめに

「あそんで学べる、ロボットトイ」toioは、
キューブを動かすためのBLEの通信仕様が公開されています


[コアキューブ技術仕様](https://toio.github.io/toio-spec/)

公式では、[javascriptライブラリ](https://github.com/toio/toio.js)がありますが、Python派のため
Mac + Python 環境で使えるライブラリを作成しました

↓↓↓
[非公式 Python ライブラリ(https://github.com/mizumasa/toio.py.git)](https://github.com/mizumasa/toio.py.git)

<img width="1377" alt="スクリーンショット 2018-04-08 22.49.47.png" src="https://toio.github.io/toio-spec/img/top_software.svg">


# できること

- 複数のキューブをBLE接続し、モーターやLED、サウンドをコントロールできる
- 位置座標の読み取り、ボタン、衝突判定などの基本的な状態読み取りができる

全ての仕様ではありませんが、基本的な制御を網羅しています
また、おまけの便利機能として

- toio.jsにも実装されている、特定の位置への移動コマンド
- 沢山キューブが発見されてしまった時に、キューブを見つけやすく、IDを振りなおせる機能
- キューブが手元にない環境でもダミーで実行できる機能

などの機能を盛り込んでいます


<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">toio Pythonライブラリ だいたいできた。目的地に移動するコマンドも実装済み <a href="https://twitter.com/hashtag/toio?src=hash&amp;ref_src=twsrc%5Etfw">#toio</a> <a href="https://t.co/vet0xsaRl0">pic.twitter.com/vet0xsaRl0</a></p>&mdash; 水落 大 mizumasa (@_mizumasa) <a href="https://twitter.com/_mizumasa/status/1149916127570477062?ref_src=twsrc%5Etfw">2019年7月13日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 手順

### 環境
- MacBook Pro (2.7 GHz Intel Core i5,16 GB 1867 MHz DDR3)
- macOS Mojave
- Python 2.7

### 環境構築

Python用のBLEライブラリとして、[Adafruit Python BluefruitLE](https://github.com/adafruit/Adafruit_Python_BluefruitLE)をインストールします

PyObjCも必要ですので入っていない場合は先にインストールしておきます。

```
$pip install pyobjc <- すでにある場合はスキップ

$git clone https://github.com/adafruit/Adafruit_Python_BluefruitLE.git
$cd Adafruit_Python_BluefruitLE
$sudo python setup.py install
```

続いて、今回のライブラリをクローンします

```
$git clone https://github.com/mizumasa/toio.py.git
$cd toio.py
```

環境構築は以上です

### サンプル実行

toioキューブの電源を入れて、サンプルを実行しましょう

```
$python example.py 1
```
回ったり、光ったり、音がなったりしてBLEを切断して止まると思います

# 使い方

特にBLEの仕様を意識することなく、1行ずつ実行できるようになっています


```

>>> import toio
>>> T = toio.TOIO()
>>> T.connect()

>>> cubeID = 0
>>> T.write_data_motor(cubeID,100,0) # 左車輪だけ100の速度で前進
    
>>> r,g,b = 255,0,0
>>> T.write_data_light(cubeID,0,r,g,b) # LED赤(255,0,0)点灯

>>> T.write_data_sound(cubeID,0) # サウンドID=0を流す

>>> T.get_data_sensor(cubeID) # センサー状態取得
{'slope': 1, 'collision': 0}

>>> T.get_data_button(cubeID) # ボタン状態取得
{'button': 128}

>>> T.get_data_button(cubeID) # ボタン状態取得
{'button': 128}

>>> T.get_data_id(cubeID) #座標取得
{'cr': 253, 'cx': 345, 'cy': 167, 'sr': 253, 'sx': 341, 'sy': 177}

>>> T.move_to(cubeID,345,167, speed = 40, thr = 20) #指定座標に移動

>>> T.disconnect() # 切断してから終了

```

# その他の機能

### 複数台キューブに任意のIDを割り当てる

周りに、キューブが沢山ある時に、特定のキューブを0番として T.write_data_motor(0,100,100)などのように動かしたいと思った時に、点滅しているキューブに数字を割り当てるだけであとのコマンドがその数字とキューブを対応付けしてくれる機能です

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">toio Pythonライブラリ公開しました。<br>周りに沢山キューブがあった時に順番に数字を割り当てる機能を実装しています。<a href="https://t.co/8UiGrFhOmn">https://t.co/8UiGrFhOmn</a><a href="https://t.co/r9xx5PVvZ0">https://t.co/r9xx5PVvZ0</a><a href="https://twitter.com/hashtag/toio?src=hash&amp;ref_src=twsrc%5Etfw">#toio</a> <a href="https://twitter.com/hashtag/Python?src=hash&amp;ref_src=twsrc%5Etfw">#Python</a> <a href="https://t.co/Q0bk1hk97T">pic.twitter.com/Q0bk1hk97T</a></p>&mdash; 水落 大 mizumasa (@_mizumasa) <a href="https://twitter.com/_mizumasa/status/1149925953776148480?ref_src=twsrc%5Etfw">2019年7月13日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

上の例では、connectでsearchした時は４つありましたが、左から３つだけを使用して順番に0,1,2と番号を振り直しています。（一番右だけBLE切断します）


### キューブが手元にない時にも実行コマンドがエラーを吐かないようにする

T.connect()の前に T.noToio()と叩いておくと、キューブがなくても各種コマンドがダミーで実行されます


# 構成

ライブラリの構成ファイルは以下のようになっています

| Name | Description |
| ---------- | ------ |
| toio.py | メインクラス TOIO |
| toio_config.py | 共通固定値 |
| toio_message.py | BLE通信のためのデータ変換関数(他の環境でも使いまわせる) |
| toio_util.py | BLE通信クラス(Adafruit_Python_BluefruitLEにかなり依存している) |
| toio_func.py | 一般的な関数 |


以下、参考までにライブラリ化にあたってのポイントをまとめておきます

- BLEライブラリが内部でスレッド処理をしているので、TOIOクラスはBLEライブラリとSocket通信させています
- connect,disconnectを繰り返すとポート番号が50000からインクリメントされるようにしたのでどこかで他のプログラムとバッティングしないように注意してください
- BLEで返ってくる値はリトルエンディアン（組み込み久しぶりで忘れてた）
- toio_util.py を BLEライブラリに合わせて書き換えれば、windowsとかでも使えるはず
- toio_config.py の DEBUGをTrueにすれば、Notifyも一応取得してるのが見える