シリアルモニタを開くまでArduino-Python間のシリアル通信のデータ破損
ArduinoとPython間のシリアル通信で, Arduino側から送られたシリアルデータをPythonのpySerial
モジュールで読み込むと, 破損したデータ-予想していないデータ-を受信する. だが, 一度Arduinoのシリアルモニタでデータを確認すると正常に受信できており, それ以降, pythonの方でも正常に受信できる.
本稿では, 上記の問題の原因と解決方法について述べる.
症状
- 環境
- Arduino
- Arduino UNO
- Arduino IDE v1.8.10
- Windows 10 ビルド 18363.900
- WSL1 Ubuntu -18.04
- python環境
- pipenv
- Arduino
まず, ArduinoからPythonアプリにシリアルデータを送信するプログラムを作成する.
- SerialTest
void setup() { Serial.begin(19200); } void loop() { Serial.println(millis()); delay(1000); }
一秒ごとに現在時間(ms)を送信するだけの単純なプログラムである.
この段階で, シリアルモニタを確認すると, 正常に取れていることがわかる.
次に, 受信するpythonコードを作成する.
- serial-test.py
import serial import time ser = serial.Serial() ser.baudrate = 19200 ser.port = '/dev/ttyS9' ser.open() print('Serial warming up...') time.sleep(2) while True: line = ser.readline() print(line)
ただシリアルデータを受信するだけの単純なプログラムである. 多くのサイト[1][2][3][4][5] で挙げられているサンプルコードをもとに作成した.
ここで, いったんUSBを差しなおす.
serial-test.py
を実行すると, 予期しないデータが受信される.
Serial warming up... b'\x10\n' b'\x08\x01\x19\n' b'\n' b'\n' b'\x08\x01\x11\n' b'\n' b'\n' b'\n' b'\x08\x01\x13\x02\x02\x02\n' b'\x08\x01\x13\n' b'\n' b'\n' b'\n' b'\x08\x01\x15\x02\x02\x02\n' b'\x08\x01\x16\x02\x02\x02\n'
そこで, もう一度シリアルモニタを立ち上げ, 正常に送られているのを確認後, serial-test.py
を実行すると, 正常にデータをとることができる.
Serial warming up... b'13093422\r\n' b'1394422\r\n' b'0\r\n' b'999\r\n' b'1999\r\n' b'3000\r\n' b'3999\r\n' b'5000\r\n' b'6000\r\n' b'7001\r\n'
原因
結果から言うと, 明確にわからない.
消去法で考えていくと,
- ボーレートの確認
→ 同じである
- ポートの確認
→ 受信はしている
ser
作成後のser.flushInput()
ser.flushOutput()
の実行→ 変化なし
- 参考
Try to insert ser.flushInput() and ser.flushOutput() after ser creation.
"Corrupted data with serial connection". stack overflow. (accessed at 2020-7-14)
- バイナリで送っている
→
Serial.println
を使っているので, 文字である- 参考
"PySerial: Data corrupted when reading from serial port". stack overflow. (accessed at 2020-7-14)
- Arduinoのリセット(ブートローダの再起動)を待っていない
→ 待っている
print('Serial warming up...') time.sleep(2)
- 参考
"Problem with Pyserial". Arduino Forum. (accessed at 2020-7-14)
対処
問題を多く検索していき, 最終的にこちらの解決策が有効だった.
"Connection using pyserial doesn't work properly". Arduino Forum. (accessed at 2020-7-14)
このポストによると,
pySerial
のパリティオプションをいじった結果,serial.PARITY_ODD
を選択すると文字が違って変だとしても, ある程度のコミュニケーションが取れた.- デフォルト値(
serial.PARITY_NONE
)に戻すと、すべてが正常に機能する. - なぜだかわからない 🥺
- コードに次のものを入れると解決
ser.parity = serial.PARITY_ODD ser.open() ser.close() ser.parity = serial.PARITY_NONE ser.open()
上記に従って, serial-test.py
を変更
- serial-test.py
import serial import time ser = serial.Serial() ser.baudrate = 19200 ser.port = '/dev/ttyS9' ser.parity = serial.PARITY_ODD ser.open() ser.close() ser.parity = serial.PARITY_NONE ser.open() print('Serial warming up...') time.sleep(2) while True: line = ser.readline() print(line)
シリアルモニタを開かなくても, 正常に受信できた.
- ^ "【Python入門】pySerialでシリアル通信を実行する方法を解説". Samurai Blog. (accessed at 2020-7-14)
- ^ "Pythonでシリアル通信". Qitta. (accessed at 2020-7-14)
- ^ "PythonのpySerialでシリアル通信する方法を現役エンジニアが解説【初心者向け】". TECH ACADEMY. (accessed at 2020-7-14)
- ^ "Arduino Python Communication Via USB". instructables circuits. (accessed at 2020-7-14)
- ^ "Python Datalogger - Using pySerial to Read Serial Data Output from Arduino". Maker Portal. (accessed at 2020-7-14)