MicroBitを使ってみる(2)

今回はボードに搭載されている磁気センサーを使って方位の検出をしてみた。ボードのmicroUSBの端子がある方向を北に向けるとセンサーからの値は0になり、反対側を向けると180になる。つまり反時計回りに0から360までの値をセンサーは取る。

プログラムはボードの向く方向に拘わらず表示板(5X5のled)に北の方向を示す矢印を表示するといったプログラムである。


from microbit import *

#compass.calibrate()

dd = [Image.ARROW_N, Image.ARROW_NW, Image.ARROW_W,
        Image.ARROW_SW, Image.ARROW_S, Image.ARROW_SE, 
        Image.ARROW_E, Image.ARROW_NE]
a0 = 45 // 2
a1 = 360 - a0
while True:
    n_index = 0
    head = compass.heading()
    print((head,))
    if (head > a0) and (head < a1):
        n_index = ((head - a0)) // 45 + 1
    display.show(dd[n_index])
    sleep(100)
    

実行例を画像で示す。ボードは南東を向いて配置されているが、矢印は北を向いている。

「北」の方向を指す矢印

このpyhtonプログラミングでは初期に実行時のエラーがあったがこれを見つけるのに苦労した。実行時のエラーがあるとMicroBitは停止するがそれ以外の情報はない。随所にprint文を入れて変数の値を調べることが唯一の対処法である。

MicroBitを使ってみる

写真のようにMicroBitをmicroUSBを使ってPC(windows7)に接続してPCからPythonプログラムを転送しそれをMicroBitで実行するという手順である。PC側ではMuと呼ばれるエディター(むしろ統合環境)を使った。Muという統合環境ではPythonプログラムの編集、シンタックスチェック、プログラムのMicroBitへの転送ができる。

プログラム実行中のMicroBit。ボードが右に傾いているので”R”を表示。

さらにインタープリタモードでPythonのコマンドを実行することもできる。このモード(REPLと名前がついている)に入ると転送したプログラムは一時停止した状態になる。このモード画面をprint文の出力画面にも利用できる。そのばあいにはMicroBitの裏面にあるリセットボタンを押し、一時停止していたプログラムを実行させる(リセットの操作が面倒)。

例として使ったプログラム:


from microbit import *

while True:
    reading = accelerometer.get_x()
    sleep(20)
    print((reading,))
    if reading > 120:
        display.show("R")
    elif reading < -120:
        display.show("L")
    else:
        display.show("-")

加速度センサーでボードの傾きを検出し、左右(”L”、”R”)を表示する簡単なプログラムである。プログラム中のプリント文print((reading,))はインタープリタモード画面やMuが持つプロッタ機能のためである。プロッタ機能は繰り返しの出力(出力形式はタプルである。一つのみの値をタプルにするには(x,)とすればよい)をグラフ化する。このプロッタ機能は便利である。

実行中の画面

Muのプロッタ機能(縦軸はセンサーからの値、横軸は回数)

Micro BitとPython

Micro Bitは英国BBCを主体として開発された教育用のmicro-computerボードである。この製品の主な仕様は以下のようである:

  • MCU:32 bit ARM Cortex M0ベース Nordic nRF51822
    • 動作周波数:16 MHz
    • RAM:16 KB
    • BLE搭載
  • LED × 25個(明るさセンサとしても使える)
  • ボタンスイッチ × 2個
  • 加速度センサ × 1個
  • 磁力センサ × 1個
  • バッテリーコネクタ × 1個(JST製PHコネクタ2ピン)
  • サイズ:43 × 52 × 11 mm(コネクタ部含む)
  • 重さ:9 g

つまり独自にmicro-computerを搭載し、周辺装置として25個(5X5)のLED、加速度センサー、磁力センサーを持っている。プログラムによっては25個のLEDで文字を表現することもできるし、加速度センターの値を読むことでこのボードの水平からの傾き、磁気センサーで方向を知ることもできる。

プログラムは別のPCで開発しUSBを通じてこのボードに転送する。電源が別途あればUSBを外しても転送されたプログラムは実行される。

このボードにはPythonインタープリタを移植することができる。つまりPythonでプログラミングをすることができるようになっている。

面白いボードであるが、中学生高学年あたりがコンピュータやプログラミングについて学習するのに適しているかなという印象をもった。

 

藤沢周平の世界:データベースの話

藤沢周平は好きな作家の一人である。以前のこのブログで話題にしたことがある。

文庫本のかたちで全作品を持っている。どの作品がどのタイトルの文庫本に収録されているかを検索できるデータベースを作ってみた。

一例を示す:

検索結果の表示

wxPythonにはデータベースの結果表示に便利なgridクラスがあり表になったデータを適切に表示できる。

Pythonのマルチスレッドの覚書

マルチスレッドの一般論はここにある。プログラムで重たい処理の部分を干渉なしにバッチ処理的にやる部分を一つのスレッドと他の部分と独立に実行させる。こんなイメージがスレッドである。

Python上でスレッドを使った一例を示す:


import threading

a_final = 0


def count():
    global a_final
    for i in range(10000000):
        a = i+1
    a_final = a   
    print('end_count')
    return
def main():
    t = threading.Thread(target=count)
    t.daemon = True
    t.start()
    t.join()
    print(a_final)
    print('end_main')

if __name__ == '__main__':
    main()

関数mainの中で関数countをスレッドとして走らせる。メソッドJoin()はスレッドとそのスレッドを走らせた関数(今の場合はmain)が同時に終了するように同期をとるメソッドである。

これのGUI版は以下のようになる:


import tkinter as tk
from tkinter import ttk
import threading


a_final = 0

root = tk.Tk()
label = tk.Label(text='vinoth')
label.pack()

def fix():
    t = threading.Thread(target=count)
    t.daemon = True
    t.start()
    t.join()
    label['text'] = a_final
    return
    

def count():
    global a_final

    for i in range(100000000):
        a = i+1
    a_final = a


button = tk.Button(text='sub', command=fix)
button.pack()
dropdown = ttk.Combobox()
dropdown.pack()

root.mainloop()

こんな感じになる。

スレッド・コンカーレント・Pythonコンパイラ

Pythonで書いたプログラムを高速に実行する仕掛けを調べていたら面白い記事に出会った。そこで公開されているプログラムを紹介しつつ、僕のところで実行した結果を示す。

基本になるプログラム(killing_time.py)は以下のようなものである:


import time


# 単に時間がかかるだけの処理
def killing_time(number):
    return_list = []
    for i in range(1, number + 1):
        if number % i == 1:
            if i <= 9999:
                return_list.append(i)
    return return_list


start = time.time()
num_list = [25000000, 20000000, 20076000, 14500000]
for n in num_list:
    result_list = list(killing_time(n))
stop = time.time()
print('%.3f seconds' % (stop - start))

このプログラムを実行してみた。使った環境はwindows 7でPyhtonのヴァージョンは3.7.6である。
実行結果は
5.763 seconds
このプログラムをスレッド化したもの(killing_time_thread.py)がある。プログラムはここ
実行結果は
5.779 seconds
となり、Pythonスレッドは速度向上には繋がらない。
またこのプログラムを並列処理させるようにしてみる(killing_time_concurrent.py)。プログラムはここ(CPUの最大数は4)。
実行結果は
3.703 seconds
となり、実行速度は若干改良される。
ここまでがオリジナルの記事を追試したもので記事の結果をほぼ再現した。

次にこの三つのプログラムをPythonコンパイラ(pypy)で実行させてみた結果を述べる。pypyのヴァージョンは
Python 3.6.9 (2ad108f17bdb, Apr 07 2020, 03:05:35)
[PyPy 7.3.1 with MSC v.1912 32 bit]
実行結果は


killing_time.py -------------> 0.713 seconds
killing_time_thread.py) -----> 0.462 seconds
killing_time_concurrent.py --> 1.049 seconds

となった。なにも手を入れないプログラムでもコンパイラで実行するとかなりの実行速度向上ができることが分る。

pypyはnumpyモジュールなどの拡張モジュールとの相性が悪い。しかしネイティヴPythonのみを使ったプログラムは高速に実行できる。

Pythonで作った高速ライフゲーム

最近亡くなったコンウェイ(John Horton Conway)が提唱したライフゲームを高速に実行するPythonプログラムの話である。

この「ゲーム」はセル・オートマトンの一種で二次元格子にオートマトンを置きその時間変化を追い、描画する。各格子のセルオートマトンの状態は生(1)か死(0)の二状態をとる(ライフゲームの由来?)。各格子の状態変化は当該のセルの状態と周囲のセルの状態によって決まる。ここの状態変化の計算は超並列に行うことができる。

計算式は極めて簡単でPythonでも実行時間は掛からないが、格子の数が増えるとセルの状態を描画する時間がバカにならない。そこで描画をヴィデオデータにしてしまってそのデータを画面表示する。こんなことを考えて調べていたら、同じようなことを考えているヒトがいてプログラムを公開している。かなり高速なシミュレーションができる。使ったプログラムはここ。セルの数は300X300=9万である。

実行結果

High_speed_life

TKinterの拡張:ヴィデオを見る

Pythonに同梱されているTKinterはあまり苦労しないでGUIのPythonアプリケーションが作れる詳しい説明はここ)。アプリケーションで静止画像を見せることなどは追加のモジュール無しでできる。そこでTKinterアプリケーションでヴィデオを見せることができるか調べてみた。

  • オンラインのヴィデオカメラで撮影している映像をTKinter内で表示る方法

映像は毎秒60コマで更新されるのでこの頻度で映像を取り込み表示すればよい。取り込んだ映像はlabelウィジェットに表示する。プログラムはここ

  • 動画ファイルを読み込み表示する方法

映像によってフレーム・レイト(毎秒のコマ数)が異なるのでそれを反映した頻度で画面を更新することが必要である。また大きな画面サイズの動画は再生速度が足らなくなる問題がある。プログラムはここ

実行例

TKinter_video_file

この二例でみるようにTKinterは充分でヴィデオ・データにも対応できる。