跳到主要内容

从站分组

从站分组功能允许将从站分配到不同的组(1-7;group=0 表示未分配,映射前自动归入组 1),每组可配置独立的 PDO 周期分频器,实现不同组以不同频率交换数据。

典型应用场景:

  • 伺服驱动(组1):默认组,每周期发送,31.25us 32KHz
  • IO 模块(组2):每4周期发送一次,125us 8000Hz
  • 传感器(组3):每6400周期发送一次,200ms 5Hz
核心简化
  • 无需手动启用组 — 系统在进入 SafeOp 时自动启用有从站的组,禁用空组
  • 属性式分频器 — 通过 master.divider(group, value) 直接设置
  • 每组独立收发 — 每个组对应独立的 PDO 数据报文

快速开始​

try (EtherCATMaster master = EtherCATMaster.create()) {
int slaveCount = master.setNetwork("\\Device\\NPF_{...}"); // 返回从站数,-1=失败(getLastError() 取原因)

// 1. 分配从站到组(必须在 SAFE_OP 之前)
// master.getSlave(1~2) 不设置,保持 group=0(未分配,映射前自动归入组 1,每周期发送)
master.getSlave(3).group((byte) 2); // IO 模块 -> 组2
master.getSlave(4).group((byte) 2);
master.getSlave(5).group((byte) 3); // 传感器 -> 组3

// 2. 设置组分频器(组级配置只接受组号 1-7)
master.divider((byte) 2, (byte) 4); // 组2: 每4周期发送
master.divider((byte) 3, (byte) 10); // 组3: 每10周期发送
// 组1(默认组)分频器默认=1,无需额外设置

// 3. 切换到 OP — 系统自动启用有从站的组
boolean ok = master.setState(EcState.OP); // true=切换成功,false=失败
master.start();

// 4. 查看组状态
System.out.println("活跃组: " + master.activeGroupCount());
}

组语义​

组号含义
0未分配标记 — 不设置时保持 0;进入 SAFE_OP 映射前自动归入组 1,不独立收发
1-7有效 PDO 组 — 用户手动分配,组号无需连续;未显式分组的从站最终都在组 1
备注
  • 有效组范围为 1-7,每个组独立收发 PDO 数据
  • slave.group() 可写 0-7;组级配置与查询(divider、按组丢帧统计)只接受 1-7,对组 0 设置无效
  • 组号可以不连续(如 1, 3, 5),系统会跳过空组
  • 进入 SafeOp 时自动启用有从站的组,禁用空组

从站组分配​

类别方法类型读写说明
组归属slave.group() / slave.group(byte)byte读写从站组归属(0-7,0=未分配,映射前自动归入组 1),须在 SAFE_OP 之前设置
组分频器master.divider(byte) / master.divider(byte, byte)byte读写组 PDO 周期分频器(1-255,组号 1-7)
组状态master.activeGroupCount()byte只读活跃组数量

slave.group() / slave.group(byte)​

public byte group()
public void group(byte group)

获取或设置从站的组归属(0-7,0=未分配,映射前自动归入组 1)。必须在 SAFE_OP 之前设置。

示例:

// 分配从站到组
master.getSlave(1).group((byte) 1); // 显式分到组1
master.getSlave(2).group((byte) 2); // 显式分到组2
// master.getSlave(3).group() 不设置,保持 0(未分配,映射前归入组 1)

// 读取从站所在组
byte group = master.getSlave(1).group();

组分频器​

master.divider(byte group) / master.divider(byte group, byte value)​

public byte divider(byte group)
public void divider(byte group, byte value)

获取或设置组的 PDO 周期分频器(1-255)。组号只接受 1-7(组 0 是未分配标记,设置无效);各组分频器默认 1。

  • 1 — 每周期发送(1000Hz,主周期 1ms 时)
  • 2 — 每2周期发送(500Hz)
  • 4 — 每4周期发送(250Hz)
  • 10 — 每10周期发送(100Hz)

示例:

// 设置分频器
master.divider((byte) 1, (byte) 4); // 组1: 每4周期
master.divider((byte) 2, (byte) 10); // 组2: 每10周期

// 读取分频器
byte div = master.divider((byte) 2); // 10

活跃组数量​

master.activeGroupCount()​

public byte activeGroupCount()

获取活跃组数量(扫描从站集合计算)。

分频器频率计算​

分频器值与实际频率的关系:

主周期分频器实际频率适用场景
1ms (1000Hz)11000 Hz伺服驱动
1ms (1000Hz)4250 HzIO 模块
1ms (1000Hz)10100 Hz传感器
1ms (1000Hz)2005 Hz慢速监控
31.25us (32KHz)132000 Hz高速伺服
31.25us (32KHz)48000 HzIO 模块
31.25us (32KHz)64005 Hz慢速传感器

公式: 实际频率 = 主周期频率 / 分频器值

自动启用/禁用​

进入 SafeOp 状态时,系统自动扫描每个组(1-7)是否有从站:

  • 有从站的组 -> 自动启用,确保分频器至少为 1
  • 空组 -> 自动禁用,跳过 PDO 收发

无需手动启用组,组号也无需连续。

组诊断​

每组独立跟踪 PDO 丢帧统计。

按组查询丢帧​

// 查询指定组的丢帧统计
int[] stats = master.diagnostics().getPDO().getFrameLossStats(1); // 组1
System.out.printf("组1: 累计丢帧=%d, 连续=%d%n", stats[0], stats[1]);

int[] stats2 = master.diagnostics().getPDO().getFrameLossStats(2); // 组2
System.out.printf("组2: 累计丢帧=%d%n", stats2[0]);

PDOFrameLoss 事件​

PDO 连续丢帧事件的 group 参数标识哪个组发生了丢帧:

master.events().addPDOFrameLossListener((masterIndex, group, consecutive, total) -> {
System.out.printf("组 %d 丢帧: 连续=%d, 累计=%d%n", group, consecutive, total);

if (group == 1) {
// 伺服组丢帧,紧急处理
System.out.println("警告: 伺服组通信异常!");
}
});

配置时序​

INIT -> PRE_OP -> SAFE_OP -> OP
| | |
| | +-- 组配置已锁定,PDO 开始按组发送
| |
| +-- 设置从站组归属: slave.group(N)
| 设置组分频器: master.divider(N, divider)
| (进入 SafeOp 时自动启用有从站的组)
|
+-- 初始化主站
警告
  • slave.group() 在进入 SAFE_OP 时生效
  • 组分频器建议在初始化之后、OP 之前设置
  • 进入 SAFE_OP 后组配置自动锁定

完整示例​

try (EtherCATMaster master = EtherCATMaster.create()) {
int slaveCount = master.setNetwork("\\Device\\NPF_{...}"); // 返回从站数,-1=失败(getLastError() 取原因)

// 1. 分配从站到组
// master.getSlave(1~3) 不设置,保持 group=0(伺服驱动,未分配,映射前归入组 1)
master.getSlave(4).group((byte) 2); // IO 模块 -> 组2
master.getSlave(5).group((byte) 2);
master.getSlave(6).group((byte) 3); // 传感器 -> 组3

// 2. 设置组分频器(组号 1-7)
master.divider((byte) 2, (byte) 4); // 组2: 250Hz
master.divider((byte) 3, (byte) 10); // 组3: 100Hz
// 组1(默认组)分频器默认=1(1000Hz),无需设置

// 3. 设置周期
master.config().loopCycle(1_000_000); // 1ms

// 4. PDO 丢帧监控(每组独立)
master.events().addPDOFrameLossListener((masterIndex, group, consecutive, total) -> {
System.out.printf("组 %d 丢帧: 连续=%d, 累计=%d%n", group, consecutive, total);
});

// 5. 启动 -- 自动启用有从站的组
boolean ok = master.setState(EcState.OP); // true=切换成功,false=失败
master.start();

// 6. 查看组状态
System.out.println("活跃组: " + master.activeGroupCount());

// 7. 遍历从站,显示组归属
for (Slave slave : master.slaves()) {
System.out.printf("从站 %d: 组 %d%n", slave.SlaveNum, slave.group());
}

// 8. 应用线程中按组轮询 copyInputPdo / writeOutputPdo
new Thread(() -> {
while (running) {
for (Slave servo : master.slaves()) {
if (servo.group() == 1) {
// 组1 伺服: servo.PDO().copyInputPdo / writeOutputPdo
}
}
try { Thread.sleep(1); } catch (InterruptedException e) { break; }
}
}).start();

// 9. 查询每组丢帧统计
MasterDiagnosticsInfo.MasterPDODiagnostics pdo = master.diagnostics().getPDO();
int[] g1 = pdo.getFrameLossStats(1);
int[] g2 = pdo.getFrameLossStats(2);
System.out.printf("组1 丢帧: %d, 组2 丢帧: %d%n", g1[0], g2[0]);
}