DC 配置
什么是 DC?
DC(分布式时钟)是 EtherCAT 的硬件级时间同步机制。它让网络中所有从站共享同一个时间基准,使各从站能在完全相同的时刻执行动作。
- 多轴同步运动 — 所有伺服驱动器在同一时刻更新位置指令,消除轴间抖动,轨迹插补更平滑
- IO 同步采样 — 所有输入输出在同一时刻,主站读取时数据一致,适合高速控制和测量
- 精确 I/O 时间戳 — 输入数据带有硬件时间戳,主站可精确知道采样发生的物理时刻
- 确定性输出 — 输出在固定时刻生效,不受 EtherCAT 帧到达时间的抖动影响,降低系统延迟和不确定性
主站级 DC 配置。通过 master 直接调用。
- 单个从站的 DC 配置请参见 从站 DC 同步
- 周期属性请参考 配置 - 周期配置
- DC 同步监控请参考 主站诊断 - DC 同步
属性
| 类别 | 属性 | 类型 | 访问 | 说明 |
|---|---|---|---|---|
| DC 状态 | HasDC | bool | 只读 | 网络中是否有支持 DC 的从站 |
方法
ConfigureDC(uint sync0CycleNs, uint sync1CycleNs = 0, int? shiftNs = null)
public void ConfigureDC(uint sync0CycleNs, uint sync1CycleNs = 0, int? shiftNs = null)
为所有 DC 从站配置 DC 同步。所有参数单位:纳秒(ns)。自动完成传播延迟测量、偏移计算和 DC 参数写入。
参数:
sync0CycleNs(uint) — SYNC0 周期(纳秒),0 表示禁用 DCsync1CycleNs(uint) — SYNC1 增量时间(纳秒),0 表示仅 SYNC0shiftNs(int?) — 相位偏移(纳秒):null=自动计算(默认),0=不设置偏移,其他值=手动偏移(所有从站使用相同值)
示例:
master.ConfigureDC(1_000_000); // SYNC0 = 1ms
master.ConfigureDC(1_000_000, shiftNs: 0); // SYNC0 = 1ms, 不设置偏移
master.ConfigureDC(1_000_000, 500_000); // SYNC0 = 1ms, SYNC1 = 500µs
125μs 高性能配置(WDK 驱动推荐):
master.Config.LoopCycle = 125_000; // PDO 交换周期 125μs
master.ConfigureDC(125_000); // SYNC0 = 125μs,自动计算偏移
1ms 常规配置(通用场景):
master.Config.LoopCycle = 1_000_000; // PDO 交换周期 1ms
master.ConfigureDC(1_000_000); // SYNC0 = 1ms,自动计算偏移
- SYNC0 与 LoopCycle — 应保持一致或为其整数倍,数据未到达的同步没有意义
- 自动偏移(推荐) — shiftNs 不传 / null,主站自动测量传播延迟并计算
- 手动偏移 — 也可设置一个较高的固定值,如 0.8 × sync0CycleNs
- 过采样例外 — Oversampling 设备中 SYNC0 < LoopCycle,需设备硬件和 PDO 映射专门支持
SYNC1 是相对于 SYNC0 的增量时间。例如 SYNC0=1,000,000ns, SYNC1=500,000ns 表示 SYNC1 在每个 SYNC0 后 500µs 触发。
master.ConfigureDC()— 一次性配置所有 DC 从站slave.ConfigureDC()— 配置单个从站
两者都默认自动计算偏移。仅在需要对个别从站设置不同参数时使用从站级方法。
Master.ConfigureDC(DcSyncMode mode, uint sync0CycleNs = 0, uint sync1CycleNs = 0, int? shiftNs = null)
public void ConfigureDC(DcSyncMode mode, uint sync0CycleNs = 0, uint sync1CycleNs = 0, int? shiftNs = null)
主站级重载: 根据同步模式为所有 DC 从站配置 DC(ETG.1020)。自动配置各从站的同步类型。从站级单独配置使用 slave.ConfigureDC。
参数:
mode(DcSyncMode) — DC 同步模式sync0CycleNs(uint) — SYNC0 周期(纳秒),仅 DcSynchron 模式使用sync1CycleNs(uint) — SYNC1 周期(纳秒),仅 DcSynchron 模式使用shiftNs(int?) — 相位偏移(纳秒),仅 DcSynchron 模式使用
示例:
master.ConfigureDC(DcSyncMode.DcSynchron, 1_000_000); // 所有 DC 从站 SYNC0 = 1ms
master.ConfigureDC(DcSyncMode.SmSynchron); // 所有 DC 从站 SM 同步模式
master.ConfigureDC(DcSyncMode.FreeRun); // 禁用所有 DC 从站的 DC 同步
EnableContinuousMeasurement(bool enable, uint intervalSec = 0)
public void EnableContinuousMeasurement(bool enable, uint intervalSec = 0)
启用或禁用持续传播延迟测量(ETG.1500 5.13.2)。启用后主站定期重新测量传播延迟,适用于温度漂移等导致延迟变化的场景。
参数:
enable(bool) —true启用,false禁用intervalSec(uint) — 测量间隔(秒),0 表示使用默认间隔
示例:
master.EnableContinuousMeasurement(true, 60); // 每 60 秒重新测量
master.EnableContinuousMeasurement(false); // 禁用
默认情况下 DC 偏移在 ConfigureDC() 时一次性计算。仅在长时间运行且环境温度变化较大时启用此功能。
同步窗口监控
主站每秒自动检查各 DC 从站的时间偏差。当从站偏差超出 SyncWindowThreshold 阈值时触发 DCSyncLost 事件。
// 阈值:默认 1000ns,可调整
master.Diagnostics.SyncWindowThreshold = 500; // 设为 500ns
// 事件:从站从"同步"变为"失同步"时触发一次(不重复触发)
master.Events.DCSyncLost += (masterIdx, slaveIdx, diffNs) =>
Console.WriteLine($"从站 {slaveIdx} DC 同步丢失: 偏差 {diffNs}ns");
GetMaxSyncDifference()
public int GetMaxSyncDifference()
获取所有 DC 从站中的最大时间偏差(纳秒)。
返回值:
int— 最大时间偏差(纳秒),失败返回 -1
示例:
int maxDiff = master.GetMaxSyncDifference();
Console.WriteLine($"最大同步偏差: {maxDiff}ns");
IsAllSlavesInSync()
public bool IsAllSlavesInSync()
检查所有 DC 从站是否都在同步窗口内(偏差 ≤ SyncWindowThreshold)。
返回值:
bool— 所有从站同步返回true
示例:
if (!master.IsAllSlavesInSync())
Console.WriteLine("存在从站同步偏差过大");
ResetAllSyncWindowStats()
public void ResetAllSyncWindowStats()
重置所有从站的同步窗口统计(最大/最小时间差、超出同步次数等)。
示例:
master.ResetAllSyncWindowStats();
单个从站的同步窗口详细状态请使用 slave.GetSyncWindowStatus(),包含 DiffNs、MaxDiffNs、MinDiffNs、InSync、OutOfSyncCount。
完整示例
125μs 高性能(WDK 驱动)
var master = new DarraEtherCAT()
.SetENI(@"C:\config.xml");
var (success, message) = master.Build();
if (!success) return;
// 1. 配置周期 — 125μs(WDK 驱动推荐值)
master.Config.LoopCycle = 125_000;
// 2. 切换到 SafeOp
master.SetState(EcState.SafeOp);
// 3. 配置 DC(自动偏移)— SYNC0 与 LoopCycle 保持一致
if (master.HasDC)
{
master.ConfigureDC(125_000);
}
Thread.Sleep(1000);
// 4. 切换到 Op
master.SetState(EcState.OP);
// 监听 DC 同步丢失事件
master.Events.DCSyncLost += (masterIdx, slaveIdx, diffNs) =>
Console.WriteLine($"从站 {slaveIdx} DC 同步丢失: 偏差 {diffNs}ns");
持续测量与同步监控
// 长时间运行:启用持续传播延迟测量(温度漂移补偿)
master.EnableContinuousMeasurement(true, 60);
// 同步窗口监控
if (!master.IsAllSlavesInSync())
{
int maxDiff = master.GetMaxSyncDifference();
Console.WriteLine($"同步偏差过大: {maxDiff}ns");
}
// 重置统计
master.ResetAllSyncWindowStats();
SM 同步类型通过从站级 slave.ConfigureDC(DcSyncMode mode, ...) 方法自动配置,无需手动调用。详见 从站 DC 同步。
DC 漂移补偿
EnableDriftCompensation(bool enable, int thresholdNs = 1000, int gain = 512)
public void EnableDriftCompensation(bool enable, int thresholdNs = 1000, int gain = 512)
启用或禁用 DC 漂移补偿。漂移补偿在主站侧持续修正系统时钟与 DC 参考时钟之间的偏差,防止长时间运行后同步精度下降。
参数:
enable(bool) —true启用,false禁用thresholdNs(int) — 触发补偿的偏差阈值(纳秒),偏差低于此值时不做修正,默认 1000nsgain(int) — 补偿增益,控制修正速率(值越大修正越快但可能引入振荡),默认 512
示例:
// 使用默认参数启用漂移补偿
master.EnableDriftCompensation(true);
// 自定义参数:500ns 阈值,较低增益(更平滑的修正)
master.EnableDriftCompensation(true, thresholdNs: 500, gain: 256);
// 禁用漂移补偿
master.EnableDriftCompensation(false);
对于长时间运行的系统(>24小时),建议启用漂移补偿。默认参数适合大多数场景,仅在需要更精细控制时调整阈值和增益。
CurrentDcSyncMode 是从站级属性,通过 slave.CurrentDcSyncMode 访问。详见 从站 DC 同步。
主站当前 DC 时间查询
主站每个 PDO 周期会通过 FRMW (Feed-Read-Multiple-Write) 从参考时钟从站取回 64 位 DC 系统时间。SDK 将该时间戳暴露给应用层, 用于:
- 日志时间对齐 — 应用层日志可用 DC 时间打戳, 与从站侧事件 (EMCY / Diagnosis History) 时间轴严格对齐
- 跨站事件关联 — 多从站同时上报事件时, 基于 DC 时间可判断绝对先后
- 漂移诊断 — 与本机墙上时钟或外部 NTP 做差值, 观察时钟漂移趋势
- 周期起始对齐 — 需要在特定 DC 时刻触发应用层动作时, 作为基准计算等待时长
DC 时间单位为纳秒, 起算点为 2000-01-01 00:00:00 UTC (ETG 规范定义)。与 UNIX 时间戳有 30 年偏移, 换算时注意。
MasterDCTimeNs
public long MasterDCTimeNs { get; }
主站最近一次 PDO 周期从参考时钟从站 FRMW 取回的 64 位 DC 系统时间 (纳秒, 2000-01-01 纪元)。
返回值:
long— DC 时间戳 (纳秒); 无 DC 从站或主站未运行时返回 0
ReferenceClockSlaveIndex
public ushort ReferenceClockSlaveIndex { get; }
当前参考时钟从站的索引 (1-based)。由 DLL 在 DC 配置阶段自动选为链路上第一个支持 DC 的从站, 应用无需配置。
返回值:
ushort— 从站索引 (1-based); 0 表示网络中无 DC 从站
示例
// 打印当前 DC 时间与参考时钟从站
long dcNs = master.MasterDCTimeNs;
ushort refIdx = master.ReferenceClockSlaveIndex;
if (dcNs == 0 || refIdx == 0)
{
Console.WriteLine("网络中无 DC 从站");
}
else
{
// 转换为可读 UTC 时间 (DC 纪元 2000-01-01)
var dcEpoch = new DateTime(2000, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var utc = dcEpoch.AddTicks(dcNs / 100);
Console.WriteLine(
$"当前主站 DC 时间 = {dcNs} ns ({utc:yyyy-MM-dd HH:mm:ss.fffffff} UTC), " +
$"参考从站 = #{refIdx}");
}
日志时间戳场景:
master.Events.DCSyncLost += (masterIdx, slaveIdx, diffNs) =>
{
long now = master.MasterDCTimeNs;
Console.WriteLine(
$"[DC={now}ns] 从站 {slaveIdx} 同步丢失: 偏差 {diffNs}ns");
};
MasterDCTimeNs 由主站周期线程更新, 应用层读取是近似值, 与当前 CPU 真实时刻可能相差一个 PDO 周期以内。高精度场景可结合 Diagnostics.CycleJitter 评估抖动上限。