// LEARN · MCプロトコル入門

MCプロトコル直書き・McpX・MX Component を C# で書き比べる

三菱電機 PLC の D100〜D102 を読む同じ処理を3通りの方法で書き比べます。MCプロトコルの電文を自分で組み立てる方法、.NET ライブラリ McpX、三菱電機の MX Component それぞれのコード量・準備・対応環境・向いている場面を比べます。

更新

C# から三菱電機の PLC を読み書きする方法は、大きく3つあります。MCプロトコルの電文を自分で組み立てる方法、McpX のようなライブラリを使う方法、そして三菱電機の MX Component を使う方法です。

この記事では、3つとも同じ処理を書きます。お題は「Ethernet でつないだ PLC から、D100〜D102 の3ワードを読む」です。書いてみると、それぞれが何を引き受け、何を利用者に任せているのかがよく見えます。

1. MCプロトコルを直接書く

.NET 標準の TcpClient だけで書きます。3E フレームの記事で読んだ電文をそのままバイト列にします。デバイスコードは D なので A8、点数は3です。

using System.Buffers.Binary;
using System.Net.Sockets;

using var client = new TcpClient();
client.Connect("192.168.3.39", 5000);
using var stream = client.GetStream();

// 3E フレーム・バイナリ:D100 から 3 ワードを一括読出し(0401)
byte[] request =
[
    0x50, 0x00,                   // サブヘッダ
    0x00, 0xFF, 0xFF, 0x03, 0x00, // あて先(自局)
    0x0C, 0x00,                   // 要求データ長 = 12
    0x10, 0x00,                   // 監視タイマ = 4 秒
    0x01, 0x04, 0x00, 0x00,       // コマンド 0401 / サブコマンド 0000
    0x64, 0x00, 0x00,             // 先頭デバイス番号 = 100
    0xA8,                         // デバイスコード = D
    0x03, 0x00,                   // 点数 = 3
];
stream.Write(request);

// 応答の先頭 9 バイト(サブヘッダ〜応答データ長)を読む
byte[] header = new byte[9];
stream.ReadExactly(header);
if (header[0] != 0xD0 || header[1] != 0x00)
    throw new InvalidDataException("3E フレームの応答ではありません");
int length = BinaryPrimitives.ReadUInt16LittleEndian(header.AsSpan(7));

// 残り(終了コード+データ)を読む
byte[] body = new byte[length];
stream.ReadExactly(body);
ushort endCode = BinaryPrimitives.ReadUInt16LittleEndian(body);
if (endCode != 0)
    throw new Exception($"PLC がエラーを返しました: {endCode:X4}");

short[] values = new short[3];
for (int i = 0; i < values.Length; i++)
    values[i] = BinaryPrimitives.ReadInt16LittleEndian(body.AsSpan(2 + i * 2));

動くことは動きますが、このコードが面倒を見ているのは「D を3ワード、バイナリで読む」場合だけです。実際に使おうとすると、次のような処理を自分で足していくことになります。

  • 961 ワード以上を読むときに、要求を分けて送る
  • int や float のように2ワードで1つの値になるデータを組み立てる
  • M のようなビットデバイスや、X・Y のような16進番号のデバイスを扱う
  • 応答が返らないときのタイムアウトと、その後の接続の立て直し
  • iQ-R 向けのサブコマンドや、リモートパスワードへの対応

電文の中身を理解するには一番の方法です。ただ、アプリケーションに組み込むなら、これらをすべて自前でテストすることになります。

2. McpX を使う

NuGet で McpX を追加して、同じ処理を書きます。

using McpXLib;
using McpXLib.Enums;

using var mcpx = new McpX("192.168.3.39", 5000);
short[] values = mcpx.BatchRead<short>(Prefix.D, "100", 3);

1 で組み立てた電文と応答の解析は、BatchRead<short> の1行が引き受けます。型を int や float に変えれば、ワード数の計算と値の組み立ても McpX が行います。960 ワードを超える読み出しは、自動で分割して送ります。

PLC がエラーを返したときは McProtocolException が発生し、ErrorCode プロパティでエラーコードを取り出せます。

McpX は .NET だけで書かれているので、Windows に加えて Linux・macOS でも動きます。そのかわり、対応している通信経路は Ethernet(TCP/UDP)と GX Simulator3 です。USB やシリアルでは接続できません。

3. MX Component を使う

MX Component は、三菱電機が提供する通信ライブラリです。ここでは Version 5 の64ビット版をマニュアルの手順どおりに使います。事前に次の2つを準備します。

  1. MX Component をインストールし、付属の通信設定ユーティリティで接続先を設定する。設定には論理局番という番号が付く
  2. Visual Studio の[参照の追加]で、COM の「ActUtlType64 Control」をプロジェクトに追加する
using ActUtlType64Lib;

var plc = new ActUtlType64Class();
plc.ActLogicalStationNumber = 1; // 通信設定ユーティリティで作った論理局番

int ret = plc.Open();
if (ret != 0)
    throw new Exception($"接続に失敗しました: {ret:X8}");
try
{
    short[] values = new short[3];
    ret = plc.ReadDeviceBlock2("D100", values.Length, out values[0]);
    if (ret != 0)
        throw new Exception($"読み出しに失敗しました: {ret:X8}");
}
finally
{
    plc.Close();
}

IP アドレスやポート番号はコードに出てきません。接続先の情報は通信設定ユーティリティの側にあり、コードは論理局番でそれを指定するだけです。

ReadDeviceBlock2 は、デバイス名を "D100" のような文字列で受け取り、2バイト(short)単位で値を読み出します。読み出し先の配列は、点数以上の大きさを呼び出し側で確保します。マニュアルは、領域が足りないとアプリケーションエラーなどの重大な現象が起きるおそれがあると注意しています。エラーは例外ではなく戻り値で返るので、呼び出しのたびに0かどうかを確かめます。

MX Component の強みは、通信経路の多さです。Ethernet のほかにも、次のような経路に同じ書き方で接続できます。

  • USB、シリアル
  • MELSECNET/H や CC-Link IE などのネットワークボード
  • GX Simulator2/3 などのシミュレータ

一方で動作環境は Windows に限られ、使うには製品の購入が必要です。

3つを並べて比べる

MCプロトコル直書きMcpXMX Component
追加するものなし(.NET 標準)NuGet パッケージ McpXMX Component のインストールと COM 参照
接続先の指定コードに IP とポートコンストラクタに IP とポート通信設定ユーティリティ+論理局番
動く OS.NET が動く環境Windows・Linux・macOSWindows
通信経路自分で実装したもの(Ethernet)Ethernet(TCP/UDP)、GX Simulator3Ethernet、USB、シリアル、各種ネットワークボード、シミュレータなど
値の型自分でバイトから変換bool・short・int・float などを型で指定ReadDeviceBlock2 は short。int などは自分で組み立てる
エラーの扱い終了コードを自分で判定例外(McProtocolException)戻り値を毎回確認
1回に指定できる点数上限(一括読出しは 960 ワード)を超えたら自分で分割上限を超えると自動で分割デバイスの範囲内なら点数を気にせず指定できる
ライセンス—MIT(無償・商用利用可)有償

どれを選ぶか

選ぶときに考えるのは、次の3つの問いです。上から順に答えていけば、たいていはどれかに決まります。

1. Ethernet 以外で接続するか

USB、シリアル、MELSECNET/H や CC-Link IE のネットワークボードで PLC とつなぐなら、選ぶのは MX Component です。McpX も直書きも、Ethernet でしか通信できません。

2. Windows 以外で動かすか

Ethernet で接続するなら、次は動かす環境を考えます。Linux のサーバー、Docker コンテナ、Raspberry Pi、macOS の開発機で動かすなら McpX です。MX Component は Windows でしか動きません。

3. 配布とライセンスをどう考えるか

Windows で Ethernet 接続なら、McpX と MX Component のどちらでも実現できます。ここで決め手になるのは、アプリをどう配るかです。

  • McpX が向いている場合:多くの PC に配るアプリや、社外に提供するアプリ。MIT ライセンスで無償なうえ、NuGet の参照だけでアプリに含まれるので、実行する PC ごとのインストールや接続設定が要りません
  • MX Component が向いている場合:すでに MX Component で接続先を管理していて、社内の決まった PC で使うアプリ。コードを直さなくても、通信設定ユーティリティで接続先を変えられます

よくある場面

場面選ぶもの
工場の稼働データを Linux サーバーで集め、Web ダッシュボードに表示するMcpX
PLC のデータをクラウドへ送るゲートウェイを Docker で動かすMcpX
検査装置の Windows アプリから、USB でつないだ PLC を操作するMX Component
CC-Link IE のボードを挿した PC で、複数の PLC をまとめて監視するMX Component
C# 以外の言語やマイコンから PLC と通信する直書き(この入門の電文の知識)

直書きの知識は、どれを選んでも役に立つ

実際のシステムを電文から自作することは少ないはずです。それでも電文の構造を知っていれば、ライブラリを使っていてもトラブルの原因を追えます。Wireshark で通信を覗いたときに各バイトが何を意味するのか、PLC が返したエラーコードが何を指すのかがわかるからです。3E フレームとエラーコードの記事が、そのための知識になります。

出典

  • MX Component Version 5 リファレンスマニュアル(SH-082394)p.29, 48〜49, 56〜57, 473〜478, 647
  • MELSECコミュニケーションプロトコルリファレンスマニュアル(SH-080003)p.41〜44, 付7 p.473
  • SLMPリファレンスマニュアル(SH-080931)p.34〜38