Skip to content

Latest commit

 

History

History
161 lines (121 loc) · 6.21 KB

README.md

File metadata and controls

161 lines (121 loc) · 6.21 KB

Simple toio API for Python Users


WebsiteAboutHow To UseExamplesCustomsCommunityLicense

About

This is unofficial toio control API for python users. Suitable to handle asynchronous operations using several toio cubes.

これはtoio好きのtoio好きによるtoio好きのための非公式APIです。Pythonで複数のtoioキューブを非同期制御したい方向けのライブラリです。

How To Use

基本的に$ python main.pyまたは$ python gui_main.pyで実行できます。toioの行動パターンは実装した「シナリオ」に基づいており、例として以下の4つのシナリオを用意しています。

spinrun_spinchasecollision_avoidance

main.pyではmake_scenario(scenario_name='spin', ...)がデフォルトで設定されていますが、その他のシナリオでtoioを制御したい場合は該当するシナリオ名に変更してください。

# main.py

import asyncio

from toio_API.scenarios import make_scenario
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'])
    scenario = make_scenario(scenario_name='spin', toios=toios)

    scenario.run()

その他

  • asyncio.run(discover_toios()): 接続可能なtoioを見つけます。発見できた場合、そのtoioのBLE_addressがリスト型で返されます。
  • create_toios(toio_addresses): 見つけたtoioのBLE_addresを基にtoio制御クラスを作成します。引数に名前も設定できます。
  • make_scenario(toios): toioの行動パターンを決めるシナリオを作成します。この時、自動的にtoioとのBLE通信が開始されます。
  • scenario.run(): 作成したシナリオを実行します。 

gui_main.pyを実行すると以下のようなGUIがが出力されます。左下のバーより任意のシナリオを選択してRun toioを押してください。

GUI

Examples

4つのシナリオの実装コードです。たったの数行のコードでtoioを簡単に制御できます。

Spin

toioがグルグルとその場で回転して、5秒後に停止します。

# scenarios/examples/spin.py

class Spin(AbstractSenario):
    async def _main(self):
        for _ in range(50):
            await asyncio.gather(*[toio.motor.control() for toio in self.toios])
            await asyncio.sleep(0.1)

Demo video clip

Run and Spin

toioが1秒間走り、その後1秒間スピンします。

# scenarios/examples/run_spin.py

class RunSpin(AbstractSenario):
    async def _main(self):
        await asyncio.gather(*[self.__run_spin(toio) for toio in self.toios])

    async def __run_spin(self, toio: Toio):
        await toio.motor.control(left_speed=100, right_speed=100)
        await asyncio.sleep(1)
        await toio.motor.control(left_speed=-100, right_speed=100)
        await asyncio.sleep(1)

Demo video clip

Chase

2体以上のtoioが必要です。1体のtoioに目掛けてその他のtoioが追いかけます。

# scenarios/examples/chase.py

class Chase(AbstractSenario):
    async def _main(self):
        for _ in range(50):
            response = await read_information(self.toios)
            await asyncio.gather(*[self.__chase(toio, toio_idx, **response) for toio_idx, toio in enumerate(self.toios)])
            await asyncio.sleep(0.1)

    async def __chase(self, toio: Toio, toio_idx: int, **kwargs):
        if toio_idx == 0:
            await toio.motor.acceleration_control(rotation_speed=90)
        else:
            await toio.motor.target_control(
                max_speed=50,
                x_coordinate=kwargs[self.toios[0].name]['center_x'],
                y_coordinate=kwargs[self.toios[0].name]['center_y']
            )

Demo video clip

Collision Avoidance

2体のtoioが必要です。toioを互いの正面に向き合わせて実行します。初めに直進しますが、近づいたら衝突回避行動をします。

# scenarios/examples/collision_avoidance.py

class CollisionAvoidance(AbstractSenario):
    async def _main(self):
        for _ in range(50):
            response = await read_information(self.toios)
            await asyncio.gather(*[self.__chase(toio, toio_idx, **response) for toio_idx, toio in enumerate(self.toios)])
            await asyncio.sleep(0.01)

    async def __chase(self, toio: Toio, toio_idx: int, **kwargs):
        distance = math.dist(
            [kwargs[self.toios[0].name]['center_x'], kwargs[self.toios[0].name]['center_y']],
            [kwargs[self.toios[1].name]['center_x'], kwargs[self.toios[1].name]['center_y']]
        )
        if distance < 70:
            await toio.motor.control(-10, -10)
        else:
            await toio.motor.control(left_speed=50, right_speed=50)

Demo video clip

Customs

自分のオリジナルコードでtoioを制御する場合、scenarios/customs/に用意したカスタムシナリオにコーディングしてください(Custom1 ~ Custom3まで実装できます)。完成したらmain.pyでシナリオ名を'custom1'に変更して実行してみましょう!

# scenarios/customs/custom1.py

class Custom1(AbstractSenario):
    async def _main(self):
        raise NotImplementedError()