chakokuのブログ(rev4)

テック・コミック・DTM・・・ごくまれにチャリ

RP2040上のMicroPythonにmqtt clientを入れる

背景:MicroPythonに接続したセンサーデータを手軽にグラフ化したい
取り組み:MQTTを介してMicroPythonのデータをPCに転送する。PC側ではNode-REDのNodeを組み合わせてMQTT Subscribeして得られた値をグラフ化する
結論:追従できる速度に課題があるが*1、仕組みとしては実現できた。以下は構成図

詳細:
ESP32版のMicroPythonなら最初からMQTT Clientが入っているのだが、RP2040用のMicroPythonにはMQTT Clientが入っていない様である。umqtt.simpleパッケージが提供されているので、パッケージで入れてみる。
CPythonだとpipコマンドでパッケージインストールできるが、MicroPythonの場合、ホスト側からmpremoteコマンドを使って、ターゲット(RP2040)のFlashにパッケージをインストールすることができる。

自分の場合、諸般の事情により、mpremoteコマンドはUbuntu(WSL)上に入っているので、まずはUSBを透過する必要がある。

PS C:\Windows\system32> usbipd list
Connected:
BUSID  VID:PID    DEVICE                                                        STATE
2-1    2e8a:0005  USB シリアル デバイス (COM20)                                 Not shared
2-3    046d:c058  USB 入力デバイス                                              Not shared
2-5    1199:90b1  Sierra Wireless EM7431 Qualcomm® Snapdragon™ X16 LTE-A, S...  Not shared
2-7    5986:118f  USB FHD Camera, IR Camera, Camera DFU Device                  Not shared
2-8    06cb:00c6  Synaptics UWP WBDI                                            Not shared
2-10   8087:0033  インテル(R) ワイヤレス Bluetooth(R)                           Not shared

Persisted:
GUID                                  DEVICE
2a4f2781-19c5-4922-a1dd-e96106844633  USB シリアル デバイス (COM14), USB JTAG debug unit
6b9e6ec4-1707-401f-8d5d-8ac0b21d899c  USB シリアル デバイス (COM18), USB JTAG/serial debug unit
820033e8-df76-408a-b5b9-8807c63590eb  USB-Enhanced-SERIAL CH9102 (COM19)
b24984ee-275b-44bd-905e-387f22edb9c5  USB シリアル デバイス (COM17), USB JTAG/serial debug unit
c8df5152-439b-47bc-b8b6-de2c8a0e55f2  USB シリアル デバイス (COM13), USB JTAG/serial debug unit

PS C:\Windows\system32> usbipd bind --busid 2-1
PS C:\Windows\system32> usbipd attach --wsl --busid=2-1
usbipd: info: Using WSL distribution 'Ubuntu' to attach; the device will be available in all WSL 2 distributions.
usbipd: info: Using IP address 172.17.96.1 to reach the host.

上記操作によりUbuntu(WSL)からPC上のCOMポートが参照可能になった。

$ ls /dev/ttyACM0
/dev/ttyACM0

mpremoteコマンドを使って、umqtt.simpleパッケージをインストールする

$ mpremote mip install umqtt.simple
Install umqtt.simple
Installing umqtt.simple (latest) from https://micropython.org/pi/v2 to /lib
Installing: /lib/umqtt/simple.mpy
Done

Windows環境からTereTermでMicroPythonコンソールに接続したいので、一旦透過を戻す

> usbipd detach  --busid 2-1

MicroPythonコンソールから、umqttが入ったことを確認。確認の方法がイマイチだが、一応パッケージが入ったようである。

>>> import umqtt
>>> dir(umqtt)
['__class__', '__name__', '__dict__', '__file__', '__path__']

MQTT Clientのセットアップ等は省略しますが、、以下の内容で50msec周期でpublish(テストなのでセンサーデータはRandom値)

import random
import json
while True:
  value = int(100*random.random())
  msg = {"data" : value}
  print(f'send message {msg} on topic: {TOPIC}')
  client.publish(TOPIC, json.dumps(msg), qos=0)
  time.sleep_ms(50)

Node-REDにより、MQTTでSubscribeしてグラフに描画するプログラムは以下

描画されたグラフは以下(欠損なく50msec周期で描けているのかは未確認)

欠損状態が分かりやすいように、センサデータとして、周期1秒のSin波を描いてみる
50msec周期でsin波をpublishするサンプル。1波20publish(sin波の周期は1秒)として実装

import random
import json
import math
while True:
  for nth in range(20):
      value = 100 * math.sin(2 * math.pi * nth / 20)
      msg = {"data" : value}
      print(f'send message {msg} on topic: {TOPIC}')
      client.publish(TOPIC, json.dumps(msg), qos=0)
      time.sleep_ms(50)

Node-REDによって描画される波は以下

50msec周期だと大幅な乱れもなく描画できている。さらにPublishの周期を短くして、10msec 周期にしてみた。
ソースコードは以下

import random
import json
import math
while True:
  for nth in range(100):
      value = 100 * math.sin(2 * math.pi * nth / 100)
      msg = {"data" : value}
      print(f'send message {msg} on topic: {TOPIC}')
      client.publish(TOPIC, json.dumps(msg), qos=0)
      time.sleep_ms(10)

ここまで周期が短くなるとさすがに描画も苦しくなって以下のように波形もひずんでいる。

■追記
やはりNode-RED/dashboard/MQTT Clientの組み合わせだと、性能的にちょっと心配な所がある(しかもデータ集計はPythonで行う予定なので、どうにかしてPythonと接続必要)。そんな中、WSLではGUIアプリが動かせると知りまして、だったら、PC上のUbuntu(WSL)でPython + tkinterの組み合わせで自作グラフ描画させたらいいのではと思った。 UbuntuでPython3用 tkinterパッケージのインストールは以下

$ sudo apt-get install python3-tk

パッケージを入れた状態で、以下tkinterモジュールを指定してPythonを起動すると、WSLの環境からTkのWindowが表示できた。

$ python3 -m tkinter

Node-RED環境ではなく、Python3 + MQTT Client + tkinterの組み合わせでグラフ描画させる取り組みを行う。Python環境でデータが取り込めたら、データ解析も同時に行えるので効率が良い。

■追記
RP2040にセンサを取り付けMicroPythonからMQTTでPublishしてUbuntu(WSL)上のNode-REDでSubscribeしてdashboardでグラフ化した例


■参考URL
Tkinterでグラフを表示したい! #Python - Qiita
(tkinterでグラフをリアルタイムに描画する方法が紹介されている)
python - Using MQTT to update Tkinter GUI? - Stack Overflow
tkinterとMQTTを組み合わせる実装例

*1:50msec周期でpublishされるデータは遅延なく描画可能