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つを準備します。
- MX Component をインストールし、付属の通信設定ユーティリティで接続先を設定する。設定には論理局番という番号が付く
- 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プロトコル直書き | McpX | MX Component | |
|---|---|---|---|
| 追加するもの | なし(.NET 標準) | NuGet パッケージ McpX | MX Component のインストールと COM 参照 |
| 接続先の指定 | コードに IP とポート | コンストラクタに IP とポート | 通信設定ユーティリティ+論理局番 |
| 動く OS | .NET が動く環境 | Windows・Linux・macOS | Windows |
| 通信経路 | 自分で実装したもの(Ethernet) | Ethernet(TCP/UDP)、GX Simulator3 | Ethernet、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