用户指南
概述
EthernetIPForUE v1.0.1.1 是一个在 Unreal Engine 5.0~5.7 中实现 EtherNet/IP (CIP) 协议的插件。它使 UE 项目能够与工业 PLC、机器人控制器及其他 EIP 兼容设备通过标准 TCP/IP 网络进行通信。
插件支持两大角色,各角色下可创建多个命名实例,每个实例独立连接不同的设备:
Adapter(服务端)
UE 作为 EIP 设备,等待外部 Scanner 连接。支持两种协议:
| 协议 | 实例类 | 说明 |
|---|---|---|
| Assembly | UEIPAssemblyAdapter |
暴露固定长度的 Assembly 数据缓冲区 |
| Tag | UEIPTagAdapter |
暴露按名称读写的 Tag 标签(CIP Symbol 服务) |
Scanner(客户端)
UE 作为扫描器连接远程 EIP 设备。支持两种协议:
| 协议 | 实例类 | 说明 |
|---|---|---|
| Assembly | UEIPAssemblyScanner |
通过 Assembly 实例号循环读写 |
| Tag | UEIPTagScanner |
通过 CIP Symbol 服务按名称读写标签 |
快速入门
1. 启用插件
- 打开 UE 项目
- 进入 编辑 → 插件
- 搜索 "EthernetIPForUE" 并勾选 已启用
- 重启编辑器
2. 启动 Adapter(UE 作为服务端)
通过 UEIPAdapterManager 创建并启动一个 Adapter 实例:
Event BeginPlay
→ GetGameInstance → Get EIP Adapter Manager
→ GetAssemblyAdapter("MyAdapter")
→ Start(Port: 44818)
适配器开始监听端口 44818。外部 EIP 扫描器可以连接并读写数据。
同时启动多个 Adapter(不同端口):
→ GetAssemblyAdapter("RobotArm") → Start(44818)
→ GetTagAdapter("SensorHub") → Start(44819)
3. 启动 Scanner(UE 作为客户端)
通过 UEIPScannerManager 连接远程设备:
→ GetGameInstance → Get EIP Scanner Manager
→ GetAssemblyScanner("PLCMain")
→ SetConnectionParams("192.168.1.100", 44818)
→ Start()
4. 管理实例
| 方法 | 说明 |
|---|---|
GetAssemblyAdapter(Name) |
获取或创建 Assembly Adapter |
GetTagAdapter(Name) |
获取或创建 Tag Adapter |
GetAssemblyScanner(Name) |
获取或创建 Assembly Scanner |
GetTagScanner(Name) |
获取或创建 Tag Scanner |
Del(Name) |
删除指定实例 |
DelAll() |
删除所有实例 |
GetActiveNames() |
获取所有活跃实例名称列表 |
GetActiveCount() |
获取活跃实例数量 |
实例通过
UPROPERTY持有,不会被 GC 回收。Del(Name)从管理器移除后自动进入回收队列。
5. 读写数据
所有实例名称(
Name/TagName)均为FName类型。
Assembly Adapter(服务端) — 读写远程 Scanner 写入/读取的数据缓冲区:
| 方法 | 说明 |
|---|---|
ReadFloat(ByteOffset) |
从输入缓冲区读取浮点数(Scanner 写入的数据) |
ReadFloat16(ByteOffset) |
从输入缓冲区读取半精度浮点数 |
ReadInt32(ByteOffset) |
从输入缓冲区读取 32 位整数 |
ReadInt16(ByteOffset) |
从输入缓冲区读取 16 位整数 |
ReadByte(ByteOffset) |
从输入缓冲区读取字节 |
ReadBool(ByteOffset, BitIndex) |
从输入缓冲区读取布尔值 |
ReadRaw(ByteOffset, Count) |
从输入缓冲区读取原始字节序列 |
WriteFloat(ByteOffset, Value) |
写入浮点数到输出缓冲区(Scanner 读取的数据) |
WriteFloat16(ByteOffset, Value) |
写入半精度浮点数到输出缓冲区 |
WriteInt32(ByteOffset, Value) |
写入 32 位整数到输出缓冲区 |
WriteInt16(ByteOffset, Value) |
写入 16 位整数到输出缓冲区 |
WriteByte(ByteOffset, Value) |
写入字节到输出缓冲区 |
WriteBool(ByteOffset, BitIndex, Value) |
写入布尔值到输出缓冲区 |
Assembly Scanner(客户端) — 读写远程设备的 Assembly 数据缓冲区:
| 方法 | 说明 |
|---|---|
WriteFloat(ByteOffset, Value) |
写入浮点数到远程设备 |
WriteFloat16(ByteOffset, Value) |
写入半精度浮点数到远程设备 |
WriteInt32(ByteOffset, Value) |
写入 32 位整数到远程设备 |
WriteInt16(ByteOffset, Value) |
写入 16 位整数到远程设备 |
WriteByte(ByteOffset, Value) |
写入字节到远程设备 |
WriteBool(ByteOffset, BitIndex, Value) |
写入布尔值到远程设备 |
ReadFloat(ByteOffset) |
从远程设备读取浮点数 |
ReadFloat16(ByteOffset) |
从远程设备读取半精度浮点数 |
ReadInt32(ByteOffset) |
从远程设备读取 32 位整数 |
ReadInt16(ByteOffset) |
从远程设备读取 16 位整数 |
ReadByte(ByteOffset) |
从远程设备读取字节 |
ReadBool(ByteOffset, BitIndex) |
从远程设备读取布尔值 |
ReadRaw(ByteOffset, Count) |
从远程设备读取原始字节序列 |
Tag Scanner(客户端):
| 方法 | 说明 |
|---|---|
ReadTag(TagName) |
按名称读取标签(FName) |
WriteTag(TagName, Value) |
按名称写入标签(FName) |
Tag Adapter(服务端):
| 方法 | 说明 |
|---|---|
RegisterTag(TagName, InitialValue) |
注册一个外部可访问的标签(FName) |
SetTagValue(TagName, Value) |
设置标签值(FName) |
GetTagValue(TagName) |
获取标签值(FName) |
管理器参考
UEIPAdapterManager
管理器,管理所有 Adapter 实例。
| 方法 | 返回类型 | 说明 |
|---|---|---|
GetAssemblyAdapter(Name) |
UEIPAssemblyAdapter* |
获取或创建 Assembly Adapter 实例 |
GetTagAdapter(Name) |
UEIPTagAdapter* |
获取或创建 Tag Adapter 实例 |
Del(Name) |
void | 停止并删除指定名称的实例 |
DelAll() |
void | 停止并删除所有实例 |
GetActiveNames() |
TArray<FName> |
获取所有活跃实例名称 |
GetActiveCount() |
int32 | 获取活跃实例数量 |
所有实例名称参数(
Name)为FName类型。
UEIPScannerManager
管理器,管理所有 Scanner 实例。
| 方法 | 返回类型 | 说明 |
|---|---|---|
GetAssemblyScanner(Name) |
UEIPAssemblyScanner* |
获取或创建 Assembly Scanner 实例 |
GetTagScanner(Name) |
UEIPTagScanner* |
获取或创建 Tag Scanner 实例 |
Del(Name) |
void | 停止并删除指定名称的实例 |
DelAll() |
void | 停止并删除所有实例 |
GetActiveNames() |
TArray<FName> |
获取所有活跃实例名称 |
GetActiveCount() |
int32 | 获取活跃实例数量 |
所有实例名称参数(
Name)为FName类型。
组件参考
UEIPLinkComponent
挂载到任意 Actor 上。通过 ByteOffset 或 DataBind 索引读写绑定的 Scanner 实例。
属性:
| 属性 | 默认值 | 说明 |
|---|---|---|
ScannerName |
Default |
绑定的 Scanner 实例名称(传给 GetAssemblyScanner/GetTagScanner),FName 类型 |
SubsystemType |
Assembly | 绑定的子系统类型(Assembly / Tag) |
ReadInstance |
100 | 读取实例号 |
WriteInstance |
101 | 写入实例号 |
UpdateInterval |
0.0 | 数据更新间隔(秒),0 = 每帧 |
DataBinds |
— | 数据绑定列表(ByteOffset + DataType + Scale + Offset),每帧自动读取 |
InitialBufferSize |
24 | 原始值缓冲区初始大小,DataBinds 超出时自动扩展 |
事件:
| 事件 | 说明 |
|---|---|
OnEIPConnected |
连接成功时触发 |
OnEIPDisconnected |
断开连接时触发 |
OnDataUpdated |
数据更新时触发 |
OnEIPError |
发生错误时触发 |
逐字节读取方法:
GetFloatValue(ByteOffset)GetFloat16Value(ByteOffset)GetIntValue(ByteOffset)GetInt16Value(ByteOffset)GetBoolValue(ByteOffset, BitIndex)GetByteValue(ByteOffset)
逐字节写入方法:
WriteFloatValue(ByteOffset, Value)WriteFloat16Value(ByteOffset, Value)WriteIntValue(ByteOffset, Value)WriteInt16Value(ByteOffset, Value)WriteByteValue(ByteOffset, Value)WriteBoolValue(ByteOffset, BitIndex, Value)
DataBind 索引读取方法:
| 方法 | 说明 |
|---|---|
GetItem(Index) |
获取单个 DataBind 条目的原始字节缓冲区 |
GetItems() |
获取所有 DataBind 条目的原始字节缓冲区 |
GetValueAsFloat(Index) |
获取 DataBind 索引处的值(float,已应用 Scale/Offset) |
GetValueAsInt(Index) |
获取 DataBind 索引处的值(int32) |
GetValueAsInt64(Index) |
获取 DataBind 索引处的值(int64) |
GetValuesAsFloat() |
获取全部值(float 数组,索引与 DataBinds 对齐) |
GetValuesAsInt() |
获取全部值(int32 数组) |
内部通过 UEIPScannerManager 的 GetAssemblyScanner(ScannerName) 或 GetTagScanner(ScannerName) 进行读写。
UEIPAnimLinkComponent
继承自 UEIPLinkComponent。添加了每帧平滑值缓存,支持可配置的插值速度。
| 属性 | 默认值 | 说明 |
|---|---|---|
MonitorLinks |
— | 监视链接数组(ByteOffset + DataType + Scale + Offset) |
InterpSpeed |
10.0 | FInterpTo 插值速度(0 = 无平滑) |
CachedValues |
— | (只读)平滑后的值缓存 |
全局配置 (v1.0.1.1+ 灵活模式)
从 v1.0.1.1 开始,配置系统转向更自由的使用方式。UEIPGlobalConfig 是一个 BlueprintType 的 UObject,你可以在蓝图中创建、修改配置对象,再传递给 Scanner/Adapter 使用。
核心类:UEIPGlobalConfig
配置对象可通过 GetEipConfig(Key) 获取命名单例(Key 默认为 "Default"),自动从 Config/EIPConfig.ini 加载/保存。
| 蓝图方法 | 说明 |
|---|---|
GetEipConfig(Key) |
获取命名配置单例(不存在则创建) |
LoadFromFile() |
从 EIPConfig.ini 加载(缺失字段保持默认值) |
SaveToFile() |
保存到 EIPConfig.ini |
所有字段均可通过 BlueprintReadWrite 在蓝图编辑器中直接修改。
Scanner 用法(推荐)
两种方式任选:
方式一 — 蓝图加载配置传递给 Scanner:
→ GetEipConfig("PLC1") // 获取命名配置
→ Set AssemblyIPAddress / AssemblyPort / ... // 可选:在蓝图中修改
→ GetAssemblyScanner("PLCMain")
→ LoadConfig("PLC1") // 从 Config 加载参数
→ Start() // 启动连接
LoadConfig(Key) 会自动读取对应配置对象的 Assembly 连接参数(IP、端口、Assembly ID、缓冲区大小等)。找不到预设时会写出当前配置到文件。
方式二 — 手动设置参数(适合简单场景):
→ GetAssemblyScanner("PLCMain")
→ SetConnectionParams("192.168.1.100", 44818, 100, 101)
→ Start()
Adapter 用法
Adapter 更简单,直接指定端口启动即可:
→ GetAssemblyAdapter("RobotArm")
→ Start(44818)
Tag Adapter 同理:
→ GetTagAdapter("SensorHub")
→ Start(44819)
Adapter 的端口号也可通过 UEIPGlobalConfig.AdapterPort 管理,但非必须。
你也可以自己管理 Config
UEIPGlobalConfig 是普通的 UObject,你可以完全自行控制:
- 创建后手动设置字段,调用
SaveToFile()持久化 - 下次运行时调用
GetEipConfig(Key)自动加载 - 多个命名配置对应 INI 文件中的不同节(
[EIPGlobalConfig_PLC1]、[EIPGlobalConfig_PLC2])
配置字段一览
| 分类 | 字段 | 默认值 | 说明 |
|---|---|---|---|
| Assembly | AssemblyIPAddress |
127.0.0.1 |
目标设备 IP |
| Assembly | AssemblyPort |
44818 |
目标端口 |
| Assembly | ReadAssemblyID |
100 |
读取实例号 |
| Assembly | WriteAssemblyID |
101 |
写入实例号 |
| Assembly | AssemblyBlockSize |
256 |
数据块大小 |
| Assembly | AssemblyOutBufSize |
256 |
输出缓冲区大小 |
| Assembly | AssemblyInBufSize |
256 |
输入缓冲区大小 |
| Assembly | bAssemblyAutoReconnect |
true |
自动重连 |
| Assembly | AssemblyReconnectDelay |
3.0 |
重连延迟(秒) |
| Assembly | AssemblySyncPeriod |
0.1 |
同步周期(秒) |
| Adapter | AdapterPort |
44818 |
监听端口 |
| Adapter | AdapterBlockSize |
512 |
数据块大小 |
| Adapter | bAdapterAutoStart |
false |
自动启动 |
| Tag | TagIPAddress |
192.168.1.1 |
目标设备 IP |
| Tag | TagPort |
44818 |
目标端口 |
| Tag | bTagAutoReconnect |
true |
自动重连 |
| Tag | TagSyncFrequencyHz |
10.0 |
同步频率(Hz) |
| Tag | TagRequestTimeout |
5.0 |
请求超时(秒) |
配置文件路径:
<项目>/Config/EIPConfig.ini,每个命名配置对应一个独立节([EIPGlobalConfig_<Key>])。向后兼容旧的[EIPGlobalConfig]节。
版本历史
| 版本 | 变更 |
|---|---|
| 1.0.1.1 | ⚠️ 与 1.0.0.x 不兼容! |
| 增加了多 Adapter、多 Scanner 支持 | |
重构为多实例架构:管理器管理多个命名实例,FString 全面更换为 FName |
|
新增 Tag Adapter 支持(UEIPTagAdapter) |
|
| 删除旧单例子系统(旧版 GetEIP*Subsystem 方法已移除) | |
Adapter 数据 API:SetBufferData/ReadBufferData → ReadFloat/WriteFloat 等类型化方法 |
|
Scanner 数据 API:WriteValue/ReadValue → WriteFloat/ReadFloat 等类型化方法 |
|
GetActiveNames() 返回类型从 TArray<FString> 改为 TArray<FName> |
|
Scanner/Adapter/Tag 实例类属性 InstanceName 改为 FName |
|
增加了对位的读写操作功能(ReadBool/WriteBool 支持 BitIndex) |
|
UEIPLinkComponent 新增 ScannerName(FName,默认 "Default")、DataBinds、事件、DataBind 索引读取 |
|
| 将 Config 从子系统中分离出来,让用户更自由的控制 | |
UEIPGlobalConfig 作为 BlueprintType UObject,通过 GetEipConfig(Key) 多命名配置,支持 LoadFromFile()/SaveToFile() |
|
GetEipConfig 参数从 FString 改为 FName |
|
Scanner 启动方式改为 SetConnectionParams(...) → Start()(Start() 不再传参) |
|
| 1.0.0.6 | 修复 FSocket 跨平台兼容性(WinSock2 → UE Socket API) |
| 1.0.0.5 | 初始 Fab 发布版本 |
重要说明
- 端口冲突: 每个监听实例需要独立端口。确保没有其他服务占用。
- 防火墙: Windows 防火墙可能阻止端口。如需入站连接,请为 UE 编辑器进程添加入站规则。
- Assembly 实例约定: Scanner 从实例 100(默认)读取,写入实例 101(默认)。
- 线程安全: 所有读取 API 线程安全。蓝图调用始终在主线程执行。
- 平台: 仅支持 Windows(Win64)。使用 UE5 Socket API,跨平台兼容。
- GC: 实例由管理器通过 UPROPERTY 持有,不会被垃圾回收。