JavaScriptを有効にしてください

pyserialとPySimpleGUIでシリアルモニタ

 ·   ·  ☕ 3 分で読めます

pyserialとPySimpleGUIを使ってシリアルモニタを作りました。ArduinoをGUIで操作できます。


使用したライブラリ

pyserial

pyserialを使うとPythonでシリアル通信を行えます。これだけでArduinoとの通信は可能ですが、今回はGUIにするためPySimpleGUIも使用しました。

PySimpleGUI

PySimpleGUIはPythonでGUIを扱うためのライブラリで、tkinter・Qt・WxPython・Remiといった既存のライブラリをまとめて簡単にコードを書けるようにしたものです。学習コストをかけずサクッとGUIアプリを作りたい場合は、簡単に書けるPythonとこのライブラリの組み合わせが最適だと思います。

シリアルモニタ

このようなシリアルモニタを自作できます。
serialmonitor

コード全体をのせます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import PySimpleGUI as sg
import serial
import serial.tools.list_ports
import time
import threading

coms = serial.tools.list_ports.comports()
comlist = []
for com in coms:
    comlist.append(str(com.device))

sg.theme('DarkBlack')

layout = [[sg.Text('COMポート'),sg.Combo(comlist, size=(10, 1),key='selectCOM', enable_events=True),sg.Text('',size=(16, 1),key='com_state'),sg.InputText('', size=(18, 1), key='uplink'),sg.Button('送信', key='send')],
    [sg.Output(size=(97,10))]
]

window = sg.Window('Serial Monitor', layout,enable_close_attempted_event=True)

ser = serial.Serial()
ser.baudrate = 115200
ser.timeout = 0.1 

def GUIloop():
    while True:
        event, values = window.read()

        if event == "-WINDOW CLOSE ATTEMPTED-":
            if(sg.popup_ok_cancel("終了しますか?")=='OK'):
                ser.close()
                window.close()
                break

        if event == sg.WIN_CLOSED: #ウィンドウのXボタンを押したときの処理
            break

        if event == 'selectCOM':
            if ser.is_open:
                ser.close()
            ser.port = values['selectCOM']
            ser.open()

        if event == 'send':
            try:
                ser.write(values['uplink'].encode())
                window['uplink'].update('')
            except:
                print('err')

def COMloop():
    while True:
        if ser.is_open:
            window['com_state'].update('connected')            
            try:
                text=ser.readline().decode('UTF-8').rstrip()
                print(text)
            except:
                time.sleep(0.1)
        else:            
            window['com_state'].update('disconnected')
            time.sleep(0.1)

thread_GUI = threading.Thread(target=GUIloop)
thread_COM = threading.Thread(target=COMloop, daemon=True)
thread_GUI.start()
time.sleep(0.5)
thread_COM.start()
time.sleep(1)

PySimpleGUI

PySimpleGUIについては以下の記事を参考にしました。

ドロップダウンリストを利用したCOMポートの選択

pyserialの機能で使用可能なCOMポートをlistで受け取れます。この要素を文字列に変換してPySimpleGUIのコンボボックスに追加しています。valuesを通して選択された文字列が受け取れるので、これをもとにCOMポートを開くことができます。

pyserialでの文字列の送受信

文字列ではなくバイナリデータとしてシリアル通信を行うので、送信時は'文字列'.encode()とする必要があります。逆に受信時はser.readline().decode('UTF-8')とします。このプログラムではさらにrstrip()を使いました。

GUI用スレッドとCOMポート用スレッドの処理

GUI用ループとCOMポート用ループを別で走らせるためにデーモンを使用しました。

応用

これを応用して少し込み入ったGUIも実装できます。これはハイブリッドロケットの地上局のソフトウェアです。この詳細は別の記事に書きました。


8bitマイコン
著者
8bitマイコン
組み込み周りで遊ぶ宇宙好き