【PLC】PCとリンクしてリアルタイムデータを読み書きして連携する
Keyence製KVシリーズで上位リンク通信
上位リンク通信の仕組みを詳しく
通信フロー図

コマンド一覧
クライアントからサーバーに送るコマンドの一覧は下記の通りです。
機能 | コマンド |
モード変更 | Mn |
エラークリア | ER |
エラー番号確認 | ?E |
機種の問い合わせ | ?K |
動作モード確認 | ?M |
時刻設定 | WRT |
強制セット/強制リセット | ST/RS |
連続強制セット/連続強制リセット | STS/RSS |
データ読み出し | RD |
連続データ読み出し | RDS |
連続データ読み出し | RDE |
データ書き込み | WR |
連続データ書き込み | WRS |
連続データ書き込み | WRE |
設定値書き込み | WS |
連続設定値書き込み | WSS |
モニタ登録 | MBS/MWS |
モニタ読み出し | MBR/MWR |
コメント読み出し | RDC |
バンク切り替え | BE |
拡張ユニットバッファメモリ読み出し | URD |
拡張ユニットバッファメモリ書き込み | UWR |
今回は、このコマンドの中からデータ読み出し、データ書き込みについて詳しく使い方を書いてみようと思います。
データ読み出し「RD」連続データ読み出し「RDS」
PLCの特定のデバイス値の値を読み出すコマンドです。
RD:指定したデバイスのデータを1つ読み出し

備考「␣」:スペース(空欄)
RDS:指定した個数のデバイスのデータを連続で読み出し

レスポンス:返り値

例えば、DM1000のデバイス値の値を知りたいとき、
コマンド:[RD␣DM 1000]
をクライアントからサーバーに送ると「DM1000」のデバイス値が返ってくる仕組みです。
具体例を載せておきます。
DM200~DM202の3デバイス分の値をデータ形式[.S]で読み出すコマンド

string strRDSCOm = "RDS DM200.S 3\r"
※末尾は「\r」
レスポンス返り値は、スペース区切りで返ってくる。

string res = "+15025 -25400 +00000\r\n";
エラーレスポンス
エラーが起きた場合のレスポンスもあるので、きちんと作るならエラー処理も作れます。
E0:デバイス番号異常

E1:コマンド異常

データ書き込み「WR」連続データ書き込み「WRS」
PLCの特定のデバイス番号に値を書き込むコマンドです。
WR:指定したデバイスにデータを1つ書き込む

備考「␣」:スペース(空欄)
WRS:指定した個数のデバイスにデータを連続で書き込み

WR,WRSコマンドは、書き込みコマンドになっています。
PCからPLCに値を書き込み出来ます。
サンプル例:DM200~DM202にデータ形式「.S」で書き込む場合

string strWRSCom = "WRS DM200.S 3 +15025 -05400 200\r";
※末尾は「\r」
レスポンス
書き込みコマンドを送って完了したら、「OK」のレスポンスが返ってきます。

エラーレスポンス
[E0]と[E1]は読み出しの時と同じエラーレスポンスになります。E0:デバイス番号異常
E1:コマンド異常
書き込みの場合のエラーとして[E4]のレスポンスが返ってきます。
E4:書き込み禁止

データ形式※
データ形式 | 設定値1~n | ||
サイズ | 範囲 | ||
.U | 10進数16ビット符号なし | 5byte | 00000~65535 |
.S | 10進数16ビット符号あり | 6byte | -32768~+32767(0の場合+00000) |
.D(省略可) | 10進数32ビット符号なし | 10byte | 0000000000~4294967295 |
.L | 10進数16ビット符号あり | 11byte | -2147483648~+2147483647(0nの場合+0000000000) |
.H | 16進数16ビット | 4byte | 0000~FFFF |
PLC側は細かい設定不要
まず、サーバーであるPLC側はいっさいクライアントであるPCとの通信を気にしなくて大丈夫。
PLC側はフロー図に示した通り、自動でクライアントとの通信を確立してくれます。
制御屋は難しい事は考えなくて済むので、PC側のシステム屋が大変なだけです。
なので、実際の現場の方が見ているなら、システム屋には十分な工数を与えてくれると幸いです。
PC側でのシステム実装
さてここからが本題です。クライアント側のPCでは、今回はC#.Netで実装していく方向で説明します。
Socket通信でTcpClientを使います。
余談ですが、仕事でPLCと通信するシステムを作ることになったのですが、
PLCとの通信はしたことなかったので、最初はどうやるのか全くわからない状態でした。
TcpClientでPLCと通信確立
では早速、TcpClientでconnectするソースコードは以下の通りです。
public int portNo = 8501; //上位リンク通信用ポート番号(初期設定) public IPAddress iPAddress = IPAddress.Parse("135.15.79.20"); //PLCのIPアドレス(適宜設定) private void PLCconnect() { //PLCコネクション接続 TcpClient client = new TcpClient(); try { //接続 client.Connect(iPAddress, portNo); } catch { //接続エラー MessageBox.Show("PLCとの接続エラー"); } //// //ここに処理するコードを書いていく。 //// }
PLC側の上位リンク通信用ポートが初期設定値:8501なのでそれを定義する。
PLC側のIPアドレスを定義する。(PLCで設定しているIPアドレスを当ててあげればいい)
そして、TcpClientのインスタンス作成。
Connectで引数にIPアドレス、ポート番号を設定してあげる。
これだけで、PLCとPCとの通信が確立します。
意外と簡単にPLCと接続できたんだと驚きました。
RDコマンド処理
//NetworkStreamを取得 NetworkStream ns = client.GetStream(); //読み出しコマンド string strRDCom = "RD DM500.D\r"; //コマンド内容⇒DM500デバイスの10進数32ビット符号ありの値を読み出す //配列定義 char[] chArray2 = strRDCom.ToCharArray(); byte[] bArray_send = new byte[chArray2.Length]; //データをバイト配列に変換 for (int iCount = 0; iCount < chArray2.Length; iCount++) { bArray_send[iCount] = Convert.ToByte(chArray2[iCount] & 0xFFFF); } ///////コマンド送信 処理終了確認用コマンド///////// ns.Write(bArray_send, 0, bArray_send.Length); //レスポンス格納用バイト配列定義 int byteValue = 50; //レスポンス用バイト容量 適当余裕を持たせて。 byte[] bArray_res = new byte[byteValue]; //////レスポンスデータ受信////// ns.Read(bArray_res, 0, bArray_res .Length); //レスポンス文字列 string res = Encoding.GetEncoding(932).GetString(bArray_res); //通信クローズ ns.Close(); ns.Dispose(); client.Close(); client.Dispose();
WRコマンド処理
//NetworkStreamを取得 NetworkStream ns = client.GetStream(); //コマンド string strWRCom = "WR DM502.D 2\r"; //コマンド内容⇒DM502デバイス番号に[2]を書き込む //配列定義 char[] chArray2 = strWRCom.ToCharArray(); byte[] bArray_send = new byte[chArray2.Length]; //コマンド文字列をバイト配列に変換 for (int iCount = 0; iCount < chArray2.Length; iCount++) { bArray_send[iCount] = Convert.ToByte(chArray2[iCount] & 0xFFFF); } //コマンド送信 ns.Write(bArray_send, 0, bArray_send.Length); //レスポンス格納用バイト配列定義 int byteValue = 50; //レスポンス用バイト容量 適当余裕を持たせて。 byte[] bArray_res = new byte[byteValue]; //////レスポンスデータ受信////// ns.Read(bArray_res, 0, bArray_res .Length); //レスポンス文字列 string res = Encoding.GetEncoding(932).GetString(bArray_res); //正常終了なら[OK]が返ってくる //通信クローズ ns.Close(); ns.Dispose(); client.Close(); client.Dispose();
PLCとPCを通信してデータをPCのデータベースに格納蓄積して、商品のトレーサビリティを実現するシステムの一部で役に立ってます。
他の記事も参考にして下さい。
【PLC】キーエンスKV-7500で上位リンク通信でPCとPLCの通信を確立してデータを読み書きする方法