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

LS XGI / XBC / XBM (FEnet) ドライバ

概要

LS ELECTRIC (旧 LS産電) の XGI / XBC / XBM PLC シリーズと FEnet (Fast Ethernet) 標準プロトコルで 通信します。

項目
opc_typeLS
実装クラスplantpulse.driver.protocol.ls.LSDriver
通信ライブラリ独自 Java 実装 (plantpulse-plc-driver-ls.jarFEnetClient)
read
write❌ (独自 Java ドライバに write API 未公開)
セキュリティなし (社内網前提)
ネイティブ → Java 移行

以前は .NET で書かれた外部ネイティブバイナリ (FENetClient.exe) を外部プロセスとして起動して利用する NativeProcessDriver ベースでした。2025 年から独自 Java 実装 (plantpulse-plc-driver-ls.jar) に移行し、socket による直接通信を行います。結果として OS 依存 / 外部 プロセス管理の負担がなくなりました。


OPC 登録フォーム

フィールド意味
opc_agent_ipPLC IP192.168.0.80
opc_agent_portFEnet ポート2004 (XGT デフォルト)
timecycleポーリング周期 (ms)1000
options.company-idFEnet company ID (任意)(通常は空欄)
options.use-checksumBCC チェックサム使用false (default)
options.use-hex-bit-indexビット index の 16 進使用false (default)
options.connect-timeout接続タイムアウト (ms)3000
options.read-timeoutread タイムアウト (ms)3000

connect 段階で NetUtils.isReachable(ip) ping 検査を先に実行します → 到達不可の場合は即時失敗。


タグ plc_address 形式

FEnet 標準 (正式形式)

%<DeviceType><DataType><Index>
意味
%DW00309Data 領域、Word、index 309
%DD00600Data 領域、Double Word (32-bit)、index 600
%DL00800Data 領域、Long Word (64-bit)、index 800
%MX02704Memory 領域、Bit、index 0x2704 (または 10 進 2704)
%MW00100Memory 領域、Word、index 100

DeviceType の文字: D (Data)、M (Memory)、K (Keep)、F (Flag)、T (Timer)、C (Counter)、R など LS XGI の標準デバイスコード。

DataType の文字: X (Bit)、B (Byte)、W (Word, 16-bit)、D (Double Word, 32-bit)、L (Long Word, 64-bit)。

Edge short form (推奨)

Edge は short form を受け取り、自動的に FEnet 標準へ変換します。

Edge 入力data_typeformat自動変換結果
D00309Integer(empty)%DW00309
D00600IntegerDW%DD00600
D00800Long(empty)%DL00800
M02704Boolean(empty)%MX02704
D00100FloatREAL (または default)%DD00100
D00200DoubleLREAL%DL00200
D00300StringSTR[10]%DW00300 から 10 ワード read

内部実装 (LSDriver.toFEnet):

// raw plc_address (D00309) → %D<dataCh>00309
static String toFEnet(String rawAddr, char dataCh) {
if (rawAddr.charAt(0) == '%') return rawAddr; // 이미 표준이면 유지
return "%" + Character.toUpperCase(rawAddr.charAt(0)) + dataCh + rawAddr.substring(1);
}

dataChdata_typeformat で決定 (次節を参照)。


data_type / format マッピング (詳細)

LS ドライバは同一の short address でも format だけで メモリ幅を明示的に変更 できるため、1 つの デバイスのデバイスコードを 16/32/64-bit へ自由にマッピングできます。

Integer 系 (data_type=Integer / Short / Int / Int16 …)

format意味FEnet DataType呼び出し
(empty)Word (signed)16-bit%DWclient.readWord
UI / UW / UWORDUWord (unsigned)16-bit%DWclient.readUWord
DW / DWORD / DOUBLE_WORDDWord (signed)32-bit%DDclient.readDWord
UL / UDW / DUW / UDWORDUDWord (unsigned)32-bit%DDclient.readUDWord
LW / LWORD / LONG_WORDLWord (signed)64-bit%DLclient.readLWord
ULW / ULWORDULWord (unsigned)64-bit%DLclient.readULWord
format 未指定の意味

D00309 + data_type=Integer + format= (空欄) は 16-bit signed Word です。 32-bit が必要な場合は format=DW で明示します。これは LS XGI の一般的な慣例と一致します。

Float / Double

data_typeformatFEnet呼び出し
Float / REAL(empty) / REAL / FLOAT32-bit IEEE 754%DDclient.readFloat
Double / LREAL(empty) / LREAL / DOUBLE64-bit IEEE 754%DLclient.readDouble

format=DW + data_type=Float の場合も 32-bit float として解釈します (isFloat(dt) 分岐)。

Boolean

data_typeformat意味
Boolean / Bool / Bit(empty) / X / BIT%MX... または %PX... のビット単位 read

short form のまま: M02704%MX02704

String

format意味
STR1 ワード (2 文字)16-bit × 1
STR[N]N ワード (2N 文字)16-bit × N

ASCII エンコーディング + low byte first (LS spec)。末尾の NUL バイトは trim 処理されます。

// readStringMulti: N 워드 연속 read, low byte 먼저
for (int i = 0; i < wordCount; i++) {
int w = client.readUWord("%" + dev + "W" + (startIdx + i));
bytes[b++] = (byte) (w & 0xFF);
bytes[b++] = (byte) ((w >> 8) & 0xFF);
}

BIN / BIN[idx]

ワード 1 個を読み取り、ビット idx のみを抽出 (Modbus と同じ慣例)。

format動作
BINワード read 後に bit 0 を抽出
BIN[5]bit 5 を抽出
BIN[F]hex F (=15) bit を抽出 (1 文字は 16 進を許容)

よくあるエラー + 解決

メッセージ / 症状原因解決
LS-PLC Ping failed : <ip>ICMP 到達不可ケーブル/ファイアウォールを確認。ICMP block 環境の場合は遮断ポリシーを検討
LS connect failedFEnet モジュール未稼働 / ポート mismatchXG5000 で FEnet モジュールの IP/Port を確認 (通常 2004)
値が常に 0short form → 幅 mismatch (Word なのに DWord で読み取り)format を空欄にするか DW で正確に明示
32-bit float が壊れるformat が欠落 → Word として読まれるdata_type=Float + format=REAL を明示
文字列が文字化けするLS の low-byte-first が未反映edge 側で自動処理。外部で bytes を直接解釈する場合は注意
Bit が読めないshort form が D00100 として入っているM02704 (M 領域) を使用、または format=BIN[idx]

curl 登録例

XGI / XBC / XBM の D、M 領域混在の例:

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_LS_XBM_0001",
"opc_type": "LS",
"opc_name": "XBM Line A",
"opc_agent_ip": "192.168.0.80",
"opc_agent_port": "2004",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": {
"connect-timeout": "3000",
"read-timeout": "3000",
"use-checksum": "false"
},
"tag_list": [
{
"tag_id": "OPC_LS_XBM_0001_TAG_00001",
"tag_name": "Counter",
"plc_address": "D00309",
"data_type": "Integer"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00002",
"tag_name": "Production32",
"plc_address": "D00600",
"data_type": "Integer",
"format": "DW"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00003",
"tag_name": "Pressure",
"plc_address": "D00100",
"data_type": "Float",
"format": "REAL"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00004",
"tag_name": "Status",
"plc_address": "M02704",
"data_type": "Boolean"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00005",
"tag_name": "BatchName",
"plc_address": "D00500",
"data_type": "String",
"format": "STR[10]"
},
{
"tag_id": "OPC_LS_XBM_0001_TAG_00006",
"tag_name": "Bit3OfStatus",
"plc_address": "D00400",
"data_type": "Integer",
"format": "BIN[3]"
}
]
}'

値の read:

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

動作メモ

  • Read 分岐の優先順位 (LSDriver.read()):
    1. data_type=String または formatSTR / STR[N]readStringMulti
    2. formatBIN または BIN[idx] → ワード read 後にビット抽出
    3. format の明示分岐 (UI, DW, UL, LW, REAL, LREAL など) → readByFormat
    4. フォールバック: data_type 単独 (readByDataType)
  • client の呼び出しは synchronized されているため、1 つの OPC 内の複数タグ read は直列。別の OPC は別スレッド。
  • write は未実装。Sparkplug NCMD を使用するには、今後 FEnetClient.write* の公開が必要です。

例集 (データタイプ別)

LS XGI / XBC / XBM の運用現場で頻繁に使う組み合わせをすべて 1 つの表にまとめました。plc_address は short form 基準であり、自動的に %D... 標準表記へ変換されます。

ビット / ブール (Boolean)

data_typeformatplc_addressメモリ幅意味 / 備考
Boolean(empty)M027041 bitメモリ領域のビット。最も一般的な形
Boolean(empty)P0001F1 bitLS XGI の 16 進ビットインデックス (F=15)。use-hex-bit-index=true の場合
Boolean(empty)K000101 bitKeep relay ビット
Boolean(empty)T01101 bitTimer 出力ビット
BooleanBIND0030916 bit → bit 0ワード read 後に 0 ビット抽出
BooleanBIN[3]D0030916 bit → bit 3bit 3 抽出
BooleanBIN[F]D0030916 bit → bit 15hex インデックス F=15

16-bit 整数 (Integer/Word)

data_typeformatplc_addressメモリ幅意味
Integer(empty)D0030916 bitsigned Word (%DW00309)
IntegerUID0030016 bitUWord (unsigned, client.readUWord)
IntegerUWORDD0030016 bitUI と同一

32-bit 整数 (DWord)

data_typeformatplc_addressメモリ幅意味
IntegerDWD0060032 bitDWord signed (%DD00600D00600/00601 を結合)
IntegerDWORDD0060032 bit上と同一
IntegerDUWD0069032 bitUDWord (unsigned 32)
IntegerUDWD0069032 bitUDW と同一
IntegerULD0069032 bitULong = UDWord (alias)

64-bit 整数 (LWord)

data_typeformatplc_addressメモリ幅意味
Long(empty)D0070064 bitLWord signed (%DL00700)
LongLWD0070064 bit明示的 LWord
LongLWORDD0070064 bit同一
LongULWD0075064 bitULWord (unsigned 64)

実数 (Float / Double)

data_typeformatplc_addressメモリ幅意味
Float(empty)D0045032 bitIEEE 754 single (%DD00450)
FloatREALD0045032 bit明示
FloatDWD0045032 bitisFloat(dt) 分岐で float 処理
DoubleLREALD0050064 bitIEEE 754 double (%DL00500)
Double(empty)D0050064 bitLREAL と同一

文字列 (String)

data_typeformatplc_addressメモリ幅意味
StringSTRD0080316 bit (1 word)2 chars (low byte first)
StringSTR[5]D0080080 bit (5 words)10 chars、NUL trim
StringSTR[10]D00500160 bit (10 words)20 chars
StringSTR[16]D0010032 word32 chars (32 byte) — XGI 推奨アライメント

Formula の活用 (LS 現場パターン)

用途data_typefomula入力 → 出力
整数 raw → 小数 1 桁Float${VALUE}*0.11638163.8
整数 raw → 小数 2 桁Float${VALUE}*0.0112345123.45
signed 16 → unsigned 変換Integer${VALUE}+65536負値 raw の補正 (16-bit 換算)
ゼロ点補正 (別タグ)Float${VALUE}-${TAG_ZERO}1024 - 24 = 1000
キャリブレーション (gain × x + offset)Float${VALUE}*${TAG_GAIN}+${TAG_OFFSET}補正係数は別タグ
Hz 変換 (rpm → Hz)Float${VALUE}/60180030.0

fomula の詳しい使い方は Formula リファレンス を参照してください。

curl 総合例 (すべての型を一度に)

curl -X POST http://<edge-host>/api/v1/opc \
-H "Content-Type: application/json" \
-d '{
"opc_id": "OPC_LS_FULL",
"opc_type": "LS",
"opc_name": "LS XGI Full",
"opc_agent_ip": "192.168.0.80",
"opc_agent_port": "2004",
"site_id": "SITE_00001",
"auto_collect": true,
"timecycle": 1000,
"options": { "use-hex-bit-index": "true" },
"tag_list": [
{"tag_id":"OPC_LS_FULL_T01", "tag_name":"BitM", "plc_address":"M02704", "data_type":"Boolean"},
{"tag_id":"OPC_LS_FULL_T02", "tag_name":"BitPHex", "plc_address":"P0001F", "data_type":"Boolean"},
{"tag_id":"OPC_LS_FULL_T03", "tag_name":"WordSigned", "plc_address":"D00309", "data_type":"Integer"},
{"tag_id":"OPC_LS_FULL_T04", "tag_name":"WordU", "plc_address":"D00300", "data_type":"Integer", "format":"UI"},
{"tag_id":"OPC_LS_FULL_T05", "tag_name":"DWordS", "plc_address":"D00600", "data_type":"Integer", "format":"DW"},
{"tag_id":"OPC_LS_FULL_T06", "tag_name":"DWordU", "plc_address":"D00690", "data_type":"Integer", "format":"DUW"},
{"tag_id":"OPC_LS_FULL_T07", "tag_name":"LWord", "plc_address":"D00700", "data_type":"Long"},
{"tag_id":"OPC_LS_FULL_T08", "tag_name":"Real", "plc_address":"D00450", "data_type":"Float", "format":"REAL"},
{"tag_id":"OPC_LS_FULL_T09", "tag_name":"LReal", "plc_address":"D00500", "data_type":"Double", "format":"LREAL"},
{"tag_id":"OPC_LS_FULL_T10", "tag_name":"Str1Word", "plc_address":"D00803", "data_type":"String", "format":"STR"},
{"tag_id":"OPC_LS_FULL_T11", "tag_name":"Str10Word", "plc_address":"D00500", "data_type":"String", "format":"STR[10]"},
{"tag_id":"OPC_LS_FULL_T12", "tag_name":"BitOfWord", "plc_address":"D00309", "data_type":"Boolean", "format":"BIN[3]"},
{"tag_id":"OPC_LS_FULL_T13", "tag_name":"PressScale", "plc_address":"D00100", "data_type":"Float", "format":"REAL", "fomula":"${VALUE}*0.1"}
]
}'