pythonのシリアル通信は、PySerialでやろう
この記事は以下のような方を対象に書きました。
- pythonでシリアル通信の方法を探している
- ポートの設定が面倒だ
- 送受信がうまくいかない
- ArduinoとPCのシリアル通信の具体的な方法を知りたい
今回、Pythonでシリアル通信を行う方法を書いていくのですが、題材として「Arduino」を使いたいと思います。Arduinoは(Wikipediaはこちら)は、もともとイタリアで教育用として2005年に開発されたマイコンですが、十分仕事にも通用するマイコンだと思います。
いろいろな種類があるのですが、今回は「Aaarduino nano」という機種を使います。純正品でも2000円強で買えますし、互換品だと500円くらいの値段で手に入るものです。このArduino nanoとPCをつないで実験します。また、Arduinoについては、別の記事にてご紹介します。
それでは、本題のシリアル通信ですが、pyserialというライブラリーを使いますので、インストールしましょう。下記のpipコマンドで一発です。
さっそく、通信したいのですが、シリアルポート番号を下の図みたいにデバイスマネージャーで探すことはしたくないですよね。
でも、最初くらいはやってもいいかな(^^;)
import serial ser = serial.Serial("COM8",19200) print(ser)
インポートする名前はserialですので、ご注意を・・・pyserialじゃないです。
あとは、調べたポート名とボーレート(通信速度:bpsという単位)を指定して、
インスタンスを生成させる。これでエラーが出なかったら、まずは第一段階成功ですね。
ちなみにこのserをprintさせてみると
Serial<id=0x1ba79597e88, open=True>(port='COM8', baudrate=19200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
こんな表示です。ポート名:COM8、ボーレート:19200、バイトサイズ:8、パリティ:なし、ストップビット:1、タイムアウト:なし、その他全部Falseのようです。
簡単に通信ポートを調べる方法がある(list_ports.comports())
実は、pyserialライブラリーには、便利なコマンドがあるのです。list_ports.comports()です。
以下のようにコードを書けば、ポート名がリストとしてdevicesに格納されるのです。
import serial from serial.tools import list_ports ser = serial.Serial() devices = [info.device for info in list_ports.comports()] print(devices)
リストなので、複数存在する場合も調べられます。
この場合は、さきほどの「COM8」が次のように表示されます。
['COM8']
たとえば二つArduinoを接続していると
['COM7', 'COM8']
こんな感じで二つ出てきます。
複数出てきたら、選択できるようにすると便利ですね。以下のように自動サーチ関数にしてみましょう。ボーレートを渡すとさきほどのオブジェクト「ser」を返してくれます。
def select_port(baudrate=19200): ser = serial.Serial() ser.baudrate = baudrate ser.timeout = None # タイムアウトの時間 ports = list_ports.comports() # ポートデータを取得 devices = [info.device for info in ports] if len(devices) == 0: # シリアル通信できるデバイスが見つからなかった場合 print("エラー: ポートが見つかりませんでした") return None elif len(devices) == 1: print(f"一つだけポートがありました {devices[0]}") ser.port = devices[0] else: # 複数ポートの場合、選択 for i in range(len(devices)): print(f"input {i:d} open {devices[i]}") num = int(input("ポート番号を入力してください:" )) ser.port = devices[num] # 開いてみる try: ser.open() return ser except: print("エラー:ポートが開けませんでした。") return None
ポート自動サーチ関数の使い方
これで、ポートを開くのはとてもシンプルになりました。
import serial from serial.tools import list_ports ser=select_port(19200)
pythonでシリアル通信: データ送信方法 ser.write(b’moji’)
ポートオブジェクトserに対して、write()を使えば、送信できます。
ただし、文字列の部分は、バイト型にする必要があるのでb’文字列’のように文字列の前にbを付けないとエラーがでてしまいます。
ser.write(b'文字列')
基本的にこのようにbをつけて送ればよいのですが、文字列は変数に入っている場合もありますよね。さあ、困った。
しかし、大丈夫です。encode()を使って、バイトに変換してやればよいのです。
moji='文字列' ser.write(moji.encode('utf-8'))
改行コードはどうやって送ればよいか?それは、\r\nでOKです
\rはキャリッジリターン(CR)で\nはラインフィード(LF)を表しています。
さきほどのmoji変数にもともと moji=’文字列\r\n’ という具合に埋め込んでもよいし
いつも改行コードを付加するのであれば
ser.write((moji+\r\n).encode('utf-8'))
のように送信するコマンドに入れても大丈夫です。ポートを開いてから少し待ち時間を入れたほうがよい場合があります。timeライブラリーのsleepコマンドで1秒待たせます。送信したあと、プログラムを終了する場合は、ポートをクローズします。ser.close()でOKです。
通しでコード書きます。
import serial from serial.tools import list_ports import time time.sleep(1) ser=select_port(19200) print(ser) moji='文字列\r\n' ser.write(moji.encode('utf-8')) ser.close()
pythonでシリアル通信:データ受信方法 ser.readline()
受信する場合も簡単です。ser.readline()を使えば、改行文字までを送信します。あまりやらないかもしれませんが、1バイトずつ受信する場合はser.read()を使います。下記のコードで、lineという変数に1行分のデータを受信することができます。
line = ser.readline()
さきほど、送信する場合に気を付けることとして、バイト型で送信する必要がありました。受信は、受け取ったデータがバイト型なので、通常の文字列処理をする場合には、decode()を使います。
line_disp=line.strip().decode('UTF-8')
受信したデータをまずstrip()関数で改行文字や空白などを取り除いたあとにdecode()により文字列に変換しています。line_dispは変換後の格納するための変数です。
ずっと、受信し続けるなら、以下のように無限ループにすることもできます。
while 1: line = ser.readline() line_disp=line.strip().decode('UTF-8') print(line_disp)
シリアル通信テスト用ケーブル
最後におまけです。
一台のパソコンでふたつの通信コネクタとクロスケーブルを利用してテストする方法がおすすめです。仮想通信チャンネルを使う方法もあるようですが、実際にケーブルを使う方が臨場感があって楽しいのも大きなモチベーションとなります。
まずはRS-232Cコネクタですが、近ごろはパソコンに搭載されていないことが多いので、「USB変換コネクタ」を使うのが一般的になりました。どれを選べばいいのか迷いますよね~。
私は、安いものを買って、結局うまく通信できずに買いなおした経験があります。
私は以下の製品を使ってうまく通信テストができたのでおすすめです。(価格はまずまずの安さ)
クロスケーブルも忘れずに購入してください。テストするには必須です。
以上、シリアル通信講座でした。
コメント