三菱MELSEC MCプロトコルをpythonで送信


Pythonで三菱MELSECのMCプロトコル(Ethernet)を送信します

MCプロトコルは三菱のシーケンサのデバイスを値を読み書きすることができます
ここではpythonを使ってEthernet(UDP)でMCプロトコルで通信するクラスを作りました
MCP.py

環境

伝文

3Eフレームでバイナリコードを使用します
3EフレームはMELSEC-QnAシリーズのEthernetインタフェースで使用する伝文構成です

クライアント側環境

python 3.9

使い方

オブジェクトの作成

mcp = MCProtcol3E('192.168.0.41', 4999)

MCProtocol3Eクラスは通信相手のIPアドレスとポート番号を指定してオブジェクトを作ります

ワード単位でデバイスの読出し (最大640点)

data = mcp.read('D0', 10)

readメソッドでアドレスと点数を指定して実行すると戻り値には読み出したデータがバイト配列(bytes)で取得できます

ビット単位で読み出し (最大7168点)

data = mcp.read('SM0', 8, True)

第3引数をTrueにするとビット単位での読出しになります

対象のデバイスは以下のデバイスです

X: 入力
Y: 出力
M: 内部リレー
L: ラッチ
F アナンシエータ
V: エッジリレー
B: リンクリレー
D: データレジスタ
W: リンクレジスタ
TS: タイマ(接点)
TC: タイマ(コイル)
TN: タイマ(現在値)
SS: 積算タイマ(接点)
SC: 積算タイマ(コイル)
SN: 積算タイマ(現在値)
CS: カウンタ(接点)
CC: カウンタ(コイル)
CN: カウンタ(現在値)
SB: リンク特殊リレー
SW: リンク特殊レジスタ
S: ステップリレー
DX:ダイレクト入力
DY: ダイレクト出力
SM: 特殊リレー
SD: 特殊レジスタ

ワード単位で書込み

# 数値の場合の例
data = struct.pack('hhh', 123, 456, 789)
rcv = mcp.write('D20', data)

# 実数の場合の例
data = struct.pack('f', 1.23)
rcv = mcp.write('D10', data)

writeメソッドでアドレスと書込みデータを渡して実行すると戻り値に終了コードが返ってきます
書込みデータはバイト配列で渡します
ちなみに数値をバイト列にするstruct.packでよく使いそうなフォーマットを書いておきます

フォーマット バイト数
h Int16 2
H UInt16 2
i Int32 4
I UInt32 4
q Int64 8
Q UInt64 8
f Float 4
d Double 8

ビット単位で書込み

# ビットの場合の例
data = [0x11, 0x11, 0x10]
rcv = mcp.write('M10', data, 5)

第3引数に書き込むビット数を入れるとビット単位での書込みになります

データ変換

メソッド名 変換するデータの長さ
toBin バイナリ data = mcp.read('SM0', 8)
print(mcp.toBin(data))
> 0b11000100
toInt16 16bit数値 data = mcp.read('D0', 5)
print(mcp.toInt16(data))
> [-1, 1, 2, 3, 4]
toUInt16 16bit符号なし data = mcp.read('D0', 5)
print(mcp.toUInt16(data))
> [65535, 1, 2, 3, 4]
toInt32 32bit数値 data = mcp.read('D0', 6)
print(mcp.toInt32(data))
> [-1, 196610, 327684]
toUInt32 32bit符号なし data = mcp.read('D0', 6)
print(mcp.toUInt32(data))
> [131071, 196610, 327684]
toInt64 64bit数値 data = mcp.read('D0', 8)
print(mcp.toInt64(data))
> [-1, 1970350607106052]
toUInt64 64bit符号なし data = mcp.read('D0', 8)
print(mcp.toUInt64(data))
> [844433520197631, 1970350607106052]
toFloat 浮動小数点 data = mcp.read('D0', 4)
print(mcp.toFloat(data))
> [-2.2, 0.0]
toDouble 倍精度 data = mcp.read('D0', 8)
print(mcp.toDouble(data))
> [-2.2, 0.0]
toString 文字列 data = mcp.read('D0', 2)
print(mcp.toString(data))
> ABCD

参考

伝文フォーマット

一括読出し

D100から10ワード読出しコマンド

サブヘッダ ネットワーク番号 PC番号 要求先ユニットI/O番号 要求先ユニット局番号
50 00 00 FF FF 03 00
要求データ長 *1 監視タイマ コマンド サブコマンド *2 先頭番号 デバイスコード 点数
0C 00 10 00 01 04 00 00 64 00 00 A8 0A 00

*1 要求データ長から後ろのバイト数
*2 ビット読出しのときはサブコマンドを01 00にする

正常時の応答伝文
サブヘッダ ネットワーク番号 PC番号 要求先ユニットI/O番号 要求先ユニット局番号
D0 00 00 FF FF 03 00
応答データ長 *1 終了コード 読出しデータ
16 00 00 00 ...

*1 応答データ長から後ろのバイト数

一括書込み

D100から10ワード書込みコマンド

サブヘッダ ネットワーク番号 PC番号 要求先ユニットI/O番号 要求先ユニット局番号
50 00 00 FF FF 03 00
要求データ長 *1 監視タイマ コマンド サブコマンド *2 先頭番号 デバイスコード
20 00 10 00 01 14 00 00 64 00 00 A8
点数 書込みデータ
0A 00 01 00 02 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00

*1 要求データ長から後ろのバイト数
*2 ビット読出しのときはサブコマンドを01 00にする

正常時の応答伝文
サブヘッダ ネットワーク番号 PC番号 要求先ユニットI/O番号 要求先ユニット局番号
D0 00 00 FF FF 03 00
応答データ長 *1 終了コード
02 00 00 00

*1 応答データ長から後ろのバイト数