跳到主要内容

CiA 402 — 伺服驱动器辅助

CiA 402 (IEC 61800-7-204) 是基于 CoE 的伺服驱动器设备协议。CiA402Instance 封装了驱动器状态机管理、操作模式切换和运动参数访问功能。

CiA 402 运行在 CoE (SDO) 之上。CiA402Instance 需要独立构造 (CiA402Instance::new(...)),不是从站对象上的链式访问方法。

两种使用方式: slave.cia402_* vs CiA402Instance​

SDK 提供两套 CiA 402 接口, 按场景选择:

slave.cia402_* — 轻量直调 (SDO-only)​

挂在 Slave 上的快捷方法, 不依赖 PDO 映射, 全程走 SDO. 适合单次操作 / 调试 / 非周期场景。

可用方法:

  • slave.cia402_state() → CiA402State — 读当前驱动器状态
  • slave.cia402_enable() → Result<()> — 一键使能 (SDO 推进状态机)
  • slave.cia402_set_mode(mode: i8) → Result<()> / slave.cia402_mode() → i8 — 操作模式读写 (0x6060 / 0x6061)
  • slave.cia402_status_word() → u16 — 读 0x6041
  • slave.cia402_write_control_word(cw: u16) → Result<()> — 写 0x6040
  • slave.cia402_fault_reset() → Result<()> — 复位 0x6040 Bit 7

示例:

let slave = master.slave(1);

// 调试: 上电检查驱动器是否处于 OperationEnabled
println!("当前状态: {:?}", slave.cia402_state());

// 一次性使能 + 读状态
slave.cia402_enable()?;
println!("使能后状态字: 0x{:04X}", slave.cia402_status_word());

CiA402Instance — 高性能完整接口 (PDO + SDO)​

需要先通过 Cia402PdoMap::scan() 扫描 PDO 映射, 然后构造完整实例。 0x1C12 / 0x1C13 中已映射的对象走 PDO 整帧 copy/write, 未映射的对象自动回退 SDO. 适合周期运动控制 / 高频读写。

典型场景:

  • PDO 周期内频繁读取 ActualPosition / ActualVelocity / StatusWord
  • 周期内写入 TargetPosition / ControlWord, 走 PDO 不阻塞
  • 需要 enable() / quick_stop() / fault_reset() 等高级状态机封装

选择对比​

  • 调试 / 离线诊断 / 一次性操作 → 用 slave.cia402_*, 不需要扫描 PDO 映射, 接口简单
  • 周期运动控制 / 实时数据流 → 用 CiA402Instance, 走 PDO 整帧 copy/write
  • 混合: 启动时用 slave.cia402_enable() 一键使能, 进入 OP 后切换为 CiA402Instance 做周期控制 (两者可在同一从站上共存)
两种状态枚举不通用

SDK 内有两个独立的 CiA 402 状态枚举, 取值含义相同但类型不同, 不能互相比较:

  • slave.cia402_state() 返回 darra_ethercat::CiA402State(#[repr(i32)], 变体 NotReady / FaultReaction / ...)
  • CiA402Instance::state_drive() 返回 darra_ethercat::slave::StateCiA402(#[repr(u8)], 变体 NotReadyToSwitchOn / FaultReactionActive / ...)

两者变体名不一致(NotReady vs NotReadyToSwitchOn、FaultReaction vs FaultReactionActive)。 比较时务必使用对应方法返回的同一枚举, 例如 slave.cia402_state() == CiA402State::OperationEnabled、 drv.state_drive() == StateCiA402::OperationEnabled, 不要把两者混用。

构造方式​

CiA 402 实例需要先扫描 PDO 映射表,然后独立构造:

use darra_ethercat::{Cia402PdoMap, CiA402Instance};

// 1. 扫描 PDO 映射 (读取 0x1C12/0x1C13)
let pdo_map = Cia402PdoMap::scan(master.index(), 1)?;

// 2. 创建 CiA 402 实例
let drv = CiA402Instance::new(master.index(), 1, pdo_map);

PDO 映射扫描​

Cia402PdoMap::scan()​

pub fn scan(master_index: u16, slave_index: u16) -> Result<Self>

扫描从站 PDO 映射,读取 0x1C12/0x1C13 系列对象的映射参数,建立完整映射缓存。

映射建立后,CiA402Instance 的读写会优先通过 PDO 整帧 copy/write,不在映射中的对象自动回退到 SDO。

示例:

let pdo_map = Cia402PdoMap::scan(master.index(), 1)?;

// 查看映射信息
for entry in pdo_map.output_entries() {
println!("RxPDO: 0x{:04X}:{:02X} {}bit @offset {}",
entry.od_index, entry.sub_index, entry.bit_length, entry.byte_offset);
}
for entry in pdo_map.input_entries() {
println!("TxPDO: 0x{:04X}:{:02X} {}bit @offset {}",
entry.od_index, entry.sub_index, entry.bit_length, entry.byte_offset);
}

状态控制​

enable() 一次性推进到 OperationEnabled (内部完成完整状态链 + Fault 复位 + QuickStop 恢复 + 0x605A 选项码判断); disable / disable_operation / quick_stop / fault_reset 仅写一次 Controlword 后立即返回, 通过 state_drive() 检查结果。

enable(max_retries) / enable_default()​

pub fn enable(&self, max_retries: i32) -> bool
pub fn enable_default(&self) -> bool // 等价于 enable(10)

使能驱动器: 内部按 CiA 402-2 完成 SwitchOnDisabled → ReadyToSwitchOn → SwitchedOn → OperationEnabled 全套时序、Fault 复位、QuickStop 恢复。

参数:

  • max_retries — 最大重试次数

返回值:

  • bool — true = 已使能到 OperationEnabled, false = 失败/超时

示例:

// 一次性使能 (内部完成完整状态机)
if drv.enable_default() {
drv.set_target_position(next_position);
} else {
println!("使能失败, 当前状态: {:?}", drv.state_drive());
}

disable()​

pub fn disable(&self)

禁用伺服 (-> SwitchOnDisabled),完全断电。

disable_operation()​

pub fn disable_operation(&self)

禁用运行 (OperationEnabled -> SwitchedOn)。

quick_stop()​

pub fn quick_stop(&self)

快速停止。

fault_reset()​

pub fn fault_reset(&self)

清除故障。

状态读取​

state_drive()​

pub fn state_drive(&self) -> StateCiA402

从 StatusWord 解析当前驱动器状态。

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StateCiA402 {
NotReadyToSwitchOn = 0, // 初始化中
SwitchOnDisabled = 1, // 驱动禁用
ReadyToSwitchOn = 2, // 准备就绪
SwitchedOn = 3, // 已开启
OperationEnabled = 4, // 运行使能
QuickStopActive = 5, // 快速停止
FaultReactionActive = 6, // 故障反应中
Fault = 7, // 故障
Unknown = 99, // 未知状态
}

statusword() / controlword()​

pub fn statusword(&self) -> u16
pub fn controlword(&self) -> u16
pub fn set_controlword(&self, value: u16)

相关方法:

  • target_reached() -> bool — 目标已到达 (Bit 10)
  • has_fault() -> bool — 存在故障 (Bit 3)
  • has_warning() -> bool — 存在警告 (Bit 7)
  • is_remote() -> bool — 远程模式 (Bit 9)

操作模式​

operation_mode() / set_operation_mode()​

pub fn operation_mode(&self) -> i8
pub fn set_operation_mode(&self, mode: ModeCiA402)
#[repr(i8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ModeCiA402 {
PP = 1, // 轮廓位置模式
VL = 2, // 速度模式
PV = 3, // 轮廓速度模式
PT = 4, // 轮廓转矩模式
HM = 6, // 回零模式
IP = 7, // 插补位置模式
CSP = 8, // 周期同步位置模式
CSV = 9, // 周期同步速度模式
CST = 10, // 周期同步转矩模式
CSTCA = 11, // 周期同步转矩加速度模式
}

is_mode_supported()​

pub fn is_mode_supported(&self, mode: ModeCiA402) -> bool

检查驱动器是否支持指定操作模式(通过 0x6502 SupportedDriveModes 判断)。

运动参数​

类别方法类型读写说明
位置position_actual()i32只读实际位置 (0x6064)
速度velocity_actual()i32只读实际速度 (0x606C)
转矩torque_actual()i16只读实际转矩 (0x6077)
位置target_position() / set_target_position()i32读写目标位置 (0x607A)
速度target_velocity() / set_target_velocity()i32读写目标速度 (0x60FF)
转矩target_torque() / set_target_torque()i16读写目标转矩 (0x6071)

轮廓参数​

类别方法类型读写说明
轮廓profile_velocity() / set_profile_velocity()u32读写轮廓速度 (0x6081)
profile_acceleration() / set_profile_acceleration()u32读写轮廓加速度 (0x6083)
profile_deceleration() / set_profile_deceleration()u32读写轮廓减速度 (0x6084)
停止quick_stop_deceleration() / set_quick_stop_deceleration()u32读写快速停止减速度 (0x6085)

极性与轮廓配置​

类别方法类型读写说明
配置polarity() / set_polarity()u8读写极性 (0x607E)
配置motion_profile_type() / set_motion_profile_type()i16读写运动轮廓类型 (0x6086)
选项码quick_stop_option_code() / set_quick_stop_option_code()i16读写快速停止选项 (0x605A, OD/SDO 路径)。读失败折叠为 0,无法与真值 0 区分;同对象的 quick_stop_option_native() 走读失败哨兵口径,见下方「选项码 (0x605A–0x605E)」一节

选项码 (0x605A–0x605E)​

五类驱动器选项码,决定各状态转换时的减速/停止行为,经 native 直读/直写。每个均为 i16 读写。

类别方法类型读写说明
选项码quick_stop_option_native() / set_quick_stop_option_native()i16读写快速停止选项码 (0x605A)。0=直接切断, 1=斜坡减速, 2=Quick Stop 减速, 3=转矩停止; 5/6/7/8=减速后保持 QuickStopActive (允许 T16 直接 → OperationEnabled)
shutdown_option() / set_shutdown_option()i16读写Shutdown 选项码 (0x605B): OperationEnabled → ReadyToSwitchOn 时的减速行为
disable_operation_option() / set_disable_operation_option()i16读写Disable Operation 选项码 (0x605C): OperationEnabled → SwitchedOn 时的行为
halt_option() / set_halt_option()i16读写Halt 选项码 (0x605D): CW Bit8 Halt 行为 (1=轮廓斜坡, 2=QS 减速, 3=转矩停止)
fault_reaction_option() / set_fault_reaction_option()i16读写Fault Reaction 选项码 (0x605E): 故障检测后行为 (-1=厂商, 0=直接切断, 1/2/3=减速)

返回值与读失败哨兵:正常 = 真值;读失败返回哨兵值。哨兵值不是合法取值(本节合法选项码为小值含 0),请勿当作真实数值使用。Rust 无重载,读失败哨兵按返回形分三档,判别函数也按返回形拆成三个同名后缀函数:

  • READ_FAIL_SENTINEL_I16 (i16) — 值 -32768 (INT16_MIN)。有符号 16 位选项码 (0x605A–0x605E) 读失败
  • READ_FAIL_SENTINEL_U16 (u16) — 值 0xFFFF。无符号 16 位 drive_error_code (0x603F) 读失败
  • READ_FAIL_SENTINEL_INT (i32) — 值 -1。返回 int 的计数形读取接口(error_history / supported_homing_methods_native 等)底层读失败整体返回 -1(fail-closed)

判别函数(按返回形取对应的一个):

  • is_read_fail_sentinel_i16(v) (bool) — 判别 i16 读失败哨兵
  • is_read_fail_sentinel_u16(v) (bool) — 判别 u16 读失败哨兵
  • is_read_fail_sentinel_int(v) (bool) — 判别 int 读失败哨兵
i8 方法编号(0x60E3 列表项,-128..-1 为厂商自定义方法)是真实取值,不属哨兵,请勿用 is_read_fail_sentinel_int 判别。
quick_stop_option_native() (0x605A) 与本文「极性与轮廓配置」中的 quick_stop_option_code() (0x605A) 指向同一对象。读失败哨兵口径适用于本表五个方法的读取侧。

示例:

// 快速停止后保持在 QuickStopActive (5), 便于直接恢复运行
drv.set_quick_stop_option_native(5);

// 故障反应使用斜坡减速 (2) 而非直接切断
drv.set_fault_reaction_option(2);

// 读选项码: 读失败 = -32768 哨兵 (非合法取值), 按失败处理
let qs = drv.quick_stop_option_native();
if is_read_fail_sentinel_i16(qs) {
println!("QuickStopOption 读取失败, 按失败处理");
}

错误代码与错误历史​

类别方法类型读写说明
错误drive_error_code()u16只读当前 Error Code (0x603F, CiA 402 附录)。正常 = 真值;读失败 = 0xFFFF 哨兵 (READ_FAIL_SENTINEL_U16)。0xFFFF 不是合法取值 (0x0000 表无错误), 请勿当作真实数值使用, 判别用 is_read_fail_sentinel_u16(v)
错误历史error_history()Vec<u32>只读读取 Pre-defined Error Field (0x1003), 返回驱动器内部持久错误历史 (Error Code 低 16 位)。底层读失败整体返回 -1 (READ_FAIL_SENTINEL_INT 哨兵, fail-closed), 封装层映射为空 Vec, 调用方应按失败处理 (空 Vec 不代表确认无历史)
clear_error_history()bool读写清除驱动器内部错误历史 (0x1003:00 = 0)

示例:

// 当前错误码 (读失败 = 0xFFFF 哨兵, 不是真实错误码)
let ec = drv.drive_error_code();
if is_read_fail_sentinel_u16(ec) {
println!("Error Code 读取失败, 按失败处理");
}

// 错误历史 (底层读失败整体返回 -1, 封装层映射为空 Vec, 按失败处理)
let history = drv.error_history();

触发探针 (Touch Probe)​

类别方法类型读写说明
探针configure_touch_probe(function: u16)-只写配置探针功能 (0x60B8)
touch_probe_status()u16只读探针状态 (0x60B9)
touch_probe_positive_edge()i32只读正边沿捕获位置 (0x60BA)
touch_probe_negative_edge()i32只读负边沿捕获位置 (0x60BB)

数字 IO​

类别方法类型读写说明
输入digital_inputs()u32只读数字输入 (0x60FD),32 位位图
输出digital_outputs() / set_digital_outputs()u32读写数字输出 (0x60FE:01),32 位位图

示例:

// 读取数字输入
let inputs = drv.digital_inputs();
let limit_switch = (inputs & 0x01) != 0; // 位 0

// 设置数字输出
drv.set_digital_outputs(0x03); // 输出位 0 和位 1

软件位置限制​

类别方法类型读写说明
限位software_position_limit_min() / set_software_position_limit_min()i32读写软件位置限位下限 (0x607D:01)
software_position_limit_max() / set_software_position_limit_max()i32读写软件位置限位上限 (0x607D:02)

示例:

// 设置运动范围限制
drv.set_software_position_limit_min(-1_000_000);
drv.set_software_position_limit_max(1_000_000);

扩展运动参数​

类别方法类型读写说明
转矩max_torque() / set_max_torque()u16读写最大转矩 (0x6072),千分之额定
motor_rated_torque() / set_motor_rated_torque()u32读写电机额定转矩 (0x6076),mNm
偏移position_offset() / set_position_offset()i32读写位置偏移 (0x60B0),CSP 模式叠加
velocity_offset() / set_velocity_offset()i32读写速度偏移 (0x60B1),CSV 模式叠加
torque_offset() / set_torque_offset()i16读写转矩偏移 (0x60B2)
插补interpolation_time_period_value() / set_interpolation_time_period_value()u8读写插补时间周期值 (0x60C2:01)
interpolation_time_period_index() / set_interpolation_time_period_index()i8读写插补时间周期指数 (0x60C2:02),周期 = Value × 10^Index 秒

力矩限制​

类别方法类型读写说明
转矩positive_torque_limit() / set_positive_torque_limit()u16读写正方向力矩限制 (0x60E0),千分之额定
negative_torque_limit() / set_negative_torque_limit()u16读写负方向力矩限制 (0x60E1),千分之额定

回零速度与加速度​

类别方法类型读写说明
回零homing_speed_search() / set_homing_speed_search()u32读写回零搜索速度 (0x6099:01),快速搜索参考信号
homing_speed_zero() / set_homing_speed_zero()u32读写回零零位速度 (0x6099:02),慢速精确定位零位
homing_acceleration() / set_homing_acceleration()u32读写回零加速度 (0x609A)

示例:

drv.set_operation_mode(ModeCiA402::HM);
drv.set_homing_method(1);

// 设置回零速度和加速度
drv.set_homing_speed_search(5000); // 搜索速度
drv.set_homing_speed_zero(500); // 零位速度
drv.set_homing_acceleration(10000); // 回零加速度

快速运动控制​

new_setpoint()​

pub fn new_setpoint(&self, position: i32, relative: bool)

PP 模式发送新定位命令。设置目标位置并触发 Controlword Bit 4 (New Setpoint)。

参数:

  • position -- 目标位置
  • relative -- true = 相对定位,false = 绝对定位

示例:

drv.set_operation_mode(ModeCiA402::PP);
drv.set_profile_velocity(10000);
drv.set_profile_acceleration(50000);

// 在 PDO 回调中: 先使能,使能后发送定位命令
if drv.state_drive() == StateCiA402::OperationEnabled {
drv.new_setpoint(100000, false); // 绝对定位到 100000
// drv.new_setpoint(5000, true); // 或相对移动 5000
}

clear_new_setpoint()​

pub fn clear_new_setpoint(&self)

PP 模式清除 NewSetpoint 标志(Controlword Bit4=0)。在 target_reached() 后调用,完成 SetPointAck 握手。

示例:

if drv.target_reached() {
drv.clear_new_setpoint();
}

start_homing()​

pub fn start_homing(&self)

HM 模式启动回零。需先设置 set_homing_method()。

相关方法:

  • homing_method() / set_homing_method() (i8) -- 回零方法 (0x6098)
  • home_offset() / set_home_offset() (i32) -- 回零偏移 (0x607C)
  • homing_attained() (bool) -- 回零完成 (Bit 12)
  • homing_error() (bool) -- 回零错误 (Bit 13)

示例:

drv.set_operation_mode(ModeCiA402::HM);
drv.set_homing_method(35); // 当前位置回零

// 在 PDO 回调中:
if drv.state_drive() == StateCiA402::OperationEnabled {
drv.start_homing();
// 后续周期检查 drv.homing_attained() / drv.homing_error()
}

驱动器信息​

supported_drive_modes()​

pub fn supported_drive_modes(&self) -> u32

支持的驱动模式位掩码 (0x6502)。Bit 0=PP, Bit 1=VL, Bit 2=PV, Bit 3=PT, Bit 5=HM, Bit 6=IP, Bit 7=CSP, Bit 8=CSV, Bit 9=CST。

supported_homing_methods()​

pub fn supported_homing_methods(&self) -> Vec<i8>

读取从站报告的支持回零方法编号列表 (0x60E3)。

参数:

  • 无

返回值:

  • Vec<i8> — 回零方法编号列表(0x60E3 列表项)。空 Vec 同时对应下列三种情形,不可只按一种解读

三种情形各返什么:

  • 失败(SDO 超时 / 通讯异常 / 其它 abort)— 返空 Vec
  • 空集(SI0=0 且读成功,从站真返回 0 条)— 返空 Vec
  • 不支持(从站无 0x60E3 或 0x60E3:00,SDO abort 0x06020000 对象不存在 / 0x06090011 子索引不存在)— 返空 Vec
空 Vec 不可读成「支持 0 种回零方法」

本封装把上述三种情形折叠成同一个形状(空 Vec),因此空 Vec 既可能是真失败,也可能是从站真返回 0 条,还可能是从站根本不支持 0x60E3。底层 CiA402_GetSupportedHomingMethods(supported_homing_methods_native() 所走的那条 FFI)是区分的:读失败整体返回 -1,真返回 0 条返回 0(fail-closed,那里可分)。 现在已有专用入口 try_supported_homing_methods(),try_read_* 便捷方法仍不覆盖 0x60E3。需要区分三态请用该专用入口;本文「可观测只读」一节的 try_read_object() 仍是通用途径(单独读条目数 0x60E3:00,其 status 如实区分读成功 / 不支持 / 读取失败,成功时值为 0 即真返回 0 条;再按条目数逐条读 0x60E3:01..n 取方法编号,这是一条独立的读取路径)。

示例:

let methods = drv.supported_homing_methods();
// 空 Vec = 失败 / 空集 / 不支持, 不能当成「支持 0 种回零方法」
if methods.is_empty() {
println!("未能确认支持的回零方法 (失败 / 空集 / 不支持)");
} else {
println!("支持的回零方法: {:?}", methods);
}

try_supported_homing_methods()​

pub fn try_supported_homing_methods(&self) -> Cia402ReadResult<Vec<i8>>

读取从站报告的支持回零方法编号列表 (0x60E3),真值 / 读失败 / 不支持三态可分。与 try_read_error_code() 同载体 Cia402ReadResult<T>。

参数:

  • 无

返回值:

  • Cia402ReadResult<Vec<i8>> — 带状态的回零方法编号列表,status / value / abort_code 三字段配合判读

三种情形各返什么:

  • 真值(status == Success)— 拿到完整列表 value;空 Vec = 从站真返回 0 条回零方法(真不支持任何回零方法),这是真值不是失败
  • 读失败(status == ReadFailed,SDO 超时 / 通讯异常 / 其它 abort)— value 无意义(空 Vec)
  • 不支持(status == NotSupported,0x60E3 对象/子索引不存在,SDO abort 0x06020000 / 0x06090011 / 0x06090012)— value 无意义(空 Vec)
备注

子项读失败绝不许造条目:只要有一个子项没读到,整体如实报该状态(取首个失败子项的状态与 abort code),value 不作真值用,不许把失败当 0 号方法推进列表。abort_code 照常携带 SDO Abort Code(成功为 0)。方法编号是 i8,-128..-1 是厂商自定义方法,是真实取值不是哨兵,别拿读失败哨兵判别去过滤。

备注

旧入口 supported_homing_methods() / supported_homing_methods_native() 把「失败 / 真空集 / 不支持」折叠成同一个形状(空 Vec),失败也会得到空 Vec,要可分辨请用 try_supported_homing_methods();旧入口对读不到的子项是「跳过、不造条目」。

示例:

let r = drv.try_supported_homing_methods();
match r.status {
Cia402ReadStatus::Success if r.value.is_empty() =>
println!("从站确认不支持任何回零方法"),
Cia402ReadStatus::Success =>
println!("支持的回零方法: {:?}", r.value),
Cia402ReadStatus::NotSupported =>
println!("从站不支持 0x60E3"),
_ => println!("读取失败: abort=0x{:08X}", r.abort_code),
}

supported_homing_methods_native()​

pub fn supported_homing_methods_native(&self) -> Vec<i8>

读取从站报告的支持回零方法编号列表 (0x60E3, native 直读)。

参数:

  • 无

返回值:

  • Vec<i8> — 回零方法编号列表(0x60E3 列表项)。空 Vec 同时对应下列三种情形,不可只按一种解读

三种情形各返什么:

  • 失败(SDO 超时 / 通讯异常 / 其它 abort)— 返空 Vec
  • 空集(SI0=0 且读成功,从站真返回 0 条)— 返空 Vec
  • 不支持(从站无 0x60E3 或 0x60E3:00,SDO abort 0x06020000 对象不存在 / 0x06090011 子索引不存在)— 返空 Vec,与失败同档
空 Vec 不代表确认不支持任何回零方法

本封装把上述三种情形折叠成同一个形状(空 Vec),三种同档。底层 CiA402_GetSupportedHomingMethods 读失败整体返回 -1,真返回 0 条返回 0(fail-closed,那里可分);区分口径见上方 supported_homing_methods() 的说明。要可分辨请用 try_supported_homing_methods()。

示例:

let methods = drv.supported_homing_methods_native();
// 空 Vec = 失败 / 空集 / 不支持, 不能当成「支持 0 种回零方法」
if methods.is_empty() {
println!("未能确认支持的回零方法 (失败 / 空集 / 不支持)");
} else {
println!("支持的回零方法: {:?}", methods);
}

可观测只读 (区分真值 / 不支持 / 失败)​

普通 getter (如 statusword() / operation_mode()) 在 SDO 读失败时会回退到默认值 0,调用方无法分辨"从站真返 0"还是"读失败被吞成 0"。例外:选项码 getter (quick_stop_option_native() / shutdown_option() / disable_operation_option() / halt_option() / fault_reaction_option()) 与 drive_error_code() 读失败返回哨兵 -32768 / 0xFFFF(非合法取值),不再吞成 0,见本文「选项码 (0x605A–0x605E)」与「错误代码与错误历史」两节。try_read_* 系列做一次真正的 SDO 只读尝试,并据 SDO Abort Code 如实区分三态:读成功(真值)/ 从站不支持 / 读取失败。严格只读,无任何写对象字典 / 写 PDO / 改状态机的副作用。

何时用
  • 调试 / 设备能力探测:判断从站是否真支持某个可选对象(如 0x6502 / 0x60FD)。
  • 高频实时读仍用普通 getter(statusword() / position_actual() 等,PDO 优先零开销);try_read_* 强制走 SDO,不适合周期调用。

Cia402ReadStatus​

读取状态枚举,区分"读成功的真值"与"读失败 / 从站不支持"。

#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Cia402ReadStatus {
NotAttempted = 0, // 尚未尝试读取
Success = 1, // 读取成功, 返回的是从站真值
NotSupported = 2, // 从站不支持该对象 (SDO abort 0x06020000 / 0x06090011)
ReadFailed = 3, // SDO 读取失败 (超时 / 通讯异常 / 其它 abort)
}

相关方法:

  • classify_abort(abort_code: u32) (Cia402ReadStatus) — 把 SDO Abort Code 归类为 NotSupported / ReadFailed
  • description() (&'static str) — 状态中文描述(实现了 Display)

Cia402ReadResult<T>​

带状态的读取结果。调用方据 status 区分真值 / 不支持 / 失败,value 仅在 status == Success 时可信。

#[derive(Debug, Clone, Copy)]
pub struct Cia402ReadResult<T> {
pub value: T, // 读到的值 (仅 Success 时有意义)
pub status: Cia402ReadStatus, // 读取状态
pub abort_code: u32, // SDO Abort Code (0 = 无 abort)
}

相关方法:

  • ok() (bool) — 是否读取成功且值可信(status == Success)
  • not_supported() (bool) — 从站是否不支持该对象(status == NotSupported)

try_read_object<T>()​

pub fn try_read_object<T: Cia402Readable>(&self, index: u16, subindex: u8) -> Cia402ReadResult<T>

对任意 CiA 402 对象做一次可观测 SDO 只读尝试。T 需实现 Cia402Readable(已为 u8/i8/u16/i16/u32/i32/u64/i64 提供)。字节不足时按可用宽度零扩展。

示例:

let r = drv.try_read_object::<u32>(0x6502, 0);
match r.status {
Cia402ReadStatus::Success => println!("支持模式位掩码: 0x{:08X}", r.value),
Cia402ReadStatus::NotSupported => println!("从站不支持 0x6502"),
_ => println!("读取失败: abort=0x{:08X}", r.abort_code),
}

便捷只读方法​

针对常用只读对象的封装,均返回 Cia402ReadResult<T>,纯只读:

  • try_read_statusword() (Cia402ReadResult<u16>) — 状态字 (0x6041)。实时高频读请用 statusword()
  • try_read_error_code() (Cia402ReadResult<u16>) — 错误代码 (0x603F),三态区分真值/不支持/失败。drive_error_code() 走 0xFFFF 读失败哨兵口径,见「错误代码与错误历史」一节
  • try_read_supported_drive_modes() (Cia402ReadResult<u32>) — 支持的驱动模式位掩码 (0x6502)
  • try_read_digital_inputs() (Cia402ReadResult<u32>) — 数字输入 (0x60FD)
  • try_read_operation_mode_display() (Cia402ReadResult<i8>) — 操作模式显示 (0x6061)
  • try_read_drive_data(subindex: u8) (Cia402ReadResult<u32>) — 厂商特定驱动数据 (0x6510, RECORD)
  • try_read_position_actual() (Cia402ReadResult<i32>) — 实际位置 (0x6064)
  • try_read_torque_actual() (Cia402ReadResult<i16>) — 实际转矩 (0x6077),千分之额定

supported_drive_modes_readable()​

pub fn supported_drive_modes_readable(&self) -> bool

从站是否真支持 0x6502 (Supported Drive Modes) 对象。true = 读成功;false = 不支持或读失败(用 try_read_supported_drive_modes().status 进一步区分原因)。

示例:

if drv.supported_drive_modes_readable() {
let modes = drv.try_read_supported_drive_modes().value;
println!("支持的驱动模式: 0x{:08X}", modes);
} else {
println!("从站不支持 0x6502 或读取失败");
}

TxPDO 数据有效性​

txpdo_data_invalid()​

pub fn txpdo_data_invalid(&self) -> bool

TxPDO 数据是否无效 (0x603E)。非零表示驱动器 TxPDO 数据不可信(如编码器未就绪时位置值无意义)。

if !drv.txpdo_data_invalid() {
let pos = drv.position_actual(); // 数据有效
}

同步功能​

类别方法类型读写说明
同步synchronization_settings() / set_synchronization_settings()u16读写同步设置 (0x60D9:01)
drive_sync_status()u16只读驱动同步状态 (0x60DA)

完整示例​

CSP 模式 — 周期同步位置控制​

use darra_ethercat::{Cia402PdoMap, CiA402Instance, ModeCiA402, StateCiA402};

let pdo_map = Cia402PdoMap::scan(master.index(), 1)?;
let drv = CiA402Instance::new(master.index(), 1, pdo_map);

// 设置操作模式
drv.set_operation_mode(ModeCiA402::CSP);

// 一次性使能 (内部完成完整状态机)
if !drv.enable_default() {
println!("使能失败: {:?}", drv.state_drive());
return Ok(());
}

// PDO 回调中每周期下发目标
let events = master.events();
events.on_pdo_cyclic_sync(move |_master_idx| {
drv.set_target_position(calculate_next_position());
});

PP 模式 — 轮廓位置控制​

use darra_ethercat::{Cia402PdoMap, CiA402Instance, ModeCiA402};
use std::sync::atomic::{AtomicBool, Ordering};

let pdo_map = Cia402PdoMap::scan(master.index(), 1)?;
let drv = CiA402Instance::new(master.index(), 1, pdo_map);

drv.set_operation_mode(ModeCiA402::PP);
drv.set_profile_velocity(10000);
drv.set_profile_acceleration(50000);
drv.set_profile_deceleration(50000);

// 一次性使能
if !drv.enable_default() {
println!("使能失败: {:?}", drv.state_drive());
return Ok(());
}

// 发送定位命令
drv.new_setpoint(100000, false); // 绝对定位

// PDO 回调等待目标到达后清标志
let homing_done = AtomicBool::new(false);
let events = master.events();
events.on_pdo_cyclic_sync(move |_| {
if !homing_done.load(Ordering::Relaxed) && drv.target_reached() {
drv.clear_new_setpoint();
homing_done.store(true, Ordering::Relaxed);
}
});

HM 模式 — 回零​

use darra_ethercat::{Cia402PdoMap, CiA402Instance, ModeCiA402};

let pdo_map = Cia402PdoMap::scan(master.index(), 1)?;
let drv = CiA402Instance::new(master.index(), 1, pdo_map);

drv.set_operation_mode(ModeCiA402::HM);
drv.set_homing_method(35); // 当前位置回零
drv.set_homing_speed_search(5000);
drv.set_homing_speed_zero(500);
drv.set_homing_acceleration(10000);

// 一次性使能
if !drv.enable_default() {
println!("使能失败: {:?}", drv.state_drive());
return Ok(());
}

// 启动回零
drv.start_homing();

let events = master.events();
events.on_pdo_cyclic_sync(move |_| {
if drv.homing_attained() {
println!("回零完成");
}
if drv.homing_error() {
println!("回零错误");
}
});

参数验证​

let drv = CiA402Instance::new(master.index(), 1, pdo_map);

// 检查轮廓参数是否满足 PP/PV 模式需求
let warnings = drv.validate_profile_parameters(Some(1)); // PP 模式
for w in &warnings {
println!("警告: {}", w);
}

标准对象索引常量​

可搭配 slave.sdo_read/sdo_write 使用:

常量值说明
OD_CONTROLWORD0x6040控制字
OD_STATUSWORD0x6041状态字
OD_MODES_OF_OPERATION0x6060操作模式设置
OD_MODES_OF_OPERATION_DISPLAY0x6061操作模式显示
OD_TARGET_POSITION0x607A目标位置
OD_POSITION_ACTUAL0x6064实际位置
OD_TARGET_VELOCITY0x60FF目标速度
OD_VELOCITY_ACTUAL0x606C实际速度
OD_TARGET_TORQUE0x6071目标转矩
OD_TORQUE_ACTUAL0x6077实际转矩
OD_PROFILE_VELOCITY0x6081轮廓速度
OD_PROFILE_ACCELERATION0x6083轮廓加速度
OD_PROFILE_DECELERATION0x6084轮廓减速度
OD_MAX_TORQUE0x6072最大转矩
OD_MOTOR_RATED_TORQUE0x6076电机额定转矩
OD_HOME_OFFSET0x607C回零偏移
OD_SOFTWARE_POSITION_LIMIT0x607D软件位置限制
OD_POLARITY0x607E极性
OD_MAX_PROFILE_VELOCITY0x6080最大轮廓速度
OD_MOTION_PROFILE_TYPE0x6086运动轮廓类型
OD_HOMING_METHOD0x6098回零方法
OD_HOMING_SPEEDS0x6099回零速度
OD_HOMING_ACCELERATION0x609A回零加速度
OD_POSITION_OFFSET0x60B0位置偏移 (CSP)
OD_VELOCITY_OFFSET0x60B1速度偏移 (CSV)
OD_TORQUE_OFFSET0x60B2转矩偏移
OD_TOUCH_PROBE_FUNCTION0x60B8Touch Probe 功能控制
OD_TOUCH_PROBE_STATUS0x60B9Touch Probe 状态
OD_TOUCH_PROBE_POS_EDGE0x60BATouch Probe 正边沿位置
OD_TOUCH_PROBE_NEG_EDGE0x60BBTouch Probe 负边沿位置
OD_INTERPOLATION_TIME_PERIOD0x60C2插补时间周期
OD_DIGITAL_INPUTS0x60FD数字输入
OD_DIGITAL_OUTPUTS0x60FE数字输出
OD_QUICK_STOP_OPTION_CODE0x605A快速停止选项码
OD_QUICK_STOP_DECELERATION0x6085快速停止减速度
OD_SUPPORTED_DRIVE_MODES0x6502支持的驱动模式位掩码
OD_ERROR_CODE0x603F错误码
OD_DRIVE_DATA0x6510厂商特定驱动数据 (RECORD, 只读)

控制字命令常量​

常量值说明
CW_SHUTDOWN0x06关机命令
CW_SWITCH_ON0x07开启命令
CW_ENABLE_OPERATION0x0F使能运行
CW_DISABLE_VOLTAGE0x00禁用电压
CW_QUICK_STOP0x02快速停止
CW_FAULT_RESET0x80故障复位
CW_HALT0x0100暂停位 (Bit 8, 暂停运动但不禁用)

状态字位掩码常量​

常量值说明
SW_READY_TO_SWITCH_ON0x0001 (Bit 0)准备就绪
SW_SWITCHED_ON0x0002 (Bit 1)已开启
SW_OPERATION_ENABLED0x0004 (Bit 2)运行使能
SW_FAULT0x0008 (Bit 3)故障
SW_VOLTAGE_ENABLED0x0010 (Bit 4)电压已使能
SW_QUICK_STOP0x0020 (Bit 5)快速停止
SW_SWITCH_ON_DISABLED0x0040 (Bit 6)开启已禁用
SW_WARNING0x0080 (Bit 7)警告
SW_REMOTE0x0200 (Bit 9)远程模式
SW_TARGET_REACHED0x0400 (Bit 10)目标已到达
SW_INTERNAL_LIMIT0x0800 (Bit 11)内部限位激活
SW_OP_MODE_SPECIFIC_10x1000 (Bit 12)模式相关位 1
SW_OP_MODE_SPECIFIC_20x2000 (Bit 13)模式相关位 2