目次 このページのソースコードを表示

シリアルモニタを開くまでArduino-Python間のシリアル通信のデータ破損

公開日:
更新日:

ArduinoとPython間のシリアル通信で, Arduino側から送られたシリアルデータをPythonのpySerialモジュールで読み込むと, 破損したデータ-予想していないデータ-を受信する. だが, 一度Arduinoのシリアルモニタでデータを確認すると正常に受信できており, それ以降, pythonの方でも正常に受信できる.

pythonで受信. 予期しないデータが受信されている
pythonで受信. 予期しないデータが受信されている

本稿では, 上記の問題の原因と解決方法について述べる.

症状

環境
  • Arduino
    • Arduino UNO
    • Arduino IDE v1.8.10
  • Windows 10 ビルド 18363.900
  • WSL1 Ubuntu -18.04
  • python環境
    • pipenv

まず, 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'
pythonで受信. 予期しないデータが受信されている
pythonで受信. 予期しないデータが受信されている

そこで, もう一度シリアルモニタを立ち上げ, 正常に送られているのを確認後, 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'
シリアルモニタで確認後pythonで受信. 正常にデータが受信されている
シリアルモニタで確認後pythonで受信. 正常にデータが受信されている

原因

結果から言うと, 明確にわからない.

消去法で考えていくと,

  • ボーレートの確認

    → 同じである

  • ポートの確認

    → 受信はしている

  • 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)

シリアルモニタを開かなくても, 正常に受信できた.

正常に受信できている
正常に受信できている

  1. ^ "【Python入門】pySerialでシリアル通信を実行する方法を解説". Samurai Blog. (accessed at 2020-7-14)
  2. ^ "Pythonでシリアル通信". Qitta. (accessed at 2020-7-14)
  3. ^ "PythonのpySerialでシリアル通信する方法を現役エンジニアが解説【初心者向け】". TECH ACADEMY. (accessed at 2020-7-14)
  4. ^ "Arduino Python Communication Via USB". instructables circuits. (accessed at 2020-7-14)
  5. ^ "Python Datalogger - Using pySerial to Read Serial Data Output from Arduino". Maker Portal. (accessed at 2020-7-14)
「https://contentsviewer.work/Master/Arduino/Troubleshooting/serial-python-corruption/serial-python-corruption」から取得