pySerialとは
PythonとArduinoなどの機器との間でシリアル通信を実現させるのがpySerialというパッケージです。
pySerialを使えば通信の設定からオープン、送受信からクローズまでを簡単に実行させることが出来ます。
標準でプリインストールされているパッケージではないのでpipを使ってインストールをしておきましょう。
pySerialの使い方
それでは早速pySerialを使ってみましょう。
シリアル通信を受信する
まずはシリアル通信を受信してみましょう。
こちらのコードをご覧ください。
このコードを実行することで、指定したデバイスから送信されたデータを受信して表示することが出来ます。
まずはデバイス名と通信速度(ボーレート)、タイムアウトの有無を指定しています。
そこでreadline関数で受信したデータをprint関数で表示しています。
最後はcloseすることを忘れないようにしましょう。
ここで出てくるデバイス名はそれぞれの環境で変わってくるので、このコマンドで確認しておきましょう。
Macであればこのコマンドを、シリアル通信したい機器を接続する前とした後で実行させることで、その差分を確認してデバイス名を確認することが出来ます。
このコマンドでは/dev配下のtty.から始まるファイルをすべて表示させています。
シリアル通信を送信する
次はシリアル通信を送信してみましょう。
こちらのコードをご覧ください。
このコードを実行することで指定したデバイスにデータ(ここではtest)を送信することが出来ます。
基本的には受信するコードと同じようにデバイス名やボーレート、タイムアウトの有無を指定してインスタンスを作成します。
ここではwrite関数を使ってtestという文字列を送信しています。
最後にcloseする部分は同じですね。
Pythonとハードウェア ー PythonでRS232Cを利用する
必要にせまられつつあり、勉強のため調べているメモです。内容についての実機での確認をほとんどしていない人によるメモだということに注意してください。
ハードウェアを制御するときには、CPUの種類・OSの種類のごとに、使用するライブラリが異なってしまいがちである。#include <windows.h>という行が入っていることが多い。
そのままでは、他のOSでは使えない。
移植性の高いシリアルポート用ライブラリ(C++) Boost
OS依存性のない共通なライブラリを提供しているBoostにはシリアルポート用のライブラリが提供されている。Boost.AsioSerial Ports解説記事【Boost】シリアル通信Boost.Asioでシリアル通信してみるBoost C++ libraries for Raspberry PiBoost C++ librariesをRaspberryPi上でビルドできていることが記されている。
Libraries only (static + dynamic)が公開されている。
USBシリアル変換ケーブル
WindowsでのUSB-シリアルでのCOMポート番号の変更の仕方
デバイスマネージャCOMポートを変更する
Linux(RaspberryPiも含む)ではUSB-シリアル変換でのIOは
/dev/ttyUSB0
といったデバイス名で表示されている。
Zynq USB-UART ドライバ
ISE & Vivado 設定 on Ubuntu
ここでも
/dev/ttyUSB0
というデバイス名が表示される。
PySerial
OS依存性が少ないもの
・pySerial 配布元
・pySerialモジュールについて Pythonによるシリアルデバイスの使い方 Python(windows)での送信例
・pySerial を使う Macでも動くpythonのシリアル通信モジュール。 送信と受信の例あり
・pyserialを使って, macからarduinoにシリアル通信をした Python(Mac)からの送信、arduino C++での受信例
・Pythonでシリアル通信 インストール方法、送信例、受信例
・pySerial/pyWin32でシリアル通信、でも受信が…送受信例
・Pythonでシリアル通信(その2)送受信例
・Pythonでシリアル通信
RaspberryPiを含むLinuxマシンでは、/devの下にあるデバイス名をls で表示して確認できます。/dev/ttyUSB0というのが見えました。
PySerialを用いて記述しても、windowsのcomポートかLinuxのデバイス名かが、pythonスクリプトに残る。でもそれくらいの違いだけになるので、記述がとても簡単になる。
そのポートに対するアクセスが、ファイルオブジェクトへのアクセスと同じように記述できるので、考えやすい。
GPIOかUSBか
RPiにはシリアルポートがありませんので、当然のことながらそれ以外のインタフェースからシリアル通信を行うことになります。基板上のGPIOピンか、USB端子かです。金がかからないのはGPIOピンだと思います。
USB-シリアル
相手の接続先がシリアルポートの場合。IO-DATAの変換アダプター USB-RSAQ6 は動作しました。
PyUSB
USBカメラ
USBカメラへの供給電力が不足すると、USBカメラが認識されません。電力の供給のあるUSBハブを使いましょう。
特別なドライバなしにWindowsで認識されるUSBカメラの場合は、RaspberryPiでもそのまま認識されます。
マシン依存性が避けられないもの
GPIO
・[Raspberry Pi]GPIOでLEDの点滅(Python)http://make.bcde.jp/category/5/
・Raspberry Pi GPIO入出力のサンプル(Python, C言語, shellスクリプト)
http://netlog.jpn.org/r271-635/2013/01/raspberry_pi_gpio_test.html
FPGAが利用可能なボードでのPythonに関するメモ
ZYBOのARMhfのUbuntu 14.04 LTS にOpenCV 2.4.10をインストール
このページではOpenCVのビルドをしており、pythonをCMake時に指定しているので、ZilinxのZynqを利用したボードでpythonが利用可能なのは確かなようだ。
RaspberryPi 用によく使うライブラリをそろえる
Raspberry Pi(ラズベリーパイ)にPythonのモジュールをインポートする
にはscipy, numpy, PySerialがRaspberry Piで利用
Numpy/Scipy/Matplotlib on Raspberry Pi
にあるようにmatplotlibを使うグラフの表示が出来ます。
Upgrading skimage version on Raspberry pi
に説明してあるとおり、ソースコードからコンパイルすることができます。
マイクロソフトのMS-DOSとWindows環境では、シリアルポートをCOMポートとして参照する。COM1、COM2、..などとしてである。COM9よりも大きい番号のポートは\.\COM10構文を用いて参照する必要がある
https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E3%83%9D%E3%83%BC%E3%83%88
RS485
その他のIO
Pythonには限らない参考記事
RaspberryPiのシリアル接続
必要にせまられつつあり、勉強のため調べているメモです。内容についての実機での確認をほとんどしていない人によるメモだということに注意してください。
ハードウェアを制御するときには、CPUの種類・OSの種類のごとに、使用するライブラリが異なってしまいがちである。#include <windows.h>という行が入っていることが多い。
そのままでは、他のOSでは使えない。
移植性の高いシリアルポート用ライブラリ(C++) Boost
OS依存性のない共通なライブラリを提供しているBoostにはシリアルポート用のライブラリが提供されている。Boost.AsioSerial Ports解説記事【Boost】シリアル通信Boost.Asioでシリアル通信してみるBoost C++ libraries for Raspberry PiBoost C++ librariesをRaspberryPi上でビルドできていることが記されている。
Libraries only (static + dynamic)が公開されている。
USBシリアル変換ケーブル
WindowsでのUSB-シリアルでのCOMポート番号の変更の仕方
デバイスマネージャCOMポートを変更する
Linux(RaspberryPiも含む)ではUSB-シリアル変換でのIOは
/dev/ttyUSB0
といったデバイス名で表示されている。
Zynq USB-UART ドライバ
ISE & Vivado 設定 on Ubuntu
ここでも
/dev/ttyUSB0
というデバイス名が表示される。
PySerial
OS依存性が少ないもの
・pySerial 配布元
・pySerialモジュールについて Pythonによるシリアルデバイスの使い方 Python(windows)での送信例
・pySerial を使う Macでも動くpythonのシリアル通信モジュール。 送信と受信の例あり
・pyserialを使って, macからarduinoにシリアル通信をした Python(Mac)からの送信、arduino C++での受信例
・Pythonでシリアル通信 インストール方法、送信例、受信例
・pySerial/pyWin32でシリアル通信、でも受信が…送受信例
・Pythonでシリアル通信(その2)送受信例
・Pythonでシリアル通信
RaspberryPiを含むLinuxマシンでは、/devの下にあるデバイス名をls で表示して確認できます。/dev/ttyUSB0というのが見えました。
PySerialを用いて記述しても、windowsのcomポートかLinuxのデバイス名かが、pythonスクリプトに残る。でもそれくらいの違いだけになるので、記述がとても簡単になる。
そのポートに対するアクセスが、ファイルオブジェクトへのアクセスと同じように記述できるので、考えやすい。
GPIOかUSBか
RPiにはシリアルポートがありませんので、当然のことながらそれ以外のインタフェースからシリアル通信を行うことになります。基板上のGPIOピンか、USB端子かです。金がかからないのはGPIOピンだと思います。
USB-シリアル
相手の接続先がシリアルポートの場合。IO-DATAの変換アダプター USB-RSAQ6 は動作しました。
PyUSB
USBカメラ
USBカメラへの供給電力が不足すると、USBカメラが認識されません。電力の供給のあるUSBハブを使いましょう。
特別なドライバなしにWindowsで認識されるUSBカメラの場合は、RaspberryPiでもそのまま認識されます。
マシン依存性が避けられないもの
GPIO
・[Raspberry Pi]GPIOでLEDの点滅(Python)http://make.bcde.jp/category/5/
・Raspberry Pi GPIO入出力のサンプル(Python, C言語, shellスクリプト)
http://netlog.jpn.org/r271-635/2013/01/raspberry_pi_gpio_test.html
FPGAが利用可能なボードでのPythonに関するメモ
ZYBOのARMhfのUbuntu 14.04 LTS にOpenCV 2.4.10をインストール
このページではOpenCVのビルドをしており、pythonをCMake時に指定しているので、ZilinxのZynqを利用したボードでpythonが利用可能なのは確かなようだ。
RaspberryPi 用によく使うライブラリをそろえる
Raspberry Pi(ラズベリーパイ)にPythonのモジュールをインポートする
にはscipy, numpy, PySerialがRaspberry Piで利用
Numpy/Scipy/Matplotlib on Raspberry Pi
にあるようにmatplotlibを使うグラフの表示が出来ます。
Upgrading skimage version on Raspberry pi
に説明してあるとおり、ソースコードからコンパイルすることができます。
マイクロソフトのMS-DOSとWindows環境では、シリアルポートをCOMポートとして参照する。COM1、COM2、..などとしてである。COM9よりも大きい番号のポートは\.\COM10構文を用いて参照する必要がある
https://ja.wikipedia.org/wiki/%E3%82%B7%E3%83%AA%E3%82%A2%E3%83%AB%E3%83%9D%E3%83%BC%E3%83%88
RS485
その他のIO
Pythonには限らない参考記事
RaspberryPiのシリアル接続
最近は、PCでもRS232Cポートがなくなっているので、USBシリアル変換ケーブルとUSBシリアル変換ドライバが必要になっている。
なんでもかんでもPythonでできることはまずPythonで行いたい私としては、Python用のライブラリを調べてみることとした。
接続させるCOMポートの番号は、そのUSB-シリアルを接続させる前と後とにデバイスマネージャーでCOMポート表示をさせると、新規に現れたポート番号が、そのUSB-シリアルのポート番号です。
PyUSB comes with builtin backends for libusb 0.1, libusb 1.0 and OpenUSB.
USB-Serialを使う際には関係ありません。
COMポートのポート番号について
RS485 というシリアル通信規格をサポートするPythonのライブラリがある。
pyserial/serial/rs485.py
どう使えるものなのか興味深い。
Pythonでシリアル通信
この記事は最終更新日から3年以上が経過しています。
pySerialを使ったシリアル通信
未だに組み込み系においては何かとお世話になるシリアル通信。最近ではRaspberry Piなどの組み込みようとに使えるLinuxボードが出てきているので、Pythonからシリアル通信が使えると何かと便利です。
Install
PyPiに登録されているのでpipまたはeasy_installを使ってインストール
$ pip install pyserial
or
$ easy_install -U pyserial
使い方
オープンと出力(write)
文字を出力するだけなら至って簡単
>>> import serial
>>> ser = serial.Serial('/dev/ttyUSB0', 9600) # デバイス名とボーレートを設定しポートをオープン
>>> ser.write("hello") # 出力
>>> ser.close() # ポートのクローズ
リード
timeoutを簡単に設定できるのでノンブロッキングの形にも簡単にできる
>>> import serial
>>> ser = serial.Serial('/dev/ttyS0', timeout=0.1) # timeoutを秒で設定(default:None)ボーレートはデフォルトで9600
>>> c = ser.read() # 1文字読み込み
>>> str = ser.read(10) # 指定も字数読み込み ただしtimeoutが設定されている婆は読み取れた分だけ
>>> line = ser.readline() # 行終端'¥n'までリードする
>>> ser.close()
参考
公式ドキュメント
Welcome to pySerial’s documentation
Welcome to pySerial’s documentation
目的
本稿の目的は, Python を用いて
Arduino
とシリアル通信を行い, 更に同通信により得た値を数値として処理できるようにすることである.目標
- PC側から
Arduino
にデータを送信, その内容に応じてArduino
の動作を変化させる - PCが,
Arduino
から受信したデータを数値的に処理できるようにする
具体的目標
- PCから文字データを送信し,
Arduino
のLEDの明滅を操作するプログラムを組む - 超音波距離センサ
HC-SR04
から得たデータから数値を取り出すプログラムを組む - 上記プログラム言語には Python 3.x を利用する
準備
- Arduino Uno Rev.3
- USBケーブル
- LED
- ジャンパワイヤ 4本
- HC-SR04
- Python 3.x , Arduino IDE
- Python モジュール : PySerial
環境
- Windowsだがおそらく汎用的なので省略
PC → Arduino シリアル通信
- Arduino の13番ピンとGNDにLEDをつなげる
- LEDの足が長いほうが13番, 短い方はGND
- 以下のプログラム
Serial_Com_LED.ino
をArdino IDEで書いて, Arduino に書き込む
一旦このプログラムをArduino IDE上で実行し, シリアルモニタを用いてLEDの明滅を制御できるか確認する - 以下のプログラム
Serial_Com_LED.py
を作成する Serial_Com_LED.py
を実行すると, Arduino IDEで実行した際と同様の動作が得られる
Serial_Com_LED.ino
void setup(){
pinMode(13,OUTPUT); //13番ピンを出力に設定
Serial.begin(9600);//シリアル通信のレートを9600に設定
}
void loop(){
int inputchar; //入力状態の読み取りに使う
inputchar = Serial.read(); //シリアル通信で送信された値を読み取る
if(inputchar!=-1){
switch(inputchar){
case 's':
digitalWrite(13,HIGH);
break;
case 'q':
digitalWrite(13,LOW);
break;
}
}
else{
}
}
Serial_Com_LED.py
#coding:utf-8
#シリアル通信で文字をArduino側に送信
#aが押されたら通信を中止するプログラム
import serial #モジュール名はpyserialだが, importする際はserialである
def main():
with serial.Serial('COM3',9600,timeout=1) as ser:
while True:
flag=bytes(input(),'utf-8')
#シリアル通信で文字を送信する際は, byte文字列に変換する
#input()する際の文字列はutf-8
ser.write(flag)
#シリアル通信:送信
if(flag==bytes('a','utf-8')):
break;
ser.close()
if __name__ == "__main__":
main()
Arduino → PC シリアル通信
- ピン接続
ジャンパワイヤとブレッドボードを用いてそれぞれ以下のように接続する
Arduino | HC-SR04 |
---|---|
5V | Vcc |
GND | GND |
Pin-9 | Trig |
Pin-10 | Echo |
- 以下の
.ino
,.py
プログラムを書き込む
Serial_Com_Sonic.ino
#define echoPin 10 // Echo Pin
#define trigPin 9 // Trigger Pin
double Duration = 0; //受信した間隔
double Distance = 0; //距離
void setup() {
Serial.begin( 9600 );
pinMode( echoPin, INPUT );
pinMode( trigPin, OUTPUT );
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite( trigPin, HIGH ); //超音波を出力
delayMicroseconds( 10 ); //
digitalWrite( trigPin, LOW );
Duration = pulseIn( echoPin, HIGH ); //センサからの入力
if (Duration > 0) {
Duration = Duration/2; //往復距離を半分にする
Distance = Duration*340*100/1000000; // 音速を340m/sに設定
Serial.println(Distance);
}
delay(500);
}
Serial_Com_Sonic.py
#coding utf-8
import serial
import re
def main():
with serial.Serial('COM3',9600,timeout=1) as ser:
while True:
c = ser.readline()
d = re.findall('[0-9]+\.+[0-9]',str(c),flags=0)
d = [float(i) for i in d]
for i in range(0, len(d)): #要素を1つずつ順番に出力します
print(d[i])
print
ser.close()
if __name__=="__main__":
main()
実行
HC-SR04 についてのプログラムで, list型ではなく, float型を返させるのに苦労しました
- 以下の手続きを踏んでいる
ser.readline()
で,serial.Serial...
の出力を一行分読み込むd = re.findall...
で正規表現によって所望の出力を得る- re.findallが返す値の型はlist(str)であるため
- リストから文字列を得る
- floatに変換
Python 2.7.11ですが、モジュールがserialでは動作せず、serialをアンインストールしてpySerialを導入(import serialはそのまま)するとうまく動きました。
Python 2.6 以降だと PySerial で '\r' が readline の delimiter に使えない
PySerial では Python 2.6 以降の場合には、'\r' (CR) が readline のときの delimiter に使えません。つまり、装置側の出力に '\r' が delimiter として使われている場合、次の code だと '\n' (LF) を待ってしまうために time out してしまいます。
これは、Python 2.6 以降の場合に PySerial が io.RawIOBase.readline を使うようになっているからです。io.RawIOBase は delimiter が '\n' に決め打ちなため、制御する装置側で delimiter の変更ができない場合は詰んじゃいます。
Python 2.5 以前の場合だと、PySerial は serialutil.FileLike という独自の file IO を使うため、delimiter を自分で設定することができました。
どうしても '\r' を delimiter に使いたい場合は、単純には serial.Serial.readline を override してしまいます。
単純に '\r' を読むまで 1 文字ずつ進めているだけですが、実用上は問題ないでしょう。