【pySerial-asyncio】pySerialでArduinoの非同期I/Oを実現していく

はじめに

こんにちは、がんがんです。
最近はRaspberry Pi to Arduinoの実験をコツコツと行っています。
pySerialを用いてArduinoへのシリアル通信を行っているのですが、試しに非同期で処理を出来ないかなと考えました。

そこで試しに「pyserial asyncio」で検索をかけてみると、なんとpipでインストールできるバージョンに遭遇することが出来ました。
Welcome to pySerial-asyncio’s documentation — pySerial-asyncio 0.4 documentation

そこで今回はこちらを試していこうと思います。
以前asyncioを試してみた記事はこちらです。
【メモ】Pythonの非同期I/Oライブラリ「asyncio」について触ってみる - ganganの技術備忘録

環境

  • 送信側:Raspberry Pi(Raspbian Stretch)
  • 受信側:Arduino Uno
  • Python3.4以上(asyncioが使用できないため)

調査を進めてみると…

いろいろと調査を進めてみると、本ライブラリはpySerialの制作人が作成したリポジトリでした。
github.com

そのため、試しにpySerialのドキュメントをいろいろあさってみると
pySerial API — pySerial 3.0 documentation
予想通りありました。

ただ、この一文がこわいですね。自己責任か…

Warning This implementation is currently in an experimental state. Use at your own risk.

Exampleをみてみる

まずはExampleをみていきます。コードは以下の通りです。

import asyncio
import serial_asyncio


class Output(asyncio.Protocol):
    def connection_made(self, transport):
        self.transport = transport
        print('port opened', transport)
        transport.serial.rts = False
        transport.write(b'hello world\n')

    def data_received(self, data):
        print('data received', repr(data))
        self.transport.close()

    def connection_lost(self, exc):
        print('port closed')
        asyncio.get_event_loop().stop()

loop = asyncio.get_event_loop()
coro = serial_asyncio.create_serial_connection(loop, Output, '/dev/ttyUSB0', baudrate=115200)
loop.run_until_complete(coro)
loop.run_forever()
loop.close()

クラスの中に分からない関数があるので1つずみ見ていきます。

connection_made()

コネクションが作成されたときに呼び出される関数です。今回の場合だと、Serial通信の接続が完了した時に呼び出される関数です(イメージ的には__init__的な感じ)。

Transports and Protocols — Python 3.7.5 ドキュメント

data_received()

名前の通り、データ受信時の対応を決める関数です。exampleでは、portを閉じるようになっています。

Transports and Protocols — Python 3.7.5 ドキュメント

connection_lost()

コネクションの接続が解除されたときに呼び出される関数です。exampleでは、loop.stop()を実行するようになっっています。

Transports and Protocols — Python 3.7.5 ドキュメント

実際に実験してみる

次にArduinoで実験を行ってみます。実験としては以下の通りです。

・接続時にラズパイからbytes("1;")を送信
・Arduino側は受信文字列に合わせてLEDが点滅

ラズパイ側のコード

Arduino側のコード


おわりに

今回はPythonの非同期I/Oライブラリを利用したpyserial-asyncioを試してみました。
data_received()部分をもう少し改良すれば非同期的にラズパイとの処理を行うことが出来るかなと思います。

改めてasyncioのドキュメントを読む必要がありそうですね。頑張ります。