LoginSignup
6

posted at

updated at

Organization

PythonでModbus TCP通信を行う

はじめに

今回は産業界で広く使われているModbus TCP通信をPythonで行う方法を紹介します。
PyModbusパッケージを使用することで手軽にModbus通信を行うことができます。

Modbus / Modbus TCPとは

Modbus1とは、産業界で広く使われているオープンな通信プロトコルです。
マスタ・スレーブ方式の通信で、マスタのリクエストに対してスレーブがレスポンスを返すという形で通信が行われます。
modbus1.png

保持できるデータには1ビット単位のコイルと16ビット単位のレジスタがあり、アクセス権に応じて以下の4種類に分類されます。

データ 単位 アクセス権
コイル 1bit 読み書き
入力リレー 1bit 読み出しのみ
保持レジスタ 16bit 読み書き
入力レジスタ 16bit 読み出しのみ

Modbus TCPとは、Modbus通信をTCP/IP上で行えるようにしたもので、インターネット環境でModbusメッセージのやり取りを行うことができます。
Modbus TCPはクライアント/サーバー方式の通信であり、クライアントがModbusマスタ、サーバーがModbusスレーブに対応します。
Modbusについてのより詳しい情報は、こちらのサイトをご覧ください。

構成

エッジデバイス(クライアント)で現場にある機器(サーバー)のデータを収集するという状況を想定して、以下の構成で通信を行います。
今回は現場にある機器の代わりにPCをサーバーとして使用し、エッジデバイスがPCのデータを読み書きします。
modbus2.png

動作確認済みデバイス

動作確認済デバイス(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を読み書きします。

coil.py
#!/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の値を読み出します。

discrete_input.py
#!/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の値を読み書きします。

holding_register.py
#!/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の値を読み出します。

input_register.py
#!/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通信を利用したデータ収集アプリケーションを紹介する予定です。

  1. The Modbus Organization

  2. 産業用AIプラットフォーム | 横河電機株式会社

  3. GitHub - riptideio/pymodbus: A full modbus protocol written in python

  4. Pymodbus — PyModbus 2.5.0 documentation

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
6