昨日の回で、「リモート」のmicro:bitから「PC脇」のmicro:bit経由でPCまで、無線でデータを送りました。今回は、そのスクリプトを改造しながら、ラズパイ上のMuエディタに慣れて行きたいと思います。だいたいmicro:bit上で走るスクリプトにバグがあったらどうなるの?
※「MicroPython的午睡」投稿順 Indexはこちら
ラズパイ上のMuエディタは、BBC mico:bit上で実行可能なMicroPythonスクリプトの「クロス開発」が可能、かつ、ラズパイ上の普通のPython3スクリプトの「セルフ」開発が可能です。昨日は、2台のmicro:bitの間で無線通信するMicroPythonスクリプトを作成してみました。本日は、以下が目標です。
- リモートのmicro:bit(緑)は電池動作、MicroPythonでサーミスタの「値」を読み取り無線で送信。
- 無線レシーバ担当micro:bit(赤)はRaspberry PiにUSBシリアル接続。MicroPythonで無線で送られてきたサーミスタの「値」を受信。UART経由でラズパイへ転送(赤機の接続先が昨日のPCからラズパイに変わった。)
- ラズパイ上ではPython3のスクリプトが走っていてUARTからもたらされるデータを「若干」加工して表示
3台それぞれでPythonスクリプトが走りますが、これをすべてMuエディタで作成する、と。
まずは、Muエディタの上部にあるアイコン群を御覧ください(下のキャプチャはmicro:bitモードのとき。)一番左の「モード」がmicro:bit用のMicroPythonモードとラズパイ上のPython3モードの切り替えボタンとなります。
micro:bitに「転送」したスクリプトにバグがあったらどうなるか?
上の転送ボタン(micro:bitを接続し、認識されると黄色の〇になる)を押せばエディタで編集したスクリプトが書きこまれ、即実行されます。エラーが発生すると
micro:bitのLEDアレイにエラーメッセージがスクロール表示
されるので、やっちまった、ことだけは分かります。しかし、小さな「画面」上をあれよあれよと流れていってしまうので、正直何だか読み取れません。
そのようなトホホな状況に陥らないためには以下の2つかと思います。
- 「転送」前に右から2つめの「チェック」ボタン使う
- 実行時のエラー発生時にはREPLを開く
チェックボタンで静的なチェックがなされ、ソースコードの問題部分付近に的確な指摘が表示されます。つまらないエラーは大体なくなるように思われます。お節介ついでに、文法違反ではないけれど、こうした方がいいみたいなことも指摘されます。この辺の塩梅を制御する方法は今のところ不明なので、指摘0を目指します。すると「褒めて」くれます。
しかしチェックボタンでは実行時のエラーまで分かりません。そのとき、REPLボダンでREPLウインドウを開くとエラーメッセージを確認できるかもしれません。REPLウインドウを開くと、実行中のスクリプトは停止されMicroPythonのプロンプトが表示されます。行の先頭で
CTRL-D
すれば、ソフトリセットされて書きこまれているスクリプトが先頭から再実行されるので経過観察もできます。また、スクリプトに割り込んでプロンプトに制御を戻すのは CTRL-Cでできます。なお、REPLは、USBポートにmicro:bitを接続すると生成される以下のシリアルデバイス経由で動作しているようです(Raspbian buster)。
/dev/ttyACM0
micro:bit上のスクリプトで外部端子に向けてuartを再初期化していなければ、uart.write()すると上記のデバイスに送られるので、スクリプトから「伝統的」printfデバッグに使うことができると思います。MuエディタのREPLを開くと実行中のスクリプトは必ず中断されてしまうので、中断したくない場合は、エディタの外の cu コマンドなどで表示した方が便利かもしれません。なお、このREPLの挙動はmicro:bitモードの場合で、python3ではまた異なります。
リモートで電池でうごくmicro:bit「センサ・ノード」
さて、リモート側(緑)に、サーミスタモジュールと、電池ボックスをとりつけました。サーミスタモジュールは、こちらで使用したものをmicro:bitらしくワニ口クリップ経由で接続いたしました。現物の様子は先頭のアイキャッチ画像を御覧ください。回路はこんな感じ。現在の室温にてP0ポートで扱いやすい値が出るように抵抗を「調整」したらこんなんなってしまいました。
ここで、分かったのは micro:bit 上のMicroPythonではArduinoのようなPinModeの指定が不要ということです。最初、入力端子でプルアップをオフにするにはどうしたらよいの?と探し回ってしまいました。ドキュメントの入出力端子のページから1箇所引用させていただきます。
端子のプルモードは、端子が入力モードに変わると自動的に構成されます。入力モードは read_analog read_digital is_touched を呼び出すと自動で設定されます。
というわけで非常に簡単。昨日のコードを改造し、サーミスタ端子の電圧を read_analog(0~1023の整数値がよめる)して送信するようにしたもの。ついでにmicro:bitの「温度」(Nordic nRF51822チップのだと思う)も送信。
import radio import utime from microbit import * radio.on() packetNum = 0 tempExt = -999 tempInt = -999 uartLog = False interval = 6 def measureTemperature(): global tempExt, tempInt tempInt = temperature() # microbit module, internal temp sensor. tempExt = pin0.read_analog() def sendPacket(opt): global packetNum, tempExt, tempInt packet = ":".join([str(packetNum), str(tempExt), str(tempInt)]) + "\r\n" radio.send(packet) if opt: uart.write(packet) while True: if button_a.was_pressed(): uartLog = True if button_b.was_pressed(): uartLog = False measureTemperature() sendPacket(uartLog) display.scroll(str(packetNum)) packetNum += 1 utime.sleep(interval)
Raspberry PiのUSBポートに接続したmicro:bit「レシーバ」
送られてきたデータを受ける「レシーバ」側は昨日とほとんど変わりませぬ。ちょっと画面をいじったくらい。ただUART接続先は、PCではなくRaspberry PiのUSBシリアル(ttyACM0)に変更しています。
# radio to UART(via USB) test import radio from microbit import * radio_on = False while True: if button_a.was_pressed(): radio.on() radio_on = True if button_b.was_pressed(): radio.off() radio_on = False if radio_on: dataStr = None try: dataStr = radio.receive() except: display.show(Image.SAD) dataStr = None if dataStr is not None: display.show(Image.HEART) uart.write(dataStr) else: display.show(Image.TRIANGLE) sleep(100) display.clear() sleep(500)
Raspberry Pi上で動作するPython3スクリプト
さてラズパイ上でttyACM0から到来するデータを処理するスクリプトはこちら。テスト用なので決めた回数処理すると終わってしまいますが。
#! /usr/bin/python3 import serial recMax = 500 rec = 0 ser = serial.Serial('/dev/ttyACM0', '115200', timeout=0.5) while (rec < recMax): mes = ser.readline().decode('utf-8').strip() dat = mes.split(":") if len(dat) == 3: recSend = dat[0] thermistorV = dat[1] chipTemp = dat[2] print( \ "REC={0} Thermistor={1} ChipTemp={2}".format(recSend, thermistorV, chipTemp)) rec += 1 ser.close()
なお、Python3モードでは、スクリプトの実行ボタンを押すとそのコンソール的なウインドウが自動で開くので即結果をみれます。
こんな感じ。