冗余 (Redundancy)
EtherCAT 冗余通过双网卡 + 环形拓扑实现链路级容错: 主网口走 primary 帧, 副网口走 secondary 帧, 任一段断线时 SDK 自动从两侧 WKC 合并完成的从站状态, 整个网络仍正常运行.
通过 master 直接调用启用 / 强制故障转移, 通过 master.diagnostics 查看冗余诊断。
冗余在初始化阶段通过 set_network(adapter, redundant_adapter) 指定副网卡, 再调用 enable_redundancy(True) 启用 (必须在 start() 之前)。运行时无需手动控制。
- 冗余诊断 /
ring_mode/break_point详见 主站诊断 - 冗余状态 - 冗余链路状态变化事件:
on_redundancy_mode_changed - 副网卡通过
set_network(adapter, redundant_adapter)第二参数指定
RedundancyState
from enum import IntEnum
class RedundancyState(IntEnum):
NONE = 0 # 无冗余
PRIMARY = 1 # 仅使用主网络
SECONDARY = 2 # 仅使用备用网络
BOTH = 3 # 使用双网络 (活动冗余)
RedundancyStatusInfo
冗余运行时状态详细信息。
@dataclass
class RedundancyStatusInfo:
state: RedundancyState # 冗余总体状态
primary_link_up: bool # 主链路是否在线
secondary_link_up: bool # 副链路是否在线
primary_tx_frames: int # 主网口发送帧数
primary_rx_frames: int # 主网口接收帧数
secondary_tx_frames: int # 副网口发送帧数
secondary_rx_frames: int # 副网口接收帧数
failover_count: int # 故障切换次数
last_failover_time: float # 上次切换时间 (Unix 时间戳)
主站层暴露的冗余 API: enable_redundancy(bool) / force_failover() / check_redundancy_health() / set_redundancy_mode(mode), 以及只读属性 ring_mode / secondary_link_ok / redundancy_mode / redundancy_status。RedundancyManager(master._dll, master.master_index) 类对上述接口做便捷封装, 通过 mgr.get_status() -> RedundancyStatus (别名 RedundancyStatusInfo) 一次性获取冗余快照。
冗余 WKC 读取 (合并 WKC)
环形冗余下, 主帧 (primary) 从 P0 入网走 ring + branch, 副帧 (secondary) 从 P1 入网仅走 ring。某段断开时一侧帧只能看到断点之前的从站, 另一侧从反方向补齐 —— SDK 把两侧 WKC 合并, 得到本周期真正完成 PDO 交换的从站数。
铁律: 合并 WKC == 期望 WKC, 即网络完好; 此时单口 WKC 可以 < 期望, 不是故障。
Python SDK 通过 master.diagnostics_info (类型 MasterDiagnosticsInfo) 的只读属性读取合并后的 WKC, 这些镜像由内核每周期维护, 薄读零帧:
| 类别 | 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|---|
| 合并 WKC (权威) | diag.wkc_actual_mirror | int | 只读 | 主+副合并后本周期真正完成交换的从站数 |
| 期望 WKC | diag.wkc_expected_mirror | int | 只读 | 拓扑固定真值, 永不下调迁就劣化总线 |
| 缺额 | diag.wc_deficit | int | 只读 | 期望 - 合并实测, >0 才表示真有从站掉了 |
| 冗余激活 | diag.redundancy_active | bool | 只读 | 双端口均有流量 (即存在被补偿的断点) |
判健康的正确写法 — 以合并 WKC 为准:
diag = master.diagnostics_info
# ✅ 正确: 合并 WKC == 期望 WKC, 网络完好 (即使有断点被冗余补偿)
link_healthy = diag.wkc_actual_mirror == diag.wkc_expected_mirror
if link_healthy and diag.redundancy_active:
print(f"有断点, 但冗余已补齐, 网络仍完整 (合并 WKC={diag.wkc_actual_mirror})")
elif not link_healthy:
print(f"真有从站掉了: 合并 WKC={diag.wkc_actual_mirror} "
f"< 期望={diag.wkc_expected_mirror} (缺额={diag.wc_deficit})")
完整示例
启用冗余 + 健康监控
import time
from darra_ethercat import EtherCATMaster, EcState
with EtherCATMaster() as master:
# 同时指定主/副网卡 (推荐通过 get_network_info() 自动识别冗余对)
master.set_network(
r"\Device\NPF_{primary-guid}",
r"\Device\NPF_{secondary-guid}",
)
# 启用冗余 (start 前调用)
master.enable_redundancy(True)
master.set_state(EcState.OP)
master.start()
# 订阅冗余模式变化
master.on_redundancy_mode_changed(
lambda mi, old, new: print(f"冗余模式: {old} -> {new}")
)
# 周期性健康检查 — 通过诊断模块查看冗余状态
diag = master.diagnostics_info
while True:
print(f"冗余: ring_mode={master.ring_mode}, "
f"active={diag.redundancy_active}, "
f"primary_ok={diag.primary_port_ok}, "
f"secondary_ok={diag.secondary_port_ok}")
if diag.break_point is not None:
print(f"故障点: {diag.break_point}")
time.sleep(1)
ETG.1500 §5.7 Cable Redundancy