稼働中

Raspberry Pi Pico(s_26)uasyncio の動作例 ThreadSafeFlag

uasyncio.ThreadSafeFlag()

Raspberry Pi PicoのMicroPythonにはmodule’uasyncio’があります。
uasyncioを使うと非同期動作するそうです。並行処理ができるようです。
module’uasyncio’にclass ‘ThreadSafeFlagがあります。

ThreadSafeFlagの使い方を他サイトなど調べて見ましたがよくわかりませんでした。
記事s_23で使ったフラグの代わり、記事s_24で使ったclass ‘Event’と同じように使うと動作しました。
(注意)本当に正しい使い方なのかは不明ですが記載しておきます。
素人なので詳しくはわかりません。わかる範囲で動作を確認しています。
※開発環境はThonnyです。ThonnyでMicroPythonをRaspberry Pi Pico with RP2040にインストールして使っています。

class ‘ThreadSafeFlag

class ‘ThreadSafeFlagにはset、waitのメソッドがあります。
tsf = uasyncio.ThreadSafeFlag()で初期化した場合の例になります。
■tsf.set()
フラグを設定します。フラグセット待ちのタスクが実行されます。
■tsf.wait()
フラグが設定されるのを待ちます。
すでに設定されていればすぐに戻ります。wait から戻ったときに自動的にフラグはリセットされます。

ThreadSafeFlag動作

ThreadSafeFlagの動作の雰囲気だけ確認します。
単純に以下の時間毎に経過時間を印字するだけの関数test1、test2とします。
test1 0.5sec間隔、経過時間を3回印字
test2 0.2sec間隔、経過時間を5回印字

test1はtsf.wait()でフラグセットまで待機。
test2は3回目にtsf.set()でフラグをセット、test1が実行される。
図にすると以下のような感じです。
0.4sec + αくらいでtest2がフラグをセット、test1が実行されます。
ThreadSafeFlag

以下のスクリプトで動作を確認しました


#ThreadSafeFlag_test_01b.py
import uasyncio
async def test1(tsf):
    global st       
    print('tsf.wait---')
    await tsf.wait()                # フラグセット待ち
    print('from wait--')
    for i in range(3):
        et=uasyncio.ticks()     # et-st 経過時間
        print(f'task1 ({i})s--- {et-st}')
        await uasyncio.sleep(0.5)  
     
async def test2(tsf):
    for i in range(5):
        et=uasyncio.ticks()
        print(f'task2 ({i})s--- {et-st}')
        if i==2:
            print('tsf.set----')
            tsf.set()               # 3回目にセット
        await uasyncio.sleep(0.2)
    
async def main():
    global st
    st=uasyncio.ticks()     #開始時間
    #ThreadSafeFlag オブジェクトを作成
    tsf=uasyncio.ThreadSafeFlag()    
    task1 = uasyncio.create_task(test1(tsf)) #tsf設定
    task2 = uasyncio.create_task(test2(tsf)) #tsf設定
    await task1
    await task2    
    et=uasyncio.ticks()
    print('end',et-st)
     
uasyncio.run(main())

実行すると以下のようになりました。
フラグセットされるまで待機しているのがわかります。


>>> %Run -c $EDITOR_CONTENT
tsf.wait---
task2 (0)s--- 29
task2 (1)s--- 230
task2 (2)s--- 432
tsf.set----
from wait--
task1 (0)s--- 434
task2 (3)s--- 634
task2 (4)s--- 835
task1 (1)s--- 935
task1 (2)s--- 1436
end 1937
>>> 

スクリプト

ThreadSafeFlagの動作が少しわかったので、LED1の点滅とIRセンサーの検出を常時行いながら、物体検出後に5回LED2を点滅をさせようと思います。(記事s_23記事s_24と同じ動作を確認します。)
IRセンサー FC51の外観、接続例は記事d_28を参照ください。
ほぼhttps://www.route55go.com/self-study/pico/class/s024_event/のEventの部分を置き換えた形になります。ThreadSafeFlagにはevent.clear()に応じたメソッドがありませんが、wait から戻ったときに自動的にフラグがリセットされるので問題ないようです。結果的には物体検出フラグを使った記事s_23と同じような動きになります。

スクリプトは以下のようにしました。


#ThreadSafeFlag_01b_event.py
from machine import Pin
import time
import uasyncio

#OUT Pin
led1=Pin(22, Pin.OUT, value=0)  #Y-LED
led2=Pin(26, Pin.OUT, value=0)  #R-LED

#FC-51 IR Detector IRsens Pin
dpin=Pin(27, Pin.IN, Pin.PULL_DOWN)  # 検知 dpin='L'

#LED1は常時点滅       
async def LED1():
    print('LED1------')
    while True:
        led1.high()
        print('LED1  on')
        await uasyncio.sleep(0.2)
        led1.low()
        await uasyncio.sleep(0.2)
        print('LED1  off')

#FC-51常時監視 検出したらevent.set
async def Sens(tsf):
    print('------Sens ')
    while True:        
        if dpin.value()==0:
            print('detect-----')
            #event.set()
            tsf.set()
        await uasyncio.sleep(0.5)
        print('------Check')
        
#検出まで待機、検出後 led2点滅 5回、event.clear()
async def LED2(tsf):
    while True:
        print('LED2  waiting ...')
        #await event.wait()
        await tsf.wait()
        for i in range(5):
            print(f'LED2  blink({i})')
            led2.high()
            await uasyncio.sleep(0.2)
            led2.low()
            await uasyncio.sleep(0.2)
        #event.clear()
        print('clear------')

#非同期処理
async def main():
    # Create an Event object.
    #event=uasyncio.Event()         #オブジェクトを作成
    tsf=uasyncio.ThreadSafeFlag()
    task1 = uasyncio.create_task(LED1())
    task2=uasyncio.create_task(LED2(tsf))
    task3=uasyncio.create_task(Sens(tsf))
    
    # Wait until the task is finished.
    await task1
    await task2
    await task3

uasyncio.run(main())

実行結果

結果は以下のようになりました。※Thonnyのshellに表示されます。
出力表示だけなのでわかり難いですがThreadSafeFlag動作でtask1、task2、task3が並行処理されています。


>>> %Run -c $EDITOR_CONTENT
LED1------
LED1  on            # LED1点滅
LED2  waiting ...   # tsf.wait()
------Sens 
LED1  off
LED1  on
------Check         # 検出確認
detect-----         # IRセンサ検知 > tsf.set()
LED2  blink(0)      # LED2点滅開始
LED1  off
LED1  on            # LED1点滅
LED2  blink(1)
------Check         # 検出確認
LED1  off
LED1  on
LED2  blink(2)
------Check
LED1  off
LED1  on
LED2  blink(3)
------Check
LED1  off
LED1  on
LED2  blink(4)
LED1  off
LED1  on
------Check
clear------
LED2  waiting ...
LED1  off
LED1  on
------Check
detect-----
LED2  blink(0)
LED1  off
LED1  on
LED2  blink(1)

省略

KeyboardInterrupt: 
>>> 

まとめ

uasyncioのclass ‘ThreadSafeFlagの使い方が少しわかったような気がします。