Modbusの利用 (1) 電源S8VK-X

 Modbusには、物理層にRS-485を使うModbus/ASCIIとRTUが、TCP/IPを使うModbus/TCPがあります。Modbusは、下記の資料が詳しいです。Modbus/RTUとModbus/TCPでは、エラー・チェックを除きデータのフォーマットは同じです。

  Modbusの仕様 日本語の参考資料 

 オムロンのS8VK-Xシリーズは、カタログにModbus対応と書かれています。ここでは、5V出力のS8VK-X03005-EIPを利用します。ミスミで購入しました。このシリーズは、5~24Vの電圧、各種電流が用意されています。DINレールに取り付けられ、イーサネットのコネクタがついています。


 読み出すためのユーティリティPower Supply Monitoring Toolが無料で利用できます。

IPアドレスをふる

 デフォルトで192.168.250.20が振られています。筆者のLANは192.168.111.xxxです。通常使っているPCはDHCPサーバからIPアドレスが振られます。
 「スイッチングパワーサプライ 通信マニュアル」に設定方法が書かれています。有料のNetwork Configuratorと無料のPower Supply Monitoring Toolが使えます。Network Configuratorは、同社のPLC用のアプリケーションのようです。

 PCを192.168.240.2(2は任意、サブネットは255.255.255.0 ゲートウェイは0.0.0.0)に変更しました。Windows10は変更後にipconfigでIPアドレスが変わっていることを確認します。PCとS8VK-Xはハブにつないでいます。pingをS8VK-Xに打って、正しく応答が返ってくることを確認します。ipconfig、pingはコマンドプロンプトで実行します。

 Power Supply Monitoring ToolのIPアドレスを振る項目で、固定IPアドレス、192.168.111.20に変更しました。一度電源を入れなおし、イーサネットのLED MSとNSの両方が緑色で点滅することを確認します。正しくIPアドレスがふれなかったらNSは赤色になります。
 その時は、一度電源を切り、RSTボタンを押したまま電源を入れ、10秒待ちます。これで、工場出荷時の初期状態に戻ります。

エラーが返る

 Modbus/TCPの通信手順は、「s8vk-x通信設定」に書かれています。こちらの記事「はじめてのModbus (2) Lチカ」で有用だったツールのCAS Modbus Scannerを使っても、データではないものが返ってくるというエラーが表示されます。

ソケット・プログラムでアクセス

 動作を確認するためにWindows10のPython3で、s8vk-x通信設定に書かれているコマンド列でアクセスします。

 IPv4のプロトコルで、ポートはModbusの502です。送っているコマンドは、

  0x00,0x00,0x00,0x00,0x00,0x06,0xff,0x03,0x00,volt,0x00,0x02

です。Modbusのメッセージ構成とは異なりますが、Read Holding Register(03)の用法とは似ています。

トランザクションID プロトコルID 転送バイト ユニットID ファンクション・コード 開始アドレス 読み出しワード数
0x00 0x00 0x00 0x00 0x00 0x06 0xff 0x03 下記の表 0x0002

開始アドレス データ名 読み出したデータの範囲
0x0000 ステータス 省略
0x0001 出力電圧 0x0000(0.00V)~0x2706(99.90V)
0x0002 出力電流 0x0000(0.00A)~0x2706(99.90A)
0x0003 ピーク・ホールド電流 0x0000(0.00A)~0x2706(99.90A)
0x0004 交換時期までの年数 0x0000(0)~0x5dc0(150.0年)
0x0005 交換時期までの割合 0x0000(0)~0x3e8(100.0%)
0x0006 積算稼働時間 0x0000(0)~0x40290(262,800時間)
0x0008 連続稼働時間 0x0000(0)~0xf099c0(15,768,000分)

import socket 
volt = 0x01
current = 0x02
peakcurrent = 0x03

s=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.111.20", 502))
print("send 0x03")
s.send(bytearray([0x00,0x00,0x00,0x00,0x00,0x06,0xff,0x03,0x00,volt,0x00,0x02]))
data = s.recv(100)
s.close()
print( int(str((hex(data[9]<<8 | data[10]))),16) /100 )



 読み出した2バイトのデータ出力電圧は100倍の値なので、100で割ります。結果は5.0でした。アナログ-ディジタル変換の確度は8~10ビットと思われます。稼働しているときの電力値を得るという目的なので、十分だと言えます。