メインコンテンツまでスキップ

Modbus TCP / UDP ドライバ

概要

Modbus 産業標準 (Modbus-IDA / IEC 61158-6-12) ベースの PLC 通信。

項目
opc_typeMODBUS (TCP) / MODBUSUDP (UDP)
実装クラスplantpulse.driver.protocol.modbus.ModbusTCPDriver / ModbusUDPDriver
ライブラリ独自ネイティブ (plantpulse-plc-protocolModbusTcp / ModbusUdp)
read
write✅ (coil / holding-register)
セキュリティなし (Modbus 標準仕様上)
2026-07 ネイティブ移行 (TCP + UDP)

Modbus TCP/UDP はいずれも旧 PLC4j への委譲を廃止し、plantpulse-plc-protocol のネイティブ ModbusTcp / ModbusUdp(共通ベース AbstractNativeModbusDriver)として書き換えられました — FINS / MELSEC / AB-ETH と同一のパターンです。UDP は MBAP-over-UDP(単一データグラム = 単一 ADU)であり、アドレス・フォーマット・write レイヤは TCP と完全に同一です。アドレス構文(holding-register:N[:TYPE])は PLC4X modbus4x 表記をそのまま維持します。


OPC 登録フォーム

フィールド意味
opc_agent_ipModbus スレーブ IP192.168.0.50
opc_agent_portModbus ポート502 (TCP 既定)
timecycleポーリング周期 (ms)1000
options.request-timeoutリクエストタイムアウト (ms)5000
unit-identifier

Modbus TCP では通常 IP+ポートでスレーブを識別するため、unit-identifier(別名 unit-id) は既定で 1 です。 シリアル-TCP ゲートウェイの背後に複数スレーブがある場合は 1~247 で指定します。


タグ plc_address 形式

アドレス表記 (<area>:<address> + :<datatype> + [<count>]) — PLC4X modbus4x 構文をそのまま維持。 アドレスは 1-based(wire では 0-based に変換、holding-register:5 → wire レジスタ 4)。

表記意味
holding-register:1Holding Register 1 (16-bit)
holding-register:1:UINT16-bit unsigned
holding-register:1:DINT32-bit signed (2 register)
holding-register:1:REAL32-bit float (2 register)
holding-register:100:STRING[10]100~109 の ASCII 文字列
coil:1コイル 1 ビット
discrete-input:1discrete input 1 ビット
input-register:1input register 16-bit

詳細な表記ルールは PLC4j Modbus ドキュメント を参照してください。


data_type / format マッピング

Edge の format が PLC4j の type suffix にそのままマッピングされます。

edge data_typeedge formatPLC4j addr マッピング備考
Boolean(empty) / BOOLcoil:N または :BOOL1 bit
Integer / Short(empty):INT16-bit signed
UIntegerUI / UWORD:UINT16-bit unsigned
Integer (32)DW:DINT32-bit signed (2 reg)
UInteger (32)UDW:UDINT32-bit unsigned
FloatREAL:REAL32-bit IEEE 754
DoubleLREAL:LREAL64-bit IEEE 754
StringSTR[N]:STRING[N]N 文字

formatSTR[N]REAL[N]UDINT[N] で始まる場合は配列として処理されます (readWordValues)。


Write (ネイティブ — TCP/UDP 共通)

ModbusTCPDriver / ModbusUDPDriver は write に対応します(isWriteSupported()=true):

  • coil:N → single coil write (Boolean)。
  • holding-register:N[:TYPE] → datatype ごとの register write。REAL / DINT は MSWord-first の 2 レジスタ、それ以外は単一 16-bit。値は呼び出し側が ProtocolAddress.value で渡します。
  • discrete-input / input-register はプロトコル上 read-only — write 不可。

よくあるエラーと対処

メッセージ / 症状原因対処
PLC_READ_TIMEOUT_EXCEPTIONスレーブの応答遅延または切断ケーブル/ファイアウォール/ポート(502) を確認。request-timeout を延長
PLC_READ_RUNTIME_EXCEPTION: Invalid PLC4j addressアドレス表記の誤りholding-register:N 形式を検証、: の抜けに注意
値が 0 しか返らないレジスタ種別の mismatch (input vs holding)スレーブのマニュアルで fc 03/04/01/02 のいずれかを確認
32-bit 値の swap 異常byte/word orderスレーブが little-endian の場合は format:UDINT_LSWORD_FIRST などに変更 (PLC4j オプション)

curl 登録例 (Modbus TCP)

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_MB_HVAC",
"opc_type": "MODBUS",
"opc_name": "HVAC Slave",
"opc_agent_ip": "192.168.0.50",
"opc_agent_port": "502",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": { "request-timeout": "5000" },
"tag_list": [
{
"tag_id": "OPC_MB_HVAC_TAG_00001",
"tag_name": "Temperature",
"plc_address": "holding-register:1:REAL",
"data_type": "Float",
"format": "REAL"
},
{
"tag_id": "OPC_MB_HVAC_TAG_00002",
"tag_name": "Status",
"plc_address": "coil:1",
"data_type": "Boolean"
}
]
}'

UDP の場合は opc_type: "MODBUSUDP" に変更し、ポートは通常 502 またはスレーブ設定に従います。

値の read:

curl -s http://<edge-host>/api/v1/tag/OPC_MB_HVAC_TAG_00001/value | jq

サンプル集 (データタイプ別)

コイル / ディスクリート (Boolean)

data_typeformatplc_address備考
Boolean(empty)coil:1FC 01 (Read Coils)
Boolean(empty)discrete-input:1FC 02 (Read Discrete Inputs)
BooleanBIN[3]holding-register:1ワード read 後に bit 3 を抽出

16-bit 整数

data_typeformatplc_address備考
Integer(empty)holding-register:1signed INT 16
Integer(empty)holding-register:1:INT同一 (PLC4j 表記)
IntegerUIholding-register:1:UINTunsigned 16
Integer(empty)input-register:1input register (FC 04)

32-bit 整数

data_typeformatplc_address備考
IntegerDWholding-register:1:DINTsigned 32 (2 register)
IntegerUDWholding-register:1:UDINTunsigned 32
IntegerUDINTholding-register:1format 明示による 32-bit

実数

data_typeformatplc_address備考
FloatREALholding-register:132-bit float (2 register)
FloatREALholding-register:1:REAL同一表記
DoubleLREALholding-register:1:LREAL64-bit double (4 register)

文字列

data_typeformatplc_address備考
StringSTR[5]holding-register:105 word = 10 byte ASCII
StringSTR[16]holding-register:100:STRING[16]PLC4j 表記

Formula の活用

用途data_typefomula備考
整数 raw → 小数Float${VALUE}*0.1圧力/温度の raw スケール
Word swap 補正Float${VALUE}*1.032-bit float の byte order が異なるスレーブ用。代替: :REAL_LSWORD_FIRST
RH/Temp combo (1 ワードに 2 値)Float${VALUE}/256上位 8 bit のみ

curl 総合例

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_MB_FULL",
"opc_type": "MODBUS",
"opc_name": "Modbus Full",
"opc_agent_ip": "192.168.0.50",
"opc_agent_port": "502",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": { "request-timeout": "5000" },
"tag_list": [
{"tag_id":"OPC_MB_FULL_T01", "tag_name":"Coil1", "plc_address":"coil:1", "data_type":"Boolean"},
{"tag_id":"OPC_MB_FULL_T02", "tag_name":"DI1", "plc_address":"discrete-input:1", "data_type":"Boolean"},
{"tag_id":"OPC_MB_FULL_T03", "tag_name":"HRSigned", "plc_address":"holding-register:1", "data_type":"Integer"},
{"tag_id":"OPC_MB_FULL_T04", "tag_name":"HRUnsigned", "plc_address":"holding-register:2:UINT", "data_type":"Integer", "format":"UI"},
{"tag_id":"OPC_MB_FULL_T05", "tag_name":"DInt", "plc_address":"holding-register:3:DINT", "data_type":"Integer", "format":"DW"},
{"tag_id":"OPC_MB_FULL_T06", "tag_name":"Temp", "plc_address":"holding-register:5:REAL", "data_type":"Float", "format":"REAL"},
{"tag_id":"OPC_MB_FULL_T07", "tag_name":"BatchName", "plc_address":"holding-register:10:STRING[10]", "data_type":"String", "format":"STR[10]"},
{"tag_id":"OPC_MB_FULL_T08", "tag_name":"PressScale", "plc_address":"holding-register:7:REAL", "data_type":"Float", "format":"REAL", "fomula":"${VALUE}*0.1"}
]
}'