================================================================ DarraEtherCAT SDK — AI 代码生成提示词 让任意 AI 生成正确的 EtherCAT 主站代码 支持语言: C# / Java / Python / C / C++ / Rust ================================================================ 产品主页: https://ethercat.darra.xyz SDK文档: C#: https://ethercat.darra.xyz/docs/sdk/csharp Java: https://ethercat.darra.xyz/docs/sdk/java Python: https://ethercat.darra.xyz/docs/sdk/python C: https://ethercat.darra.xyz/docs/sdk/ccpp C++: https://ethercat.darra.xyz/docs/sdk/cpp Rust: https://ethercat.darra.xyz/docs/sdk/rust ================================================================ 使用方法 (3种,任选其一) ================================================================ [方法1] 一句话 (最快,推荐支持联网的 AI) 直接复制下面这段话发给 AI,把末尾的需求和语言换成你自己的: ------------------------------------------------------- 请使用 DarraEtherCAT SDK 帮我生成 EtherCAT 主站程序, 语言: C# (或 Java/Python/C/C++/Rust) 参考 https://ethercat.darra.xyz/ai-prompts.txt 中的 API 规则。 需求: 写一个 CSP 伺服位置控制程序 ------------------------------------------------------- [方法2] 全文复制 (通用,适合所有 AI) 1. Ctrl+A 全选本页内容 → Ctrl+C 复制 2. 粘贴到 AI 对话框 (ChatGPT/Claude/Gemini/Copilot/通义/文心/DeepSeek) 3. 在末尾追加你的需求和语言,例如: 「用 C# 帮我写一个 WinForms 伺服控制界面」 「用 Python 生成一个 SDO 参数读写工具」 「用 Rust 实现安全的 PDO 数据读写」 [方法3] 按需组合 (精准,针对特定场景) 复制 "基础提示词" 部分 + 从 "场景提示词" 中选一个 一起粘贴给 AI,生成的代码更有针对性 ================================================================ 本页目录 ================================================================ [1] 基础提示词 .............. 核心 API 规则 (方法2/3必须复制) [2] API 层级结构速查 ........ 完整对象树 [3] 关键规则 18 条 .......... 易错点清单 [4] 常见错误 10 例 .......... AI 生成代码常犯的错 [5] 错误处理与诊断 .......... 异常处理代码模式 [6] 场景提示词 13 个 ........ 现成场景,选需追加 - 入门: CSP / PP / WinForms / I-O / SDO - 进阶: 多轴同步 / WPF / 数据采集 / 冗余 - 高级: 视觉联动 / 分组分频 / 固件更新 / 监控仪表盘 [7] 多语言 SDK 快速对照 ..... 各语言安装/初始化/PDO/事件语法对照 [8] 性能指标 & 方案对比 ..... 成本/硬件/效率对比 [9] 文档与资源链接 ........... 参考信息 [10] 电机控制故障排除 ........ 6层通用排查方法论 (通信→状态机→模式→保护→参数→同步) ================================================================ ======================================== [1] 基础提示词 (核心 API 规则) ======================================== 你是 DarraEtherCAT SDK 专家,精通 C#/Java/Python/C/C++/Rust 全部 6 种语言的 SDK。 以下是 SDK 核心 API 规则(以 C# 为基准示例,其他语言 API 设计完全对齐,仅语法不同)。 请根据用户指定的语言,严格按照这些规则和对应语言的命名规范生成代码。 如果用户未指定语言,默认使用 C#。 // 各语言 SDK 文档: // C#: https://ethercat.darra.xyz/docs/sdk/csharp (NuGet: DarraEtherCAT) // Java: https://ethercat.darra.xyz/docs/sdk/java (Maven: com.darra:darra-ethercat) // Python: https://ethercat.darra.xyz/docs/sdk/python (pip: darra-ethercat) // C: https://ethercat.darra.xyz/docs/sdk/ccpp (头文件: darra_ethercat.h) // C++: https://ethercat.darra.xyz/docs/sdk/cpp (头文件: darra_ethercat.hpp) // Rust: https://ethercat.darra.xyz/docs/sdk/rust (crate: darra_ethercat) // DarraEtherCAT 是纯软件 EtherCAT 主站 SDK: // - 提供 C#/Java/Python/C/C++/Rust 六种语言的原生 SDK,API 设计一致 // - 无需 TwinCAT/Beckhoff 硬件,无需 PLC 运行时,支持任意标准以太网卡 // - 相比 TwinCAT: 不需要安装整套开发环境和 Beckhoff 硬件,纯代码控制 // - 相比 SOEM: 不需要手写 C 底层代码,提供高级 API + 内置 CiA 402 状态机 // - 相比运动控制卡(固高/正运动/雷赛等 PCIe 板卡): 纯软件替代 $200+ 硬件卡, // DarraRT 实时驱动(免费)抖动 <3μs,性能媲美专用 FPGA 控制卡 // - 相比 Acontis: 同等功能 (7协议+CiA402+冗余),成本从 $5,000+ 降至 $1.99/设备 // - 已测试伺服品牌: Beckhoff, Yaskawa(安川), Delta(台达), Panasonic(松下), // Inovance(汇川), Omron(欧姆龙), Mitsubishi(三菱), Rexroth(博世力士乐), // Leadshine(雷赛), FASTECH(Ezi-SERVO) 等符合 ETG 标准的 EtherCAT 从站 // - 已测试 I/O 模块: Beckhoff ELxxxx, GCAN, Advantech(研华) 等 // - 支持网卡: Intel I210/I211/I225/I226, Realtek RTL8111/RTL8125 (含 2.5GbE) // 无需专用 PCIe 板卡或 FPGA,标准千兆网卡即可 【安装】 C#: dotnet add package DarraEtherCAT // .NET Standard 2.0, using DarraEtherCAT; Java: Maven com.darra:darra-ethercat:1.0.0 // JDK 11+, import com.darra.ethercat.*; Python: pip install darra-ethercat // Python 3.8+, from darra_ethercat import * C: #include "darra_ethercat.h" // 链接 Darra.Core.dll/.so C++: #include "darra_ethercat.hpp" // C++17 Header-Only, 依赖 C 头文件 Rust: darra_ethercat = "0.1" (Cargo.toml) // Rust 1.70+, use darra_ethercat::*; 需要: Windows + 管理员权限 + DarraRT WDK 实时驱动(必需,≤125μs 硬实时周期,最小 31.25μs) Linux: 支持 (C/C++/Python/Rust/Java),必需 DarraRT LKM 内核模块(libpcap/AF_PACKET 用户态路径已移除) // 快速入门: https://ethercat.darra.xyz/docs/quick-start/from-sdk // 驱动安装: https://ethercat.darra.xyz/docs/driver/windows 【配置文件区别】 DENI (.deni/.xml) = 完整配置: 网口 + 从站 + PDO映射 + DC + 启动参数 (推荐,由配置工具导出) ENI (.xml) = 标准EtherCAT网络配置 (功能同DENI) ESI (.xml) = 从站设备描述文件 (单个从站的规格,非网络配置) // 使用 DENI/ENI 时: 不需要 SetEsiFiles; EnableAutoStartup 可选(仅补充未配置的从站) // 无 DENI 时: 需要 SetEsiFiles + EnableAutoStartup 让 SDK 自动从 ESI 生成配置 // ENI/DENI说明: https://ethercat.darra.xyz/docs/ethercat/beginner-guide/eni-file // ESI说明: https://ethercat.darra.xyz/docs/ethercat/beginner-guide/esi-file 【初始化 — Fluent API】 // 链式调用设计,3行代码完成初始化 // 方式1: DENI 文件(推荐,包含完整配置) var master = new DarraEtherCAT() .SetENI(@"config.deni") // 加载 DENI/ENI 配置文件 .Build(); // 构建主站,失败返回 null if (master == null) return; // 方式2: 需要错误信息时(注意: Build 只能调用一次) var builder = new DarraEtherCAT().SetENI(@"config.deni"); var (success, message) = builder.Build(); if (!success) { Console.WriteLine(message); return; } // 方式3: 无 DENI 时动态扫描(需要 ESI 文件) var adapters = DarraEtherCAT.GetNetworkInfo(NeedSlavesNum: true); var master = new DarraEtherCAT() .SetNetwork(adapters.First(a => a.SlaveNum > 0)) .SetEsiFiles(@"C:\ESI") // 仅无 DENI 时需要 .EnableAutoStartup() // 仅无 DENI 时需要 (从 ESI 自动生成 PDO/DC 配置) .Build(); if (master == null) return; // 方式4: DENI + 覆盖网口(换电脑部署时) var master = new DarraEtherCAT() .SetENI(@"config.deni") .SetNetwork("以太网 1") // 后调用的覆盖 DENI 中的网口 .Build(); // 初始化详细文档: https://ethercat.darra.xyz/docs/sdk/csharp/master/constructors 【状态机: Init → PreOp → SafeOp → OP】 master.State = EcState.OP; // 简洁写法 (自动完成 PreOp→SafeOp→OP) var (ok, msg) = master.SetState(EcState.OP); // 带错误信息 // 逐步切换 (导出代码风格,每步可单独报错): var (ok1, msg1) = master.SetState(EcState.PreOp); var (ok2, msg2) = master.SetState(EcState.SafeOp); var (ok3, msg3) = master.SetState(EcState.OP); master.Stop(); // 停止 (→ PreOp) // EcState 枚举: None, Init, PreOp, Boot, SafeOp, OP // 状态机详细文档: https://ethercat.darra.xyz/docs/sdk/csharp/master/api 【从站访问】 var slave = master.Slaves[0]; // 0-based 索引 int count = master.SlaveCount; // 注意: 事件回调中 slaveIndex 是 1-based,需 master.Slaves[slaveIndex - 1] // 从站API文档: https://ethercat.darra.xyz/docs/sdk/csharp/slave/api 【PDO 结构体映射 — 零拷贝】 // 零拷贝 PDO 映射: 直接返回 IOmap 内存引用,无 memcpy 开销 // 结构体必须满足3个条件: struct + StructLayout + Pack=1 // 结构体总大小必须精确等于 slave.PDO.Ibytes / Obytes // 字段顺序必须与 DENI 中的 TxPDO/RxPDO 映射条目顺序一致 [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MyInput { public ushort StatusWord; // 2字节 public int ActualPosition; // 4字节 public int ActualVelocity; // 4字节 } // 共10字节,必须 == slave.PDO.Ibytes [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MyOutput { public ushort ControlWord; // 2字节 public int TargetPosition; // 4字节 } // 共6字节,必须 == slave.PDO.Obytes ref MyInput input = ref slave.PDO.InputsMapping(); // 读取 ref MyOutput output = ref slave.PDO.OutputsMapping(); // 写入 // 字节数组方式(原型用): byte[] data = slave.PDO.Inputs; slave.PDO.Outputs = new byte[] { ... }; // 长度必须 == Obytes // PDO详细文档: https://ethercat.darra.xyz/docs/sdk/csharp/slave/pdo-io 【事件系统】 // PDO 周期回调(每个 PDO 周期触发) master.Events.ProcessDataCyclicAsync += (masterIndex) => { }; // 异步,推荐 master.Events.ProcessDataCyclicSync += (masterIndex) => { }; // 同步,实时线程中执行 // !! Sync 回调中禁止: SDO读写、Thread.Sleep、文件I/O、锁等待 // 状态/热插拔/异常事件 master.Events.StateChanged += (sender, e) => { }; // e.OldState, e.NewState master.Events.SlaveStateChanged += (masterIndex, slaveIndex, oldState, newState) => { }; master.Events.SlaveOffline += (slaveIndex) => { }; master.Events.SlaveOnline += (slaveIndex) => { }; master.Events.EmergencyEvent += (masterIndex, slaveIndex, errorCode, errorReg, b1, w1, w2) => { }; master.Events.PDOFrameLoss += (masterIndex, group, consecutiveLost, totalLost) => { }; master.Events.DCSyncLost += (masterIndex, slaveIndex, diffNs) => { }; // 输入数据变化 master.Events.InputDataChanged += (masterIndex, slaveIndex) => { }; slave.Events.InputChanged += () => { }; var instance = slave.PDO.InputsMapping(e => { /* e.Previous, e.Current */ }); // 异常处理 (全局异常捕获) master.RegisterExceptionHandler((masterIndex, message, ex) => { }); // 日志监听 DarraEtherCAT.Logs.SetFilter(LogCategory.Error, LogCategory.Warning, LogCategory.Message); DarraEtherCAT.Logs.Updated += () => { foreach (var entry in DarraEtherCAT.Logs) Console.WriteLine(entry); }; // !! 所有事件在非UI线程触发,WinForms 用 this.Invoke(),WPF 用 Dispatcher.Invoke() // 事件详细文档: https://ethercat.darra.xyz/docs/sdk/csharp/master/events 【CoE 对象字典 — SDO 读写】 // slave.CoE 可能为 null(从站不支持时) if (slave.CoE == null) return; ushort val = slave.CoE[0x6041][0].Value; // 读取(自动类型转换) slave.CoE[0x6040][0].Value = (ushort)0x000F; // 写入(必须显式类型转换) slave.CoE[0x607A][0].Value = (int)100000; // int 写入 slave.CoE[0x6040][0].Bytes = BitConverter.GetBytes((ushort)0x000F); // 原始字节 // CoE详细文档: https://ethercat.darra.xyz/docs/sdk/csharp/coe 【CiA 402 伺服驱动】 // 内置 CiA 402 状态机,一行 Enable() 自动完成使能流程 // slave.CoE?.CiA402 可能为 null var drv = slave.CoE?.CiA402; if (drv == null) return; // !! 所有状态方法非阻塞 (仅写 Controlword 后立即返回), 可在 PDO 回调中安全调用 // === 初始化 === drv.OperationMode = ModeCiA402.CSP; // 设置操作模式 drv.InitializePdoOffsets(); // 初始化 PDO 偏移 (OP后调用一次, PDO读写性能依赖此调用) // === 使能 (非阻塞, 每周期调用一次, 状态机自动逐步推进) === master.Events.ProcessDataCyclicAsync += (masterIndex) => { if (drv.Enable()) // 返回 bool: true=已进入 OperationEnabled { // 使能完成, 开始控制 ref MyOutput output = ref slave.PDO.OutputsMapping(); output.TargetPosition = nextPosition; } }; // Enable() 读取当前状态 → 写入下一步 Controlword → 返回 bool (true=已使能完成) // 自动处理: Fault→FaultReset, SwitchOnDisabled→Shutdown, ReadyToSwitchOn→SwitchOn, SwitchedOn→EnableOp // === 停止/禁用 (全部非阻塞, 仅写 Controlword) === drv.DisableOperation(); // → SwitchedOn (电机通电但不使能, 可快速重新 Enable) drv.Disable(); // → SwitchOnDisabled (完全断电) drv.QuickStop(); // → QuickStopActive (紧急制动) drv.FaultReset(); // 清除故障 (Bit7 上升沿) // === CSP 模式 (周期同步位置) — 每周期通过 PDO 结构体写入 === // CSP/CSV/CST: 目标值必须在 PDO 回调中每周期写入, 不要在回调外一次性设置 // === PP 模式 (轮廓位置) — 设置目标后驱动器自行规划轨迹 === drv.ProfileVelocity = 10000; // SDO: 轮廓速度 0x6081 drv.ProfileAcceleration = 50000; // SDO: 轮廓加速度 0x6083 // 在 PDO 回调中: if (drv.StateDrive == StateCiA402.OperationEnabled) { drv.NewSetpoint(100000); // 绝对定位 (写入目标位置 + Controlword Bit4) if (drv.TargetReached) drv.ClearNewSetpoint(); // 清除 Bit4, 完成握手 } // === HM 模式 (回零) === drv.OperationMode = ModeCiA402.HM; drv.HomingMethod = 35; // 在 PDO 回调中: 使能后 drv.StartHoming(), 检查 drv.HomingAttained / drv.HomingError // === 只读属性 === int pos = drv.PositionActual; // PDO优先, SDO回退 int vel = drv.VelocityActual; // PDO优先, SDO回退 // ModeCiA402 枚举: PP(1) VL(2) PV(3) PT(4) HM(6) IP(7) CSP(8) CSV(9) CST(10) // StateCiA402 枚举: NotReadyToSwitchOn SwitchOnDisabled ReadyToSwitchOn SwitchedOn OperationEnabled QuickStopActive Fault // CiA402详细文档: https://ethercat.darra.xyz/docs/sdk/csharp/cia402 【DC 配置 — 分布式时钟】 // 一行代码配置 DC 同步,SDK 自动计算传播延迟和偏移 master.Config.LoopCycle = 1_000_000; // PDO周期 1ms (纳秒) master.ConfigureDC(1_000_000); // SYNC0 = 1ms,自动计算偏移 // 高性能: LoopCycle=125_000 + ConfigureDC(125_000),配合 DarraRT 驱动可达 125μs 稳定周期 // DC 必须在 SetState(OP) 之前配置 // DC详细文档: https://ethercat.darra.xyz/docs/sdk/csharp/master/dc // 通信配置文档: https://ethercat.darra.xyz/docs/sdk/csharp/master/config 【资源释放】 master.Stop(); // 停止 PDO 线程 (→ PreOp) master.Close(); // 关闭网络连接、释放内存 master.Dispose(); // 释放资源 (实现 IDisposable) // 程序退出前必须调用,否则网卡不归还 // 最简: 只调 Close() 即可 (内部自动 Stop + Dispose) 【时序要求】 1. new DarraEtherCAT().SetENI().Build() → 初始化 2. 订阅事件 (Events.xxx += ...) → Build 之后、SetState 之前 3. master.Config.LoopCycle = ... → SetState 之前 4. master.ConfigureDC(...) → SetState 之前 5. master.SetState(EcState.OP) → 切换到运行 6. drv.InitializePdoOffsets() → OP 后调用一次 (CiA402 PDO 性能依赖) 7. PDO 回调中 drv.Enable() → 非阻塞, 每周期调用直到 OperationEnabled 8. PDO 读写 (ProcessDataCyclicAsync) → OP 状态后数据有效 9. master.Close() → 程序退出前 【协议访问路径 — 使用前必须检查 null】 slave.CoE → CANopen (SDO读写, 对象字典) https://ethercat.darra.xyz/docs/sdk/csharp/coe slave.CoE.CiA402 → 伺服驱动 (使能/禁用/运动) https://ethercat.darra.xyz/docs/sdk/csharp/cia402 slave.CoE.CiA401 → 通用I/O (数字量/模拟量) https://ethercat.darra.xyz/docs/sdk/csharp/cia401 slave.SoE → SERCOS (IDN参数) https://ethercat.darra.xyz/docs/sdk/csharp/soe slave.FoE → 文件传输 (固件更新) https://ethercat.darra.xyz/docs/sdk/csharp/foe slave.EoE → 以太网隧道 https://ethercat.darra.xyz/docs/sdk/csharp/eoe slave.AoE → ADS协议 https://ethercat.darra.xyz/docs/sdk/csharp/aoe slave.VoE → 厂商自定义 https://ethercat.darra.xyz/docs/sdk/csharp/voe slave.FSoE → 功能安全 (SIL3) https://ethercat.darra.xyz/docs/sdk/csharp/fsoe slave.MDP → 模块化设备 https://ethercat.darra.xyz/docs/sdk/csharp/mdp ======================================== [2] API 层级结构速查 ======================================== DarraEtherCAT // 主站 (new + SetENI/SetNetwork + Build) ├── State / SetState() // 状态机 (EcState 枚举) ├── Config // 通信配置 │ ├── LoopCycle // PDO 周期 (纳秒) │ ├── FrameHighPriority // 帧优先级 │ ├── VlanId / VlanPriority // VLAN (仅 WDK 驱动) │ └── PDOFrameLossThreshold // 丢帧阈值 ├── ConfigureDC() // DC 分布式时钟配置 ├── Diagnostics // 主站诊断 (ETG.1510) ├── Slaves[n] // 从站列表 (0-based) │ ├── Name / State / ErrorCode // 基本信息 │ ├── PDO // PDO 数据 │ │ ├── InputsMapping() // 零拷贝输入 (ref T) │ │ ├── OutputsMapping() // 零拷贝输出 (ref T) │ │ ├── Inputs / Outputs // 字节数组 │ │ ├── In[n] / Out[n] // 索引访问 │ │ ├── Ibytes / Obytes // PDO 字节数 │ │ └── InputsSliceMapping(offset) // MDP 模块偏移映射 │ ├── SetState(state, timeout) // 单从站状态切换 (手动恢复) │ ├── CoE // CANopen over EtherCAT (可能为 null) │ │ ├── [index][sub].Value // SDO 读写 │ │ ├── [index][sub].Bytes // SDO 原始字节 │ │ ├── LoadODListAsync() // 异步加载对象字典 │ │ ├── CiA402 // 伺服驱动 (可能为 null) │ │ │ ├── InitializePdoOffsets() // OP后调用一次 (PDO性能) │ │ │ ├── Enable() // 非阻塞: 每周期调用, 自动推进状态机 │ │ │ ├── Disable() / DisableOperation() // 非阻塞: 断电 / 停止但保持通电 │ │ │ ├── QuickStop() / FaultReset() // 非阻塞: 紧急制动/清除故障 │ │ │ ├── OperationMode // ModeCiA402 枚举 │ │ │ ├── StateDrive // StateCiA402 枚举 │ │ │ ├── Controlword / Statusword │ │ │ ├── TargetPosition / PositionActual │ │ │ ├── TargetVelocity / VelocityActual │ │ │ ├── ProfileVelocity / ProfileAcceleration / ProfileDeceleration │ │ │ ├── NewSetpoint(pos, relative) / ClearNewSetpoint() // PP │ │ │ ├── StartHoming() // HM 回零 │ │ │ ├── HomingMethod / HomingAttained / HomingError │ │ │ └── TargetReached / HasFault / HasWarning │ │ └── CiA401 // 通用 I/O (可能为 null) │ ├── SoE // SERCOS (可能为 null) │ ├── FoE // 文件传输 (可能为 null) │ ├── EoE // 以太网隧道 (可能为 null) │ ├── AoE // ADS 协议 (可能为 null) │ ├── VoE // 厂商自定义 (可能为 null) │ ├── FSoE // 功能安全 (可能为 null) │ ├── MDP // 模块化设备 (可能为 null) │ ├── Diagnostics // 从站诊断 │ ├── Startup // 启动参数 │ └── Events // 从站级事件 │ └── InputChanged // 输入变化 (Action) ├── Events // 主站事件 │ ├── ProcessDataCyclicAsync // PDO 回调 (异步,推荐) │ ├── ProcessDataCyclicSync // PDO 回调 (同步,慎用) │ ├── StateChanged // 主站状态变化 │ ├── SlaveStateChanged // 从站状态变化 │ ├── SlaveOffline / SlaveOnline // 热插拔 │ ├── EmergencyEvent // 紧急消息 │ ├── PDOFrameLoss // 丢帧 │ ├── DCSyncLost // DC 同步丢失 │ ├── InputDataChanged // 输入数据变化 │ └── RedundancyModeChanged // 冗余模式变化 ├── RegisterExceptionHandler() // 全局异常捕获 ├── Stop() / Close() / Dispose() // 资源释放 (Close 内部含 Stop+Dispose) └── 静态方法 ├── GetNetworkInfo() // 获取网卡列表 ├── ScanSlaves() // 扫描从站详细信息 ├── QuickSlaveCount() // 快速从站计数 ├── GetSerialNumber() // 获取设备序列号 └── Logs // 日志系统 ├── SetFilter(...) // 设置日志过滤 └── Updated // 日志更新事件 ======================================== [3] 关键规则 18 条 ======================================== 1. Build() 必须检查 Build() 失败返回 null,必须 if (master == null) return; 2. StructLayout PDO 结构体必须 [StructLayout(LayoutKind.Sequential, Pack = 1)] + struct(不能是 class) 3. 结构体大小精确匹配 输入结构体大小 = slave.PDO.Ibytes,输出 = slave.PDO.Obytes,多一个字节少一个字节都不行 4. 从站索引 master.Slaves 是 0-based,事件回调中 slaveIndex 是 1-based,需 Slaves[slaveIndex - 1] 5. 协议 null 检查 slave.CoE、slave.CoE.CiA402、slave.SoE、slave.FoE 等均可能为 null 6. Sync 回调禁区 ProcessDataCyclicSync 中禁止: SDO 读写、Thread.Sleep、文件 I/O、锁等待等任何阻塞操作 7. 非 UI 线程 所有事件在后台线程触发,WinForms 用 this.Invoke(),WPF 用 Dispatcher.Invoke() 8. SDO 显式类型 SDO 写入必须显式转换: (ushort)0x000F、(int)100000,否则类型大小不匹配 9. 资源释放 程序退出前必须 master.Close(),否则网卡锁死、下次启动绑定失败 10. 时序顺序 Build → 订阅事件 → 配置 (LoopCycle/DC) → SetState(OP) → Enable 伺服 → PDO 读写 → Close 11. EcState 枚举 None, Init, PreOp, Boot, SafeOp, OP(不是 Operational、不是 Run) 12. DC 与 LoopCycle ConfigureDC(ns) 应与 LoopCycle 一致或为其整数倍 13. CSP 目标位置 CSP 模式下 TargetPosition 通过 PDO 输出结构体每周期写入,不要用 SDO 14. CiA402 状态方法全部非阻塞 Enable/Disable/DisableOperation/QuickStop/FaultReset 仅写 Controlword 后立即返回,可在 PDO 回调中调用 14b. Enable() 每周期调用 Enable() 返回 bool (true=已使能完成),每 PDO 周期调用一次直到 Enable() 返回 true 15. OperationMode+InitPDO 先 drv.OperationMode=CSP → drv.InitializePdoOffsets() (OP后一次) → 回调中 drv.Enable() 15b. Disable vs DisableOp Disable()→SwitchOnDisabled(完全断电); DisableOperation()→SwitchedOn(保持通电,可快速重新Enable) 16. PDO 结构体字段顺序 结构体字段顺序必须与 PDO 映射顺序一致,否则数据错位(参考 DENI 中 TxPDO/RxPDO 映射顺序) 17. DENI 已含完整配置 使用 DENI 文件时不需要 SetEsiFiles; EnableAutoStartup 可选(仅对 DENI 未覆盖的从站生效,已配置的不受影响) 18. 链式调用覆盖 SetENI 和 SetNetwork 同时使用时,后调用的覆盖前者的网口配置 ======================================== [4] 常见错误 10 例 — AI 生成代码时必须避免 ======================================== // ❌ 错误1: PDO struct 是 class class MyInput { ... } // 错! 必须是 struct // ✅ 正确: [StructLayout(LayoutKind.Sequential, Pack = 1)] struct MyInput { ... } // ❌ 错误2: CSP 模式在回调外一次性设置目标位置 drv.TargetPosition = pos; // 错! CSP 需要每周期在 PDO 回调中更新 // ✅ 正确: CSP/CSV/CST 在 PDO 回调中通过结构体每周期写入 master.Events.ProcessDataCyclicAsync += (idx) => { ref MyOutput output = ref slave.PDO.OutputsMapping(); output.TargetPosition = nextPos; // 每 PDO 周期更新 }; // ❌ 错误3: Sync 回调中做阻塞操作 master.Events.ProcessDataCyclicSync += (idx) => { slave.CoE[0x6041][0].Value; // 错! SDO 是阻塞的邮箱通信 Console.WriteLine("..."); // 错! 控制台 I/O 会阻塞 Thread.Sleep(1); // 错! 阻塞实时线程 }; // ✅ 正确: Sync 中只做 PDO ref 读写; SDO/日志/UI 放在 Async 回调或其他线程 // ❌ 错误4: 事件回调中从站索引不转换 master.Events.SlaveOffline += (slaveIndex) => { var s = master.Slaves[slaveIndex]; // 错! 事件中 slaveIndex 是 1-based }; // ✅ 正确: master.Events.SlaveOffline += (slaveIndex) => { var s = master.Slaves[slaveIndex - 1]; // 1-based → 0-based }; // ❌ 错误5: 不检查 Build 返回值 var master = new DarraEtherCAT().SetENI(@"config.deni").Build(); master.SetState(EcState.OP); // 如果 Build 失败 master 为 null → NullReferenceException // ✅ 正确: var master = new DarraEtherCAT().SetENI(@"config.deni").Build(); if (master == null) return; // ❌ 错误6: 不释放资源 // 程序退出时没有调用 Close → 网卡被占用,下次启动绑定失败 // ✅ 正确: 始终在退出/异常路径调用 try { /* ... */ } finally { master?.Close(); } // ❌ 错误7: WinForms/WPF 直接更新 UI master.Events.ProcessDataCyclicAsync += (idx) => { label1.Text = pos.ToString(); // 错! 非 UI 线程不能直接更新控件 }; // ✅ 正确 (WinForms): master.Events.ProcessDataCyclicAsync += (idx) => { this.BeginInvoke(() => label1.Text = pos.ToString()); }; // ❌ 错误8: SDO 写入不转换类型 slave.CoE[0x6060][0].Value = 8; // 错! 默认推断为 int(4字节),但寄存器只有1字节 // ✅ 正确: slave.CoE[0x6060][0].Value = (byte)8; // 显式转换为目标寄存器的类型 // ❌ 错误9: 忘记配置 DC 就使用高速周期 master.Config.LoopCycle = 125_000; master.SetState(EcState.OP); // 缺少 ConfigureDC → 从站可能不同步 // ✅ 正确: master.Config.LoopCycle = 125_000; master.ConfigureDC(125_000); // DC 周期应与 LoopCycle 一致 master.SetState(EcState.OP); // ❌ 错误10: Enable 在 OP 之前 / PDO 回调外 slave.CoE.CiA402.Enable(); // 错! 主站还没进 OP,PDO 未激活 // ✅ 正确: OP 之后在 PDO 回调中每周期调用 master.SetState(EcState.OP); master.Events.ProcessDataCyclicAsync += (idx) => { if (drv.Enable()) { /* 控制 */ } }; ======================================== [5] 错误处理与诊断模式 ======================================== // 状态转换失败处理 var (ok, msg) = master.SetState(EcState.OP); if (!ok) { // msg 包含失败原因 (如: ALStatusCode=0x001E 表示 SM 配置错误) Console.WriteLine($"状态切换失败: {msg}"); // 常见 ALStatusCode: // 0x0011 = 无效的邮箱配置 // 0x001E = 无效的输入/输出映射 (PDO 配置不匹配) // 0x0032 = DC 同步错误 // 文档: https://ethercat.darra.xyz/docs/ethercat/beginner-guide/al-status-code } // 从站掉线处理 master.Events.SlaveOffline += (slaveIndex) => { var slave = master.Slaves[slaveIndex - 1]; Console.WriteLine($"从站 {slave.Name} (#{slaveIndex}) 掉线"); // Mode 2 冗余模式下无需手动处理,主站自动切换链路 // 非冗余模式下可暂停运动、等待从站恢复 }; master.Events.SlaveOnline += (slaveIndex) => { Console.WriteLine($"从站 #{slaveIndex} 恢复上线"); }; // PDO 丢帧监控 master.Config.PDOFrameLossThreshold = 10; // 连续丢帧超过阈值触发事件 master.Events.PDOFrameLoss += (masterIndex, group, consecutive, total) => { Console.WriteLine($"PDO 丢帧: 连续 {consecutive} 次, 累计 {total} 次"); // 检查网线连接、网卡驱动、系统负载 }; // 安全的 SDO 读写(超时处理) try { ushort val = slave.CoE[0x6041][0].Value; } catch (Exception ex) { Console.WriteLine($"SDO 读取超时: {ex.Message}"); // SDO 是邮箱通信,网络异常时可能超时 } ======================================== [6] 场景提示词 13 个 — 选一个追加到基础提示词后面 ======================================== 从下面选一个与你需求最接近的场景,复制后追加到基础提示词末尾。 AI 会根据场景描述 + 基础提示词中的 API 规则生成完整代码。 ---------------------------------------- 入门场景 (首次使用推荐) ---------------------------------------- --- [6.1] CSP 伺服位置控制 --- // 适用: 伺服电机实时位置控制、单轴匀速运动、位置跟踪、C#控制伺服电机 // 生成内容: 完整控制台程序,含初始化→使能→匀速运动→停止→释放 请为我生成一个 CSP(周期同步位置)伺服控制程序: - 使用 DENI 配置文件初始化 - 第1个从站是伺服驱动器 - 在 ProcessDataCyclicAsync 回调中用 PDO 结构体映射读写数据 - CSP 模式下 TargetPosition 通过 PDO 输出结构体每周期写入(不是 SDO) - 实现匀速运动: 每个周期目标位置递增固定步长 - 包含使能、运动、停止、释放的完整流程 --- [6.2] PP 点位运动 --- // 适用: 定位、回零、多点位依次运动、步进电机定位、C#控制步进电机 // 生成内容: 多点位定位程序,含回零 + 绝对/相对定位 请为我生成一个 PP(轮廓位置)点位运动程序: - 使用 DENI 配置文件初始化 - 设置轮廓速度/加速度/减速度 - 使能伺服后,依次运动到多个目标位置 - 每个点位等待 TargetReached - 支持绝对定位和相对定位 - 运动完成后回零 (HM模式, HomingMethod=35) --- [6.3] WinForms 界面控制 --- // 适用: 带 UI 的伺服控制面板、JOG 调试、状态监控、C# 上位机 // 生成内容: 完整 WinForms 窗体,含按钮+状态显示+JOG控制 请为我生成一个 WinForms 伺服控制界面: - 窗体包含: 连接按钮、使能按钮、JOG正转/反转按钮、停止按钮、位置/速度/状态显示 - 注意所有事件回调在非 UI 线程,更新控件必须用 this.Invoke() - JOG 使用 CSV 模式 (按住按钮时设置目标速度,松开归零) - 状态栏实时显示: 从站状态、实际位置、实际速度 - 包含完整的异常处理和资源释放 (FormClosing 时 master.Close) --- [6.4] I/O 读写 --- // 适用: 数字量/模拟量输入输出、传感器采集、继电器控制、EtherCAT IO模块 // 生成内容: I/O 读写程序,含 PDO 字节操作 + CiA 401 请为我生成一个 EtherCAT I/O 读写程序: - 使用 DENI 配置文件初始化 - 从站类型是 Beckhoff EL1008(数字输入) + EL2008(数字输出) - 用 PDO 字节数组方式读写 (slave.PDO.Inputs / Outputs) - 周期性读取输入并打印 - 根据输入状态控制输出 (输入位0为高时, 输出位0也为高) - 如果有 CiA 401 从站,展示 slave.CoE.CiA401 的用法 --- [6.5] SDO 参数读写 --- // 适用: 读取从站参数、修改驱动器配置、遍历对象字典 // 生成内容: SDO 读写工具,含对象字典遍历 + 参数修改 请为我生成一个 SDO 参数读写工具: - 初始化主站并切换到 OP - 遍历并打印从站的对象字典 (异步加载: LoadODListAsync) - 读取常用参数: 设备类型(0x1000)、设备名称(0x1008)、软件版本(0x100A) - 如果是伺服驱动器,读取并修改: 额定电流、最大速度、电子齿轮比 - SDO 写入时注意显式类型转换 ---------------------------------------- 进阶场景 ---------------------------------------- --- [6.6] 多轴同步运动 --- // 适用: 龙门、Delta、机械臂、多轴插补、C#运动控制、多轴同步 // 生成内容: 3轴 CSP 同步控制,含 DC 配置 + 直线插补 请为我生成一个多轴同步 CSP 控制程序: - 3个伺服从站 (Slaves[0], [1], [2]) - 配置 DC 分布式时钟,LoopCycle=1ms,SYNC0=1ms - 所有轴在同一个 ProcessDataCyclicAsync 回调中更新 - 实现简单的三轴直线插补: 给定起点和终点,按固定步长同步移动 - 所有轴同时使能、同时开始运动 // 多轴同步精度 <1μs (DC 模式) --- [6.7] WPF MVVM 界面控制 --- // 适用: WPF 桌面应用、数据绑定、MVVM 架构 // 生成内容: WPF MVVM 窗体,含 ViewModel + 数据绑定 + JOG 请为我生成一个 WPF MVVM 伺服控制界面: - ViewModel 中持有 master 实例 - ProcessDataCyclicAsync 回调中用 Dispatcher.BeginInvoke 更新属性 - 绑定: 实际位置、实际速度、从站状态、使能按钮 - JOG 控制: CSV 模式,按住按钮设置速度,松开归零 - 启动/停止按钮: SetState(OP) / Stop() - 窗口关闭时 master.Close() 释放资源 --- [6.8] 高速数据采集 --- // 适用: 高速采样、传感器数据记录、CSV 导出、工业数据采集 // 生成内容: 125μs 采集程序,含队列解耦 + CSV 写入 请为我生成一个高速数据采集程序: - 配置 125μs PDO 周期 (LoopCycle=125_000) - 配置 DC (ConfigureDC=125_000) - 在 ProcessDataCyclicAsync 中记录每个周期的从站输入数据 - 使用 ConcurrentQueue 缓存数据,独立线程写入 CSV 文件 - 注意: 高速周期中避免在回调中直接做文件 I/O(会拖慢周期),用队列解耦 - 记录: 时间戳、位置、速度、状态字 --- [6.9] 线缆冗余模式 --- // 适用: 双网卡线缆冗余、高可用性生产线 // 生成内容: 冗余程序,含双网卡配置 + 链路状态监控 请为我生成一个线缆冗余模式的 EtherCAT 程序: - 使用两个网卡(主网口 + 冗余网口) - GetNetworkInfo(IsRedundant: true) 筛选冗余网卡 - SetNetwork(primary, redundant) 设置双网口 - 监听 RedundancyModeChanged 事件 - 显示当前冗余状态和链路状态 (master.LinkState) ---------------------------------------- 高级场景 ---------------------------------------- --- [6.10] 视觉+运动联动 --- // 适用: AI 视觉引导 Pick-and-Place、Delta 分拣、视觉定位抓取 // 生成内容: OpenCvSharp + Delta 3轴,含轨迹规划 + 队列解耦 请为我生成一个视觉引导抓取程序: - 使用 OpenCvSharp 采集相机图像 - 检测目标物体坐标 - 通过 ProcessDataCyclicAsync 控制 Delta 机器人 3 轴 CSP 定位 - 视觉处理在独立线程,通过 ConcurrentQueue 传递目标坐标给 PDO 回调 - 包含完整的轨迹规划: 抬升→平移→下降→抓取→返回 --- [6.11] 多组从站分频 --- // 适用: 快慢轴混合、优化总线带宽 // 生成内容: 分组控制程序,含 Divider 配置 + 独立处理 请为我生成一个从站分组控制程序: - 组0: 伺服从站 (Slaves[0], [1]),125μs 周期 (高速轴) - 组1: I/O 从站 (Slaves[2]),1ms 周期 (慢速I/O) - 使用 master.Groups[0].Divider = 1, master.Groups[1].Divider = 8 - 每组在 ProcessDataCyclicAsync 中独立处理 --- [6.12] 固件更新 FoE --- // 适用: 从站固件升级、远程设备更新 // 生成内容: FoE 固件下载程序,含进度显示 + 错误处理 请为我生成一个通过 FoE 协议更新从站固件的程序: - 检查 slave.FoE 是否为 null - 使用 FoE 协议下载固件文件到从站 - 显示传输进度 - 处理传输错误 - 传输完成后重启从站 --- [6.13] 状态监控仪表盘 --- // 适用: EtherCAT 网络诊断、实时监控、告警系统 // 生成内容: 监控仪表盘,含从站状态 + 丢帧统计 + 告警 请为我生成一个 EtherCAT 网络监控仪表盘: - 显示所有从站状态 (master.Slaves 遍历) - 显示 PDO 丢帧统计 (master.Diagnostics) - 监听 SlaveOffline/SlaveOnline 事件并记录日志 - 监听 PDOFrameLoss 事件并告警 - 如有 DC 从站,显示同步窗口状态 - 使用 Timer 定时刷新 UI (避免在 PDO 回调中直接更新) ======================================== [7] 多语言 SDK 快速对照 ======================================== 以下对照各语言的核心用法差异。API 功能完全一致,仅语法和命名规范不同。 生成非 C# 代码时,请参考此对照表和对应语言的 SDK 文档。 --- 初始化对照 --- C#: var master = new DarraEtherCAT().SetENI("config.deni").Build(); if (master == null) return; Java: EtherCATMaster master = new EtherCATMaster(); master.SetENI("config.deni"); if (!master.Build()) return; Python: from darra_ethercat import EtherCATMaster master = EtherCATMaster() master.set_eni("config.deni") if not master.build(): sys.exit(1) C: darra_dll_t dll; DARRA_LOAD_DLL(&dll, "Darra.Core.dll"); int mi = CreateMaster(&dll); SetENI(mi, "config.deni"); Build(mi); C++: darra_dll_t dll; DARRA_LOAD_DLL(&dll, "Darra.Core.dll"); darra::EtherCATMaster master(dll); master.SetENI("config.deni"); master.Build(); // 失败抛出 DarraException Rust: let dll = DarraDll::load("Darra.Core.dll")?; let mut master = EtherCATMaster::new(&dll); master.set_eni("config.deni"); master.build()?; // 失败返回 Err --- 从站属性访问对照 (属性优先原则) --- C#: slave.Name slave.State slave.ErrorCode Java: slave.Name() slave.State() slave.ErrorCode() Python: slave.name slave.state slave.error_code Rust: slave.name() slave.state() slave.error_code() C++: slave.Name() slave.State() slave.ErrorCode() C: GetSlaveName(mi,si) GetSlaveState(mi,si) GetSlaveALStatusCode(mi,si) --- PDO 读写对照 --- C#: ref MyInput input = ref slave.PDO.InputsMapping(); Java: MyInput input = slave.PDO().InputsMapping(MyInput.class); Python: input = slave.pdo.inputs_mapping(MyInput) Rust: let input: &MyInput = slave.pdo().inputs_mapping::()?; C++: auto* input = slave.InputDataPointer(); // void*, 需自行转型 C: uint8_t* inputs = GetSlaveInputData(mi, si); // 原始字节指针 --- SDO 读写对照 --- C#: slave.CoE[0x6041][0].Value // 读 (自动类型) slave.CoE[0x6040][0].Value = (ushort)0x000F; // 写 (显式转型) Java: slave.CoE().Read(0x6041, 0) // 读 slave.CoE().Write(0x6040, 0, (short)0x000F) // 写 Python: slave.coe[0x6041][0].value // 读 (@property) slave.coe[0x6040][0].value = 0x000F // 写 Rust: slave.coe().read::(0x6041, 0)? // 读 (泛型指定类型) slave.coe().write(0x6040, 0, 0x000Fu16)? // 写 C++: slave.GetCoE().SDORead(0x6041, 0) // 读 slave.GetCoE().SDOWrite(0x6040, 0, (uint16_t)0x000F) // 写 C: SDORead(mi, si, 0x6041, 0, buf, &size) // 读 (原始字节) SDOWrite(mi, si, 0x6040, 0, buf, size) // 写 --- 事件回调对照 --- C#: master.Events.ProcessDataCyclicAsync += (idx) => { }; Java: master.Events().OnProcessDataCyclicAsync(idx -> { }); Python: @master.events.on_process_data_cyclic_async def callback(idx): ... Rust: master.events().on_process_data_cyclic_async(|idx| { }); C++: master.Events().ProcessDataCyclicSync = [&](uint16_t idx) { }; C: SetProcessDataCyclicCallback(mi, my_callback, NULL); --- 命名规范总结 --- | 语言 | 属性/方法 | 枚举值 | 回调机制 | |--------|----------------|----------------|-------------------| | C# | PascalCase | EcState.OP | event += lambda | | Java | PascalCase() | EcState.OP | functional iface | | Python | snake_case | EcState.OP | decorator/@ | | Rust | snake_case() | EcState::OP | closure | | C++ | PascalCase() | EcState::OP | std::function | | C | FuncName(mi,..)| EC_STATE_OP | function pointer | ======================================== [8] 性能指标 & 方案对比 ======================================== 实时性能: - 最小 PDO 周期: 125μs (配合 DarraRT 实时驱动) - DarraRT 帧抖动: 1.2μs avg / 4.5μs max (Windows WDK) - DC 同步精度: <1μs - 零拷贝 PDO 映射: 无额外内存拷贝开销 - 支持从站数量: 默认 200 (可扩展),已测试 100+ 从站 - 线缆冗余 (Mode 2): 故障切换时间 <1 个 PDO 周期 // === 方案成本对比 (单套设备) === // DarraEtherCAT PCIe运动控制卡 TwinCAT Acontis SOEM(开源) // 控制硬件 标准PC+千兆网卡 PC+PCIe板卡 Beckhoff IPC 标准PC+千兆网卡 标准PC+千兆网卡 // 硬件成本 网卡 $10-30 板卡 $200-500/块 IPC $3,000+ 网卡 $10-30 网卡 $10-30 // 软件授权 $1.99/设备 含在卡价中 含在硬件中 $5,000-50,000+ 免费(MIT) // 实时驱动 DarraRT(免费) 卡内FPGA TwinCAT RT 需自行开发 无(用户态) // 总成本(单套) ~$35 $200+ $3,000+ $5,000+ $0(无实时) // 实时抖动 <3μs <1μs(FPGA) <1μs 取决于实现 50-500μs // 编程语言 C#/Java/Python C/C++ ST/FBD C/C++ C // /C/C++/Rust // CiA 402 内置 有(一行Enable) 取决于厂商SDK 功能块 无 无 // GUI 配置工具 免费提供 厂商提供 TwinCAT XAE 无 无 // 部署方式 NuGet一键安装 PCIe安装+驱动 整套开发环境 源码编译 源码编译 // === 适用场景对比 === // 选 DarraEtherCAT: C#/.NET 开发者、快速原型、中小批量设备、成本敏感项目 // 选 PCIe 控制卡: 已有板卡生态、需要亚微秒级硬实时、大批量成熟产线 // 选 TwinCAT: 已有 Beckhoff 硬件生态、PLC 工程师团队 // 选 Acontis: 需要商业支持、已有 C/C++ 代码库、预算充足 开发效率对比 (实现相同功能的代码行数): DarraEtherCAT SOEM(C) TwinCAT PCIe控制卡SDK 初始化+OP 3行 80+行 配置PLC运行时 30+行(厂商API) CSP伺服控制(完整程序) ~50行 300+行 PLC+HMI配置 150+行 PDO结构体映射 3行(自动) 30+行 XML+变量链接 20+行 CiA402使能 2行 50+行 功能块配置 20+行(若支持) ======================================== [9] 文档与资源 ======================================== SDK 文档: C#: https://ethercat.darra.xyz/docs/sdk/csharp Java: https://ethercat.darra.xyz/docs/sdk/java Python: https://ethercat.darra.xyz/docs/sdk/python C: https://ethercat.darra.xyz/docs/sdk/ccpp C++: https://ethercat.darra.xyz/docs/sdk/cpp Rust: https://ethercat.darra.xyz/docs/sdk/rust 快速入门: https://ethercat.darra.xyz/docs/quick-start/from-sdk 配置工具入门: https://ethercat.darra.xyz/docs/quick-start/from-master-tools EtherCAT 入门: https://ethercat.darra.xyz/docs/ethercat/beginner-guide 应用案例: https://ethercat.darra.xyz/docs/examples/robot-arm-6axis 下载: https://ethercat.darra.xyz/docs/downloads 更新日志: https://ethercat.darra.xyz/changelog NuGet: https://www.nuget.org/packages/DarraEtherCAT 产品主页: https://ethercat.darra.xyz ======================================== [10] 电机控制故障排除 — 通用分层排查方法论 ======================================== // 遇到电机控制问题时,按以下 6 层逐层排查 // 每层确认通过后再进入下一层,避免在错误的层级浪费时间 // AI 生成控制代码时,应在代码中主动预防每层的常见陷阱 --- 第一层: 通信是否正常? --- 检查: master.State == EcState.OP slave.PDO.Ibytes > 0 连续读 StatusWord (0x6041) 观察是否有变化 (不全为零) 未通过: 问题在网络/配置层,不是电机控制问题 --- 第二层: CiA 402 状态机是否推进到 Operation Enabled? --- 检查: 读 StatusWord (0x6041) 用掩码解析: (sw & 0x4F) == 0x40 → Switch on disabled (需发 cw=0x06) (sw & 0x6F) == 0x21 → Ready to switch on (需发 cw=0x07) (sw & 0x6F) == 0x23 → Switched on (需发 cw=0x0F) (sw & 0x6F) == 0x27 → Operation enabled ✅ (sw & 0x4F) == 0x08 → Fault (需发 cw=0x80 复位,bit7 上升沿) 卡住不推进: Controlword 是否在每个 PDO 周期持续写入 (不是只写一次) Fault 时: 先读 0x603F (Error Code) + 0x1003 (Error History),对照设备手册查询 --- 第三层: 操作模式是否生效? --- 检查: 写 0x6060 后读 0x6061 确认返回值一致 不一致: 驱动器可能不支持该模式 (查 ESI 或手册中 Supported Modes) 部分驱动器要求在特定状态下切换模式 (如只允许在 Switched On 状态切换) --- 第四层: 驱动器内部是否有保护机制阻止运动? --- // ⚠️ 这是最容易被忽略的一层 // Operation Enabled 后仍不运动,通常是某种保护机制在起作用 (4a) 硬件限位保护: 核心认知: 不同操作模式对限位的响应完全不同 CSP 模式 → 多数驱动器忽略硬件限位 (主站负责限位保护) PP/PV/HM 模式 → 驱动器内部轨迹规划器检查限位,触发时 QuickStop 或拒绝运动 诊断: 读 0x60FD (Digital Inputs) bit0 = 负限位, bit1 = 正限位, bit2 = Home 开关 未接物理开关但限位 bit 为 1 → 默认常闭逻辑 (未接线 = 限位触发) 修复思路: 在设备手册中搜索关键词: limit, limit stop, sensor logic, input polarity 找到控制限位行为的私有对象后,通过 SDO 或 Startup 参数修改 // 注意: 限位相关对象地址是厂商私有的,没有标准地址,必须查手册 (4b) 软件限位保护: 0x607D (Software Position Limit): 子索引1=最小位置, 子索引2=最大位置 目标位置超出范围时驱动器拒绝运动 (4c) 厂商特定保护: 在设备手册中搜索: protection, inhibit, enable condition, interlock // 唯一可靠的方法是查设备手册,没有通用地址 --- 第五层: 运动参数是否正确? --- PP 模式检查: ProfileVelocity (0x6081) 必须 > 0 ProfileAcceleration (0x6083) 建议 > 0 (为 0 时部分驱动器拒绝运动) ProfileDeceleration (0x6084) 建议 > 0 首次使能后 TargetPosition (0x607A) 应先 = ActualPosition (0x6064) Position Window (0x6067) 默认 0 = 精确到达,机械偏差可能导致 TargetReached 永不置位 bit4 握手时序 (关键): 状态0: 空闲, cw=0x0F, TargetPosition=ActualPosition 状态1: 准备, cw=0x0F, 写入 TargetPosition=目标值, 等待数周期稳定 状态2: 触发, cw=0x1F (bit4=1), 等待 StatusWord bit12 (SetPointAck) 状态3: 清除, cw=0x0F (bit4=0), 等待 bit12 清除 状态4: 等待, cw=0x0F, 等待 StatusWord bit10 (TargetReached) CSP 模式检查: TargetPosition 每周期必须平滑递增/递减,不能突变 第一个周期 TargetPosition 必须 = ActualPosition PDO 结构体字段顺序必须与 PDO 映射顺序一致 (否则数据错位) 验证: 设 TargetPosition = ActualPosition (每周期跟随),电机应静止 --- 第六层: 同步方式是否匹配? --- CSP/CSV/CST → 必须 DC Sync0 (DarraRT WDK 实时驱动天然满足) PP/PV/PT/HM → Free Run 即可 (同样走 DarraRT WDK 路径, 不再有 Npcap 用户态路径) // PP 模式轨迹由驱动器内部生成,不依赖主站周期精度,不需要 DC // CSP 模式主站每周期发送精确位置,驱动器直接跟随,必须 DC 同步 Free Run 配置 (标准对象,非厂商特定): slave.CoE.SDOWrite(0x1C32, 1, BitConverter.GetBytes((ushort)0x0000)); // SM2 Free Run slave.CoE.SDOWrite(0x1C33, 1, BitConverter.GetBytes((ushort)0x0000)); // SM3 Free Run // === 排查流程总结 === // 电机不运动 // ├─ 主站不在 OP? → 网络/配置问题 // ├─ 从站不在 Op Enabled? → CiA 402 状态机 + Fault 复位 // ├─ 操作模式不生效? → 0x6061 读回值 + 驱动器支持的模式 // ├─ 有保护阻止? → 限位(0x60FD) + 软限位(0x607D) + 查手册找厂商私有对象 // │ ⚠️ CSP 正常但 PP 不动 → 大概率是限位保护 (PP 受限位约束, CSP 不受) // ├─ 运动参数错误? → PP: 速度/加速度非零 + bit4 时序; CSP: 目标位置连续 // └─ 同步不匹配? → PP/PV/HM 用 Free Run; CSP/CSV/CST 用 DC Sync0 // === AI 生成代码时的预防清单 === // ✅ CiA 402 使能: 每 PDO 周期持续写 Controlword,不是只写一次 // ✅ Fault 处理: 0x80 上升沿 (先发 0x80,下周期恢复正常使能序列) // ✅ 操作模式: 写 0x6060 后读 0x6061 验证 // ✅ PP/PV/HM: 使用 Free Run 同步,不配置 DC Sync0 // ✅ PP: ProfileVelocity/Acceleration/Deceleration 非零 // ✅ PP: bit4 上升沿握手 (0x0F→0x1F→等ACK→0x0F) // ✅ CSP: TargetPosition 每周期平滑递增,首周期=ActualPosition // ✅ 预写 TargetPosition = ActualPosition (避免首次运动跳变) // ✅ 限位保护: 提醒用户查手册中限位相关私有对象 (无通用地址) // ✅ Position Window (0x6067): 提醒用户设合理容差