跳到主要内容

初始化

推荐方式

强烈建议使用 Darra 配置工具导出的 DENI 文件进行初始化。 DENI 文件包含完整的网络配置(网口、从站、PDO 映射、DC 设置等),可确保配置的一致性和正确性。

构造函数

EtherCATMaster()

class EtherCATMaster:
def __init__(self, dll_path: Optional[str] = None,
master_index: Optional[int] = None) -> None

创建 EtherCAT 主站实例。

参数:

  • dll_path (str, 可选) — 原生库路径,None 时自动搜索
  • master_index (int, 可选) — 指定主站索引,None 时自动分配

示例:

from ethercat import EtherCATMaster, EcState

with EtherCATMaster() as master:
# 加载配置文件
master.set_eni(r"C:\EtherCAT\MyProject.deni")

# 设置网络并扫描从站
slave_count = master.set_network(r"\\Device\\NPF_{GUID}")
print(f"发现 {slave_count} 个从站")

# 状态转换到 OP
master.set_state(EcState.OP)

# 启动 PDO 循环
master.start()

上下文管理器

with EtherCATMaster() as master:
master.set_eni("config.deni")
count = master.set_network(r"\\Device\\NPF_{GUID}")
if count > 0:
master.set_state(EcState.OP)
master.start()
# master 退出 with 块时自动调用 close()

配置方法

set_eni()

def set_eni(self, eni_path: str) -> "EtherCATMaster"

加载 DENI/ENI 配置文件。返回自身实例,支持链式调用。

set_network()

def set_network(self, adapter: str, redundant_adapter: str = "") -> int

设置网络适配器并扫描从站。

参数:

  • adapter (str) — 主网卡名称(网卡设备名)
  • redundant_adapter (str) — 冗余网卡名称,空字符串表示不使用冗余

返回值:

  • int — 发现的从站数量

示例:

# Windows
slave_count = master.set_network(r"\\Device\\NPF_{GUID}")

# Linux
# slave_count = master.set_network("eth0")

# 冗余模式
slave_count = master.set_network(
r"\\Device\\NPF_{PRIMARY-GUID}",
r"\\Device\\NPF_{SECONDARY-GUID}"
)

set_esi_file()

def set_esi_file(self, file_path: str) -> "EtherCATMaster"

加载单个 ESI 文件。返回自身实例,支持链式调用。

备注

如果使用 DENI 文件,通常不需要单独加载 ESI。

set_esi_files()

def set_esi_files(self, path: str) -> "EtherCATMaster"

加载 ESI 文件或目录。返回自身实例,支持链式调用。

enable_auto_startup()

def enable_auto_startup(self) -> "EtherCATMaster"

标记需要自动配置从站。返回自身实例,支持链式调用。

备注

已有启动参数的从站会被完整跳过,不会被覆盖。此方法仅对未配置的从站生效。

DENI 优势

使用 DENI 文件时,set_network() 阶段的扫描结果会自动与 DENI 中的配置进行匹配验证。匹配策略由 config.scan_revision_match 控制(默认忽略 RevisionID)。如果网络拓扑与 DENI 不一致,set_state() 会返回详细的错误消息。

覆盖规则

set_eni()set_network() 都可以设置网口。当两者同时使用时,后调用的方法覆盖前面的冲突配置:

# set_eni 在后 -> 使用 DENI 文件中的网口配置
master.set_network(r"\\Device\\NPF_{GUID}")
master.set_eni(r"C:\config.deni") # <- DENI 中的网口覆盖 set_network

# set_network 在后 -> set_network 的网口覆盖 DENI
master.set_eni(r"C:\config.deni")
master.set_network(r"\\Device\\NPF_{GUID}") # <- 覆盖 DENI 中的网口

DENI 文件中的从站配置、PDO 映射、DC 设置等始终保留,仅网口配置受覆盖规则影响。

set_cycle_time()

def set_cycle_time(self, time_ns: int) -> None

设置 PDO 循环周期(纳秒)。

示例:

master.set_cycle_time(1_000_000)  # 1ms

一步初始化

EtherCATMaster.from_json()

@classmethod
def from_json(cls, json_config: str, dll_path: Optional[str] = None) -> "EtherCATMaster"

通过 JSON 配置字符串一步完成主站初始化。

参数:

  • json_config (str) — JSON 格式的配置字符串
  • dll_path (str, 可选) — 原生库路径

返回值:

  • EtherCATMaster — 已初始化的主站实例

JSON 配置格式:

{
"adapter": "\\\\Device\\\\NPF_{GUID}",
"redundant_adapter": "",
"cycle_time_ns": 1000000,
"target_state": "OP",
"slaves": [
{
"index": 1,
"startup_params": [
{
"index": "0x1C12", "subindex": 0,
"data": "00", "transition": "IP", "timing": "After"
}
]
}
]
}

示例:

import json

config = json.dumps({
"adapter": r"\\Device\\NPF_{GUID}",
"target_state": "OP"
})

with EtherCATMaster.from_json(config) as master:
master.start()
# 主站已初始化并进入 OP 状态

EtherCATMaster.from_json_file()

@classmethod
def from_json_file(cls, json_file_path: str, dll_path: Optional[str] = None) -> "EtherCATMaster"

通过 JSON 文件一步初始化。

示例:

with EtherCATMaster.from_json_file("config.json") as master:
master.start()

资源释放

close()

def close(self) -> None

关闭并释放主站资源(Stop + Dispose)。

__enter__ / __exit__

支持 with 语句自动释放资源。

EtherCATMaster.emergency_cleanup()

@staticmethod
def emergency_cleanup(dll_path: Optional[str] = None) -> None

紧急清理所有主站资源。在进程异常退出时调用,释放网络句柄。

示例:

import atexit
atexit.register(EtherCATMaster.emergency_cleanup)

多实例管理

EtherCATMaster.get_active_instance_count()

@staticmethod
def get_active_instance_count(dll_path: Optional[str] = None) -> int

当前活跃的主站实例数量。

EtherCATMaster.get_max_instance_count()

@staticmethod
def get_max_instance_count(dll_path: Optional[str] = None) -> int

允许的最大主站实例数量。基于可用隔离核心数和驱动上限决定。

网络扫描

get_network_info()

from ethercat import get_network_info

def get_network_info(need_slaves_num: bool = False,
dll_path: Optional[str] = None) -> List[NetworkInfo]

获取系统中可用的网络适配器列表。

NetworkInfo 数据类:

@dataclass
class NetworkInfo:
name: str # 网卡适配器名称
desc: str # 适配器描述
mac: str # MAC 地址
slave_num: Optional[int] # 从站数量(需 need_slaves_num=True)
redundant_slave_num: Optional[int] # 受冗余保护的从站数量

示例:

from ethercat import get_network_info

adapters = get_network_info(need_slaves_num=True)
for adapter in adapters:
print(f"{adapter.desc}: {adapter.slave_num or 0} 个从站")

scan_slaves()

from ethercat import scan_slaves

def scan_slaves(adapter_name: str,
secondary_adapter: Optional[str] = None,
dll_path: Optional[str] = None) -> List[ScannedSlaveInfo]

一键扫描从站并返回详细信息列表。

示例:

from ethercat import scan_slaves

slaves = scan_slaves(r"\\Device\\NPF_{GUID}")
for s in slaves:
print(f"[{s.index}] {s.name} VID=0x{s.vendor_id:08X}")

abort_scan()

from ethercat import abort_scan

def abort_scan(dll_path: Optional[str] = None) -> None

中止所有正在进行的扫描操作。用于关闭窗口或取消操作时快速中断阻塞的网络扫描。

示例:

import threading
from ethercat import scan_slaves, abort_scan

# 在后台线程中扫描
scan_thread = threading.Thread(target=lambda: scan_slaves(r"\\Device\\NPF_{GUID}"))
scan_thread.start()

# 用户点击取消
abort_scan()
scan_thread.join()

EtherCATMaster.quick_slave_count()

@staticmethod
def quick_slave_count(adapter: str, dll_path: Optional[str] = None) -> int

快速从站计数(不读取 EEPROM,仅使用广播读取)。

EtherCATMaster.get_serial_number()

@staticmethod
def get_serial_number(dll_path: Optional[str] = None) -> str

获取当前设备的序列号(用于授权验证)。

完整示例

手动初始化流程

from ethercat import EtherCATMaster, EcState

with EtherCATMaster() as master:
# 设置网络适配器
slave_count = master.set_network(r"\\Device\\NPF_{GUID}")
if slave_count == 0:
print("未发现从站")
exit()

# 设置 PDO 周期
master.set_cycle_time(1_000_000)

# 状态转换
master.set_state(EcState.OP)

# 启动 PDO 循环
master.start()

# 访问从站
slave = master[1]
status = slave.coe.sdo_read_value(0x6041, 0, dtype='u16')
print(f"StatusWord = 0x{status:04X}" if status else "读取失败")

import time
time.sleep(5)
master.stop()

使用 DENI 文件(推荐)

from ethercat import EtherCATMaster, EcState

with EtherCATMaster() as master:
master.set_eni(r"C:\EtherCAT\MyProject.deni")
slave_count = master.set_network(r"\\Device\\NPF_{GUID}")
master.set_state(EcState.OP)
master.start()

动态扫描网口

from ethercat import EtherCATMaster, EcState, get_network_info

adapters = get_network_info(need_slaves_num=True)
target = next((a for a in adapters if (a.slave_num or 0) > 0), None)
if target is None:
exit()

with EtherCATMaster() as master:
master.set_esi_files(r"C:\ESI")
master.enable_auto_startup()
slave_count = master.set_network(target.name)
if slave_count > 0:
master.set_state(EcState.OP)
master.start()

冗余模式

from ethercat import EtherCATMaster, EcState

with EtherCATMaster() as master:
master.set_redundancy_mode(2)
master.set_eni(r"C:\config.deni")
slave_count = master.set_network(
r"\\Device\\NPF_{PRIMARY}",
r"\\Device\\NPF_{SECONDARY}"
)
master.set_state(EcState.OP)
master.start()

多实例(多网卡独立总线)

每个主站实例管理一条独立的 EtherCAT 总线,使用不同的网卡。

多实例要求
  • 每个实例必须使用不同的网卡 — 同一网卡不能被多个实例同时使用
  • CPU 核心自动分配 — 每个实例自动占用不同的 CPU 核心
from ethercat import EtherCATMaster, EcState, get_network_info

adapters = [a for a in get_network_info(need_slaves_num=True)
if (a.slave_num or 0) > 0]

master1 = EtherCATMaster()
master1.set_network(adapters[0].name)
master1.set_state(EcState.OP)
master1.start()

master2 = EtherCATMaster()
master2.set_network(adapters[1].name)
master2.set_state(EcState.OP)
master2.start()

print(f"活跃主站数: {EtherCATMaster.get_active_instance_count()}")