はじめに
前回は、三菱のQSeries, FX3Series, iQ-RSeries と交信する Python プログラムについて説明しました。
今回は、オムロンの CJ2, キーエンスのKV-8000 と交信する方法について説明します。
前提条件
前提条件は以下の通りです。
- PLC のポートが開放してあること
- PLC と PC の ping 導通確認ができていること
通信用プログラム
通信用プログラムは、以下がベースとなります。
import socket
host, port = 8555, "192.168.0.1"
TCP_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM) #TCP通信
TCP_client.settimeout(10)
TCP_client.connect((host, port))
UDP_client = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) #UDP通信
UDP_client.settimeout(10)
UDP_client.connect((host, port))
# コマンド通信処理
client.close()
TCP, UDP に応じて使い分けてください。
CJ2Series UDP
UDP コマンドは以下になります。
# ================= CJSeries UDP Only ===================== #
data = [
# header
0x80, #(ICF)
0x00, #(RSV)
0x02, #(GCT)
0x00, #(DNA)
0x00, #(DA1)
0x00, #(DA2)
0x00, #(SNA)
0x9C, #(SA1)
0x00, #(SA2)
0x22, #(SID)
# command
0x01, #(MRC)
0x01, #(SRC) (0x01,0x01 で読み出し、0x01,0x02で書込み)
# data
0x82, #読出しデバイス指定 0x82=Dレジスタ
0x00, 0x00, 0x96, #読出し領域の指定(000096=150)
0x00,0x07, #読出しByte数
]
#送信
UDP_client.send(bytes(data))
#受信
response = UDP_client.recv(1024)
#受信文変換(バイナリで返ってくる)
data1 = [format(i,'02X') for i in response]
return_data = [0] * 6
data1 = data1[14:]
# 16進数を10進数に変換
# CJシリーズは、レジスタによって10進数と16進数があるので
# int関数での変換に注意
return_data[0] = int(data1[4] + data1[5], 16)
return_data[1] = int(data1[7])
return_data[2] = int(data1[8] + data1[9])
return_data[3] = int(data1[10] + data1[11])
return_data[4] = int(data1[13])
return_data[5] = int(data1[2] + data1[3] + data1[0] + data1[1], 16)
オムロンのレジスタは 10進数 と 16進数 が混在するので、読み出すレジスタに合わせて変換する必要があります。
また、三菱とは違ってビッグエンディアンでの扱いとなるので注意が必要です。
CJ2Series TCP
CJ2 の TCP はマニュアルだけでは理解し難いと思います。CIP通信に似た方式で通信します。
交信の流れとしては、shakehand(PC to PLC) → node 発行(PLC to PC) → ready(PC to PLC) → read or write (PC to PLC)
# ================= CJSeries TCP Only ===================== #
# ================= shakehand ================= #
SIA = 0x55
shakehand_protocol = [
# TCP header
0x46, 0x49, 0x4E, 0x53, # FINS
0x00, 0x00, 0x00, 0x0C, # Length
0x00, 0x00, 0x00, 0x00, # Command
0x00, 0x00, 0x00, 0x00, # Error Code
# FINS node address 0x00 = auto recieve
0x00, 0x00, 0x00, 0x00,
]
#送信
TCP_client.send(bytes(shakehand_protocol))
#受信
response = TCP_client.recv(1024)
#受信文変換(バイナリで返ってくる)
data1 = [format(i,'02X') for i in response]
print("shakehandPLC Result is : ", data1)
pc_node = int(data1[19], 16)
plc_node = int(data1[23], 16)
print("PC node is : ", data1[19])
print("PLC node is : ", data1[23])
# ================= PLC ready ================= #
standby_protocol = [
# TCP header
0x46, 0x49, 0x4E, 0x53, # FINS
0x00, 0x00, 0x00, 0x1A, # Length
0x00, 0x00, 0x00, 0x02, # Command
0x00, 0x00, 0x00, 0x00, # Error Code
]
# ================= PLC read ================= #
read_protocol = [
# header
0x80, #(ICF)
0x00, #(RSV)
0x02, #(GCT)
0x00, #(DNA)
plc_node, #(DA1)
0x00, #(DA2)
0x00, #(SNA)
pc_node, #(SA1)
0x00, #(SA2)
SIA, #(SID)
# command
0x01, #(MRC)
0x01, #(SRC)
# data
0x82, #読出しデバイス指定
0x00, 0x00, 0x96, #読出し領域
0x00, #上位読出しByte数
0x07, #読出しByte数
]
# standby
TCP_client.send(bytes(standby_protocol))
#送信
TCP_client.send(bytes(read_protocol))
#受信
response = TCP_client.recv(1024)
data1 = [format(i,'02X') for i in response]
data1 = data1[30:]
# 16進数を10進数に変換
# CJシリーズは、レジスタによって10進数と16進数があるので
# int関数での変換に注意
return_data = [0] * 6
return_data[0] = int(data1[4] + data1[5], 16)
return_data[1] = int(data1[7])
return_data[2] = int(data1[8] + data1[9])
return_data[3] = int(data1[10] + data1[11])
return_data[4] = int(data1[13])
return_data[5] = int(data1[2] + data1[3] + data1[0] + data1[1], 16)
SIA は任意です。pc_node, plc_node は shakehand 時に決定されるので必ず変数に格納しましょう。
キーエンスKVSeries TCP / UDP 共通
キーエンスは最高に分かりやすいです。マニュアル見るだけでスムーズに理解可能です。
# ================= KV Series TCP and UDP ===================== #
# ASCII 通信
# 読出し例
# RDS(\x20)(デバイス種別)(デバイス番号)(データ形式)(\x20)(読出し個数)(\x0D)
# データメモリ8000番の場合
# b"RDS\x20DM008000.U\x200002\x0D"
# 書込み例
# WRS(\x20)(デバイス種別)(デバイス番号)(データ形式)(\x20)(書込み個数)(\x20)(データ1)(\x20)(データ2)(\x20)...(\x0D)
# データメモリ8000番の場合
# b"WRS\x20DM008000.U\x200002\x20AA\x20BB\x0D"
# ZFレジスタの場合
# b"RDS\x20ZF061100.U\x201\x0D"
# b"WRS\x20ZF061104.U\x201\x202\x0D"
# ================= 通信例 ================= #
command = b"RDS\x20DM008000.U\x200002\x0D"
#送信
client.send(bytes(command))
#受信
response = client.recv(1024)
#受信文変換
data_sum = ""
for dt in response[:-2]:
temp = chr(int(format(dt, "02X"), 16))
data_sum = data_sum + temp
return_data = int(data_sum)
ASCII交信限定です。ASCIIですがコマンドが短いので通信時間は短いです。
体感的にはKV-8000 が最も早い?NJ, NX と同等。
おわりに
今回はオムロン CJ2, キーエンスKV のシーケンサと TCP/UDP 通信する方法について説明しました。
オムロンの TCP 通信は非常に癖が強いですが、CIP 通信も同様の方法なのでこれが世界標準の交信方式だと思います。
オムロンの NX, NJ シリーズは CIP 通信を採用しています。
次回はオムロンの CJ1, CJ2, CPM2 と RS232C でシリアル通信する方法について説明します。
コメント