DC 配置
什么是 DC?
DC(分布式时钟)是 EtherCAT 的硬件级时间同步机制,让网络中所有从站共享同一个时间基准。
- 多轴同步运动 — 所有伺服驱动器在同一时刻更新位置指令,消除轴间抖动,轨迹插补更平滑
- IO 同步采样 — 所有输入输出在同一时刻,主站读取时数据一致,适合高速控制和测量
- 精确 I/O 时间戳 — 输入数据带有硬件时间戳,主站可精确知道采样发生的物理时刻
- 确定性输出 — 输出在固定时刻生效,不受 EtherCAT 帧到达时间的抖动影响,降低系统延迟和不确定性
主站级 DC 配置,通过 master 直接调用。
- 单个从站的 DC 配置请参见 从站 DC 同步
- 周期属性请参考 配置 - 周期配置
- DC 同步监控请参考 主站诊断 - DC 同步
属性
| 方法 | 类型 | 说明 |
|---|---|---|
| has_dc() | bool | 网络中是否有支持 DC 的从站 |
方法
configure_dc_all()
pub fn configure_dc_all(&self, sync0_ns: u32, sync1_ns: u32) -> Result<i32>
为所有 DC 从站配置 DC 同步。所有参数单位:纳秒(ns)。默认自动完成:
- 传播延迟测量 — 读取各端口接收时间并计算延迟
- 偏移计算 — 基于传播延迟自动计算每个从站的相位偏移
- DC 应用 — 写入 SYNC0/SYNC1 周期和起始时间到各从站
参数:
sync0_ns— SYNC0 周期(纳秒),0 表示禁用 DCsync1_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 是相对于 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)。启用后主站定期重新测量传播延迟,适用于温度漂移等导致延迟变化的场景。
参数:
enable—true启用,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 参考时钟之间的偏差,防止长时间运行后同步精度下降。
参数:
enable—true启用,false禁用threshold_ns— 触发补偿的偏差阈值(纳秒),偏差低于此值时不做修正,默认 1000nsgain— 补偿增益,控制修正速率(值越大修正越快但可能引入振荡),默认 512
示例:
// 使用默认参数启用漂移补偿
master.enable_drift_compensation(true, 1000, 512);
// 自定义参数:500ns 阈值,较低增益(更平滑的修正)
master.enable_drift_compensation(true, 500, 256);
// 禁用漂移补偿
master.enable_drift_compensation(false, 0, 0);
对于长时间运行的系统(>24小时),建议启用漂移补偿。默认参数适合大多数场景,仅在需要更精细控制时调整阈值和增益。
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 同步类型通过从站级 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 传播延迟 / 漂移补偿