1. TOP
  2. Python
  3. PLC通信
  4. OMRON Fins通信

概略

OMRONの通信プロトコルのFINSコマンドをpythonで送ります
FINSコマンドはメッセージサービス用の通信コマンドでPC-PLC間やPLC-デバイス間で使用されています
ここではpythonを使ってEthernetでPLCとメッセージ通信するクラスを作りました

動作環境

動作確認環境: Win10
python3.9
PLC OMRON CJ/NJ/NX series

構成

NXシリーズの場合はポート2に接続してください (ポート1はFINS通信が制限されています)

メソッド一覧

メソッド内容
readメモリエリアの読み出し
writeメモリエリアへ書き込み
fillメモリエリアの一括書き込み
run動作モード切り替え
stopプログラムモードに切り替え
ReadUnitDataCPUユニット情報の読出し
ReadUnitStatusメモリエリアの読み出し
ReadCycletimeメモリエリアの読み出し
Clock時間情報の読出し
SetClock時間情報の書込み
ErrorClear異常解除
ErrorLogRead異常履歴の読出し
ErrorLogClear異常履歴のクリア
SendCommandその他のFINSコマンドを送信

オブジェクトの作成

fins(IPAddress, 相手FinsAddress, 自分FinsAddress, タイムアウト)

パラメータ
IPAddress接続先IPアドレス
相手FinsAddress接続先Finsアドレス
自分FinsAddress接続元Finsアドレス
タイムアウトタイムアウト (2.0s)

戻り値
戻り値finsオブジェクト

finsudp = fins('192.168.250.1', '0.1.0', '0.5.0', 1.0)

finsクラスは通信相手のIPアドレス, 相手のFINSアドレス, 自分のFINSアドレスを指定してオブジェクトを作ります
FINSアドレスを省略すると相手のIPアドレスの下1桁の数値をノードとして相手先FINSアドレスとします
タイムアウトを指定しない場合は2sになります

FINSアドレス

FINSアドレスとは 「FINSネットワークアドレス . ノードアドレス . 号機アドレス」の3つの数字を . (ドット)でつなぎます
ネットワークアドレスは直接接続することを想定して 0 (自ネットワーク)にしています
ノードアドレスはIPアドレスの一番下の数値と合わせて受信側(PLC)は 0.1.0 を、送信側(PC)はIPアドレスは192.168.250.5としているので 0.5.0 としています
号機アドレスは 0 (CPU宛て)とします
詳しくはFINSアドレスの説明を確認してください

メソッド

read(address, num)

I/Oメモリエリアの読出 (01 01)

パラメータ
addressメモリアドレス
num読出し要素数

戻り値
戻り値読出しデータ(バイト配列)

読み出したデータはデータ変換メソッドで変換してください

メモリアドレス表記方法

メモリアドレスは以下のように記載します
メモリ種別記述例
数値CIO10 = 10CH
WWRW10 = WR10
HHRH10 = HR10
DDMD10 = DM10
E0_ ~ EF_EM0 ~ EMFE0_10 = EM0_10

# E0_30000から10CH読出し
data = finsudp.read('E0_30000', 10)

上で作ったオブジェクトのreadメソッドでアドレスとCH数を指定して値を読み出します
アドレスはCIOは000、DMはD0、EMはE0_0、WRはW0のように指定します
読み出したデータはバイト列(bytes)で受け取ります


write(address, data)

メモリエリアの書込み (01 02)

パラメータ
addressメモリアドレス
data書込みデータ (バイト配列)

戻り値
0102終了コード

正常時の終了コード

01020000

# E0_0からdataを書込み
rcv = finsudp.write('E0_0', data)

fill(address, num, data)

メモリエリアの一括書込み (01 03)

連続したメモリエリアに同一のデータを書き込みます

パラメータ
addressメモリアドレス
num書込み要素数
data書込みデータ

戻り値
0103終了コード

# D110から10CH分(D110-119)に55を書込み
rcv = finsudp.fill('D110', 10, 55)

multiRead(addresses)

メモリエリアの複合読出 (01 04)

パラメータ
addressメモリアドレス カンマ区切り (MAX167)

戻り値
戻り値読出しデータ(バイト配列)

# 複合読出し D1000,D1010,D1020
data = finsudp.multiRead('D1000, D1010, D1020')

run(mode)

動作モード切り替え (04 01)

# 動作モード切り替え (0x02=Monitor 0x04=Run)
rcv = finsudp.run(0x02)

stop()

プログラムモードに切り替え (04 02)

# プログラムモードに切り替え
rcv = finsudp.stop()

ReadUnitData()

CPUユニット情報の読出し (05 01)

戻り値
byte数420204012
内容05 01 00 00CPUユニットの形式システムバージョンシステム情報エリア情報

# CPUユニット情報の読出し
rcv = finsudp.ReadUnitData()

ReadUnitStatus()

ユニット情報の読出 (06 01)

戻り値

byte数411222216
内容06 01 00 00運転状態動作モード運転停止異常情報運転継続異常情報メッセージ有無故障コード異常メッセージ

# CPUユニットステータスの読出し
rcv = finsudp.ReadUnitStatus()

ReadCycletime()

サイクルタイム読出 (06 20)

戻り値

byte数4444
内容06 20 00 00平均最大最小

# サイクルタイム読出し
rcv = finsudp.ReadCycletime()

Clock()

時間情報の読出 (07 01)

戻り値 type:datetime.datetime

# 時間情報の読出し
rcv = finsudp.Clock()

SetClock(datetime)

時間情報の書込み(PCの時間を書込み)

# 時間情報の書込み(PCの時間を書込み)
rcv = finsudp.SetClock(datetime.now())

ErrorClear()

発生中の異常を全解除 (21 01)

# 異常解除
rcv = finsudp.ErrorClear()

ErrorLogRead()

異常履歴の読出し (21 02)

戻り値

byte数422210...10
内容21 02 00 00レコード最大数格納数読出しレコード数異常履歴データ...異常履歴データ

# 異常履歴の読出し 最新10件
rcv = finsudp.ErrorLogRead()

ErrorLogClear()

異常履歴のクリア (21 03)

# 異常履歴のクリア
rcv = finsudp.ErrorLogClear()

SendCommand(cmd)

FINSコマンドを直接送信

cmd = bytearray([0x05,0x01])
rcv = finsudp.SendCommand(cmd)

データ変換用メソッド

print (finsudp.toInt16(data))

受け取ったデータのバイト列(bytes)を変換するためのメソッド
バイト列のデータがどのようなデータかによってメソッドが変わります

メソッド名変換するデータの長さ
toBinビット列
WordtoBin16ビット単位のビット列
toInt1616bit数値
toUInt1616bit符号なし
toInt3232bit数値
toUInt3232bit符号なし
toInt6464bit数値
toUInt6464bit符号なし
toFloat浮動小数点
toDouble倍精度
toString文字列

使用例

# Sample
from datetime import datetime
from finscommand import fins

try:
	# インスタンス作成
	# NXではポート2を使用
	f = fins("192.168.251.1")   #接続先IPアドレス (, 接続先FINSアドレス, 自分FINSアドレス, timeout)

	# 0CHから1CH分読出し  ビット表記
	data = f.read('0', 1)
	print(f.toBin(data))                  # ゼロサプレス表記
	print(f.WordToBin(data))              # ゼロ埋め表記
	print(list(f.WordToBin(data)))        # ゼロ埋めのリスト

	# W0から2CH分読出し  ビット表記
	data = f.read('W0', 2)
	print(f.toBin(data))
	print(f.WordToBin(data))
	print(list(f.WordToBin(data)))

	# H0から4CH分読出し  ビット表記
	data = f.read('H0', 4)
	print(f.toBin(data))
	print(f.WordToBin(data))
	print(list(f.WordToBin(data)))

	# D1000を読出し ビット表記
	data = f.read('D1000', 1)
	print(f.toBin(data))
	print(f.WordToBin(data))
	print(list(f.WordToBin(data)))

	# D1001を読出しINT
	data = f.read('D1001', 1)
	print(f.toInt16(data))

	# D1002-D1003を読出しDINT
	data = f.read('D1002', 2)
	print(f.toInt32(data))

	# D1004-D1007を読出しLINT
	data = f.read('D1004', 4)
	print(f.toInt64(data))

	# D1008を読出しUINT
	data = f.read('D1008', 1)
	print(f.toUInt16(data))

	# D1009-D1010を読出しUDINT
	data = f.read('D1009', 2)
	print(f.toUInt32(data))

	# D1011-D1014を読出しULINT
	data = f.read('D1011', 4)
	print(f.toUInt64(data))

	# D1015-D1016を読出しFLOAT
	data = f.read('D1015', 2)
	print(f.toFloat(data))

	# D1017-D1020を読出しDOUBLE
	data = f.read('D1017', 4)
	print(f.toDouble(data))

	# D1021-D1025を読出しDOUBLE
	data = f.read('D1021', 5)
	print(f.toString(data))


	# D1100から10CH分のデータを読出し
	data = f.read('D1100', 10)
	print(f.toUInt16(data))

	# E0_0から上で読み出したデータを10CH分を書込み
	rcv = f.write('E0_0', data)
	print(rcv)

	# D1000から1000CH分に連番を書込み
	l = list(range(1000))
	writedata = list()
	for num in range(1000):
		writedata.extend(list(int(l[num]).to_bytes(2,'big')))
	rcv = f.write('D1000', writedata)
	print(rcv)

	# D110から10CH分に55を書込み
	rcv = f.fill('E0_100', 10, 55)
	print(rcv)

	# 複合読出し D1000,D1010,D1020
	data = f.multiRead('D1000, D1010, D1020')
	print(f.toUInt16(data))

	# CPUユニット情報の読出し
	rcv = f.ReadUnitData()
	print(rcv)

	# CPUユニットステータスの読出し
	rcv = f.ReadUnitStatus()
	print(rcv)

	# 時間情報の読出し
	rcv = f.Clock()
	print(rcv)

	# 時間情報の書込み(PCの時間を書込み)
	rcv = f.SetClock(datetime.now())
	print(rcv)

	# 以下CJのみ
	isCJ = False
	if isCJ:
		# モニタモードに切り替え (0x02=Monitor 0x04=Run) (NJ/NXは非対応)
		rcv = f.run(0x04)
		print(rcv)

		# プログラムモードに切り替え (NJ/NXは非対応)
		rcv = f.stop()
		print(rcv)

		# サイクルタイム読出し (NJ/NXは非対応)
		rcv = f.ReadCycletime()
		print(rcv)

		# 異常解除
		rcv = f.ErrorClear()
		print(rcv)

		# 異常履歴の読出し 最新10件
		rcv = f.ErrorLogRead()
		print(rcv)

		# 異常履歴のクリア
		rcv = f.ErrorLogClear()
		print(rcv)


	# その他のFINSコマンドを送信するときはこちら
	# 例)0x05 0x01 0x01 CPUユニット情報の読出し
	cmd = bytearray([0x05,0x01])
	rcv = f.SendCommand(cmd)
	print(rcv)


except Exception as e:
	print(e)
		
		

ダウンロード

 > pip install finscommand

Qiita記事

OMRON FINSコマンドをPythonで送信する

GitHub

GitHub FinsCommand


このサイトが役に立ったと感じたら、ご支援いただけると嬉しいです

この記事へのコメント