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

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.jar → FEnetClient)
read✅
write✅ (Bit · Byte · Word · DWord · Float · LWord · Double · String、BIN[n] は read-modify-write)
セキュリティなし (社内網前提)
ネイティブ → 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);
}

dataCh は data_type と format で決定 (次節を参照)。


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_typeformat幅FEnet呼び出し
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) のビットを抽出 (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 または format が STR / STR[N] → readStringMulti
    2. format が BIN または BIN[idx] → ワード read 後にビット抽出
    3. format の明示分岐 (UI、DW、UL、LW、REAL、LREAL など) → readByFormat
    4. フォールバック: data_type 単独 (readByDataType)
  • client の呼び出しは synchronized されているため、1つの OPC の複数タグ read は直列。他の OPC は別スレッド。
  • write は 実装済みです。 ビット単位の書き込み(BIN[n])はワードを読み込み、該当ビットのみを変更して書き戻します — 同じワードを他の場所から同時に書き込むと互いに上書きされます。

例集 (データタイプ別)​

LS XGI / XBC / XBM の運用現場で頻繁に使う全組み合わせを一表にまとめました。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 (%DD00600、D00600/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.11638 → 163.8
整数 raw → 小数2桁Float${VALUE}*0.0112345 → 123.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}/601800 → 30.0

formula の詳しい使い方は 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"}
]
}'