Skip to content

Yoshi-0921/toio_API

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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()