跳到主要内容

从站分组

从站分组功能允许将从站分配到不同的组(0-7),每组可配置独立的 PDO 周期分频器,实现不同组以不同频率交换数据

典型应用场景:

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

快速开始

var master = new DarraEtherCAT()
.SetNetwork("\\Device\\NPF_{...}")
.SetENI(@"C:\config.xml");

var (success, message) = master.Build();
if (!success) return;

// 1. 分配从站到组(必须在 SAFE_OP 之前)
// master.Slaves[0~1] 不设置,保持 group=0(默认组,每周期发送)
master.Slaves[2].Group = 1; // IO 模块 → 组1
master.Slaves[3].Group = 1;
master.Slaves[4].Group = 2; // 传感器 → 组2

// 2. 设置组分频器
master.Groups[1].Divider = 4; // 组1: 每4周期发送
master.Groups[2].Divider = 10; // 组2: 每10周期发送
// 组0 默认分频器=1,无需额外设置

// 3. 切换到 OP — 系统自动启用有从站的组
master.State = EcState.OP;

// 4. 通过组索引器访问从站
var servo = master.Groups[1][0]; // 组1的第一个从站
var io = master.Groups[2][0]; // 组2的第一个从站
Console.WriteLine($"组1: {master.Groups[1].Count} 个从站");
Console.WriteLine($"组2: {master.Groups[2].Count} 个从站");

组语义

组号含义
0默认组 — 未显式分组的从站自动归入此组
1-7显式分组 — 用户手动分配,组号无需连续
备注
  • 有效组范围为 0-7(共 8 组),每个组独立收发 PDO 数据
  • 组号可以不连续(如 1, 3, 5),系统会跳过空组
  • 进入 SafeOp 时自动启用有从站的组,禁用空组

从站组分配

通过 slave.Group 属性设置从站的组归属。

Slave.Group

public byte Group { get; set; }

获取或设置从站的组归属(0-7)。必须在 SAFE_OP 之前设置。

示例:

// 分配从站到组
master.Slaves[0].Group = 1; // 显式分到组1
master.Slaves[1].Group = 2; // 显式分到组2
// master.Slaves[2].Group 不设置,保持 0(默认组)

// 读取从站所在组
byte group = master.Slaves[0].Group;

master.Groups[g][i]

public SlaveGroupAccessor Groups { get; }

组索引器,支持 master.Groups[组号] 获取该组从站列表,master.Groups[组号][索引] 获取组内指定从站。

示例:

// 获取组1的所有从站
var group1Slaves = master.Groups[1];

// 遍历组内从站
foreach (var slave in master.Groups[1])
Console.WriteLine(slave.Name);

// 按索引访问
Slave firstInGroup1 = master.Groups[1][0];

// 组内从站数
int count = master.Groups[1].Count;

// 转为列表
IReadOnlyList<Slave> list = master.Groups[2].ToList();

ActiveGroupCount

public byte ActiveGroupCount { get; }

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

组分频器与 WKC

通过 master.Groups[g] 直接设置分频器和查询 WKC。

Groups[g].Divider

public byte Divider { get; set; }

获取或设置组的 PDO 周期分频器 (1-255)。

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

Groups[g].ExpectedWKC

public ushort ExpectedWKC { get; }

获取组的期望 WKC(映射后有效)。

示例:

// 设置分频器
master.Groups[1].Divider = 4; // 组1: 每4周期
master.Groups[2].Divider = 10; // 组2: 每10周期
// 组0 默认分频器=1(每周期),无需设置

// 读取分频器
byte div = master.Groups[2].Divider; // 10

// 读取期望 WKC(映射后有效)
ushort wkc = master.Groups[2].ExpectedWKC;

组属性:

  • Groups[g].Divider (byte) — 获取或设置组的周期分频器 (1-255)
  • Groups[g].ExpectedWKC (ushort) — 获取组的期望 WKC(映射后有效)
  • Groups[g].Count (int) — 获取组内从站数量

自动启用/禁用

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

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

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

组诊断

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

按组查询丢帧

// 查询指定组的丢帧统计
var stats = master.Diagnostics.PDO.GetFrameLossStats(1); // 组1
Console.WriteLine($"组1: 累计丢帧={stats.TotalLost}, 连续={stats.ConsecutiveLost}");

var stats2 = master.Diagnostics.PDO.GetFrameLossStats(2); // 组2
Console.WriteLine($"组2: 累计丢帧={stats2.TotalLost}");

汇总所有组

// 不传参数,返回所有组的汇总统计
var total = master.Diagnostics.PDO.GetFrameLossStats();
Console.WriteLine($"总丢帧: {total.TotalLost}");

PDOFrameLoss 事件

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

master.Events.PDOFrameLoss += (masterIndex, group, consecutive, total) =>
{
Console.WriteLine($"组 {group} 丢帧: 连续={consecutive}, 累计={total}");

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

配置时序

INIT → PRE_OP → SAFE_OP → OP
│ │ │
│ │ └─ 组配置已锁定,PDO 开始按组发送
│ │
│ └─ 设置从站组归属: slave.Group = N
│ 设置组分频器: master.Groups[N].Divider = divider
│ (进入 SafeOp 时自动启用有从站的组)

└─ 初始化主站
警告
  • slave.Group 进入在 SAFE_OP 时生效
  • 组分频器建议在 Build() 之后、State = OP 之前设置
  • 进入 SAFE_OP 后组配置自动锁定

完整示例

var master = new DarraEtherCAT()
.SetNetwork("\\Device\\NPF_{...}")
.SetENI(@"C:\config.xml");

var (success, message) = master.Build();
if (!success) { Console.WriteLine(message); return; }

// 1. 分配从站到组
// master.Slaves[0~2] 不设置,保持 group=0(伺服驱动,默认组)
for (int i = 3; i < 5; i++)
master.Slaves[i].Group = 1; // 后2个从站 → 组1(IO模块)
// 其余从站保持 group=0(默认组,每周期发送)

// 2. 设置组分频器
master.Groups[1].Divider = 4; // 组1: 250Hz
// 组0 默认分频器=1(1000Hz),无需设置

// 3. 周期
master.Config.LoopCycle = 1_000_000; // 1ms

// 4. PDO 丢帧监控(每组独立)
master.Events.PDOFrameLoss += (masterIndex, group, consecutive, total) =>
{
Console.WriteLine($"组 {group} 丢帧: 连续={consecutive}");
};

// 5. 启动 — 自动启用有从站的组
var (ok, msg) = master.SetState(EcState.OP);
if (!ok) { Console.WriteLine(msg); return; }

// 6. 查看组状态
Console.WriteLine($"活跃组: {master.ActiveGroupCount}");
Console.WriteLine($"组1: {master.Groups[1].Count} 个从站, WKC={master.Groups[1].ExpectedWKC}");
Console.WriteLine($"组2: {master.Groups[2].Count} 个从站, WKC={master.Groups[2].ExpectedWKC}");

// 7. 周期回调中按组处理
master.Events.ProcessDataCyclicAsync += (masterIndex) =>
{
// 组1的伺服控制
foreach (var servo in master.Groups[1])
{
ushort status = servo.CoE[0x6041][0].Value;
}
};