PLC-Python TCP/UDP 通信コマンドまとめ2 【オムロン、キーエンス】

スポンサーリンク

スポンサーリンク

はじめに

前回は、三菱の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 でシリアル通信する方法について説明します。

コメント

タイトルとURLをコピーしました