MicroPythonで経過時間の測定をしてみよう


マイクロビットのMicroPythonでプログラムが開始してから、何らかのアクション(今回はボタンAを押す)が実行された時の経過時間を表示したいとします。


MakeCodeであれば、



経過時間の計測用のずっとブロックと、ボタンA用のずっとブロックといった形でずっとブロックを2つ使ったり、



ボタンAのイベントを切り分ける事ができますが、MicroPythonでは基本的にずっとブロックに該当するwhile True:は一回しか使用できません。

ビジュアル言語のMakeCodeからテキスト言語のMicroPythonに書き換えてみよう


from microbit import *

# 経過時間(秒)を記録する為の変数
elapsed = 0

while True:
    elapsed += 1
    sleep(1000)

のようにしたいところですが、この書き方ですと、ボタンAのようなイベントを追加することが出来ません。

※ 意図した動きに成り難いですがmicrobit.button_a.was_pressed():を使うというがあります。


経過時間を計測しつつ、何らかのイベントを追加するためには一時停止(MicroPythonではsleep)ではない方法で時間の計測を行う必要があります。


計測を行うためにmicrobitライブラリのrunning_timeを使ってみます。

Microbit モジュール — BBC micro:bit MicroPython 1.1.1 ドキュメント#microbit.running_time


running_timeはボードの電源が入ったか再起動してからの経過時間(ミリ秒)になります。


running_timeを使ったコードでは下記の二点を意識します。

・開始時間を必ず取得しておく。

・計測時間を確認したい時に(今の時間 - 開始時間)の値を取得する


この二点を加味したコードは下記のようになります。

from microbit import *

# 計測開始の合図
display.scroll("start.")

# スタート時の時間を記録
start_time = running_time()

while True:
    if button_a.was_pressed():
        display.clear()
        # 経過の秒数を表示
        # (今の時間 - 開始時間)で経過時間を知る
        # 1000で割ることで「秒」に変換
        elapsed = int((running_time() - start_time) / 1000)
        display.scroll(str(elapsed) + "s")
        break

今回のコードではボタンAを押した時に始めて経過時間を計算しますが、もし5秒以上経過していないとボタンAを押しても有効にならないといった事をしたければ、while True:の下の行に

elapsed = int((running_time() - start_time) / 1000)

をする必要があります。




microbit.running_timeはマイクロビット専用の関数になりますので、他のマイコン(ラズベリーパイPico)にコードを移植する時に書き直しが必要になります。


書き直しを加味してコードを書く時は、utimeライブラリのticks_msが重宝します。

ticks(ティックス)とは、システムの時計が刻む最小単位の鼓動のようなもの(チクタク)で、マイクロビットであれば、1ticksは0.001秒(1ミリ秒)でmicrobit.running_timeとほぼ同じになります。


utime.ticks_msで書き直すと、

from microbit import *
import utime

# 計測開始の合図
display.scroll("start.")

# スタート時の時間を記録
start_time = utime.ticks_ms()

while True:
    if button_a.was_pressed():
        display.clear()
        # 経過の秒数を表示
        # (今の時間 - 開始時間)で経過時間を知る
        # 1000で割ることで「秒」に変換
        elapsed = int((utime.ticks_ms() - start_time) / 1000)
        display.scroll(str(elapsed) + "s")
        break

になります。

utime -- 時間関連の関数 — MicroPython 1.13 ドキュメント#utime.ticks_ms




microbit.run_everyという関数を使った書き換えを見てみます。

microbit.run_everyは事前に作成しておいた関数を一定の間隔(周期)で実行する仕組みで、引数に作成した関数名と周期のルールを記述することで自動実行が開始します。

Microbit モジュール — BBC micro:bit MicroPython 2 ドキュメント#microbit.run_every


microbit.run_everyを使って書き換えたコードは下記になります。

from microbit import *

# 経過秒を記録
second = 0

display.scroll("start.")

def timer():
    global second
    second += 1

# timer関数を1秒周期で実行するように登録する
run_every(timer, s=1)

while True:
    if button_a.is_pressed():
        display.show(second)

# 経過秒を記録
second = 0

def timer():
    global second
    second += 1

timer関数内にありますglobalですが、これはグローバル宣言と呼び、関数の外側に書かれている変数を関数内で使う為の仕組みになります。


グローバル宣言により、関数で計算した後にreturnで値を返さなくても、外にある変数(上記のコードでは一行目のsecond = 0を指す)の値が変更されています。

京都の東本願寺で開催されているプログラミング教室で講師をしています。
詳しくはTera schoolを御覧ください。
同じカテゴリーの記事
マインクラフト用ビジュアルエディタを開発しています。

詳しくはinunosinsi/mcws_blockly - githubをご覧ください。