Modbus RTU から MQTT へ:レジスタマッピング、バイト順序、スケーリング

信頼できる Modbus RTU から MQTT への連携には、機器のレジスタマップと、その測定値を利用するアプリケーションの間で明確な取り決めが必要です。シリアル通信で応答が正常に返ったことは、バイトが届いたことを示すにすぎません。試運転では、そのバイトが何を意味するのか、得られた値が今も有効な新しさを保っているのかも確認する必要があります。

このガイドでは、読み取り専用のテレメトリを対象に、アドレス変換、ファンクションコード、符号付きの値、スケーリング、複数レジスタの順序、MQTT データの鮮度を扱います。以下のレジスタ割り当て、数値、ペイロードはすべて説明用の例であり、Obeita 製品の仕様や現場での測定結果ではありません。

検証済みの RTU 読み取りを一つ確立する

機器の型番、ファームウェアのリビジョン、レジスタマップのリビジョン、シリアル設定、局アドレス、既知の基準値をそろえます。設置資料に照らして、RS-485 の配線、終端、バイアスを確認してください。意図したマスターだけがバスを制御していることを確かめます。スケーリングで値を補正しようとする前に、タイムアウトや CRC エラーを解決してください。

Modbus シリアルラインガイドは、RTU のフレーム構成、タイミング、誤り検出を定義しています。本番用のポーリング処理は、これらの要件と機器の応答上の制約を守る必要があります。まず資料で定義された一つの測定点から始め、生の応答とデコードした値の整合性を確認してから、ポーリング対象を増やします。

レジスタアドレスとファンクションコードを一緒に確認する

Modbus アプリケーションプロトコル仕様では、PDU アドレスは 0 起点です。ファンクションコード 03 は保持レジスタ、04 は入力レジスタを読み取ります。これらは別々の論理テーブルです。オフセットの数値が同じでも、二つのファンクションが同じ測定値を返すとは限りません。

一般的な資料の表記では、40001 は最初の保持レジスタ、30001 は最初の入力レジスタを示します。先頭の数字はテーブルの識別子であり、送信する PDU アドレスの一部ではありません。Modbus Organization のアドレス指定の説明を参照してください。

マニュアルの記載例 ファンクション PDU 開始アドレス
保持レジスタ 40011 03 10(十進数)、0x000A
入力レジスタ 30011 04 10(十進数)、0x000A

この表記規則では、40011 − 40001 = 10 です。ただし、マニュアルに 0 起点のオフセット、1 起点のレジスタ番号、または 16 進数のアドレスが記載されていることもあります。ゲートウェイの設定画面が独自に変換する場合もあります。マニュアルの表記と実際の PDU オフセットを両方記録し、機械的に 1 を引かないでください。機器の資料でその対応関係が明示されていない限り、もっともらしい値を得るために FC03 を FC04 に置き換えてはいけません。

最初の例の要求 PDU は 03 00 0A 00 01 です。ファンクションは 03、開始アドレスは 10、数量はレジスタ一つです。これはPDU のみで、完全な RTU フレームではありません。局アドレスと CRC は省略しています。

符号付きの値をデコードしてからスケーリングする

測定点の定義には、局アドレス、ファンクション、PDU オフセット、レジスタ数、データ型、ワード順序、スケール、オフセット、単位、無効値の規則、鮮度の上限を含めます。別の技術者が変換を再現できるように、生のレジスタワードを試運転ログに残してください。

例として、温度の測定点が符号付き 16 ビット値で、スケールが 0.1 °C、オフセットがゼロだとします。応答ワード 0xFF9C を符号なしとして読むと 65436 です。符号付きの 2 の補数として解釈すると、65436 − 65536 = −100 になります。デコード後にスケーリングを適用します。

engineering_value = decoded_value × scale + offset
                  = -100 × 0.1 + 0
                  = -10.0 °C

符号なしでデコードすると、代わりに 6543.6 °C が配信されます。その結果を隠すためにスケールを変えても、根本の型の誤りは解消しません。正の値、負の値、境界値をテストしてください。スケーリング前にメーカー定義の無効コードを確認し、無効を示す特別な値が、もっともらしい測定値に変わらないようにします。

Illustrative Modbus mapping from holding register 40011 to FC03 offset 10, signed word FF9C and an MQTT temperature value of minus 10.0 degrees Celsius.
図 1. マッピングの全過程で、アドレスの表記規則、符号付きデコード、工学値へのスケールを明確にしておきます。

16 ビットのバイト順序と複数レジスタのワード順序を区別する

標準的な 16 ビット Modbus レジスタ内では、上位バイトが先に送信されます。したがって、0x4148 は 41 48 として現れます。RTU の CRC は別のフィールドで、下位バイトが先に送信されます。この順序をレジスタのデコードに適用することはできません。

32 ビットのアプリケーション値は二つのレジスタを占めますが、ワードの配置は機器によって異なります。Schneider Electric のワードを入れ替えた浮動小数点値の例は、上位ワードと下位ワードの並べ替えが必要になる理由を示しています。

IEEE 754 float32 で正確に表現できる 12.5 を例にすると、ビットパターンは 0x41480000 です。上位ワードを先に配置するマップでは 0x4148, 0x0000、下位ワードを先に配置するマップでは 0x0000, 0x4148 が返ります。マニュアルどおりにワードを並べ替えた後、結合したビットを float32 として再解釈します。結合した整数を数値として浮動小数点数へ変換するのは、これとは別の操作です。

Two illustrative register layouts for IEEE 754 float32 12.5, showing high-word-first and low-word-first mappings while each register retains high-byte-first transmission.
図 2. デコーダーが資料に示されたワード順序を使えば、どちらの配置も 12.5 を表します。

ゲートウェイの「little endian」という設定名は、意味が曖昧な場合があります。実際に行われるワードとバイトの並べ替えを正確に記録してください。メーカーによっては、マッピングでアプリケーション上のバイト交換も定義しているため、明示的に検証します。対応している場合は関連ワードを一つの要求で読み取り、更新中も機器が整合したスナップショットを保証するか確認してください。

MQTT の値と一緒に鮮度と品質を配信する

各測定値に、安定した測定点名、単位、品質状態、意味を明示したタイムスタンプを付けます。機器が取得時刻を提供しない場合は、ゲートウェイで読み取りが成功した時刻として正しく表示してください。後の配信時刻によって古いサンプルを新しく見せてはいけません。

次のアプリケーションペイロードの例では、ゲートウェイの読み取り完了時刻と、起動ごとに管理するシーケンス番号を使います。

{
  "schema_version": 1,
  "device_id": "example-device-07",
  "point": "temperature",
  "value": -10.0,
  "unit": "degC",
  "quality": "good",
  "read_completed_at": "2026-10-03T12:00:00Z",
  "time_source": "gateway_read",
  "boot_id": "example-boot-01",
  "sequence": 1042
}

ポーリングが失敗した後の動作を定義します。例えば、最後に正常取得した時刻を保持しながら品質を期限切れとして報告する方法や、利用不可を明示する値を配信する方法があります。対象プロセスに適した鮮度のしきい値、時計同期の要件、キューの上限を定めてください。バッファー内のサンプルを再送する場合も、元の読み取り時刻を保持します。

MQTT の retained メッセージは、新しいサブスクライバーが最後に配信された状態を取得するのに役立ちますが、保持されていることは鮮度の保証にはなりません。MQTT 5 の Message Expiry はキュー内のメッセージの存続時間を制限できますが、利用側では引き続きアプリケーションレベルでデータの経過時間を確認する必要があります。MQTT 5.0 の 3.3 節と 4.3 節を参照してください。

QoS の選択でエンドツーエンドの厳密に一度だけの処理を保証しない

MQTT QoS 0 は最大一回の配信、QoS 1 は少なくとも一回の配信、QoS 2 はそのプロトコル交換の範囲内で厳密に一回の配信を提供します。仕様で定める配信の範囲は、単一の送信者と受信者の間です。ブローカーからサブスクライバーへの配信は別の交換です。QoS 2 だけでは、システム全体でセンサーからの取得やデータベース更新が厳密に一度だけ行われることを保証できません。

重複が問題になる場合は、利用側の書き込みを冪等に設計します。機器、起動 ID、シーケンス番号を組み合わせたアプリケーションキーは、一意性と永続化の規則が定義されていれば重複排除に利用できます。実際のブローカー、クライアント、ストレージ構成で、再接続と下流側のリトライをテストしてください。

試運転チェックリスト

  • FC03 と FC04 の違いを含め、要求 PDU を承認済みのアドレスマップと照合する。
  • クラウド上の計算を有効にする前に、生のワードを機器の既知の表示値と照合する。
  • 負の値、無効コード、ワード順序の変更、ポーリングの一部失敗を試す。
  • シリアル機器とブローカーをそれぞれ切断し、古いデータを引き続き識別できることを確認する。
  • ゲートウェイと利用側を再起動し、再送データの経過時間、重複の扱い、シーケンスの動作を確認する。
  • テストしたファームウェア、マップのリビジョン、ペイロードスキーマ、受け入れ結果を記録する。

Modbus RTU から MQTT への要件レビューを準備する

Obeita と連携を相談する際は、機器マニュアルの関連ページ、要求と応答のフレーム例、想定する工学値、測定点数、ポーリング間隔、ブローカーの要件、停止時の動作を用意してください。パスワード、キー、顧客識別子、プライベートネットワークの詳細、共有する権限のない専有データは伏せてください。こうした情報があれば、ゲートウェイ設定を確定する前にマッピングを定義し、テストできます。

関連するエンジニアリングの範囲については、Obeita の既存機器の接続サービスと、納入済みの STM32 データ収集・MQTT 連携プロジェクト(英語)をご覧ください。お客様のマッピング要件については、Obeita にお問い合わせください。

一次資料

  1. Modbus アプリケーションプロトコル仕様 V1.1b3。関連節:4.2、4.3、4.4、6.3、6.4。
  2. Modbus 入門 — Modbus Organization。関連箇所:Modbus のデータアドレス指定とファンクション 03。
  3. Modbus シリアルライン仕様・実装ガイド V1.02。関連節:2.2、2.5.1、3。
  4. Schneider Electric — Modbus でワードが入れ替わった浮動小数点値を読み取る方法。関連箇所:Resolution(解決方法)。
  5. MQTT バージョン 5.0 — OASIS 標準。関連節:3.3.1.3、3.3.2.3.3、4.3。

類似投稿