はじめに
今回は産業界で広く使われているModbus TCP通信をPythonで行う方法を紹介します。
PyModbusパッケージを使用することで手軽にModbus通信を行うことができます。
Modbus / Modbus TCPとは
Modbus1とは、産業界で広く使われているオープンな通信プロトコルです。
マスタ・スレーブ方式の通信で、マスタのリクエストに対してスレーブがレスポンスを返すという形で通信が行われます。
保持できるデータには1ビット単位のコイルと16ビット単位のレジスタがあり、アクセス権に応じて以下の4種類に分類されます。
データ | 単位 | アクセス権 |
---|---|---|
コイル | 1bit | 読み書き |
入力リレー | 1bit | 読み出しのみ |
保持レジスタ | 16bit | 読み書き |
入力レジスタ | 16bit | 読み出しのみ |
Modbus TCPとは、Modbus通信をTCP/IP上で行えるようにしたもので、インターネット環境でModbusメッセージのやり取りを行うことができます。
Modbus TCPはクライアント/サーバー方式の通信であり、クライアントがModbusマスタ、サーバーがModbusスレーブに対応します。
Modbusについてのより詳しい情報は、こちらのサイトをご覧ください。
構成
エッジデバイス(クライアント)で現場にある機器(サーバー)のデータを収集するという状況を想定して、以下の構成で通信を行います。
今回は現場にある機器の代わりにPCをサーバーとして使用し、エッジデバイスがPCのデータを読み書きします。
動作確認済みデバイス
動作確認済デバイス(OS)
- e-RT3 Plus F3RP70-2L2(Ubuntu 18.04 32bit)
- Raspberry Pi 4 Model B (Ubuntu Server 20.04 32bit)
これらのデバイスでは armhf アーキテクチャのパッケージが動作します。
準備
パッケージのインストール
エッジデバイスとPCの両方にModbus通信で必要なPyModbus3をインストールします。
コマンド例
username@ubuntu:~$ python3 -m pip install pymodbus
username@ubuntu:~$ python3 -m pip show pymodbus
Name: pymodbus
Version: 1.3.2
...
Note
e-RT3の場合、あらかじめPyModbusがインストールされているためこの手順は不要です。
通信
エッジデバイスとPCの間でModbus通信を行います。
まず、PCでPyModbusのサーバーのサンプルプログラムsynchronous_server.pyを実行し、サーバーを起動しておきます。(プログラムのライセンスはこちら)
python3 synchronous_server.py
Note
本記事ではタグv2.5.2のコードを使用しています。
以降ではサンプルプログラムsynchronous_client.pyを参考にして作成したプログラムで各種コイル、レジスタにアクセスします。
<IP_ADDRESS_OF_SERVER_PC>
はサーバーを起動しているPCのIPアドレスで置き換えてください。
また、使用している関数の詳しい仕様については公式ドキュメント4をご参照ください。
コイルの読み書き
コイルに1bitの値True/Falseを読み書きします。
#!/usr/bin/env python
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
# サーバーに接続
client = ModbusClient('<IP_ADDRESS_OF_SERVER_PC>', port=5020)
client.connect()
"""コイルの1点読み書き"""
print("Write to a coil and read back")
# アドレス1のコイルにTrueを書き込む
rq = client.write_coil(1, True)
# 読み取る
rr = client.read_coils(1, 1)
# 返り値は8bit単位なので先頭の1bitのみ読み取る
# 読み取り指示した先頭1bit以外はすべてFalseで埋められている
print(rr.bits[0])
"""コイルの複数点読み書き"""
print("Write to multiple coils and read back")
# アドレス3から9点のコイルにTrueを書き込む
rq = client.write_coils(3, [True]*9)
# 読み取る
rr = client.read_coils(3, 9)
# 返り値は8bit単位なので16bit返ってくる
# 読み取り指示した先頭9bit以外はFalseで埋められている
print(rr.bits)
# 切断
client.close()
プログラムを実行して、以下のような出力があれば成功です。
Write to a coil and read back
True
Write to multiple coils and read back
[True, True, True, True, True, True, True, True, True, False, False, False, False, False, False, False]
入力リレーの読出し
入力リレーから1bitの値を読み出します。
#!/usr/bin/env python
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
# サーバーに接続
client = ModbusClient('<IP_ADDRESS_OF_SERVER_PC>', port=5020)
client.connect()
"""入力リレー複数点読み取り"""
print("Read discrete inputs")
# アドレス0から3点の入力リレー読み取り
rr = client.read_discrete_inputs(0, 3)
# 返り値は8bit単位なので8bit返ってくる
# 読み取り指示した先頭3bit以外はFalseで埋められている
print(rr.bits)
# 切断
client.close()
プログラムを実行して、以下のような出力があれば成功です。
Read discrete inputs
[True, True, True, False, False, False, False, False]
保持レジスタの読み書き
保持レジスタに16bitの値を読み書きします。
#!/usr/bin/env python
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
# サーバーに接続
client = ModbusClient('<IP_ADDRESS_OF_SERVER_PC>', port=5020)
client.connect()
"""保持レジスタ1点読み書き"""
print("Write to a holding register and read back")
# アドレス1の保持レジスタに10を書き込み
rq = client.write_register(1, 10)
# 読み取り
rr = client.read_holding_registers(1, 1)
print(rr.registers)
"""保持レジスタ複数点読み書き"""
print("Write to multiple holding registers and read back")
# アドレス2から10点の保持レジスタに値を書き込み
values = [i for i in range(10)]
rq = client.write_registers(2, values)
# アドレス2から10点読み取り
rr = client.read_holding_registers(2, 10)
print(rr.registers)
# 切断
client.close()
プログラムを実行して、以下のような出力があれば成功です。
Write to a holding register and read back
[10]
Write to multiple holding registers and read back
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
入力レジスタの読出し
入力レジスタから16bitの値を読み出します。
#!/usr/bin/env python
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
# サーバーに接続
client = ModbusClient('<IP_ADDRESS_OF_SERVER_PC>', port=5020)
client.connect()
"""入力レジスタ複数点読み取り"""
print("Read input registers")
# アドレス1から8点の入力レジスタを読み取り
rr = client.read_input_registers(1, 8)
print(rr.registers)
# 切断
client.close()
プログラムを実行して、以下のような出力があれば成功です。
Read input registers
[17, 17, 17, 17, 17, 17, 17, 17]
まとめ
今回はPyModbusを利用した簡単なModbus通信のやり方を紹介しました。
次回以降の記事ではModbus通信を利用したデータ収集アプリケーションを紹介する予定です。