Modbus TCP

TCP/IP 越しの Modbus のレジスターとコイル。型付きのアドレス指定、バイト順の指定、そして上限のあるネットワークのスキャン。

Markdown で表示

Modbus TCP のドライバーは、TCP/IP 越しに Modbus のレジスターとコイルを読み書きします。相手は PLC、計器、ゲートウェイ、そして Modbus/TCP を話すあらゆるサーバーです。アドレス指定は完全に型付きです。レジスターの種類と 0 起算のレジスター番号を選べば、アプリがバス上の要求を組み立てます。書き間違えるような自由記述のアドレスはありません。

機器

項目 意味 既定
ホスト Modbus サーバーかゲートウェイの DNS 名、IPv4、IPv6 のアドレス。 空のときは localhost
ポート TCP のポート。 502(0 を設定すると 502 に戻ります)
ユニット ID すべての要求が運ぶ Modbus のユニット(スレーブ)の ID で、ゲートウェイがその奥の機器へ振り分けるときに使うものです。0 から 255。 1
通信の最小間隔(ms) 互換のための間隔調整です。1 回のトランザクションが終わってから次が始まるまでの最小の休止で、0 から 1000 です。0 なら人為的な待ちを加えません。 0
読み出し周期(ms) 上書きしないタグに対する既定の読み出しの速さ。 1000

パネルの見出しに出る基準 URI は modbus+tcp://host:port/unitID で、間隔を設定していれば ?minimumTransactionIntervalMs=n が付きます。

ホストとポートを共有する機器は、1 つのトランザクションの門も共有します。同じ接続先への要求が重なることは決してなく、その接続先の有効な機器のうち最大の通信の最小間隔が、その全部の間隔を決めます。ほかの機器がここで設定した値より実効の間隔を引き上げているときは、パネルがそう伝えます。この間隔が支配するのは、このアプリケーションが出す通信だけです。応答の遅いサーバーやゲートウェイのための互換の補助であって、ネットワークの不具合を直すものではありません。

接続は最大 5 秒、応答は最大 10 秒待ちます。プロトコルの水準での再試行はありません。再接続は背後の再試行の繰り返しが受け持つので、電源の入っていない機器があっても、品質の悪い読み取りが出る以外の損はありません。

タグのアドレス指定

項目 意味 既定
レジスターの種類 タグが指す Modbus の対象です:HoldingRegisterInputRegisterCoilDiscreteInput 型とアクセスから導かれます。ブール値のタグは DiscreteInput(読み取り専用)か Coil(書き込める場合)、ほかの型は InputRegister(読み取り専用)か HoldingRegister(書き込める場合)。
レジスター番号(0 から数えます) 生のプロトコルのアドレスです。従来の 4xxxx の書き方ではなく、バス上の 0 起算のアドレスです。保持レジスターの「40001」はレジスター番号 0 です。レジスター番号は 16 ビットの数値としてバスを流れるので、この項目は 0 から 65535 を取り、それより広い値は入力したその場で拒否します。 0
個数(レジスター、空欄なら自動) 値が占める 16 ビットレジスターの数。この入力欄は文字列のタグにだけ描かれます。ほかの型は幅が決まっていて、上書きするものがないからです。 型による:ブール値は 1、Int32 と Float は 2、文字列は 4
上位バイトを先に 各 16 ビットレジスターのどちらのバイトがバス上で先に来るか。数値のタグだけです。 オン(Modbus の仕様が求める形)
上位ワードを先に 2 レジスターの値で、どちらのレジスターが上位の半分を運ぶか。数値のタグだけです。 オン

「取得元」のカードは、組み立てられたバス上のアドレス(たとえば 100?quantity=2)を読み取り専用の予告として見せるので、パネルが見せるものと要求が運ぶものはぴったり同じです。

値の型と個数

出る値の型は 4 つで、それぞれのプロトコル上の幅は決まっています。

データ型 レジスター バス上の形
Boolean 1 レジスターの種類では、0 でないレジスターは true と読まれ、書き込みは 1 か 0 を送ります。CoilDiscreteInput では、そのビットそのものです。
Int32 2 レジスター 2 つにまたがる 32 ビットの符号付き整数。
Float 2 レジスター 2 つにまたがる IEEE 754 の単精度。
String 1 つ以上(既定は 4) UTF-8 のバイトをレジスター 1 つにつき 2 つずつ詰めます。読み取りは最初の NUL バイトで止まります。書き込みは宣言した個数(レジスターあたり 2 バイト)に収まる必要があり、足りない分は 0 で埋められます。

文字列のタグは、機器がバイトを保持している順で読み書きされ、書き込みは常に UTF-8 を送ります。UTF-8 として正しくないバイト、つまり機器が一度も初期化していない範囲や、別の符号化で書かれた文字がそう見えるのですが、それは失敗ではなく Unicode の置換文字として読まれます。そのタグは目に見えておかしなものを見せますが、その機器のほかのタグは読み取りを続けます。

個数を尋ねるのは文字列のタグだけです。Boolean、Int32、Float の幅は決まっているので、タグのパネルにもタグのグリッドにも、その点では入力欄が描かれません。この上書きは、文字列のタグの大きさを決めるためにあります。

バイト順とワード順

2 つの順序の入力欄は、数値のタグに描かれます。これは独立した 2 つの問いです。各レジスターの中でどちらのバイトが先か、そして 2 つ 1 組のレジスターでどちらが先か。Modbus は文字についてはどちらも定めていないので、文字列のタグにはこれらが出ません。そのバイトは、機器が保持している順で流れます。値 0x01020304 について、最上位のバイトを A とすると、4 通りの並びは次のようになります。

上位バイトを先に 上位ワードを先に バス上のバイト
オン オン AB CD(仕様どおりの既定)
オン オフ CD AB(従来のワード入れ替え)
オフ オン BA DC
オフ オフ DC BA

読み取りと書き込みは、同じ 2 つの答えを同じ順で当てるので、書き込みは、読み取りが取ってくるはずのバイトをそのまま置きます。

機能コード

レジスターの種類 読み取り 書き込み
HoldingRegister 3(Read Holding Registers) 6(単一レジスター)または 16(複数レジスター)
InputRegister 4(Read Input Registers) 読み取り専用。書き込みは拒否されます
Coil 1(Read Coils) 5(Force Single Coil)
DiscreteInput 2(Read Discrete Inputs) 読み取り専用。書き込みは拒否されます

書き込みが成功として返るのは、サーバーのプロトコル上の応答が受け付けを確認したときだけです。保持している値が進むのも、そのときだけです。

機器検出

スキャンは明示的で、上限があります。アプリがローカルのサブネットを推測したり、まとめて掃いたりすることはありません。範囲のフォームが取るのは次のものです。

項目 意味 既定
IPv4 のホストまたは CIDR アドレス 1 つ(192.168.1.10)、または /24 より広くないサブネット(192.168.1.0/24)。ネットワークアドレスとブロードキャストアドレスは飛ばされます。 必須
ポート 探索するポート。 502
ユニット ID 値、カンマ区切りの並び、または昇順の範囲:11,5,91, 3, 8-16(0 から 255)。 1
通信の最小間隔(ms) 同じホストで探索が終わってから次までの間隔、0 から 1000。 0

1 回のスキャンが送れるのは最大で探索 256 回(ホスト × ユニット ID)です。それより大きな計画は、ソケットが 1 つも開く前に拒否されます。送られる要求は Read Basic Device Identification(機能コード 43/14)だけです。機器検出がレジスターを読んだり、レジスターの割り付けを当てたりすることはありません。完全に妥当な Modbus の例外応答は、身元は分からなくてもそのユニットの存在を示します。TCP で届くこと、タイムアウト、壊れたフレームは、示しません。同時にスキャンするホストは最大 4 つで、ホストの中では順番に行い、接続と探索のタイムアウトは 750 ms です。

結果は接続先の全体と、機器がベンダーと製品コードを報告したときはそれらから作った名前の候補を運びます。候補のタグは 0 件です。レジスターは追加のあとで設定します。すでに設定されているユニットはそう示され、重複を作る代わりに開くを出します。

知っておきたい限界

  • 幅の広い整数の型(Int64、符号なしの各幅)と Double は出ません。バス上の変換が過不足なく往復できるのは、上の 4 つの型です。
  • 1 つの接続先で同時に進む要求は 1 つだけです。1 台のゲートウェイの奥にある多数の機器は、設計上その直列化を共有します。
  • 書き込みは、一度に 1 つのコイルか 1 つのレジスターの連なりを対象にします。複数コイルをまとめて書く手段はありません。