質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Anaconda

Anacondaは、Python本体とPythonで利用されるライブラリを一括でインストールできるパッケージです。環境構築が容易になるため、Python開発者間ではよく利用されており、商用目的としても利用できます。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

7217閲覧

python マルチスレッド終了時のエラーメッセージ

sasamata

総合スコア12

Anaconda

Anacondaは、Python本体とPythonで利用されるライブラリを一括でインストールできるパッケージです。環境構築が容易になるため、Python開発者間ではよく利用されており、商用目的としても利用できます。

マルチスレッド

マルチスレッドは、どのように機能がコンピュータによって実行したのかを、(一般的にはスレッドとして参照される)実行の複合的な共同作用するストリームへ区分することが出来ます。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2020/01/17 07:17

前提・実現したいこと

arduino側より電圧値を送信し、cvsファイルに書き込むプログラムを書いています。
[開始]ボタンで測定値読み見込みはじめ[終了]ボタンで測定を終了させます。
[終了]ボタンを押すとdialogは消えて、再度起動すれば測定可能ですが、[終了]ボタンで以下エラーメッセージが出力されます。

発生している問題・エラーメッセージ

[終了]させると、下記エラーメッセージが出力されます。
動作そのものは、問題なく動いているようです。
これを解消させるためにはどのようにすればよろしいでしょうか?

エラーメッセージ
Exception in thread Thread-7:
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\lib\threading.py", line 926, in _bootstrap_inner
self.run()
File "C:\ProgramData\Anaconda3\lib\threading.py", line 870, in run
self._target(*self._args, **self._kwargs)
File "D:/Python/STAIC-SK1000/STAIC-SK1000_04.py", line 39, in serial_data_recv
fl_line = float(w_line)
ValueError: could not convert string to float:

該当のソースコード

python3.7

1 2import tkinter as tk 3import datetime 4import serial 5import time 6import threading 7 8ser = serial.Serial("COM6",9600) 9 10def serial_data_recv(): 11 global stop_flag 12 stop_flag = True 13 14 15 # 通信最初の50要素から読み(通信のゴミを読み飛ばす) 16 print("通信バッファクリア中……") 17 for i in range(50): 18 ser.readline().rstrip() #\r\n削除 19 20 print("測定開始") 21 22 f_now = datetime.datetime.now() #現在時刻取得 23 # ファイル名を時刻.csvに設定 24 recv_data = f_now.strftime('%Y%m%d_%H%M') + ".csv" 25 with open(recv_data,'w') as f: #ファイルオープン 26 while True: 27 if stop_flag == False: 28 break 29 else: 30 line = ser.readline().rstrip() #\r\n削除 31 s_line = str(line) #文字列化 32 w_line = s_line.strip("b'") #受信文字から"b、'"を削除 33 34 fl_line = float(w_line) 35 SEN_OUT = (fl_line * 5.0)/1023    # 0-5vに変換 36 SEN_OUT2 = round(SEN_OUT,2) 37 now = datetime.datetime.now() #現在時刻取得 38 39 #ファイルフォーマットを整えて書き込み 40 file_time0 = now.strftime('%H') 41 f.write(str(file_time0)) 42 f.write(":") 43 file_time1 = now.strftime('%M') 44 f.write(str(file_time1)) 45 file_time2 = now.strftime('%S') 46 f.write(":") 47 f.write(str(file_time2)) 48 f.write(",") 49 f.write(str(SEN_OUT2)) #受信データ書き込み 50 f.write(",") 51 f.write("V") 52 f.write(",\n") #","と改行挿入 53 54 print(" " + (str(SEN_OUT2)) + " V") 55 56 f.close() 57 ser.close() 58 print("測定終了") 59 time.sleep(5) 60 root.destroy() 61 62def start(): 63 global stop_flag 64 global thread 65 66 # スレッドが無いなら生成してstart()する 67 if not thread: 68 thread = threading.Thread(target = serial_data_recv) 69 stop_flag = False 70 thread.start() 71 72def stop(): 73 global stop_flag 74 global thread 75 76 ser.close() 77 root.destroy() 78 79 # スレッドがある場合停止してjoin()する 80 if thread: 81 stop_flag = True 82 thread.join() 83 thread = None 84 85 86thread = None 87 88root = tk.Tk() 89root.title("検査 電圧計") 90root.geometry("250x220+1000+10") 91 92#thread_1 = threading.Thread(target = start) 93#thread_2 = threading.Thread(target = stop) 94 95button1 = tk.Button(root, text = "測定開始", font=("MSゴシック", 14), 96 command = start) 97button1.place(x = 80, y = 30) 98 99button2 = tk.Button(root, text = "測定終了", font=("MSゴシック", 14), 100 command = stop) 101button2.place(x = 80, y = 70) 102 103root.mainloop()

試したこと

ネットで調べましたが、わからないでいます。

補足情報(FW/ツールのバージョンなど)

開発ツールは、Windows10でspyder3を使用しています。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

fl_line = float(w_line) ValueError: could not convert string to float:

float に変換できないエラーなので、変数 w_line の値を疑いましょう。

line = ser.readline().rstrip() #\r\n削除 s_line = str(line) #文字列化 w_line = s_line.strip("b'") #受信文字から"b、'"を削除

怪しい・・・

print('w_line':, w_line)

してみたら何が表示されますか?

投稿2020/01/17 09:18

shiracamus

総合スコア5406

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sasamata

2020/01/20 01:09

ご教授、ありがとうございます。 w_line: 632 3.09 V と、表示されます。計算すると正しい値のようです。
shiracamus

2020/01/20 01:16 編集

変数 w_line には "632\n3.09V" という複数行の文字列が入っているのではありませんか? print('w_line':, repr(w_line)) に変えて表示してみてください。
sasamata

2020/01/20 02:19

ご教授、ありがとうございます。 複数行の文字列は入っていないようです。 さらに、色々と試してみたところ、期待の動作をするようになりましたが、 再起動時、「カーネル停止しました。再起動中」と表示され、その後、通常に動作するようです。 import tkinter as tk import datetime import serial import time import threading ser = serial.Serial("COM6",9600) def serial_data_recv(): global stop_flag global thread stop_flag = True num = 0 # SEN_OUT = 0 # 通信最初の50要素から読み(通信のゴミを読み飛ばす) print("通信バッファクリア中……") for i in range(50): ser.readline().rstrip() #\r\n削除 print("測定開始") f_now = datetime.datetime.now() #現在時刻取得 # ファイル名を時刻.csvに設定 recv_data = f_now.strftime('%Y%m%d_%H%M') + ".csv" with open(recv_data,'w') as f: #ファイルオープン while True: if stop_flag == False: break else: line = ser.readline().rstrip() #\r\n削除 s_line = str(line) #文字列化 w_line = s_line.strip("b'") #受信文字から"b、'"を削除 fl_line = float(w_line) SEN_OUT = (fl_line * 5.0)/1023 # 0-5vに変換 SEN_OUT2 = round(SEN_OUT,2) now = datetime.datetime.now() #現在時刻取得 #ファイルフォーマットを整えて書き込み file_time0 = now.strftime('%H') f.write(str(file_time0)) f.write(":") file_time1 = now.strftime('%M') f.write(str(file_time1)) file_time2 = now.strftime('%S') f.write(":") f.write(str(file_time2)) f.write(",") f.write(str(SEN_OUT2)) #受信データ書き込み f.write(",") f.write("V") f.write(",\n") #","と改行挿入 print(" " + (str(SEN_OUT2)) + " V") num += 1 f.close() ser.close() print("測定終了") time.sleep(5) root.destroy() def stop(): global stop_flag global thread stop_flag = False root = tk.Tk() root.title("検査 静電容量") root.geometry("250x220+1000+10") thread_1 = threading.Thread(target = serial_data_recv) thread_2 = threading.Thread(target = stop) button1 = tk.Button(root, text = "測定開始", font=("MSゴシック", 14), command = thread_1.start) button1.place(x = 80, y = 30) button2 = tk.Button(root, text = "測定終了", font=("MSゴシック", 14), command = thread_2.start) button2.place(x = 80, y = 70) root.mainloop()
shiracamus

2020/01/20 02:24

コメントにソースコードを貼ってもインデントがずれてしまうので、質問欄に追記するようにしてください。
sasamata

2020/01/20 02:32

申し訳ありません。 再度、そのようにします。
guest

0

ベストアンサー

stop()内で、スレッドの終了を待ってから、以下を実施してはいかがでしょうか?
順番を入れ替えるだけですが。

python

1 ser.close() 2 root.destroy() 3

追記 -->

コメント内容から、こちらの想定と違ったのかと思ったのですが、その後にベストアンサーとなったので、一応補足しておきます。

当初のコードでは、stopメソッドを呼び出すと、すぐにserをクローズしています。その後にスレッドの終了待ちを行なっているため、serクローズ直後に読み出したデータが不正データになるのではないかと思いました。
これを、きちんとデータを読み終え、スレッドが終了するのを待ってから、serをクローズ、rootをdestroyすればと思った次第です。
ただ、serクローズ状態でデータを読もうとすると、例外が発生するかもしれず、今回のような状況になるのかはわからなかったので、まずは試していただいた方がと考えました。
なんとなく複合的な要因のようにも思いますが、本問題だけでなく、スレッド処理の際には、タイミングについても気をつけた方が良いという点を認識して貰えたらと思い、追記しました。

python

1# original code 2def stop(): 3 global stop_flag 4 global thread 5 6 ser.close() 7 root.destroy() 8 9 # スレッドがある場合停止してjoin()する 10 if thread: 11 stop_flag = True 12 thread.join() 13 thread = None

python

1# modified code 2def stop(): 3 global stop_flag 4 global thread 5 6 # スレッドがある場合停止してjoin()する 7 if thread: 8 stop_flag = True 9 thread.join() 10 thread = None 11 12 ser.close() 13 root.destroy()

また、シリアルからのデータ読み込みの際に、以下のようにバイト列を文字列にしていますが、

python

1line = ser.readline().rstrip() 2s_line = str(line) #文字列化 3w_line = s_line.strip("b'") #受信文字から"b、'"を削除

python3の場合は、以下のようにした方がよろしいかと思います。

python3

1line = ser.readline().rstrip() 2w_line = line.decode() # あるいは w_line = line.decode('utf-8')

投稿2020/01/17 07:25

編集2020/01/20 10:45
t_obara

総合スコア5488

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sasamata

2020/01/17 08:34

ありがとうございます。 変更してみましたが、同じエラーメッセージが出力されます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問