3本ローラーのスマートトレーナー化(その10)

 EPS32を使って作成したスマートトレーナーをコントロールするPC側のソフトをPythonで組んだ。
 と言っても、
 1.トレーニング表(時間(秒)とトレーニング強度(-9 ~ 9))のテキストファイルを読む。
 2.ブルートゥースにトレーニング強度の数値を上記表の時間が経過するまでだけ書き出す。
 3.同時に画面上にトレーニングの状態を示す画面を表示する。
というもの。分かってしまえば非常にシンプルなのだが、当方は素人なので、画面表示の仕組み、GUIによるファイル選択、カウントダウンとスレッド処理といったことが一々試行錯誤。特に,、最初は単に「シリアル通信」を使えば良いということに中々気が付かず、ブルートゥース周りを調べて時間をとってしまった。

# トレーニングファイルを読み込み、キャンバスにトレーニングファイルの内容(時間(秒)、レベル)を表示するとともに、シリアルポートに一定時間ごとに書き込む
# トレーニングファイルフォーマット
#        時間(単位:秒(整数))、半角スペース、運動強度(-9 ~ 9(整数))
#      (例)
#        1 1
#        3 2
#        4 3
#        2 4
#        1 5 ・・・
#         (上記を左詰め(スペース無)にする)



import serial
import time
import tkinter as tk
import tkinter.filedialog
import threading



tm = []
level=[]

# シリアル通信(ブルートゥース)設定
# 下記'COM6'はパソコン、接続機器によって異なるので、「設定→デバイス→Bluetoothとその他のデバイス
# →その他のBluetoothオプション→COMポート」から確認すること。
ser = serial.Serial('COM8',9600)

# ウィンドウ設定
root = tk.Tk()
root.title(u"トレーニング")
root.geometry("1000x200")
root.attributes("-topmost",True)


button1 = tk.Button(root, text="Start", command=lambda:start())
button1.place(x=500, y=160)


# 終了処理
def finish():
    ser.close()
    root.destroy()
    

# キャンバス作成
canvas = tkinter.Canvas(master=None, width=1000, height=100)

# キャンバス表示
canvas.place(x=0, y=0)


# ファイル選択
filetypes = [("","*")]
target_file = tkinter.filedialog.askopenfilename(filetypes=filetypes, title="ファイルを開く")

# ファイル読み込み
# 配列 tm に時間、配列 level に運動強度を格納する
with open(target_file) as f:
    lines = f.readlines()
    for line in lines:
        line = line.split()
        tm.append(line[0])
        level.append(line[1])

# トレーニングデータの個数        
ln = len(tm)

    
# 開いたファイルを閉じる
f.close()


# メインの関数を定義する

def training():

# ループ

    for i in range(ln):

# ブルートゥースに運動強度を書き込み
            line = ser.write(level[i].encode())



# キャンバスに時間(1秒ごとのカウントダウン付き)、運動強度を表示

            jmax = int(tm[i])
           
            for j in range(jmax):
                canvas.delete("all")
                canvas.create_text(40, 50, text="時間"+"{:3}".format(jmax-j) +"秒  レベル"+level[i], anchor="w", font=(None,36))

                time.sleep(1)


# トレーニングファイルの終了処理

            if(i==ln-1) :
                canvas.destroy()




        

# スレッド作成
thread1 = threading.Thread(target=training, daemon=True)

# スレッド開始
def start():
    button1.destroy()
    button2 = tk.Button(root, text="Exit", command=lambda:finish())
    button2.place(x=500, y=160)
    thread1.start()

# イベントループ

canvas.mainloop()

 その他、使用する際の注意事項(使う人がいるかどうか知らないけれど・・・)。
1.PythonはAnacondaで入れているのだが、シリアル通信を行うためにpyserialは標準で入ってないので追加でインストール。
Pyserial :: Anaconda.org

2.シリアル通信で使用するCOMポート番号は、パソコンとその使用環境によって異なるので確認して適宜変更(上記プログラムではCOM8)。
(確認方法)
(1)プログラム使用前にEPS32(スマートトレーナー)とブルートゥース接続をしておく。

設定
バイスを追加する

(2)COMポート番号を確認する。

その他のブルートゥースオプションを選択
COMポート番号を確認する。この場合、PCからはスマートトレーナーに「発信」するわけだから、COM8を使えばいい。

3.Pyinstallerというのを使って実行形式(exeファイル)にしておけば、一々Pythonを立ち上げなくてもワンクリックで起動できる(オプション-onefileにするとファイルサイズがでかくなって重くなるので、自分だけで使う分には指定しない方が良い。)。
qiita.com

 プログラムが正常に作動していることを示す動画がこちら。
youtu.be
 この状態でADコンバータが正常に作動していることも併せて確認。
youtu.be
 この時のトレーニング表のテキストデータはこちら。各行の一番目の数字が時間(秒)、二番目の数字がトレーニング強度(プラス符号の数字はレジスト、マイナス符号の数字はアシスト、数字が大きいほど強度が大きい)

5 9
4 2
3 1
2 0
3 -1
4 -2
5 -9