跳到主要内容

DC 配置

什么是 DC?

DC(分布式时钟)是 EtherCAT 的硬件级时间同步机制,让网络中所有从站共享同一个时间基准。

DC 对设备的好处
  • 多轴同步运动 — 所有伺服驱动器在同一时刻更新位置指令,消除轴间抖动,轨迹插补更平滑
  • IO 同步采样 — 所有输入输出在同一时刻,主站读取时数据一致,适合高速控制和测量
  • 精确 I/O 时间戳 — 输入数据带有硬件时间戳,主站可精确知道采样发生的物理时刻
  • 确定性输出 — 输出在固定时刻生效,不受 EtherCAT 帧到达时间的抖动影响,降低系统延迟和不确定性

主站级 DC 配置,通过 master 直接调用。

相关页面

属性

方法类型说明
has_dc()bool网络中是否有支持 DC 的从站

方法

configure_dc_all()

pub fn configure_dc_all(&self, sync0_ns: u32, sync1_ns: u32) -> Result<i32>

为所有 DC 从站配置 DC 同步。所有参数单位:纳秒(ns)。默认自动完成:

  1. 传播延迟测量 — 读取各端口接收时间并计算延迟
  2. 偏移计算 — 基于传播延迟自动计算每个从站的相位偏移
  3. DC 应用 — 写入 SYNC0/SYNC1 周期和起始时间到各从站

参数:

  • sync0_ns — SYNC0 周期(纳秒),0 表示禁用 DC
  • sync1_ns — SYNC1 增量时间(纳秒),0 表示仅 SYNC0

返回值:

  • Result<i32> — 成功返回配置的 DC 从站数量

示例:

master.configure_dc_all(1_000_000, 0)?;           // SYNC0 = 1ms
master.configure_dc_all(125_000, 0)?; // SYNC0 = 125us
master.configure_dc_all(1_000_000, 500_000)?; // SYNC0=1ms, SYNC1=500us
推荐配置

125us 高性能配置(WDK 驱动推荐):

master.config().set_loop_cycle(125_000);    // PDO 交换周期 125us
master.configure_dc_all(125_000, 0)?; // SYNC0 = 125us

1ms 常规配置(通用场景):

master.config().set_loop_cycle(1_000_000);  // PDO 交换周期 1ms
master.configure_dc_all(1_000_000, 0)?; // SYNC0 = 1ms
  • SYNC0 与 LoopCycle — 应保持一致或为其整数倍,数据未到达的同步没有意义
  • 自动偏移(推荐) — shift_ns 传 None,主站自动测量传播延迟并计算
  • 手动偏移 — 也可设置一个较高的固定值,如 0.8 × sync0_cycle_ns
  • 过采样例外 — Oversampling 设备中 SYNC0 < LoopCycle,需设备硬件和 PDO 映射专门支持
关于 SYNC1

SYNC1 是相对于 SYNC0 的增量时间。例如 SYNC0=1,000,000ns, SYNC1=500,000ns 表示 SYNC1 在每个 SYNC0 后 500us 触发。

与从站级配置的区别
  • master.configure_dc_all() — 一次性配置所有 DC 从站
  • slave.dc().configure() — 配置单个从站

仅在需要对个别从站设置不同参数时使用从站级方法。

enable_continuous_measurement()

pub fn enable_continuous_measurement(&self, enable: bool, interval_sec: u32)

启用或禁用持续传播延迟测量(ETG.1500 5.13.2)。启用后主站定期重新测量传播延迟,适用于温度漂移等导致延迟变化的场景。

参数:

  • enabletrue 启用,false 禁用
  • interval_sec — 测量间隔(秒),0 表示使用默认间隔

示例:

master.enable_continuous_measurement(true, 60);  // 每 60 秒重新测量
master.enable_continuous_measurement(false, 0); // 禁用
备注

默认情况下 DC 偏移在 configure_dc() 时一次性计算。仅在长时间运行且环境温度变化较大时启用此功能。

同步窗口监控

主站每秒自动检查各 DC 从站的时间偏差。当从站偏差超出 sync_window_threshold() 阈值时触发 on_dc_sync_lost 事件。

// 阈值:默认 1000ns,可调整
master.diagnostics_info().set_sync_window_threshold(500); // 设为 500ns

// 事件:从站从"同步"变为"失同步"时触发一次(不重复触发)
master.events().on_dc_sync_lost(|master_idx, slave_idx, diff_ns| {
println!("从站 {} DC 同步丢失: 偏差 {}ns", slave_idx, diff_ns);
});

max_sync_difference()

pub fn max_sync_difference(&self) -> i32

获取所有 DC 从站中的最大时间偏差(纳秒)。

示例:

let max_diff = master.max_sync_difference();
println!("最大同步偏差: {}ns", max_diff);

is_all_slaves_in_sync()

pub fn is_all_slaves_in_sync(&self) -> bool

检查所有 DC 从站是否都在同步窗口内(偏差 <= sync_window_threshold())。

返回值:

  • bool — 所有从站同步返回 true

示例:

if !master.is_all_slaves_in_sync() {
println!("存在从站同步偏差过大");
}

reset_all_sync_window_stats()

pub fn reset_all_sync_window_stats(&self)

重置所有从站的同步窗口统计(最大/最小时间差、超出同步次数等)。

示例:

master.reset_all_sync_window_stats();
单个从站

单个从站的同步窗口详细状态请使用 slave.get_sync_window_status(),包含 diff_ns、max_diff_ns、min_diff_ns、in_sync、out_of_sync_count。

DC 漂移补偿

enable_drift_compensation()

pub fn enable_drift_compensation(&self, enable: bool,
threshold_ns: i32, gain: i32)

启用或禁用 DC 漂移补偿。漂移补偿在主站侧持续修正系统时钟与 DC 参考时钟之间的偏差,防止长时间运行后同步精度下降。

参数:

  • enabletrue 启用,false 禁用
  • threshold_ns — 触发补偿的偏差阈值(纳秒),偏差低于此值时不做修正,默认 1000ns
  • gain — 补偿增益,控制修正速率(值越大修正越快但可能引入振荡),默认 512

示例:

// 使用默认参数启用漂移补偿
master.enable_drift_compensation(true, 1000, 512);

// 自定义参数:500ns 阈值,较低增益(更平滑的修正)
master.enable_drift_compensation(true, 500, 256);

// 禁用漂移补偿
master.enable_drift_compensation(false, 0, 0);
推荐

对于长时间运行的系统(>24小时),建议启用漂移补偿。默认参数适合大多数场景,仅在需要更精细控制时调整阈值和增益。

CurrentDcSyncMode

current_dc_sync_mode() 是从站级属性,通过 slave.current_dc_sync_mode() 访问。详见 从站 DC 同步

完整示例

125us 高性能(WDK 驱动)

let mut master = EtherCATMaster::new()?;
master.set_network(r"\Device\NPF_{...}", "")?;

// 1. 配置周期 — 125us(WDK 驱动推荐值)
master.config().set_loop_cycle(125_000);

// 2. 切换到 SafeOp
master.set_state(EcState::SafeOp)?;

// 3. 配置 DC(自动偏移)— SYNC0 与 LoopCycle 保持一致
if master.has_dc() {
master.configure_dc_all(125_000, 0)?;
}

std::thread::sleep(std::time::Duration::from_secs(1));

// 4. 切换到 Op
master.set_state(EcState::Operational)?;

// 监听 DC 同步丢失事件
master.events().on_dc_sync_lost(|_, slave_idx, diff_ns| {
println!("从站 {} DC 同步丢失: 偏差 {}ns", slave_idx, diff_ns);
});

持续测量与同步监控

// 长时间运行:启用持续传播延迟测量(温度漂移补偿)
master.enable_continuous_measurement(true, 60);

// 同步窗口监控
if !master.is_all_slaves_in_sync() {
let max_diff = master.max_sync_difference();
println!("同步偏差过大: {}ns", max_diff);
}

// 重置统计
master.reset_all_sync_window_stats();

// 漂移补偿(长时间运行推荐)
master.enable_drift_compensation(true, 1000, 512);
SM 同步类型配置

SM 同步类型通过从站级 slave.dc().configure_mode(mode, ...) 方法自动配置,无需手动调用。详见 从站 DC 同步

DC 时间查询

运行时可通过主站实例查询当前 DC 系统时间与参考时钟从站索引, 用于日志打印、时间戳对齐、跨主站时钟比对等场景.

master_dc_time()

pub fn master_dc_time(&self) -> u64

最近一次取回的 64 位 DC 系统时间 (纳秒), 纪元为 2000-01-01 00:00:00. 返回 0 表示:

  • 无 DC 从站
  • configure_dc_all() 尚未调用
  • DC 未激活

示例:

let now_ns = master.master_dc_time();
if now_ns == 0 {
println!("DC 尚未激活");
} else {
// 纳秒 -> 2000-01-01 起秒数
let sec = now_ns / 1_000_000_000;
println!("DC 时间: {} ns ({} s 自 2000-01-01)", now_ns, sec);
}

reference_clock_slave_index()

pub fn reference_clock_slave_index(&self) -> i32

当前作为 DC 参考时钟的从站索引 (1-based).

返回值:

  • > 0 — 作为参考时钟的从站索引
  • 0 — 网络中无 DC 从站

示例:

match master.reference_clock_slave_index() {
0 => println!("无 DC 参考时钟 (网络中无 DC 从站)"),
idx => println!("参考时钟从站: slave[{}]", idx),
}

示例: DC 时间戳标注日志

let ref_idx = master.reference_clock_slave_index();
let t0 = master.master_dc_time();
println!("启动时 DC 时间 = {} ns, 参考时钟 = slave[{}]", t0, ref_idx);

master.events().on_pdo_cyclic_sync(move |_| {
let t = master.master_dc_time();
// 以参考时钟从站时间标注循环帧
println!("[dc={} ns] cycle", t);
});
参考
  • ETG.1000.6 §5.3 Distributed Clocks
  • ETG.1500 §5.13 传播延迟 / 漂移补偿