2020年1月2日木曜日

上位リンクでラズパイ(Python)からキーエンスのKVシリーズPLCを制御する

 キーエンスのPLC(シーケンサ)をラズパイから制御する必要があったので、Pythonで上位リンクをやってみた。
タイトルにラズパイとあるが、ぶっちゃけPython3実行環境があるならWindowsPCでもMacでもなんでも良い。

上位リンクとは

PC(ラズパイ、マイコンなども含む)からPLCにソケット通信でコマンドを送受信しCPUユニットのデータメモリやリレーの読み書き、時刻設定や動作モード確認などを行う機能のこと。
PLC側がサーバ、PC側がクライアントとなる。PCからPLCにコマンド(読み込み命令や書き込み命令)を送り、PLCが受け取った命令を実行しレスポンス(読み込んだデータとか)を返す。
PLC側は上位リンク通信機能をON(多分デフォルトでONになってる)にするくらいで特別な設定やラダーの記述は必要ない。そのためラダーは全くわからない僕のような人間でもPLCの内部リレーを叩いたりデータメモリを読み書きしたりできる。
上位リンク自体はソケット通信でコマンドのやり取りをしているだけなので、その他言語で実装するのも容易なはず。
キーエンスの上位リンクとほぼ同様の機能は、三菱ではMCプロトコル、オムロンではFINSコマンドと呼ばれているらしい。
オムロンのPLCにも上位リンクという名前の機能があるが、こちらはソケットではなくシリアル通信(RS-232C)での通信のようだ。
盤屋じゃないのでどんな背景があるのか知らないけれど、めんどくさいからラダーもこういうプロトコルも各社統一しろよと思う。。。特にK社さんは我が道を行くで独自プロトコルとか独自規格が多すぎる。。。


必要なもの

・KEYENCE KVシリーズのCPUユニット(KV-7500とか8000とか)
・Python3が実行可能な環境(ラズパイ、PC等)
・KV STUDIO

手順

・PLCのIPアドレスと上位リンクのポート番号確認

KV STUDIOを起動しユニットエディタを開く。
CPUユニットのLANポートのIPアドレスとポート番号(上位リンク)を確認する。
なおイーサネットユニット(KV-XLE02等)の拡張ユニットのLANポートで接続することも可能。
その場合は拡張ユニットの上位リンクを使用したいLANポートのIPアドレスとポート番号(上位リンク)を確認しておく。


・作成した上位リンクモジュールの使い方

デバイスの読み込みと書き込みの機能しか実装してません。その他機能はキーエンスのマニュアル見て自分で作ってください。
下記ソースをインポートして使う。
まずはインスタンス時にIPアドレスと上位リンクのポート番号を設定する。
書き込みたいときは、WriteDevice('DM', 2000, datalist)のように書き込み先デバイス記号(DMとかRとか)、デバイス番号(番地?)、書き込みたいデータのリストを指定して書き込む。
書き込みたいデータは1ワード単位、int型にしておくこと。
読み出したいときは、ReadDevice('DM', 2000, 1000)のように読み込みデバイス記号(DMとかRとか)、デバイス番号(番地?)、読み込むワード数を指定して読み込む。
読み込みデータは1ワード単位でint型のリストで受け取れる。読み込みは一度に1000ワードまでしかできない。(上位リンクの仕様)
以下ソース
import socket

class highlink:
    def __init__(self, ipaddress, port):
        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        try:
            self.client.connect((ipaddress, port))
        except:
            print('PLC connect Error')
            
    def __del__(self):
        self.client.close()
       
    def ReadDevice(self, devicename, address, readnumber):
        command = 'RDS ' + devicename + str(address) + '.H ' + str(readnumber) + '\r'
        self.client.send(command.encode('ascii'))   #上位リンクコマンド送信
        full_response = b''
        while True:     #一度に全部受け取ろうとするとバッファがあふれてしまうので1024byteごと受け取る
            response = self.client.recv(1024)
            full_response += response
            if response[-1:] == b'\n':                
                break
        full_response = full_response.decode('UTF-8')
        readdata = [int(s,16) for s in full_response.split()]
        return readdata

    def WriteDevice(self, devicename, address, writedata):
        command = 'WRS ' + devicename + str(address) + '.H ' + str(len(writedata))
        for data in writedata:
            command += ' '+ hex(data)[2:]
        command += '\r'
        self.client.send(command.encode('ascii'))   #上位リンクコマンド送信
        response = self.client.recv(5)
        response = response.decode('UTF-8')
        return response

if __name__ == '__main__':
    test = highlink('192.168.1.20', 8501)   #インスタンス
    debuglist = []
    for i in range(1000):                   #テストデータ作成
        debuglist.append(i)    
    test.WriteDevice('DM', 2000, debuglist) #書き込み
    print(test.ReadDevice('DM', 2000, 1000))#読み込み
    del test

・テストを実行

ためしにRに書き込み・読み込みを行って、KV STUDIOのモニタで確認してみる。
初期状態

test.pyを実行するとR304がONになった。
実行後

またReadDeviceで0の値が返ってきた。
以下テストのソース
import highlink

if __name__ == '__main__':
    test = highlink.highlink('192.168.1.20', 8501) #インスタンス
    test.WriteDevice('R', 304, [1])                #書き込み
    print(test.ReadDevice('R', 310, 1))            #読み込み
    del test

・注意点

Rデバイスを読み書きするときも1ワード単位(=16bit)であることに注意。例えばWriteDevice('R', 300, [7])とするとR300、R301、R302がONになってしまう。
読み込み時も、R300=OFF、R301=ON、R302=ON、以降OFFだとReadDevice('R', 300, 1)は6が返ってくる。
本モジュールには実装していないがやろうと思えばbit単位で指示することも可能。

書き込み読み込み以外にも、PLCへ送るコマンドを変えてやればPLCの型番問い合わせ、時刻設定など多くのことができる。
詳しくはキーエンスのマニュアル参照。イーサネットユニットのマニュアルに上位リンク通信についての説明が書かれている。(たとえば「KV-XLE02 ユーザーズマニュアル」とか)

0 件のコメント:

コメントを投稿