C#

【PLC / C#】C#でKEYENCE PLCを制御【上位リンク通信】

目的

PCとKEYENCE社製PLCを通信させて、PCからPLCのデバイス値の読み書きできるようしたいと思います。
PC側のプログラムはC# .NETを使用します。今回は上位リンクという機能を使用していきたいと思います。

PLC側の設定

KV-8000 / KV STUDIO ver10を例にします。
ハードウェアはKV-7500やKV-NC1EPでも同じように行えるかと思います。

  • [ユニット構成エディタ] → [KV-8000 ユニット設定タブ] → [基本]の[IPアドレス]
  • [ユニット構成エディタ] → [KV-8000 ユニット設定タブ] → [ポート番号]の[ポート番号(上位リンク)]

上記2項目を設定するだけで、特別なラダーやKVスクリプト記述は必要ありません。
この例では下記のように設定しました。

IPアドレス 192.168.2.35
サブネットマスク 255.255.255.0
デフォルトゲートウェイ 0.0.0.0
DNSサーバ 0.0.0.0
ポート番号(上位リンク) 8501(デフォルト値)

PC側の設定

PLCと同じネットワークグループに接続しておきます。

プログラム

プログラムはDOBON.NET様のこちらの記事を参考にさせていただきました。

書き込み

MR001の値を0から1に変更したいと思います。

static void Main(string[] args)
{
    // PLCのIPアドレス
    string host = "192.168.2.35";
    // 上位リンクのデフォルト設定は8501
    int port = 8501;

    //TcpClientを作成し、サーバーと接続する
    TcpClient tcp = new TcpClient();
    tcp.Connect(host, port);
    if (tcp.Connected)
    {
        Console.WriteLine("サーバー({0}:{1})と接続しました({2}:{3})",
            ((IPEndPoint)tcp.Client.RemoteEndPoint).Address,
            ((IPEndPoint)tcp.Client.RemoteEndPoint).Port,
            ((IPEndPoint)tcp.Client.LocalEndPoint).Address,
            ((IPEndPoint)tcp.Client.LocalEndPoint).Port);
    }

    // Timeoutを設定する
    NetworkStream ns = tcp.GetStream();
    ns.ReadTimeout = 10000;
    ns.WriteTimeout = 10000;

    // MR001のデバイス値を1に書き込み
    string sendMsg = "WR MR001 1";
    Encoding enc = Encoding.ASCII;
    byte[] sendBytes = enc.GetBytes(sendMsg + '\r');

    //データを送信する
    ns.Write(sendBytes, 0, sendBytes.Length);
    Console.WriteLine(sendMsg);

    System.IO.MemoryStream ms = new System.IO.MemoryStream();
    byte[] resBytes = new byte[256];
    int resSize = 0;
    do
    {
        //データの一部を受信する
        resSize = ns.Read(resBytes, 0, resBytes.Length);
        //Readが0を返した時はサーバーが切断したと判断
        if (resSize == 0)
        {
            Console.WriteLine("サーバーが切断しました。");
            break;
        }
        //受信したデータを蓄積する
        ms.Write(resBytes, 0, resSize);
        //まだ読み取れるデータがあるか、データの最後が\nでない時は、
        // 受信を続ける
    } while (ns.DataAvailable || resBytes[resSize - 1] != '\n');

    //受信したデータを文字列に変換
    string resMsg = enc.GetString(ms.GetBuffer(), 0, (int)ms.Length);
    ms.Close();

    //末尾の\nを削除
    resMsg = resMsg.TrimEnd('\n');
    Console.WriteLine(resMsg);

    //閉じる
    ns.Close();
    tcp.Close();
    Console.WriteLine("切断しました。");
}

モニターモードでMR001の値が変更されたことが確認できたかと思います。

読み込み

MR001のデバイス値を読み込んでみます。
26行目が少し違うだけで後は同じです。

static void Main(string[] args)
{
    // PLCのIPアドレス
    string host = "192.168.2.35";
    // 上位リンクのデフォルト設定は8501
    int port = 8501;

    //TcpClientを作成し、サーバーと接続する
    TcpClient tcp = new TcpClient();
    tcp.Connect(host, port);
    if (tcp.Connected)
    {
        Console.WriteLine("サーバー({0}:{1})と接続しました({2}:{3})",
            ((IPEndPoint)tcp.Client.RemoteEndPoint).Address,
            ((IPEndPoint)tcp.Client.RemoteEndPoint).Port,
            ((IPEndPoint)tcp.Client.LocalEndPoint).Address,
            ((IPEndPoint)tcp.Client.LocalEndPoint).Port);
    }

    // Timeoutを設定する
    NetworkStream ns = tcp.GetStream();
    ns.ReadTimeout = 10000;
    ns.WriteTimeout = 10000;

    // MR001のデバイス値を読み込む
    string sendMsg = "RD MR001";
    Encoding enc = Encoding.ASCII;
    byte[] sendBytes = enc.GetBytes(sendMsg + '\r');

    //データを送信する
    ns.Write(sendBytes, 0, sendBytes.Length);
    Console.WriteLine(sendMsg);

    System.IO.MemoryStream ms = new System.IO.MemoryStream();
    byte[] resBytes = new byte[256];
    int resSize = 0;
    do
    {
        //データの一部を受信する
        resSize = ns.Read(resBytes, 0, resBytes.Length);
        //Readが0を返した時はサーバーが切断したと判断
        if (resSize == 0)
        {
            Console.WriteLine("サーバーが切断しました。");
            break;
        }
        //受信したデータを蓄積する
        ms.Write(resBytes, 0, resSize);
        //まだ読み取れるデータがあるか、データの最後が\nでない時は、
        // 受信を続ける
    } while (ns.DataAvailable || resBytes[resSize - 1] != '\n');

    //受信したデータを文字列に変換
    string resMsg = enc.GetString(ms.GetBuffer(), 0, (int)ms.Length);
    ms.Close();

    //末尾の\nを削除
    resMsg = resMsg.TrimEnd('\n');
    Console.WriteLine(resMsg);

    //閉じる
    ns.Close();
    tcp.Close();
    Console.WriteLine("切断しました。");
}

DM001.TABCDという文字列を書き込みたいときには26行目を"WR DM001.T ABCD"と変更すればOKです。