初めに
初めまして、大学院生のヨッシーです。初めてのQiita投稿なので不慣れながらも頑張ります!
遅ばせながら、最近になってtoio買いました。ちょこちょこ動く姿が可愛いんですよねぇ。
ところで、最近toioの技術仕様書も公開されたということで、試しに私のMacBookからBLE通信で操作を試したのですが、、、、
操作が難しい。
Characteristics?リトルエンディアン?などなど、バイト配列でtoioにデータを送り込むみたいですが、もっと直感的にtoioを操作したい!
ということで、Pythonで直感的なtoio操作のAPIを作成したのでこちらで紹介していきます。
前準備
こちらのレポジトリを基に話を展開していきます。
クローン後、該当ディレクトリにて$ pip install -e .
を実行してください(場合によってはsudoで)。
動作環境
- macOS Big Sur (M1 chip)
- Python 3.8.5
- bleak 0.11.0
まずは接続してみる
discover_toios
まずはご自身のPCがtoioを認識するかのテストをします。ここでは、discover_toios
というmethodを使います。試しに、toioが見つからない場合、一つ見つかった場合、二つ見つかった場合を示しています。
import asyncio
from toio_API.utils.general import discover_toios
if __name__ == '__main__':
toio_addresses = asyncio.run(discover_toios())
出力結果:
$ python tmp.py
[INFO] [2021-04-27 10:20:58,068] [general.py:49]
No toio discovered :(
$ python tmp.py
[INFO] [2021-04-27 10:21:09,650] [general.py:47]
1 toio discovered: ['33139358-E12D-45F8-9B83-A23EBC3CDD58']
$ python tmp.py
[INFO] [2021-04-27 10:21:25,622] [general.py:47]
2 toio discovered: ['B62DBD30-1D16-4796-A60F-E76903A3BEF0', '33139358-E12D-45F8-9B83-A23EBC3CDD58']
BLE通信が可能なtoioのBLE addressをリストで返します(これ意外と便利)。
create_toios
次に見つけたtoioに名前をつけてプログラムで扱いやすくするためにregisterしていきます。
ここではcreate_toios
というmethodを使います。
import asyncio
from toio_API.utils.general import create_toios, discover_toios
if __name__ == '__main__':
toio_addresses = asyncio.run(discover_toios())
toios = create_toios(toio_addresses=toio_addresses)
出力結果:
$ python tmp.py
[INFO] [2021-04-27 10:27:12,504] [general.py:47]
2 toio discovered: ['B62DBD30-1D16-4796-A60F-E76903A3BEF0', '33139358-E12D-45F8-9B83-A23EBC3CDD58']
[INFO] [2021-04-27 10:27:12,506] [general.py:30]
2 Successfully registered the toio: ['toio_0', 'toio_1']
この時、toioに名前をつけることができます!デフォルトではtoio_#
ですが、以下のように任意の名前をつけてあげることもできます。
import asyncio
from toio_API.utils.general import create_toios, discover_toios
if __name__ == '__main__':
toio_addresses = asyncio.run(discover_toios())
toios = create_toios(toio_addresses=toio_addresses, toio_names=['Yoshi', 'Moto'])
出力結果:
$ python tmp.py
[INFO] [2021-04-27 10:27:43,762] [general.py:47]
2 toio discovered: ['B62DBD30-1D16-4796-A60F-E76903A3BEF0', '33139358-E12D-45F8-9B83-A23EBC3CDD58']
[INFO] [2021-04-27 10:27:43,764] [general.py:30]
2 Successfully registered the toio: ['Yoshi', 'Moto']
やっぱり名前つけてあげたほうが愛着湧きますよねぇ笑
connect
・ disconnect
ここからは非同期処理を実際に扱っていきます。
toioをBLE通信で接続するmethodであるconnect
、及び接続解除するmethodのdisconnect
はasync def
で実装されているため、複数体のtoioを扱う場合は以下のように新しい関数connect_disconnect()
を作成します。
この関数は複数toioを一秒間だけ接続し、その後接続解除しています。
import asyncio
from toio_API.utils.general import connect, create_toios, disconnect, discover_toios
async def connect_disconnect(toios):
await asyncio.gather(*[connect(toio) for toio in toios])
await asyncio.sleep(1)
await asyncio.gather(*[disconnect(toio) for toio in toios])
if __name__ == '__main__':
toio_addresses = asyncio.run(discover_toios())
toios = create_toios(toio_addresses=toio_addresses, toio_names=['Yoshi', 'Moto'])
asyncio.run(connect_disconnect(toios))
出力結果:
$ python tmp.py
[INFO] [2021-04-27 11:19:50,834] [general.py:47]
2 toio discovered: ['33139358-E12D-45F8-9B83-A23EBC3CDD58', 'B62DBD30-1D16-4796-A60F-E76903A3BEF0']
[INFO] [2021-04-27 11:19:50,836] [general.py:30]
2 Successfully registered the toio: ['Yoshi', 'Moto']
[INFO] [2021-04-27 11:19:52,551] [general.py:62]
[Yoshi] Successfully connected the toio!
[INFO] [2021-04-27 11:19:53,069] [general.py:62]
[Moto] Successfully connected the toio!
[INFO] [2021-04-27 11:19:54,108] [general.py:79]
[Yoshi] Successfully disonnected the toio!
[INFO] [2021-04-27 11:19:54,171] [general.py:79]
[Moto] Successfully disonnected the toio!
無事に接続、接続解除ができていることが確認できますね。
動かしてみる
最後にtoioに一秒間の回転運動をしてもらいます。
これまでの手順通りtoioを接続した後に、toioのモーターをtoio.motor
を使って制御するコマンドを入力します。ここでは最もシンプルなtoio.motor.control
というモーター駆動コマンドを実行します。デフォルトで回転運動します。
import asyncio
from toio_API.utils.general import connect, create_toios, disconnect, discover_toios
async def kaiten(toios):
await asyncio.gather(*[connect(toio) for toio in toios])
await asyncio.gather(*[toio.motor.control() for toio in toios])
await asyncio.sleep(1)
await asyncio.gather(*[disconnect(toio) for toio in toios])
if __name__ == '__main__':
toio_addresses = asyncio.run(discover_toios())
toios = create_toios(toio_addresses=toio_addresses, toio_names=['Yoshi', 'Moto'])
asyncio.run(kaiten(toios))
簡単ですね、一行加えるだけで回転運動を非同期でさせることができました。
デモ動画も用意したので是非確認してみてください!
最後に
今回は自作APIでtoioをpythonで簡単に非同期制御することを目標に進めてきました。
無事できてよかったです笑
モーター以外にも他にも様々な機能のAPIも合わせて実装したのでこれから時間があればじゃんじゃん紹介していけたらと思います!
続き
- その他の
toio.motor
のコマンド紹介 - その他諸々