LoginSignup
16
17

More than 1 year has passed since last update.

PythonでModbus TCP通信を行う

Last updated at Posted at 2021-12-15

はじめに

今回は産業界で広く使われている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

16
17
0

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
  3. You can use dark theme
What you can do with signing up
16
17