---
parent: ../Troubleshooting
title: シリアルモニタを開くまでArduino-Python間のシリアル通信のデータ破損
date: 2020-07-14
tags: シリアル通信, Arduino, Python
---

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

![pythonで受信. 予期しないデータが受信されている](CURRENT_DIR/Images/corruption.jpg)

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

===

# 症状
    環境:
        * Arduino
            * Arduino UNO
            * Arduino IDE v1.8.10
        * Windows 10 ビルド 18363.900
        * WSL1 Ubuntu -18.04
        * python環境
            * pipenv
        
    まず, //ArduinoからPythonアプリにシリアルデータを送信するプログラム//を作成する.
    
    SerialTest:
        ```cpp
            void setup() {
              Serial.begin(19200);
            }
            
            void loop() {
              Serial.println(millis());
              delay(1000);
            }
        ```
        
        一秒ごとに現在時間(ms)を送信するだけの単純なプログラムである.
    
    この段階で, //シリアルモニタを確認すると, 正常に取れている//ことがわかる.
    
    ![シリアルモニタでの確認. 正常に一秒ごと現在時間が送られている](CURRENT_DIR/Images/monitor.jpg)
    
    次に, //受信するpythonコード//を作成する.
    
    serial-test.py:
        ```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)
        ```
        
        ただシリアルデータを受信するだけの単純なプログラムである.
        多くのサイト^[serial-sample-1]^[serial-sample-2]^[serial-sample-3]^[serial-sample-4]^[serial-sample-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で受信. 予期しないデータが受信されている](CURRENT_DIR/Images/corruption.jpg)
    
    そこで, //もう一度シリアルモニタを立ち上げ//, 正常に送られているのを確認後, `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で受信. 正常にデータが受信されている](CURRENT_DIR/Images/after-monitor.jpg)
    
# 原因
    結果から言うと, 明確にわからない.
    
    消去法で考えていくと,
    
    * ボーレートの確認
        -> 同じである
    * ポートの確認
        -> 受信はしている
    * `ser`作成後の`ser.flushInput()` `ser.flushOutput()` の実行
        -> 変化なし
        
        参考:
            >>>
                Try to insert ser.flushInput() and ser.flushOutput() after ser creation.
            >>>
            ["Corrupted data with serial connection"](https://stackoverflow.com/questions/40951658/corrupted-data-with-serial-connection). stack overflow. (accessed at 2020-7-14)
            
    * バイナリで送っている
        -> `Serial.println`を使っているので, 文字である
        
        参考:
            ["PySerial: Data corrupted when reading from serial port"](https://stackoverflow.com/questions/32676066/pyserial-data-corrupted-when-reading-from-serial-port). stack overflow. (accessed at 2020-7-14)
    
    
    * Arduinoのリセット(ブートローダの再起動)を待っていない
        -> 待っている
            >>>
                ```py
                print('Serial warming up...')
                time.sleep(2)
                ```
            >>>
        参考:
            ["Problem with Pyserial"](https://forum.arduino.cc/index.php?topic=585676.0). Arduino Forum. (accessed at 2020-7-14)
    
# 対処
    問題を多く検索していき, 最終的にこちらの解決策が有効だった.
    
    ["Connection using pyserial doesn't work properly"](https://forum.arduino.cc/index.php?topic=91291.0). Arduino Forum. (accessed at 2020-7-14)
    
    このポストによると,
    * `pySerial`の//パリティオプション//をいじった結果, `serial.PARITY_ODD`を選択すると文字が違って変だとしても, ある程度のコミュニケーションが取れた.
    * デフォルト値(`serial.PARITY_NONE`)に戻すと、すべてが正常に機能する.
    * なぜだかわからない 🥺
    * コードに次のものを入れると解決
        ```py
            ser.parity = serial.PARITY_ODD
            ser.open()
            ser.close()
            ser.parity = serial.PARITY_NONE
            ser.open()
        ```
    
    上記に従って, `serial-test.py`を変更
    
    serial-test.py:
        ```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)
        ```
    
    //シリアルモニタを開かなくても, 正常に受信//できた.
    
    ![正常に受信できている](CURRENT_DIR/Images/work-fine.jpg)
    
------
[serial-sample-1]: ["【Python入門】pySerialでシリアル通信を実行する方法を解説"](https://www.sejuku.net/blog/69511). Samurai Blog. (accessed at 2020-7-14)
[serial-sample-2]: ["Pythonでシリアル通信"](https://qiita.com/kosystem/items/0023cfee941fdf099087). Qitta. (accessed at 2020-7-14)
[serial-sample-3]: ["PythonのpySerialでシリアル通信する方法を現役エンジニアが解説【初心者向け】"](https://techacademy.jp/magazine/24674). TECH ACADEMY. (accessed at 2020-7-14)
[serial-sample-4]: ["Arduino Python Communication Via USB"](https://www.instructables.com/id/Arduino-Python-Communication-via-USB/). instructables circuits. (accessed at 2020-7-14)
[serial-sample-5]: ["Python Datalogger - Using pySerial to Read Serial Data Output from Arduino"](https://makersportal.com/blog/2018/2/25/python-datalogger-reading-the-serial-output-from-arduino-to-analyze-data-using-pyserial). \
    Maker Portal. (accessed at 2020-7-14)