MDP — 模块化设备
Modular Device Profile (MDP, ETG.5001) 是 EtherCAT 中描述模块化设备(槽位 + 可插拔模块)的标准协议。
通过 slave.mdp 访问 (返回 MdpDiscovery)。从站不支持 MDP 时为 None。
进入 OP 时, SDK 会对模块化设备 (如 GCAN-8200) 自动完成模块检测与 PDO 配置。
绝大多数场景下用户无需直接操作 MDP — 通过 master.enable_auto_startup() 即可。
SDK 支持 MDP 模块热插拔再配置自修复。
但生产环境中几乎不会出现 MDP 模块热插拔的使用场景。
部署 MDP 模块化设备推荐使用 DENI;
如需自动配置,请先导入对应的 ESI 文件,再调用主站 enable_auto_startup() 或从站级配置。
属性
| 类别 | 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|---|
| 模块列表 | configured_modules | List[MdpSlotInfo] | 只读 | 已配置模块列表 (由底层库实现, 0xF030) |
| detected_modules | List[MdpSlotInfo] | 只读 | 已检测模块列表, 反映物理实际插入 (由底层库实现, 0xF050) | |
| config_module_idents | List[int] | 只读 | 从 native 直读 0xF030 ConfigModuleIdent 数组 | |
| detected_module_idents | List[int] | 只读 | 从 native 直读 0xF050 DetectedModuleIdent 数组 | |
| modules | List[MdpModule] | 只读 | 最近一次 discover() 的结果快照 | |
| 设备属性 | module_index_distance | int | 只读 | 模块对象字典索引间距 (0xF000:01, 读不到或为 0 时取 0x0010) |
| max_module_count | int | 只读 | 设备支持的最大模块数量 (0xF000:02) |
MdpSlotInfo 类
模块槽位信息 (ETG.5001), 普通类:
class MdpSlotInfo:
slot_index: int # 槽位索引 (从 1 开始)
module_ident: int # 模块标识码 (32 位)
module_name: str # 模块名称 (形如 "Module 0x........")
module_type: int # 模块设备类型码 (module_ident 低 16 位)
status: str # 状态 ("已配置" / "已检测")
object_dictionary_index: int # 模块对象字典基地址 (= index_distance × slot_index)
module_io_type: str # I/O 类型;Python 层当前不填充,固定 "Unknown"
示例:
for slot in slave.mdp.configured_modules:
print(f"Slot {slot.slot_index}: {slot.module_name} (0x{slot.module_ident:08X})")
for slot in slave.mdp.detected_modules:
print(f"Slot {slot.slot_index}: 检测到模块 0x{slot.module_ident:08X}")
MdpModule 类
discover() 返回的模块信息:
class MdpModule:
slot: int # 槽位号
profile_id: int # 模块 Profile ID (raw 高 16 位)
vendor_id: int # 厂商 ID (0xF051)
module_type: int # 模块类型 (raw 低 16 位)
revision: int # 修订号 (0xF052)
方法
discover()
def discover(self) -> List[MdpModule]
执行 MDP 模块发现, 通过 CoE 读取 0xF050 模块列表对象(数量 + 各槽位 ident), 并按槽位补读 0xF051 / 0xF052 得到厂商与修订号, 返回 MdpModule 列表。
rescan()
def rescan(self) -> List[MdpSlotInfo]
重新扫描已配置 (0xF030) 与已检测 (0xF050) 模块列表, 清空索引间距 / 最大模块数缓存, 返回已检测模块列表。
check_module_match()
def check_module_match(self) -> Tuple[bool, int]
由底层库实现, 检查已配置模块与已检测模块是否一致。
返回值:
Tuple[bool, int]—(is_match, first_mismatch_slot)。is_match=True时全部匹配;False时第二项为首个不匹配槽位 (无法判定返回 -1)
示例:
ok, mismatch_slot = slave.mdp.check_module_match()
if not ok:
print(f"模块配置不一致, 首个不匹配槽位: {mismatch_slot}")
get_module_pdo_layout()
def get_module_pdo_layout(self) -> Optional[List[MdpModulePdoInfo]]
获取各模块在从站过程映像中的 PDO 布局(输入/输出字节数和偏移)。各 PDO 的字节尺寸由主站库统一给出, 按模块槽位均分后累积计算各模块在过程映像中的字节偏移。无可用模块或读取失败返回 None。
MdpModulePdoInfo 类:
class MdpModulePdoInfo:
slot_index: int # 槽位索引
input_offset: int # 输入 PDO 在过程映像中的字节偏移
input_size: int # 输入字节数
output_offset: int # 输出 PDO 在过程映像中的字节偏移
output_size: int # 输出字节数
示例:
layout = slave.mdp.get_module_pdo_layout()
if layout:
for info in layout:
print(f"Slot {info.slot_index}: "
f"输入 {info.input_size}B @{info.input_offset}, "
f"输出 {info.output_size}B @{info.output_offset}")
auto_configure_from_detected_modules()
def auto_configure_from_detected_modules(self) -> int
根据检测到的模块自动配置 — 读取 0xF050(已检测模块), 逐个写入 0xF030(已配置模块), 使已配置列表与物理实际一致。
返回值:
int— 成功配置的模块数量;0表示无检测到的模块;-1表示写入失败
示例:
n = slave.mdp.auto_configure_from_detected_modules()
if n > 0:
print(f"已按物理实际配置 {n} 个模块")
elif n < 0:
print("模块配置写入失败")
auto_enumerate()
def auto_enumerate(self) -> int
触发 native MDP 自动枚举(MDPAutoEnumerate, 主站级)。对所有从站读取 0xF030 (Config) / 0xF050 (Detected) 模块列表并自动比对一致性, 逻辑全在 native DLL 内完成;该接口作用于整个主站, 不限单个从站。
返回值:
int— native 返回码(>=0表示枚举的模块/从站数,<0表示失败)
示例:
rc = slave.mdp.auto_enumerate()
if rc < 0:
print("MDP 自动枚举失败")
自动配置
MDP 设备的自动配置需要先导入对应的 ESI 文件:
- 导入 ESI(主站) —
master.set_esi_file()/master.set_esi_files() - 标记自动配置(主站) —
master.enable_auto_startup()(在build()时执行) - 导入 ESI(从站) —
slave.set_esi_file()
链式示例(注意 set_network() 返回从站数, 需单独一行):
from darra_ethercat import EtherCATMaster, EcState
master = EtherCATMaster()
# set_network() 返回发现的从站数 (int), 不返回 master, 不能参与链式
count = master.set_network(r"\Device\NPF_{GUID}")
# 其余配置方法返回 master, 可继续链式
master = (master
.set_esi_files(r"C:\EtherCAT\ESI")
.enable_auto_startup() # 进 OP 时自动编排模块化设备
.build())
master.set_state(EcState.OP)