はじめに
Pybricks にはサブプロセスやスレッドはありませんが、v3.3よりコルーチンを利用した協調的マルチタスクをサポートしています。
CPython や 通常の MicroPython では asyncio モジュールを使うところでしょうが、Pybricksでは、APIの後方互換性やリソース削減の都合から、独自のマルチタスク機能を提供しています。
マルチタスク用のAPI
マルチタスクのための API は主に次の2つです。
from pybricks.tools import multitask, run_task
-
multitask(coroutine1, coroutine2, ...)
複数のコルーチンを実行するコルーチンを作成します。これによりマルチタスクが実現されます。 -
run_task(coroutine)
コルーチンを実行します。これはメインコルーチンの実行に利用します。
コルーチン化可能なAPI
Pybricks v3.3以降のドキュメントで await
プレフィックスのついた API はコルーチン化可能です。
たとえば Motor の API にある次のようなものです。
await run_time(speed, time, then=Stop.HOLD, wait=True)
このような API を await つきで呼び出すとコルーチンになり、await なしで呼び出すと従来どおりの呼び出しになります。
簡単な例
「きらきら星」を鳴らしながら、モーターをメトロノーム風に左右に反復させるデモです(あくまでメトロノーム風で厳密な動きはしていません)。スピーカ鳴らすのと、モーター動かすのを、それぞれ独立にコルーチンにし、マルチタスク実行しています。
from pybricks.hubs import PrimeHub
from pybricks.pupdevices import Motor
from pybricks.parameters import Port
from pybricks.tools import multitask, run_task
hub = PrimeHub()
notes = [
"C4/4", "C4/4", "G4/4", "G4/4", "A4/4", "A4/4", "G4/2",
"F4/4", "F4/4", "E4/4", "E4/4", "D4/4", "D4/4", "C4/2"
]
tempo = 120
motor_speed = tempo
motor = Motor(Port.A)
motor.reset_angle()
# きらきら星を演奏するコルーチン
async def kirakira():
await hub.speaker.play_notes(notes, tempo=tempo)
# モーターをメトロノーム風に左右に反復させるコルーチン
async def metronome():
for _ in range(len(notes)//2):
await motor.run_angle(motor_speed, 60)
await motor.run_angle(motor_speed, -60)
# メイン
async def main():
await motor.run_angle(motor_speed, -30)
await multitask(kirakira(), metronome())
await motor.run_angle(motor_speed, 30)
# 開始から終了までメインプログラムを走らせる。
run_task(main())