piper_sdk/protocol/
feedback.rs

1//! 反馈帧结构体定义
2//!
3//! 包含所有机械臂反馈帧的结构体,提供从 `PiperFrame` 解析的方法
4//! 和物理量转换方法。
5
6use crate::can::PiperFrame;
7use crate::protocol::control::{ControlModeCommand, InstallPosition, MitMode};
8use crate::protocol::{
9    ProtocolError, bytes_to_i16_be, bytes_to_i32_be,
10    ids::{
11        ID_CONTROL_MODE, ID_END_POSE_1, ID_END_POSE_2, ID_END_POSE_3, ID_FIRMWARE_READ,
12        ID_GRIPPER_CONTROL, ID_GRIPPER_FEEDBACK, ID_JOINT_CONTROL_12, ID_JOINT_CONTROL_34,
13        ID_JOINT_CONTROL_56, ID_JOINT_DRIVER_HIGH_SPEED_BASE, ID_JOINT_DRIVER_LOW_SPEED_BASE,
14        ID_JOINT_END_VELOCITY_ACCEL_BASE, ID_JOINT_FEEDBACK_12, ID_JOINT_FEEDBACK_34,
15        ID_JOINT_FEEDBACK_56, ID_ROBOT_STATUS,
16    },
17};
18use bilge::prelude::*;
19
20// ============================================================================
21// 枚举类型定义
22// ============================================================================
23
24/// 控制模式(反馈帧版本,0x2A1)
25///
26/// 注意:反馈帧和控制指令的 ControlMode 枚举值不同。
27/// 反馈帧包含完整定义(0x00-0x07),控制指令只支持部分值。
28#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
29pub enum ControlMode {
30    /// 待机模式
31    #[default]
32    Standby = 0x00,
33    /// CAN指令控制模式
34    CanControl = 0x01,
35    /// 示教模式
36    Teach = 0x02,
37    /// 以太网控制模式
38    Ethernet = 0x03,
39    /// wifi控制模式
40    Wifi = 0x04,
41    /// 遥控器控制模式(仅反馈帧有,控制指令不支持)
42    Remote = 0x05,
43    /// 联动示教输入模式(仅反馈帧有,控制指令不支持)
44    LinkTeach = 0x06,
45    /// 离线轨迹模式
46    OfflineTrajectory = 0x07,
47}
48
49impl From<u8> for ControlMode {
50    fn from(value: u8) -> Self {
51        match value {
52            0x00 => ControlMode::Standby,
53            0x01 => ControlMode::CanControl,
54            0x02 => ControlMode::Teach,
55            0x03 => ControlMode::Ethernet,
56            0x04 => ControlMode::Wifi,
57            0x05 => ControlMode::Remote,
58            0x06 => ControlMode::LinkTeach,
59            0x07 => ControlMode::OfflineTrajectory,
60            _ => ControlMode::Standby, // 默认值,或使用 TryFrom 处理错误
61        }
62    }
63}
64
65/// 机械臂状态
66#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
67pub enum RobotStatus {
68    /// 正常
69    #[default]
70    Normal = 0x00,
71    /// 急停
72    EmergencyStop = 0x01,
73    /// 无解
74    NoSolution = 0x02,
75    /// 奇异点
76    Singularity = 0x03,
77    /// 目标角度超过限
78    AngleLimitExceeded = 0x04,
79    /// 关节通信异常
80    JointCommError = 0x05,
81    /// 关节抱闸未打开
82    JointBrakeNotOpen = 0x06,
83    /// 机械臂发生碰撞
84    Collision = 0x07,
85    /// 拖动示教时超速
86    TeachOverspeed = 0x08,
87    /// 关节状态异常
88    JointStatusError = 0x09,
89    /// 其它异常
90    OtherError = 0x0A,
91    /// 示教记录
92    TeachRecord = 0x0B,
93    /// 示教执行
94    TeachExecute = 0x0C,
95    /// 示教暂停
96    TeachPause = 0x0D,
97    /// 主控NTC过温
98    MainControlOverTemp = 0x0E,
99    /// 释放电阻NTC过温
100    ResistorOverTemp = 0x0F,
101}
102
103impl From<u8> for RobotStatus {
104    fn from(value: u8) -> Self {
105        match value {
106            0x00 => RobotStatus::Normal,
107            0x01 => RobotStatus::EmergencyStop,
108            0x02 => RobotStatus::NoSolution,
109            0x03 => RobotStatus::Singularity,
110            0x04 => RobotStatus::AngleLimitExceeded,
111            0x05 => RobotStatus::JointCommError,
112            0x06 => RobotStatus::JointBrakeNotOpen,
113            0x07 => RobotStatus::Collision,
114            0x08 => RobotStatus::TeachOverspeed,
115            0x09 => RobotStatus::JointStatusError,
116            0x0A => RobotStatus::OtherError,
117            0x0B => RobotStatus::TeachRecord,
118            0x0C => RobotStatus::TeachExecute,
119            0x0D => RobotStatus::TeachPause,
120            0x0E => RobotStatus::MainControlOverTemp,
121            0x0F => RobotStatus::ResistorOverTemp,
122            _ => RobotStatus::Normal, // 默认值
123        }
124    }
125}
126
127/// MOVE 模式
128#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
129pub enum MoveMode {
130    /// MOVE P
131    #[default]
132    MoveP = 0x00,
133    /// MOVE J
134    MoveJ = 0x01,
135    /// MOVE L
136    MoveL = 0x02,
137    /// MOVE C
138    MoveC = 0x03,
139    /// MOVE M
140    MoveM = 0x04,
141}
142
143impl From<u8> for MoveMode {
144    fn from(value: u8) -> Self {
145        match value {
146            0x00 => MoveMode::MoveP,
147            0x01 => MoveMode::MoveJ,
148            0x02 => MoveMode::MoveL,
149            0x03 => MoveMode::MoveC,
150            0x04 => MoveMode::MoveM,
151            _ => MoveMode::MoveP, // 默认值
152        }
153    }
154}
155
156/// 示教状态
157#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
158pub enum TeachStatus {
159    /// 关闭
160    #[default]
161    Closed = 0x00,
162    /// 开始示教记录(进入拖动示教模式)
163    StartRecord = 0x01,
164    /// 结束示教记录(退出拖动示教模式)
165    EndRecord = 0x02,
166    /// 执行示教轨迹(拖动示教轨迹复现)
167    Execute = 0x03,
168    /// 暂停执行
169    Pause = 0x04,
170    /// 继续执行(轨迹复现继续)
171    Continue = 0x05,
172    /// 终止执行
173    Terminate = 0x06,
174    /// 运动到轨迹起点
175    MoveToStart = 0x07,
176}
177
178impl From<u8> for TeachStatus {
179    fn from(value: u8) -> Self {
180        match value {
181            0x00 => TeachStatus::Closed,
182            0x01 => TeachStatus::StartRecord,
183            0x02 => TeachStatus::EndRecord,
184            0x03 => TeachStatus::Execute,
185            0x04 => TeachStatus::Pause,
186            0x05 => TeachStatus::Continue,
187            0x06 => TeachStatus::Terminate,
188            0x07 => TeachStatus::MoveToStart,
189            _ => TeachStatus::Closed, // 默认值
190        }
191    }
192}
193
194/// 运动状态
195#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
196pub enum MotionStatus {
197    /// 到达指定点位
198    #[default]
199    Arrived = 0x00,
200    /// 未到达指定点位
201    NotArrived = 0x01,
202}
203
204impl From<u8> for MotionStatus {
205    fn from(value: u8) -> Self {
206        match value {
207            0x00 => MotionStatus::Arrived,
208            0x01 => MotionStatus::NotArrived,
209            _ => MotionStatus::NotArrived, // 默认值
210        }
211    }
212}
213
214// ============================================================================
215// 位域结构定义(使用 bilge)
216// ============================================================================
217
218/// 故障码位域(Byte 6: 角度超限位)
219///
220/// 协议定义(Motorola MSB 高位在前):
221/// - Bit 0: 1号关节角度超限位(0:正常 1:异常)
222/// - Bit 1: 2号关节角度超限位
223/// - Bit 2: 3号关节角度超限位
224/// - Bit 3: 4号关节角度超限位
225/// - Bit 4: 5号关节角度超限位
226/// - Bit 5: 6号关节角度超限位
227/// - Bit 6-7: 保留
228///
229/// 注意:协议使用 Motorola (MSB) 高位在前,这是指**字节序**(多字节整数)。
230/// 对于**单个字节内的位域**,协议明确 Bit 0 对应 1号关节,这是 LSB first(小端位序)。
231/// bilge 默认使用 LSB first 位序,与协议要求一致。
232#[bitsize(8)]
233#[derive(FromBits, DebugBits, Clone, Copy, Default)]
234pub struct FaultCodeAngleLimit {
235    pub joint1_limit: bool, // Bit 0: 1号关节角度超限位
236    pub joint2_limit: bool, // Bit 1: 2号关节角度超限位
237    pub joint3_limit: bool, // Bit 2: 3号关节角度超限位
238    pub joint4_limit: bool, // Bit 3: 4号关节角度超限位
239    pub joint5_limit: bool, // Bit 4: 5号关节角度超限位
240    pub joint6_limit: bool, // Bit 5: 6号关节角度超限位
241    pub reserved: u2,       // Bit 6-7: 保留
242}
243
244/// 故障码位域(Byte 7: 通信异常)
245///
246/// 协议定义(Motorola MSB 高位在前):
247/// - Bit 0: 1号关节通信异常(0:正常 1:异常)
248/// - Bit 1: 2号关节通信异常
249/// - Bit 2: 3号关节通信异常
250/// - Bit 3: 4号关节通信异常
251/// - Bit 4: 5号关节通信异常
252/// - Bit 5: 6号关节通信异常
253/// - Bit 6-7: 保留
254#[bitsize(8)]
255#[derive(FromBits, DebugBits, Clone, Copy, Default)]
256pub struct FaultCodeCommError {
257    pub joint1_comm_error: bool, // Bit 0: 1号关节通信异常
258    pub joint2_comm_error: bool, // Bit 1: 2号关节通信异常
259    pub joint3_comm_error: bool, // Bit 2: 3号关节通信异常
260    pub joint4_comm_error: bool, // Bit 3: 4号关节通信异常
261    pub joint5_comm_error: bool, // Bit 4: 5号关节通信异常
262    pub joint6_comm_error: bool, // Bit 5: 6号关节通信异常
263    pub reserved: u2,            // Bit 6-7: 保留
264}
265
266// ============================================================================
267// 机械臂状态反馈结构体
268// ============================================================================
269
270/// 机械臂状态反馈 (0x2A1)
271///
272/// 包含控制模式、机械臂状态、MOVE 模式、示教状态、运动状态、
273/// 轨迹点索引以及故障码位域。
274#[derive(Debug, Clone, Copy, Default)]
275pub struct RobotStatusFeedback {
276    pub control_mode: ControlMode,                   // Byte 0
277    pub robot_status: RobotStatus,                   // Byte 1
278    pub move_mode: MoveMode,                         // Byte 2
279    pub teach_status: TeachStatus,                   // Byte 3
280    pub motion_status: MotionStatus,                 // Byte 4
281    pub trajectory_point_index: u8,                  // Byte 5
282    pub fault_code_angle_limit: FaultCodeAngleLimit, // Byte 6 (位域)
283    pub fault_code_comm_error: FaultCodeCommError,   // Byte 7 (位域)
284}
285
286impl TryFrom<PiperFrame> for RobotStatusFeedback {
287    type Error = ProtocolError;
288
289    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
290        // 验证 CAN ID
291        if frame.id != ID_ROBOT_STATUS {
292            return Err(ProtocolError::InvalidCanId { id: frame.id });
293        }
294
295        // 验证数据长度
296        if frame.len < 8 {
297            return Err(ProtocolError::InvalidLength {
298                expected: 8,
299                actual: frame.len as usize,
300            });
301        }
302
303        // 解析所有字段
304        Ok(Self {
305            control_mode: ControlMode::from(frame.data[0]),
306            robot_status: RobotStatus::from(frame.data[1]),
307            move_mode: MoveMode::from(frame.data[2]),
308            teach_status: TeachStatus::from(frame.data[3]),
309            motion_status: MotionStatus::from(frame.data[4]),
310            trajectory_point_index: frame.data[5],
311            fault_code_angle_limit: FaultCodeAngleLimit::from(u8::new(frame.data[6])),
312            fault_code_comm_error: FaultCodeCommError::from(u8::new(frame.data[7])),
313        })
314    }
315}
316
317// ============================================================================
318// 关节反馈结构体
319// ============================================================================
320
321/// 机械臂臂部关节反馈12 (0x2A5)
322///
323/// 包含 J1 和 J2 关节的角度反馈。
324/// 单位:0.001°(原始值),可通过方法转换为度或弧度。
325#[derive(Debug, Clone, Copy, Default)]
326pub struct JointFeedback12 {
327    pub j1_deg: i32, // Byte 0-3: J1角度,单位 0.001°
328    pub j2_deg: i32, // Byte 4-7: J2角度,单位 0.001°
329}
330
331impl JointFeedback12 {
332    /// 获取 J1 原始值(0.001° 单位)
333    pub fn j1_raw(&self) -> i32 {
334        self.j1_deg
335    }
336
337    /// 获取 J2 原始值(0.001° 单位)
338    pub fn j2_raw(&self) -> i32 {
339        self.j2_deg
340    }
341
342    /// 获取 J1 角度(度)
343    pub fn j1(&self) -> f64 {
344        self.j1_deg as f64 / 1000.0
345    }
346
347    /// 获取 J2 角度(度)
348    pub fn j2(&self) -> f64 {
349        self.j2_deg as f64 / 1000.0
350    }
351
352    /// 获取 J1 角度(弧度)
353    pub fn j1_rad(&self) -> f64 {
354        self.j1() * std::f64::consts::PI / 180.0
355    }
356
357    /// 获取 J2 角度(弧度)
358    pub fn j2_rad(&self) -> f64 {
359        self.j2() * std::f64::consts::PI / 180.0
360    }
361}
362
363impl TryFrom<PiperFrame> for JointFeedback12 {
364    type Error = ProtocolError;
365
366    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
367        // 验证 CAN ID
368        if frame.id != ID_JOINT_FEEDBACK_12 {
369            return Err(ProtocolError::InvalidCanId { id: frame.id });
370        }
371
372        // 验证数据长度
373        if frame.len < 8 {
374            return Err(ProtocolError::InvalidLength {
375                expected: 8,
376                actual: frame.len as usize,
377            });
378        }
379
380        // 解析 J1 角度(Byte 0-3,大端字节序)
381        let j1_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
382        let j1_deg = bytes_to_i32_be(j1_bytes);
383
384        // 解析 J2 角度(Byte 4-7,大端字节序)
385        let j2_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
386        let j2_deg = bytes_to_i32_be(j2_bytes);
387
388        Ok(Self { j1_deg, j2_deg })
389    }
390}
391
392/// 机械臂腕部关节反馈34 (0x2A6)
393///
394/// 包含 J3 和 J4 关节的角度反馈。
395/// 单位:0.001°(原始值),可通过方法转换为度或弧度。
396#[derive(Debug, Clone, Copy, Default)]
397pub struct JointFeedback34 {
398    pub j3_deg: i32, // Byte 0-3: J3角度,单位 0.001°
399    pub j4_deg: i32, // Byte 4-7: J4角度,单位 0.001°
400}
401
402impl JointFeedback34 {
403    /// 获取 J3 原始值(0.001° 单位)
404    pub fn j3_raw(&self) -> i32 {
405        self.j3_deg
406    }
407
408    /// 获取 J4 原始值(0.001° 单位)
409    pub fn j4_raw(&self) -> i32 {
410        self.j4_deg
411    }
412
413    /// 获取 J3 角度(度)
414    pub fn j3(&self) -> f64 {
415        self.j3_deg as f64 / 1000.0
416    }
417
418    /// 获取 J4 角度(度)
419    pub fn j4(&self) -> f64 {
420        self.j4_deg as f64 / 1000.0
421    }
422
423    /// 获取 J3 角度(弧度)
424    pub fn j3_rad(&self) -> f64 {
425        self.j3() * std::f64::consts::PI / 180.0
426    }
427
428    /// 获取 J4 角度(弧度)
429    pub fn j4_rad(&self) -> f64 {
430        self.j4() * std::f64::consts::PI / 180.0
431    }
432}
433
434impl TryFrom<PiperFrame> for JointFeedback34 {
435    type Error = ProtocolError;
436
437    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
438        // 验证 CAN ID
439        if frame.id != ID_JOINT_FEEDBACK_34 {
440            return Err(ProtocolError::InvalidCanId { id: frame.id });
441        }
442
443        // 验证数据长度
444        if frame.len < 8 {
445            return Err(ProtocolError::InvalidLength {
446                expected: 8,
447                actual: frame.len as usize,
448            });
449        }
450
451        // 解析 J3 角度(Byte 0-3,大端字节序)
452        let j3_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
453        let j3_deg = bytes_to_i32_be(j3_bytes);
454
455        // 解析 J4 角度(Byte 4-7,大端字节序)
456        let j4_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
457        let j4_deg = bytes_to_i32_be(j4_bytes);
458
459        Ok(Self { j3_deg, j4_deg })
460    }
461}
462
463/// 机械臂腕部关节反馈56 (0x2A7)
464///
465/// 包含 J5 和 J6 关节的角度反馈。
466/// 单位:0.001°(原始值),可通过方法转换为度或弧度。
467#[derive(Debug, Clone, Copy, Default)]
468pub struct JointFeedback56 {
469    pub j5_deg: i32, // Byte 0-3: J5角度,单位 0.001°
470    pub j6_deg: i32, // Byte 4-7: J6角度,单位 0.001°
471}
472
473impl JointFeedback56 {
474    /// 获取 J5 原始值(0.001° 单位)
475    pub fn j5_raw(&self) -> i32 {
476        self.j5_deg
477    }
478
479    /// 获取 J6 原始值(0.001° 单位)
480    pub fn j6_raw(&self) -> i32 {
481        self.j6_deg
482    }
483
484    /// 获取 J5 角度(度)
485    pub fn j5(&self) -> f64 {
486        self.j5_deg as f64 / 1000.0
487    }
488
489    /// 获取 J6 角度(度)
490    pub fn j6(&self) -> f64 {
491        self.j6_deg as f64 / 1000.0
492    }
493
494    /// 获取 J5 角度(弧度)
495    pub fn j5_rad(&self) -> f64 {
496        self.j5() * std::f64::consts::PI / 180.0
497    }
498
499    /// 获取 J6 角度(弧度)
500    pub fn j6_rad(&self) -> f64 {
501        self.j6() * std::f64::consts::PI / 180.0
502    }
503}
504
505impl TryFrom<PiperFrame> for JointFeedback56 {
506    type Error = ProtocolError;
507
508    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
509        // 验证 CAN ID
510        if frame.id != ID_JOINT_FEEDBACK_56 {
511            return Err(ProtocolError::InvalidCanId { id: frame.id });
512        }
513
514        // 验证数据长度
515        if frame.len < 8 {
516            return Err(ProtocolError::InvalidLength {
517                expected: 8,
518                actual: frame.len as usize,
519            });
520        }
521
522        // 解析 J5 角度(Byte 0-3,大端字节序)
523        let j5_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
524        let j5_deg = bytes_to_i32_be(j5_bytes);
525
526        // 解析 J6 角度(Byte 4-7,大端字节序)
527        let j6_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
528        let j6_deg = bytes_to_i32_be(j6_bytes);
529
530        Ok(Self { j5_deg, j6_deg })
531    }
532}
533
534// ============================================================================
535// 末端位姿反馈结构体
536// ============================================================================
537
538/// 机械臂末端位姿反馈1 (0x2A2)
539///
540/// 包含 X 和 Y 坐标反馈。
541/// 单位:0.001mm(原始值),可通过方法转换为 mm。
542#[derive(Debug, Clone, Copy, Default)]
543pub struct EndPoseFeedback1 {
544    pub x_mm: i32, // Byte 0-3: X坐标,单位 0.001mm
545    pub y_mm: i32, // Byte 4-7: Y坐标,单位 0.001mm
546}
547
548impl EndPoseFeedback1 {
549    /// 获取 X 原始值(0.001mm 单位)
550    pub fn x_raw(&self) -> i32 {
551        self.x_mm
552    }
553
554    /// 获取 Y 原始值(0.001mm 单位)
555    pub fn y_raw(&self) -> i32 {
556        self.y_mm
557    }
558
559    /// 获取 X 坐标(mm)
560    pub fn x(&self) -> f64 {
561        self.x_mm as f64 / 1000.0
562    }
563
564    /// 获取 Y 坐标(mm)
565    pub fn y(&self) -> f64 {
566        self.y_mm as f64 / 1000.0
567    }
568}
569
570impl TryFrom<PiperFrame> for EndPoseFeedback1 {
571    type Error = ProtocolError;
572
573    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
574        // 验证 CAN ID
575        if frame.id != ID_END_POSE_1 {
576            return Err(ProtocolError::InvalidCanId { id: frame.id });
577        }
578
579        // 验证数据长度
580        if frame.len < 8 {
581            return Err(ProtocolError::InvalidLength {
582                expected: 8,
583                actual: frame.len as usize,
584            });
585        }
586
587        // 解析 X 坐标(Byte 0-3,大端字节序)
588        let x_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
589        let x_mm = bytes_to_i32_be(x_bytes);
590
591        // 解析 Y 坐标(Byte 4-7,大端字节序)
592        let y_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
593        let y_mm = bytes_to_i32_be(y_bytes);
594
595        Ok(Self { x_mm, y_mm })
596    }
597}
598
599/// 机械臂末端位姿反馈2 (0x2A3)
600///
601/// 包含 Z 坐标和 RX 角度反馈。
602/// 单位:Z 为 0.001mm(原始值),RX 为 0.001°(原始值)。
603#[derive(Debug, Clone, Copy, Default)]
604pub struct EndPoseFeedback2 {
605    pub z_mm: i32,   // Byte 0-3: Z坐标,单位 0.001mm
606    pub rx_deg: i32, // Byte 4-7: RX角度,单位 0.001°
607}
608
609impl EndPoseFeedback2 {
610    /// 获取 Z 原始值(0.001mm 单位)
611    pub fn z_raw(&self) -> i32 {
612        self.z_mm
613    }
614
615    /// 获取 RX 原始值(0.001° 单位)
616    pub fn rx_raw(&self) -> i32 {
617        self.rx_deg
618    }
619
620    /// 获取 Z 坐标(mm)
621    pub fn z(&self) -> f64 {
622        self.z_mm as f64 / 1000.0
623    }
624
625    /// 获取 RX 角度(度)
626    pub fn rx(&self) -> f64 {
627        self.rx_deg as f64 / 1000.0
628    }
629
630    /// 获取 RX 角度(弧度)
631    pub fn rx_rad(&self) -> f64 {
632        self.rx() * std::f64::consts::PI / 180.0
633    }
634}
635
636impl TryFrom<PiperFrame> for EndPoseFeedback2 {
637    type Error = ProtocolError;
638
639    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
640        // 验证 CAN ID
641        if frame.id != ID_END_POSE_2 {
642            return Err(ProtocolError::InvalidCanId { id: frame.id });
643        }
644
645        // 验证数据长度
646        if frame.len < 8 {
647            return Err(ProtocolError::InvalidLength {
648                expected: 8,
649                actual: frame.len as usize,
650            });
651        }
652
653        // 解析 Z 坐标(Byte 0-3,大端字节序)
654        let z_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
655        let z_mm = bytes_to_i32_be(z_bytes);
656
657        // 解析 RX 角度(Byte 4-7,大端字节序)
658        let rx_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
659        let rx_deg = bytes_to_i32_be(rx_bytes);
660
661        Ok(Self { z_mm, rx_deg })
662    }
663}
664
665/// 机械臂末端位姿反馈3 (0x2A4)
666///
667/// 包含 RY 和 RZ 角度反馈。
668/// 单位:0.001°(原始值),可通过方法转换为度或弧度。
669#[derive(Debug, Clone, Copy, Default)]
670pub struct EndPoseFeedback3 {
671    pub ry_deg: i32, // Byte 0-3: RY角度,单位 0.001°
672    pub rz_deg: i32, // Byte 4-7: RZ角度,单位 0.001°
673}
674
675impl EndPoseFeedback3 {
676    /// 获取 RY 原始值(0.001° 单位)
677    pub fn ry_raw(&self) -> i32 {
678        self.ry_deg
679    }
680
681    /// 获取 RZ 原始值(0.001° 单位)
682    pub fn rz_raw(&self) -> i32 {
683        self.rz_deg
684    }
685
686    /// 获取 RY 角度(度)
687    pub fn ry(&self) -> f64 {
688        self.ry_deg as f64 / 1000.0
689    }
690
691    /// 获取 RZ 角度(度)
692    pub fn rz(&self) -> f64 {
693        self.rz_deg as f64 / 1000.0
694    }
695
696    /// 获取 RY 角度(弧度)
697    pub fn ry_rad(&self) -> f64 {
698        self.ry() * std::f64::consts::PI / 180.0
699    }
700
701    /// 获取 RZ 角度(弧度)
702    pub fn rz_rad(&self) -> f64 {
703        self.rz() * std::f64::consts::PI / 180.0
704    }
705}
706
707impl TryFrom<PiperFrame> for EndPoseFeedback3 {
708    type Error = ProtocolError;
709
710    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
711        // 验证 CAN ID
712        if frame.id != ID_END_POSE_3 {
713            return Err(ProtocolError::InvalidCanId { id: frame.id });
714        }
715
716        // 验证数据长度
717        if frame.len < 8 {
718            return Err(ProtocolError::InvalidLength {
719                expected: 8,
720                actual: frame.len as usize,
721            });
722        }
723
724        // 解析 RY 角度(Byte 0-3,大端字节序)
725        let ry_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
726        let ry_deg = bytes_to_i32_be(ry_bytes);
727
728        // 解析 RZ 角度(Byte 4-7,大端字节序)
729        let rz_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
730        let rz_deg = bytes_to_i32_be(rz_bytes);
731
732        Ok(Self { ry_deg, rz_deg })
733    }
734}
735
736// ============================================================================
737// 关节驱动器高速反馈结构体
738// ============================================================================
739
740/// 关节驱动器高速反馈 (0x251~0x256)
741///
742/// 包含关节速度、电流和位置反馈。
743/// - 速度单位:0.001rad/s(原始值)
744/// - 电流单位:0.001A(原始值)
745/// - 位置单位:rad(原始值)
746///
747/// 注意:关节索引从 CAN ID 推导(0x251 -> 1, 0x252 -> 2, ..., 0x256 -> 6)
748#[derive(Debug, Clone, Copy, Default)]
749pub struct JointDriverHighSpeedFeedback {
750    pub joint_index: u8,   // 从 ID 推导:0x251 -> 1, 0x252 -> 2, ...
751    pub speed_rad_s: i16,  // Byte 0-1: 速度,单位 0.001rad/s
752    pub current_a: i16,    // Byte 2-3: 电流,单位 0.001A(有符号 i16,支持负值表示反向电流)
753    pub position_rad: i32, // Byte 4-7: 位置,单位 rad (TODO: 需要确认真实单位)
754}
755
756impl JointDriverHighSpeedFeedback {
757    /// 关节 1-3 的力矩系数(CAN ID: 0x251~0x253)
758    ///
759    /// 根据官方参考实现,关节 1、2、3 使用此系数计算力矩。
760    /// 公式:torque = current * COEFFICIENT_1_3
761    pub const COEFFICIENT_1_3: f64 = 1.18125;
762
763    /// 关节 4-6 的力矩系数(CAN ID: 0x254~0x256)
764    ///
765    /// 根据官方参考实现,关节 4、5、6 使用此系数计算力矩。
766    /// 公式:torque = current * COEFFICIENT_4_6
767    pub const COEFFICIENT_4_6: f64 = 0.95844;
768
769    /// 获取速度原始值(0.001rad/s 单位)
770    pub fn speed_raw(&self) -> i16 {
771        self.speed_rad_s
772    }
773
774    /// 获取电流原始值(0.001A 单位)
775    pub fn current_raw(&self) -> i16 {
776        self.current_a
777    }
778
779    /// 获取位置原始值(rad 单位)
780    pub fn position_raw(&self) -> i32 {
781        self.position_rad
782    }
783
784    /// 获取速度(rad/s)
785    pub fn speed(&self) -> f64 {
786        self.speed_rad_s as f64 / 1000.0
787    }
788
789    /// 获取电流(A)
790    ///
791    /// 注意:电流可以为负值(反向电流)
792    pub fn current(&self) -> f64 {
793        self.current_a as f64 / 1000.0
794    }
795
796    /// 获取位置(rad)
797    pub fn position(&self) -> f64 {
798        self.position_rad as f64
799    }
800
801    /// 获取位置(度)
802    pub fn position_deg(&self) -> f64 {
803        self.position() * 180.0 / std::f64::consts::PI
804    }
805
806    /// 计算力矩(N·m)
807    ///
808    /// 根据关节索引和电流值计算力矩。
809    /// - 关节 1-3 (CAN ID: 0x251~0x253) 使用系数 `COEFFICIENT_1_3 = 1.18125`
810    /// - 关节 4-6 (CAN ID: 0x254~0x256) 使用系数 `COEFFICIENT_4_6 = 0.95844`
811    ///
812    /// 公式:`torque = current * coefficient`
813    ///
814    /// # 参数
815    /// - `current_opt`: 可选的电流值(A)。如果为 `None`,则使用当前反馈的电流值。
816    ///
817    /// # 返回值
818    /// 计算得到的力矩值(N·m)
819    ///
820    /// # 示例
821    /// ```rust
822    /// # use piper_sdk::protocol::feedback::JointDriverHighSpeedFeedback;
823    /// # use piper_sdk::can::PiperFrame;
824    /// # let frame = PiperFrame::new_standard(0x251, &[0; 8]);
825    /// # let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
826    /// // 使用反馈中的电流值计算力矩
827    /// let torque = feedback.torque(None);
828    ///
829    /// // 使用指定的电流值计算力矩
830    /// let torque = feedback.torque(Some(2.5)); // 2.5A
831    /// ```
832    pub fn torque(&self, current_opt: Option<f64>) -> f64 {
833        let current = current_opt.unwrap_or_else(|| self.current());
834        let coefficient = if self.joint_index <= 3 {
835            Self::COEFFICIENT_1_3
836        } else {
837            Self::COEFFICIENT_4_6
838        };
839        current * coefficient
840    }
841
842    /// 获取力矩原始值(0.001N·m 单位)
843    ///
844    /// 返回以 0.001N·m 为单位的力矩原始值(整数形式)。
845    /// 这对应于官方参考实现中 `effort` 字段的单位。
846    ///
847    /// # 返回值
848    /// 力矩原始值(0.001N·m 单位,即毫牛·米)
849    ///
850    /// # 示例
851    /// ```rust
852    /// # use piper_sdk::protocol::feedback::JointDriverHighSpeedFeedback;
853    /// # use piper_sdk::can::PiperFrame;
854    /// # let frame = PiperFrame::new_standard(0x251, &[0; 8]);
855    /// # let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
856    /// let torque_raw = feedback.torque_raw(); // 例如:1181 (表示 1.181 N·m)
857    /// ```
858    pub fn torque_raw(&self) -> i32 {
859        (self.torque(None) * 1000.0).round() as i32
860    }
861}
862
863impl TryFrom<PiperFrame> for JointDriverHighSpeedFeedback {
864    type Error = ProtocolError;
865
866    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
867        // 验证 CAN ID 范围(0x251~0x256)
868        if frame.id < ID_JOINT_DRIVER_HIGH_SPEED_BASE
869            || frame.id > ID_JOINT_DRIVER_HIGH_SPEED_BASE + 5
870        {
871            return Err(ProtocolError::InvalidCanId { id: frame.id });
872        }
873
874        // 从 CAN ID 推导关节索引(0x251 -> 1, 0x252 -> 2, ..., 0x256 -> 6)
875        let joint_index = (frame.id - ID_JOINT_DRIVER_HIGH_SPEED_BASE + 1) as u8;
876
877        // 验证数据长度
878        if frame.len < 8 {
879            return Err(ProtocolError::InvalidLength {
880                expected: 8,
881                actual: frame.len as usize,
882            });
883        }
884
885        // 解析速度(Byte 0-1,大端字节序,i16)
886        let speed_bytes = [frame.data[0], frame.data[1]];
887        let speed_rad_s = bytes_to_i16_be(speed_bytes);
888
889        // 解析电流(Byte 2-3,大端字节序,i16,支持负值表示反向电流)
890        let current_bytes = [frame.data[2], frame.data[3]];
891        let current_a = bytes_to_i16_be(current_bytes);
892
893        // 解析位置(Byte 4-7,大端字节序,i32)
894        let position_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
895        let position_rad = bytes_to_i32_be(position_bytes);
896
897        Ok(Self {
898            joint_index,
899            speed_rad_s,
900            current_a,
901            position_rad,
902        })
903    }
904}
905
906// ============================================================================
907// 关节驱动器低速反馈结构体
908// ============================================================================
909
910/// 驱动器状态位域(Byte 5: 8 位)
911///
912/// 协议定义(Motorola MSB 高位在前):
913/// - Bit 0: 电源电压是否过低(0:正常 1:过低)
914/// - Bit 1: 电机是否过温(0:正常 1:过温)
915/// - Bit 2: 驱动器是否过流(0:正常 1:过流)
916/// - Bit 3: 驱动器是否过温(0:正常 1:过温)
917/// - Bit 4: 碰撞保护状态(0:正常 1:触发保护)
918/// - Bit 5: 驱动器错误状态(0:正常 1:错误)
919/// - Bit 6: 驱动器使能状态(0:失能 1:使能)
920/// - Bit 7: 堵转保护状态(0:正常 1:触发保护)
921#[bitsize(8)]
922#[derive(FromBits, DebugBits, Clone, Copy, Default)]
923pub struct DriverStatus {
924    pub voltage_low: bool,          // Bit 0: 0正常 1过低
925    pub motor_over_temp: bool,      // Bit 1: 0正常 1过温
926    pub driver_over_current: bool,  // Bit 2: 0正常 1过流
927    pub driver_over_temp: bool,     // Bit 3: 0正常 1过温
928    pub collision_protection: bool, // Bit 4: 0正常 1触发保护
929    pub driver_error: bool,         // Bit 5: 0正常 1错误
930    pub enabled: bool,              // Bit 6: 0失能 1使能
931    pub stall_protection: bool,     // Bit 7: 0正常 1触发保护
932}
933
934/// 关节驱动器低速反馈 (0x261~0x266)
935///
936/// 包含电压、温度、驱动器状态和母线电流反馈。
937/// - 电压单位:0.1V(原始值)
938/// - 温度单位:1℃(原始值)
939/// - 电流单位:0.001A(原始值)
940#[derive(Debug, Clone, Copy, Default)]
941pub struct JointDriverLowSpeedFeedback {
942    pub joint_index: u8,      // 从 ID 推导:0x261 -> 1, 0x262 -> 2, ...
943    pub voltage: u16,         // Byte 0-1: 电压,单位 0.1V
944    pub driver_temp: i16,     // Byte 2-3: 驱动器温度,单位 1℃
945    pub motor_temp: i8,       // Byte 4: 电机温度,单位 1℃
946    pub status: DriverStatus, // Byte 5: 驱动器状态位域
947    pub bus_current: u16,     // Byte 6-7: 母线电流,单位 0.001A
948}
949
950impl JointDriverLowSpeedFeedback {
951    /// 获取电压原始值(0.1V 单位)
952    pub fn voltage_raw(&self) -> u16 {
953        self.voltage
954    }
955
956    /// 获取驱动器温度原始值(1℃ 单位)
957    pub fn driver_temp_raw(&self) -> i16 {
958        self.driver_temp
959    }
960
961    /// 获取电机温度原始值(1℃ 单位)
962    pub fn motor_temp_raw(&self) -> i8 {
963        self.motor_temp
964    }
965
966    /// 获取母线电流原始值(0.001A 单位)
967    pub fn bus_current_raw(&self) -> u16 {
968        self.bus_current
969    }
970
971    /// 获取电压(V)
972    pub fn voltage(&self) -> f64 {
973        self.voltage as f64 / 10.0
974    }
975
976    /// 获取驱动器温度(℃)
977    pub fn driver_temp(&self) -> f64 {
978        self.driver_temp as f64
979    }
980
981    /// 获取电机温度(℃)
982    pub fn motor_temp(&self) -> f64 {
983        self.motor_temp as f64
984    }
985
986    /// 获取母线电流(A)
987    pub fn bus_current(&self) -> f64 {
988        self.bus_current as f64 / 1000.0
989    }
990}
991
992impl TryFrom<PiperFrame> for JointDriverLowSpeedFeedback {
993    type Error = ProtocolError;
994
995    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
996        // 从 CAN ID 推导关节序号
997        let joint_index = (frame.id - ID_JOINT_DRIVER_LOW_SPEED_BASE + 1) as u8;
998        if !(1..=6).contains(&joint_index) {
999            return Err(ProtocolError::InvalidCanId { id: frame.id });
1000        }
1001
1002        // 验证数据长度
1003        if frame.len < 8 {
1004            return Err(ProtocolError::InvalidLength {
1005                expected: 8,
1006                actual: frame.len as usize,
1007            });
1008        }
1009
1010        // 处理大端字节序
1011        let voltage_bytes = [frame.data[0], frame.data[1]];
1012        let voltage = u16::from_be_bytes(voltage_bytes);
1013
1014        let driver_temp_bytes = [frame.data[2], frame.data[3]];
1015        let driver_temp = bytes_to_i16_be(driver_temp_bytes);
1016
1017        let motor_temp = frame.data[4] as i8;
1018
1019        // 使用 bilge 解析位域(Byte 5)
1020        let status = DriverStatus::from(u8::new(frame.data[5]));
1021
1022        let bus_current_bytes = [frame.data[6], frame.data[7]];
1023        let bus_current = u16::from_be_bytes(bus_current_bytes);
1024
1025        Ok(Self {
1026            joint_index,
1027            voltage,
1028            driver_temp,
1029            motor_temp,
1030            status,
1031            bus_current,
1032        })
1033    }
1034}
1035
1036// ============================================================================
1037// 关节末端速度/加速度反馈结构体
1038// ============================================================================
1039
1040/// 关节末端速度/加速度反馈 (0x481~0x486)
1041///
1042/// 包含关节末端线速度、角速度、线加速度和角加速度反馈。
1043/// - 线速度单位:0.001m/s(原始值)
1044/// - 角速度单位:0.001rad/s(原始值)
1045/// - 线加速度单位:0.001m/s²(原始值)
1046/// - 角加速度单位:0.001rad/s²(原始值)
1047///
1048/// 注意:这是"末端"速度和加速度,不是关节本身的速度和加速度。
1049#[derive(Debug, Clone, Copy, Default)]
1050pub struct JointEndVelocityAccelFeedback {
1051    pub joint_index: u8,                 // 从 ID 推导:0x481 -> 1, 0x482 -> 2, ...
1052    pub linear_velocity_m_s_raw: u16,    // Byte 0-1: 末端线速度,单位 0.001m/s
1053    pub angular_velocity_rad_s_raw: u16, // Byte 2-3: 末端角速度,单位 0.001rad/s
1054    pub linear_accel_m_s2_raw: u16,      // Byte 4-5: 末端线加速度,单位 0.001m/s²
1055    pub angular_accel_rad_s2_raw: u16,   // Byte 6-7: 末端角加速度,单位 0.001rad/s²
1056}
1057
1058impl JointEndVelocityAccelFeedback {
1059    /// 获取末端线速度原始值(0.001m/s 单位)
1060    pub fn linear_velocity_raw(&self) -> u16 {
1061        self.linear_velocity_m_s_raw
1062    }
1063
1064    /// 获取末端角速度原始值(0.001rad/s 单位)
1065    pub fn angular_velocity_raw(&self) -> u16 {
1066        self.angular_velocity_rad_s_raw
1067    }
1068
1069    /// 获取末端线加速度原始值(0.001m/s² 单位)
1070    pub fn linear_accel_raw(&self) -> u16 {
1071        self.linear_accel_m_s2_raw
1072    }
1073
1074    /// 获取末端角加速度原始值(0.001rad/s² 单位)
1075    pub fn angular_accel_raw(&self) -> u16 {
1076        self.angular_accel_rad_s2_raw
1077    }
1078
1079    /// 获取末端线速度(m/s)
1080    pub fn linear_velocity(&self) -> f64 {
1081        self.linear_velocity_m_s_raw as f64 / 1000.0
1082    }
1083
1084    /// 获取末端角速度(rad/s)
1085    pub fn angular_velocity(&self) -> f64 {
1086        self.angular_velocity_rad_s_raw as f64 / 1000.0
1087    }
1088
1089    /// 获取末端线加速度(m/s²)
1090    pub fn linear_accel(&self) -> f64 {
1091        self.linear_accel_m_s2_raw as f64 / 1000.0
1092    }
1093
1094    /// 获取末端角加速度(rad/s²)
1095    pub fn angular_accel(&self) -> f64 {
1096        self.angular_accel_rad_s2_raw as f64 / 1000.0
1097    }
1098}
1099
1100impl TryFrom<PiperFrame> for JointEndVelocityAccelFeedback {
1101    type Error = ProtocolError;
1102
1103    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
1104        // 验证 CAN ID 范围(0x481~0x486)
1105        if frame.id < ID_JOINT_END_VELOCITY_ACCEL_BASE
1106            || frame.id > ID_JOINT_END_VELOCITY_ACCEL_BASE + 5
1107        {
1108            return Err(ProtocolError::InvalidCanId { id: frame.id });
1109        }
1110
1111        // 从 CAN ID 推导关节序号(0x481 -> 1, 0x482 -> 2, ..., 0x486 -> 6)
1112        let joint_index = (frame.id - ID_JOINT_END_VELOCITY_ACCEL_BASE + 1) as u8;
1113
1114        // 验证数据长度(需要 8 字节:线速度 2 + 角速度 2 + 线加速度 2 + 角加速度 2)
1115        if frame.len < 8 {
1116            return Err(ProtocolError::InvalidLength {
1117                expected: 8,
1118                actual: frame.len as usize,
1119            });
1120        }
1121
1122        // 处理大端字节序(所有字段都是 uint16)
1123        let linear_velocity_bytes = [frame.data[0], frame.data[1]];
1124        let linear_velocity_m_s_raw = u16::from_be_bytes(linear_velocity_bytes);
1125
1126        let angular_velocity_bytes = [frame.data[2], frame.data[3]];
1127        let angular_velocity_rad_s_raw = u16::from_be_bytes(angular_velocity_bytes);
1128
1129        let linear_accel_bytes = [frame.data[4], frame.data[5]];
1130        let linear_accel_m_s2_raw = u16::from_be_bytes(linear_accel_bytes);
1131
1132        let angular_accel_bytes = [frame.data[6], frame.data[7]];
1133        let angular_accel_rad_s2_raw = u16::from_be_bytes(angular_accel_bytes);
1134
1135        Ok(Self {
1136            joint_index,
1137            linear_velocity_m_s_raw,
1138            angular_velocity_rad_s_raw,
1139            linear_accel_m_s2_raw,
1140            angular_accel_rad_s2_raw,
1141        })
1142    }
1143}
1144
1145// ============================================================================
1146// 夹爪反馈结构体
1147// ============================================================================
1148
1149/// 夹爪状态位域(Byte 6: 8 位)
1150///
1151/// 协议定义(Motorola MSB 高位在前):
1152/// - Bit 0: 电源电压是否过低(0:正常 1:过低)
1153/// - Bit 1: 电机是否过温(0:正常 1:过温)
1154/// - Bit 2: 驱动器是否过流(0:正常 1:过流)
1155/// - Bit 3: 驱动器是否过温(0:正常 1:过温)
1156/// - Bit 4: 传感器状态(0:正常 1:异常)
1157/// - Bit 5: 驱动器错误状态(0:正常 1:错误)
1158/// - Bit 6: 驱动器使能状态(**1:使能 0:失能**,注意:反向逻辑)
1159/// - Bit 7: 回零状态(0:没有回零 1:已经回零)
1160#[bitsize(8)]
1161#[derive(FromBits, DebugBits, Clone, Copy, Default)]
1162pub struct GripperStatus {
1163    pub voltage_low: bool,         // Bit 0: 0正常 1过低
1164    pub motor_over_temp: bool,     // Bit 1: 0正常 1过温
1165    pub driver_over_current: bool, // Bit 2: 0正常 1过流
1166    pub driver_over_temp: bool,    // Bit 3: 0正常 1过温
1167    pub sensor_error: bool,        // Bit 4: 0正常 1异常
1168    pub driver_error: bool,        // Bit 5: 0正常 1错误
1169    pub enabled: bool,             // Bit 6: **1使能 0失能**(注意:反向逻辑,与通常相反)
1170    pub homed: bool,               // Bit 7: 0没有回零 1已经回零
1171}
1172
1173/// 夹爪反馈指令 (0x2A8)
1174///
1175/// 包含夹爪行程、扭矩和状态反馈。
1176/// - 行程单位:0.001mm(原始值)
1177/// - 扭矩单位:0.001N·m(原始值)
1178#[derive(Debug, Clone, Copy, Default)]
1179pub struct GripperFeedback {
1180    pub travel_mm: i32, // Byte 0-3: 单位 0.001mm
1181    pub torque_nm: i16, // Byte 4-5: 单位 0.001N·m(牛·米)
1182    pub status: GripperStatus, // Byte 6: 位域
1183                        // Byte 7: 保留
1184}
1185
1186impl GripperFeedback {
1187    /// 获取行程原始值(0.001mm 单位)
1188    pub fn travel_raw(&self) -> i32 {
1189        self.travel_mm
1190    }
1191
1192    /// 获取扭矩原始值(0.001N·m 单位)
1193    pub fn torque_raw(&self) -> i16 {
1194        self.torque_nm
1195    }
1196
1197    /// 获取行程(mm)
1198    pub fn travel(&self) -> f64 {
1199        self.travel_mm as f64 / 1000.0
1200    }
1201
1202    /// 获取扭矩(N·m)
1203    pub fn torque(&self) -> f64 {
1204        self.torque_nm as f64 / 1000.0
1205    }
1206}
1207
1208impl TryFrom<PiperFrame> for GripperFeedback {
1209    type Error = ProtocolError;
1210
1211    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
1212        // 验证 CAN ID
1213        if frame.id != ID_GRIPPER_FEEDBACK {
1214            return Err(ProtocolError::InvalidCanId { id: frame.id });
1215        }
1216
1217        // 验证数据长度
1218        if frame.len < 7 {
1219            return Err(ProtocolError::InvalidLength {
1220                expected: 7,
1221                actual: frame.len as usize,
1222            });
1223        }
1224
1225        // 处理大端字节序
1226        let travel_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
1227        let travel_mm = bytes_to_i32_be(travel_bytes);
1228
1229        let torque_bytes = [frame.data[4], frame.data[5]];
1230        let torque_nm = bytes_to_i16_be(torque_bytes);
1231
1232        // 使用 bilge 解析位域
1233        let status = GripperStatus::from(u8::new(frame.data[6]));
1234
1235        Ok(Self {
1236            travel_mm,
1237            torque_nm,
1238            status,
1239        })
1240    }
1241}
1242
1243#[cfg(test)]
1244mod tests {
1245    use super::*;
1246
1247    #[test]
1248    fn test_control_mode_from_u8() {
1249        assert_eq!(ControlMode::from(0x00), ControlMode::Standby);
1250        assert_eq!(ControlMode::from(0x01), ControlMode::CanControl);
1251        assert_eq!(ControlMode::from(0x02), ControlMode::Teach);
1252        assert_eq!(ControlMode::from(0x03), ControlMode::Ethernet);
1253        assert_eq!(ControlMode::from(0x04), ControlMode::Wifi);
1254        assert_eq!(ControlMode::from(0x05), ControlMode::Remote);
1255        assert_eq!(ControlMode::from(0x06), ControlMode::LinkTeach);
1256        assert_eq!(ControlMode::from(0x07), ControlMode::OfflineTrajectory);
1257        // 无效值应该返回默认值
1258        assert_eq!(ControlMode::from(0xFF), ControlMode::Standby);
1259    }
1260
1261    #[test]
1262    fn test_robot_status_from_u8() {
1263        assert_eq!(RobotStatus::from(0x00), RobotStatus::Normal);
1264        assert_eq!(RobotStatus::from(0x01), RobotStatus::EmergencyStop);
1265        assert_eq!(RobotStatus::from(0x0F), RobotStatus::ResistorOverTemp);
1266        // 测试所有值
1267        for i in 0x00..=0x0F {
1268            let status = RobotStatus::from(i);
1269            assert_eq!(status as u8, i);
1270        }
1271    }
1272
1273    #[test]
1274    fn test_move_mode_from_u8() {
1275        assert_eq!(MoveMode::from(0x00), MoveMode::MoveP);
1276        assert_eq!(MoveMode::from(0x01), MoveMode::MoveJ);
1277        assert_eq!(MoveMode::from(0x02), MoveMode::MoveL);
1278        assert_eq!(MoveMode::from(0x03), MoveMode::MoveC);
1279        assert_eq!(MoveMode::from(0x04), MoveMode::MoveM);
1280        // 无效值应该返回默认值
1281        assert_eq!(MoveMode::from(0xFF), MoveMode::MoveP);
1282    }
1283
1284    #[test]
1285    fn test_teach_status_from_u8() {
1286        assert_eq!(TeachStatus::from(0x00), TeachStatus::Closed);
1287        assert_eq!(TeachStatus::from(0x01), TeachStatus::StartRecord);
1288        assert_eq!(TeachStatus::from(0x07), TeachStatus::MoveToStart);
1289        // 测试所有值
1290        for i in 0x00..=0x07 {
1291            let status = TeachStatus::from(i);
1292            assert_eq!(status as u8, i);
1293        }
1294    }
1295
1296    #[test]
1297    fn test_motion_status_from_u8() {
1298        assert_eq!(MotionStatus::from(0x00), MotionStatus::Arrived);
1299        assert_eq!(MotionStatus::from(0x01), MotionStatus::NotArrived);
1300        // 无效值应该返回默认值
1301        assert_eq!(MotionStatus::from(0xFF), MotionStatus::NotArrived);
1302    }
1303
1304    #[test]
1305    fn test_enum_values_match_protocol() {
1306        // 验证枚举值与协议文档一致
1307        assert_eq!(ControlMode::Standby as u8, 0x00);
1308        assert_eq!(ControlMode::CanControl as u8, 0x01);
1309        assert_eq!(ControlMode::Remote as u8, 0x05);
1310        assert_eq!(ControlMode::LinkTeach as u8, 0x06);
1311
1312        assert_eq!(RobotStatus::Normal as u8, 0x00);
1313        assert_eq!(RobotStatus::EmergencyStop as u8, 0x01);
1314        assert_eq!(RobotStatus::ResistorOverTemp as u8, 0x0F);
1315
1316        assert_eq!(MoveMode::MoveP as u8, 0x00);
1317        assert_eq!(MoveMode::MoveM as u8, 0x04);
1318    }
1319
1320    // ========================================================================
1321    // 位域结构测试 - 验证 bilge 位序是否符合协议要求
1322    // ========================================================================
1323
1324    /// 验证 bilge 的位序是否符合协议要求
1325    ///
1326    /// 协议要求:
1327    /// - Bit 0: 1号关节
1328    /// - Bit 1: 2号关节
1329    /// - Bit 2: 3号关节
1330    /// - Bit 3: 4号关节
1331    /// - Bit 4: 5号关节
1332    /// - Bit 5: 6号关节
1333    ///
1334    /// 如果只有 1号关节超限位,字节值应该是 0b0000_0001 = 0x01
1335    /// 如果只有 2号关节超限位,字节值应该是 0b0000_0010 = 0x02
1336    /// 如果 1号和2号关节都超限位,字节值应该是 0b0000_0011 = 0x03
1337    #[test]
1338    fn test_fault_code_angle_limit_bit_order() {
1339        // 测试:只有 1号关节超限位
1340        // 协议:Bit 0 = 1,其他位 = 0
1341        // 期望字节值:0b0000_0001 = 0x01
1342        let byte = 0x01;
1343        let fault = FaultCodeAngleLimit::from(u8::new(byte));
1344        assert!(fault.joint1_limit(), "1号关节应该超限位");
1345        assert!(!fault.joint2_limit(), "2号关节应该正常");
1346        assert!(!fault.joint3_limit(), "3号关节应该正常");
1347        assert!(!fault.joint4_limit(), "4号关节应该正常");
1348        assert!(!fault.joint5_limit(), "5号关节应该正常");
1349        assert!(!fault.joint6_limit(), "6号关节应该正常");
1350
1351        // 测试:只有 2号关节超限位
1352        // 协议:Bit 1 = 1,其他位 = 0
1353        // 期望字节值:0b0000_0010 = 0x02
1354        let byte = 0x02;
1355        let fault = FaultCodeAngleLimit::from(u8::new(byte));
1356        assert!(!fault.joint1_limit(), "1号关节应该正常");
1357        assert!(fault.joint2_limit(), "2号关节应该超限位");
1358        assert!(!fault.joint3_limit(), "3号关节应该正常");
1359
1360        // 测试:1号和2号关节都超限位
1361        // 协议:Bit 0 = 1, Bit 1 = 1,其他位 = 0
1362        // 期望字节值:0b0000_0011 = 0x03
1363        let byte = 0x03;
1364        let fault = FaultCodeAngleLimit::from(u8::new(byte));
1365        assert!(fault.joint1_limit(), "1号关节应该超限位");
1366        assert!(fault.joint2_limit(), "2号关节应该超限位");
1367        assert!(!fault.joint3_limit(), "3号关节应该正常");
1368
1369        // 测试:所有关节都超限位(Bit 0-5 = 1)
1370        // 期望字节值:0b0011_1111 = 0x3F
1371        let byte = 0x3F;
1372        let fault = FaultCodeAngleLimit::from(u8::new(byte));
1373        assert!(fault.joint1_limit(), "1号关节应该超限位");
1374        assert!(fault.joint2_limit(), "2号关节应该超限位");
1375        assert!(fault.joint3_limit(), "3号关节应该超限位");
1376        assert!(fault.joint4_limit(), "4号关节应该超限位");
1377        assert!(fault.joint5_limit(), "5号关节应该超限位");
1378        assert!(fault.joint6_limit(), "6号关节应该超限位");
1379    }
1380
1381    #[test]
1382    fn test_fault_code_angle_limit_encode() {
1383        // 创建位域结构:设置 1号、3号、5号关节超限位
1384        // 协议:Bit 0 = 1, Bit 2 = 1, Bit 4 = 1
1385        // 期望字节值:0b0001_0101 = 0x15
1386        let mut fault = FaultCodeAngleLimit::from(u8::new(0));
1387        fault.set_joint1_limit(true);
1388        fault.set_joint3_limit(true);
1389        fault.set_joint5_limit(true);
1390
1391        // 编码回 u8
1392        let encoded = u8::from(fault).value();
1393        assert_eq!(encoded, 0x15, "编码值应该是 0x15 (Bit 0, 2, 4 = 1)");
1394
1395        // 验证各个位
1396        assert!(fault.joint1_limit());
1397        assert!(!fault.joint2_limit());
1398        assert!(fault.joint3_limit());
1399        assert!(!fault.joint4_limit());
1400        assert!(fault.joint5_limit());
1401        assert!(!fault.joint6_limit());
1402    }
1403
1404    #[test]
1405    fn test_fault_code_angle_limit_roundtrip() {
1406        // 测试编码-解码循环
1407        // 设置关节3,4,5,6超限位(Bit 2,3,4,5 = 1)
1408        // 期望字节值:0b0011_1100 = 0x3C
1409        let original_byte = 0x3C;
1410        let fault = FaultCodeAngleLimit::from(u8::new(original_byte));
1411        let encoded = u8::from(fault).value();
1412
1413        // 验证解析
1414        assert!(!fault.joint1_limit());
1415        assert!(!fault.joint2_limit());
1416        assert!(fault.joint3_limit());
1417        assert!(fault.joint4_limit());
1418        assert!(fault.joint5_limit());
1419        assert!(fault.joint6_limit());
1420
1421        // 验证编码(保留位可能被清零,所以只比较有效位)
1422        assert_eq!(encoded & 0b0011_1111, original_byte & 0b0011_1111);
1423    }
1424
1425    #[test]
1426    fn test_fault_code_comm_error_bit_order() {
1427        // 测试:只有 1号关节通信异常
1428        // 协议:Bit 0 = 1,其他位 = 0
1429        // 期望字节值:0b0000_0001 = 0x01
1430        let byte = 0x01;
1431        let fault = FaultCodeCommError::from(u8::new(byte));
1432        assert!(fault.joint1_comm_error(), "1号关节应该通信异常");
1433        assert!(!fault.joint2_comm_error(), "2号关节应该正常");
1434
1435        // 测试:只有 2号关节通信异常
1436        // 协议:Bit 1 = 1,其他位 = 0
1437        // 期望字节值:0b0000_0010 = 0x02
1438        let byte = 0x02;
1439        let fault = FaultCodeCommError::from(u8::new(byte));
1440        assert!(!fault.joint1_comm_error(), "1号关节应该正常");
1441        assert!(fault.joint2_comm_error(), "2号关节应该通信异常");
1442    }
1443
1444    #[test]
1445    fn test_fault_code_comm_error_encode() {
1446        // 设置 2号和6号关节通信异常
1447        // 协议:Bit 1 = 1, Bit 5 = 1
1448        // 期望字节值:0b0010_0010 = 0x22
1449        let mut fault = FaultCodeCommError::from(u8::new(0));
1450        fault.set_joint2_comm_error(true);
1451        fault.set_joint6_comm_error(true);
1452
1453        let encoded = u8::from(fault).value();
1454        assert_eq!(encoded, 0x22, "编码值应该是 0x22 (Bit 1, 5 = 1)");
1455    }
1456
1457    #[test]
1458    fn test_fault_code_comm_error_all_joints() {
1459        // 测试所有关节都通信异常
1460        // 协议:Bit 0-5 = 1
1461        // 期望字节值:0b0011_1111 = 0x3F
1462        let mut fault = FaultCodeCommError::from(u8::new(0));
1463        fault.set_joint1_comm_error(true);
1464        fault.set_joint2_comm_error(true);
1465        fault.set_joint3_comm_error(true);
1466        fault.set_joint4_comm_error(true);
1467        fault.set_joint5_comm_error(true);
1468        fault.set_joint6_comm_error(true);
1469
1470        let encoded = u8::from(fault).value();
1471        assert_eq!(encoded & 0b0011_1111, 0x3F, "前6位应该都是1");
1472    }
1473
1474    // ========================================================================
1475    // RobotStatusFeedback 测试
1476    // ========================================================================
1477
1478    #[test]
1479    fn test_robot_status_feedback_parse() {
1480        let frame = PiperFrame::new_standard(
1481            ID_ROBOT_STATUS as u16,
1482            &[
1483                0x01,        // Byte 0: CAN指令控制模式
1484                0x00,        // Byte 1: 正常
1485                0x01,        // Byte 2: MOVE J
1486                0x00,        // Byte 3: 示教关闭
1487                0x00,        // Byte 4: 到达指定点位
1488                0x05,        // Byte 5: 轨迹点索引 5
1489                0b0011_1111, // Byte 6: 所有关节角度超限位(Bit 0-5 = 1)
1490                0b0000_0000, // Byte 7: 无通信异常
1491            ],
1492        );
1493
1494        let status = RobotStatusFeedback::try_from(frame).unwrap();
1495
1496        assert_eq!(status.control_mode, ControlMode::CanControl);
1497        assert_eq!(status.robot_status, RobotStatus::Normal);
1498        assert_eq!(status.move_mode, MoveMode::MoveJ);
1499        assert_eq!(status.teach_status, TeachStatus::Closed);
1500        assert_eq!(status.motion_status, MotionStatus::Arrived);
1501        assert_eq!(status.trajectory_point_index, 5);
1502        assert!(status.fault_code_angle_limit.joint1_limit());
1503        assert!(status.fault_code_angle_limit.joint6_limit());
1504        assert!(!status.fault_code_comm_error.joint1_comm_error());
1505    }
1506
1507    #[test]
1508    fn test_robot_status_feedback_invalid_id() {
1509        let frame = PiperFrame::new_standard(0x999, &[0; 8]);
1510        let result = RobotStatusFeedback::try_from(frame);
1511        assert!(result.is_err());
1512        match result.unwrap_err() {
1513            ProtocolError::InvalidCanId { id } => assert_eq!(id, 0x999),
1514            _ => panic!("Expected InvalidCanId error"),
1515        }
1516    }
1517
1518    #[test]
1519    fn test_robot_status_feedback_invalid_length() {
1520        let frame = PiperFrame::new_standard(ID_ROBOT_STATUS as u16, &[0; 4]);
1521        let result = RobotStatusFeedback::try_from(frame);
1522        assert!(result.is_err());
1523        match result.unwrap_err() {
1524            ProtocolError::InvalidLength { expected, actual } => {
1525                assert_eq!(expected, 8);
1526                assert_eq!(actual, 4);
1527            },
1528            _ => panic!("Expected InvalidLength error"),
1529        }
1530    }
1531
1532    #[test]
1533    fn test_robot_status_feedback_all_fields() {
1534        // 测试所有字段的各种值
1535        let frame = PiperFrame::new_standard(
1536            ID_ROBOT_STATUS as u16,
1537            &[
1538                0x07,        // Byte 0: 离线轨迹模式
1539                0x0F,        // Byte 1: 释放电阻NTC过温
1540                0x04,        // Byte 2: MOVE M
1541                0x07,        // Byte 3: 运动到轨迹起点
1542                0x01,        // Byte 4: 未到达指定点位
1543                0xFF,        // Byte 5: 轨迹点索引 255
1544                0b0011_1111, // Byte 6: 所有关节超限位(Bit 0-5 = 1)
1545                0b0011_1111, // Byte 7: 所有关节通信异常(Bit 0-5 = 1)
1546            ],
1547        );
1548
1549        let status = RobotStatusFeedback::try_from(frame).unwrap();
1550
1551        assert_eq!(status.control_mode, ControlMode::OfflineTrajectory);
1552        assert_eq!(status.robot_status, RobotStatus::ResistorOverTemp);
1553        assert_eq!(status.move_mode, MoveMode::MoveM);
1554        assert_eq!(status.teach_status, TeachStatus::MoveToStart);
1555        assert_eq!(status.motion_status, MotionStatus::NotArrived);
1556        assert_eq!(status.trajectory_point_index, 0xFF);
1557
1558        // 验证所有关节故障位
1559        assert!(status.fault_code_angle_limit.joint1_limit());
1560        assert!(status.fault_code_angle_limit.joint2_limit());
1561        assert!(status.fault_code_angle_limit.joint3_limit());
1562        assert!(status.fault_code_angle_limit.joint4_limit());
1563        assert!(status.fault_code_angle_limit.joint5_limit());
1564        assert!(status.fault_code_angle_limit.joint6_limit());
1565
1566        // 验证所有关节通信异常位
1567        assert!(status.fault_code_comm_error.joint1_comm_error());
1568        assert!(status.fault_code_comm_error.joint2_comm_error());
1569        assert!(status.fault_code_comm_error.joint3_comm_error());
1570        assert!(status.fault_code_comm_error.joint4_comm_error());
1571        assert!(status.fault_code_comm_error.joint5_comm_error());
1572        assert!(status.fault_code_comm_error.joint6_comm_error());
1573    }
1574
1575    // ========================================================================
1576    // 关节反馈测试
1577    // ========================================================================
1578
1579    #[test]
1580    fn test_joint_feedback12_parse() {
1581        // 测试数据:J1 = 90.0° = 90000 (0.001° 单位),J2 = -45.0° = -45000
1582        let j1_val = 90000i32;
1583        let j2_val = -45000i32;
1584        let mut data = [0u8; 8];
1585        data[0..4].copy_from_slice(&j1_val.to_be_bytes());
1586        data[4..8].copy_from_slice(&j2_val.to_be_bytes());
1587        let frame = PiperFrame::new_standard(ID_JOINT_FEEDBACK_12 as u16, &data);
1588
1589        let feedback = JointFeedback12::try_from(frame).unwrap();
1590        assert_eq!(feedback.j1_raw(), 90000);
1591        assert_eq!(feedback.j2_raw(), -45000);
1592        assert!((feedback.j1() - 90.0).abs() < 0.0001);
1593        assert!((feedback.j2() - (-45.0)).abs() < 0.0001);
1594    }
1595
1596    #[test]
1597    fn test_joint_feedback12_physical_conversion() {
1598        // 测试物理量转换精度
1599        let frame = PiperFrame::new_standard(
1600            ID_JOINT_FEEDBACK_12 as u16,
1601            &[
1602                0x00, 0x00, 0x00, 0x00, // J1: 0°
1603                0x00, 0x00, 0x01, 0xF4, // J2: 500 (0.001° 单位) = 0.5°
1604            ],
1605        );
1606
1607        let feedback = JointFeedback12::try_from(frame).unwrap();
1608        assert_eq!(feedback.j1(), 0.0);
1609        assert!((feedback.j2() - 0.5).abs() < 0.0001);
1610
1611        // 测试弧度转换
1612        assert!((feedback.j1_rad() - 0.0).abs() < 0.0001);
1613        assert!((feedback.j2_rad() - (0.5 * std::f64::consts::PI / 180.0)).abs() < 0.0001);
1614    }
1615
1616    #[test]
1617    fn test_joint_feedback12_boundary_values() {
1618        // 测试最大正值:i32::MAX / 1000 ≈ 2147483.647°
1619        let max_positive = i32::MAX;
1620        let mut data = [0u8; 8];
1621        data[0..4].copy_from_slice(&max_positive.to_be_bytes());
1622        data[4..8].copy_from_slice(&max_positive.to_be_bytes());
1623        let frame = PiperFrame::new_standard(ID_JOINT_FEEDBACK_12 as u16, &data);
1624
1625        let feedback = JointFeedback12::try_from(frame).unwrap();
1626        assert_eq!(feedback.j1_raw(), max_positive);
1627        assert_eq!(feedback.j2_raw(), max_positive);
1628
1629        // 测试最大负值:i32::MIN / 1000 ≈ -2147483.648°
1630        let min_negative = i32::MIN;
1631        let mut data = [0u8; 8];
1632        data[0..4].copy_from_slice(&min_negative.to_be_bytes());
1633        data[4..8].copy_from_slice(&min_negative.to_be_bytes());
1634        let frame = PiperFrame::new_standard(ID_JOINT_FEEDBACK_12 as u16, &data);
1635
1636        let feedback = JointFeedback12::try_from(frame).unwrap();
1637        assert_eq!(feedback.j1_raw(), min_negative);
1638        assert_eq!(feedback.j2_raw(), min_negative);
1639    }
1640
1641    #[test]
1642    fn test_joint_feedback12_invalid_id() {
1643        let frame = PiperFrame::new_standard(0x999, &[0; 8]);
1644        let result = JointFeedback12::try_from(frame);
1645        assert!(result.is_err());
1646        match result.unwrap_err() {
1647            ProtocolError::InvalidCanId { id } => assert_eq!(id, 0x999),
1648            _ => panic!("Expected InvalidCanId error"),
1649        }
1650    }
1651
1652    #[test]
1653    fn test_joint_feedback12_invalid_length() {
1654        let frame = PiperFrame::new_standard(ID_JOINT_FEEDBACK_12 as u16, &[0; 4]);
1655        let result = JointFeedback12::try_from(frame);
1656        assert!(result.is_err());
1657        match result.unwrap_err() {
1658            ProtocolError::InvalidLength { expected, actual } => {
1659                assert_eq!(expected, 8);
1660                assert_eq!(actual, 4);
1661            },
1662            _ => panic!("Expected InvalidLength error"),
1663        }
1664    }
1665
1666    #[test]
1667    fn test_joint_feedback34_parse() {
1668        // 测试数据:J3 = 30.0° = 30000, J4 = -60.0° = -60000
1669        let j3_val = 30000i32;
1670        let j4_val = -60000i32;
1671        let mut data = [0u8; 8];
1672        data[0..4].copy_from_slice(&j3_val.to_be_bytes());
1673        data[4..8].copy_from_slice(&j4_val.to_be_bytes());
1674        let frame = PiperFrame::new_standard(ID_JOINT_FEEDBACK_34 as u16, &data);
1675
1676        let feedback = JointFeedback34::try_from(frame).unwrap();
1677        assert_eq!(feedback.j3_raw(), 30000);
1678        assert_eq!(feedback.j4_raw(), -60000);
1679        assert!((feedback.j3() - 30.0).abs() < 0.0001);
1680        assert!((feedback.j4() - (-60.0)).abs() < 0.0001);
1681    }
1682
1683    #[test]
1684    fn test_joint_feedback56_parse() {
1685        // 测试数据:J5 = 180.0° = 180000, J6 = -90.0° = -90000
1686        let j5_val = 180000i32;
1687        let j6_val = -90000i32;
1688        let mut data = [0u8; 8];
1689        data[0..4].copy_from_slice(&j5_val.to_be_bytes());
1690        data[4..8].copy_from_slice(&j6_val.to_be_bytes());
1691        let frame = PiperFrame::new_standard(ID_JOINT_FEEDBACK_56 as u16, &data);
1692
1693        let feedback = JointFeedback56::try_from(frame).unwrap();
1694        assert_eq!(feedback.j5_raw(), 180000);
1695        assert_eq!(feedback.j6_raw(), -90000);
1696        assert!((feedback.j5() - 180.0).abs() < 0.0001);
1697        assert!((feedback.j6() - (-90.0)).abs() < 0.0001);
1698    }
1699
1700    #[test]
1701    fn test_joint_feedback_roundtrip() {
1702        // 测试编码-解码循环(通过原始值验证)
1703        let test_cases = vec![
1704            (0i32, 0i32),
1705            (90000i32, -45000i32),
1706            (i32::MAX, i32::MIN),
1707            (180000i32, -90000i32),
1708        ];
1709
1710        for (j1_val, j2_val) in test_cases {
1711            let frame = PiperFrame::new_standard(
1712                ID_JOINT_FEEDBACK_12 as u16,
1713                &[
1714                    j1_val.to_be_bytes()[0],
1715                    j1_val.to_be_bytes()[1],
1716                    j1_val.to_be_bytes()[2],
1717                    j1_val.to_be_bytes()[3],
1718                    j2_val.to_be_bytes()[0],
1719                    j2_val.to_be_bytes()[1],
1720                    j2_val.to_be_bytes()[2],
1721                    j2_val.to_be_bytes()[3],
1722                ],
1723            );
1724
1725            let feedback = JointFeedback12::try_from(frame).unwrap();
1726            assert_eq!(feedback.j1_raw(), j1_val);
1727            assert_eq!(feedback.j2_raw(), j2_val);
1728        }
1729    }
1730
1731    // ========================================================================
1732    // 末端位姿反馈测试
1733    // ========================================================================
1734
1735    #[test]
1736    fn test_end_pose_feedback1_parse() {
1737        // 测试数据:X = 100.0mm = 100000 (0.001mm 单位),Y = -50.0mm = -50000
1738        let x_val = 100000i32;
1739        let y_val = -50000i32;
1740        let mut data = [0u8; 8];
1741        data[0..4].copy_from_slice(&x_val.to_be_bytes());
1742        data[4..8].copy_from_slice(&y_val.to_be_bytes());
1743        let frame = PiperFrame::new_standard(ID_END_POSE_1 as u16, &data);
1744
1745        let feedback = EndPoseFeedback1::try_from(frame).unwrap();
1746        assert_eq!(feedback.x_raw(), 100000);
1747        assert_eq!(feedback.y_raw(), -50000);
1748        assert!((feedback.x() - 100.0).abs() < 0.0001);
1749        assert!((feedback.y() - (-50.0)).abs() < 0.0001);
1750    }
1751
1752    #[test]
1753    fn test_end_pose_feedback1_unit_conversion() {
1754        // 测试单位转换(0.001mm -> mm)
1755        let x_val = 1234i32; // 1.234mm
1756        let y_val = -5678i32; // -5.678mm
1757        let mut data = [0u8; 8];
1758        data[0..4].copy_from_slice(&x_val.to_be_bytes());
1759        data[4..8].copy_from_slice(&y_val.to_be_bytes());
1760        let frame = PiperFrame::new_standard(ID_END_POSE_1 as u16, &data);
1761
1762        let feedback = EndPoseFeedback1::try_from(frame).unwrap();
1763        assert!((feedback.x() - 1.234).abs() < 0.0001);
1764        assert!((feedback.y() - (-5.678)).abs() < 0.0001);
1765    }
1766
1767    #[test]
1768    fn test_end_pose_feedback1_invalid_id() {
1769        let frame = PiperFrame::new_standard(0x999, &[0; 8]);
1770        let result = EndPoseFeedback1::try_from(frame);
1771        assert!(result.is_err());
1772    }
1773
1774    #[test]
1775    fn test_end_pose_feedback2_parse() {
1776        // 测试数据:Z = 200.0mm = 200000, RX = 45.0° = 45000
1777        let z_val = 200000i32;
1778        let rx_val = 45000i32;
1779        let mut data = [0u8; 8];
1780        data[0..4].copy_from_slice(&z_val.to_be_bytes());
1781        data[4..8].copy_from_slice(&rx_val.to_be_bytes());
1782        let frame = PiperFrame::new_standard(ID_END_POSE_2 as u16, &data);
1783
1784        let feedback = EndPoseFeedback2::try_from(frame).unwrap();
1785        assert_eq!(feedback.z_raw(), 200000);
1786        assert_eq!(feedback.rx_raw(), 45000);
1787        assert!((feedback.z() - 200.0).abs() < 0.0001);
1788        assert!((feedback.rx() - 45.0).abs() < 0.0001);
1789        assert!((feedback.rx_rad() - (45.0 * std::f64::consts::PI / 180.0)).abs() < 0.0001);
1790    }
1791
1792    #[test]
1793    fn test_end_pose_feedback3_parse() {
1794        // 测试数据:RY = 90.0° = 90000, RZ = -30.0° = -30000
1795        let ry_val = 90000i32;
1796        let rz_val = -30000i32;
1797        let mut data = [0u8; 8];
1798        data[0..4].copy_from_slice(&ry_val.to_be_bytes());
1799        data[4..8].copy_from_slice(&rz_val.to_be_bytes());
1800        let frame = PiperFrame::new_standard(ID_END_POSE_3 as u16, &data);
1801
1802        let feedback = EndPoseFeedback3::try_from(frame).unwrap();
1803        assert_eq!(feedback.ry_raw(), 90000);
1804        assert_eq!(feedback.rz_raw(), -30000);
1805        assert!((feedback.ry() - 90.0).abs() < 0.0001);
1806        assert!((feedback.rz() - (-30.0)).abs() < 0.0001);
1807    }
1808
1809    // ========================================================================
1810    // 关节驱动器高速反馈测试
1811    // ========================================================================
1812
1813    #[test]
1814    fn test_joint_driver_high_speed_feedback_parse() {
1815        // 测试数据:
1816        // - 关节1 (ID: 0x251)
1817        // - 速度: 1.5 rad/s = 1500 (0.001rad/s 单位)
1818        // - 电流: 2.5 A = 2500 (0.001A 单位)
1819        // - 位置: 根据协议单位是 rad(signed int32),直接返回 i32 转 f64
1820        let speed_val = 1500i16;
1821        let current_val = 2500u16;
1822        let position_val = 1000000i32; // 测试值,实际单位需要根据硬件确认
1823
1824        let mut data = [0u8; 8];
1825        data[0..2].copy_from_slice(&speed_val.to_be_bytes());
1826        data[2..4].copy_from_slice(&current_val.to_be_bytes());
1827        data[4..8].copy_from_slice(&position_val.to_be_bytes());
1828
1829        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16, &data);
1830        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1831
1832        assert_eq!(feedback.joint_index, 1);
1833        assert_eq!(feedback.speed_raw(), 1500);
1834        assert_eq!(feedback.current_raw(), 2500i16); // 电流现在是有符号 i16
1835        assert_eq!(feedback.position_raw(), 1000000);
1836        assert!((feedback.speed() - 1.5).abs() < 0.0001);
1837        assert!((feedback.current() - 2.5).abs() < 0.0001);
1838        // 位置单位:根据协议是 rad,但 i32 是整数,实际精度需要根据硬件确认
1839        assert_eq!(feedback.position(), 1000000.0);
1840    }
1841
1842    #[test]
1843    fn test_joint_driver_high_speed_feedback_all_joints() {
1844        // 测试所有 6 个关节的 ID 识别
1845        for joint_id in 1..=6 {
1846            let can_id = ID_JOINT_DRIVER_HIGH_SPEED_BASE + (joint_id - 1);
1847            let frame = PiperFrame::new_standard(can_id as u16, &[0; 8]);
1848            let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1849            assert_eq!(feedback.joint_index, joint_id as u8);
1850        }
1851    }
1852
1853    #[test]
1854    fn test_joint_driver_high_speed_feedback_physical_conversion() {
1855        // 测试物理量转换
1856        let speed_val = 3141i16; // 3.141 rad/s
1857        let current_val = 5000u16; // 5.0 A
1858        let position_val = 3141592i32; // 约 π rad(如果按 0.001rad 单位)
1859
1860        let mut data = [0u8; 8];
1861        data[0..2].copy_from_slice(&speed_val.to_be_bytes());
1862        data[2..4].copy_from_slice(&current_val.to_be_bytes());
1863        data[4..8].copy_from_slice(&position_val.to_be_bytes());
1864
1865        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16, &data);
1866        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1867
1868        assert!((feedback.speed() - std::f64::consts::PI).abs() < 0.001);
1869        assert!((feedback.current() - 5.0).abs() < 0.001);
1870        // 位置:根据协议单位是 rad,直接返回 i32 转 f64
1871        assert_eq!(feedback.position(), position_val as f64);
1872    }
1873
1874    #[test]
1875    fn test_joint_driver_high_speed_feedback_boundary_values() {
1876        // 测试边界值
1877        // 最大速度:i16::MAX = 32767 = 32.767 rad/s
1878        let speed_val = i16::MAX;
1879        let current_val = i16::MAX; // 32767 = 32.767 A(最大正电流)
1880        let position_val = i32::MAX;
1881
1882        let mut data = [0u8; 8];
1883        data[0..2].copy_from_slice(&speed_val.to_be_bytes());
1884        data[2..4].copy_from_slice(&current_val.to_be_bytes());
1885        data[4..8].copy_from_slice(&position_val.to_be_bytes());
1886
1887        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16, &data);
1888        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1889
1890        assert_eq!(feedback.speed_raw(), i16::MAX);
1891        assert_eq!(feedback.current_raw(), i16::MAX);
1892        assert_eq!(feedback.position_raw(), i32::MAX);
1893    }
1894
1895    #[test]
1896    fn test_joint_driver_high_speed_feedback_invalid_id() {
1897        // 测试无效的 CAN ID
1898        let frame = PiperFrame::new_standard(0x250, &[0; 8]); // 小于 0x251
1899        let result = JointDriverHighSpeedFeedback::try_from(frame);
1900        assert!(result.is_err());
1901
1902        let frame = PiperFrame::new_standard(0x257, &[0; 8]); // 大于 0x256
1903        let result = JointDriverHighSpeedFeedback::try_from(frame);
1904        assert!(result.is_err());
1905    }
1906
1907    #[test]
1908    fn test_joint_driver_high_speed_feedback_invalid_length() {
1909        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16, &[0; 4]);
1910        let result = JointDriverHighSpeedFeedback::try_from(frame);
1911        assert!(result.is_err());
1912        match result.unwrap_err() {
1913            ProtocolError::InvalidLength { expected, actual } => {
1914                assert_eq!(expected, 8);
1915                assert_eq!(actual, 4);
1916            },
1917            _ => panic!("Expected InvalidLength error"),
1918        }
1919    }
1920
1921    #[test]
1922    fn test_joint_driver_high_speed_feedback_negative_speed() {
1923        // 测试负速度(反向旋转)
1924        let speed_val = -1000i16; // -1.0 rad/s
1925        let current_val = 1000u16; // 1.0 A
1926        let position_val = 0i32;
1927
1928        let mut data = [0u8; 8];
1929        data[0..2].copy_from_slice(&speed_val.to_be_bytes());
1930        data[2..4].copy_from_slice(&current_val.to_be_bytes());
1931        data[4..8].copy_from_slice(&position_val.to_be_bytes());
1932
1933        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16, &data);
1934        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1935
1936        assert_eq!(feedback.speed_raw(), -1000);
1937        assert!((feedback.speed() - (-1.0)).abs() < 0.0001);
1938    }
1939
1940    #[test]
1941    fn test_joint_driver_high_speed_feedback_torque_joints_1_3() {
1942        // 测试关节 1-3 的力矩计算(使用系数 1.18125)
1943        // 关节 1 (CAN ID: 0x251)
1944        let current_val = 1000u16; // 1.0 A
1945        let mut data = [0u8; 8];
1946        data[2..4].copy_from_slice(&current_val.to_be_bytes());
1947
1948        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16, &data);
1949        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1950
1951        assert_eq!(feedback.joint_index, 1);
1952        let expected_torque = 1.0 * JointDriverHighSpeedFeedback::COEFFICIENT_1_3; // 1.18125 N·m
1953        assert!((feedback.torque(None) - expected_torque).abs() < 0.0001);
1954        assert_eq!(
1955            feedback.torque_raw(),
1956            (expected_torque * 1000.0).round() as i32
1957        );
1958
1959        // 关节 2 (CAN ID: 0x252)
1960        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16 + 1, &data);
1961        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1962        assert_eq!(feedback.joint_index, 2);
1963        assert!((feedback.torque(None) - expected_torque).abs() < 0.0001);
1964
1965        // 关节 3 (CAN ID: 0x253)
1966        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16 + 2, &data);
1967        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1968        assert_eq!(feedback.joint_index, 3);
1969        assert!((feedback.torque(None) - expected_torque).abs() < 0.0001);
1970    }
1971
1972    #[test]
1973    fn test_joint_driver_high_speed_feedback_torque_joints_4_6() {
1974        // 测试关节 4-6 的力矩计算(使用系数 0.95844)
1975        // 关节 4 (CAN ID: 0x254)
1976        let current_val = 1000u16; // 1.0 A
1977        let mut data = [0u8; 8];
1978        data[2..4].copy_from_slice(&current_val.to_be_bytes());
1979
1980        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16 + 3, &data);
1981        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1982
1983        assert_eq!(feedback.joint_index, 4);
1984        let expected_torque = 1.0 * JointDriverHighSpeedFeedback::COEFFICIENT_4_6; // 0.95844 N·m
1985        assert!((feedback.torque(None) - expected_torque).abs() < 0.0001);
1986        assert_eq!(
1987            feedback.torque_raw(),
1988            (expected_torque * 1000.0).round() as i32
1989        );
1990
1991        // 关节 5 (CAN ID: 0x255)
1992        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16 + 4, &data);
1993        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
1994        assert_eq!(feedback.joint_index, 5);
1995        assert!((feedback.torque(None) - expected_torque).abs() < 0.0001);
1996
1997        // 关节 6 (CAN ID: 0x256)
1998        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16 + 5, &data);
1999        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
2000        assert_eq!(feedback.joint_index, 6);
2001        assert!((feedback.torque(None) - expected_torque).abs() < 0.0001);
2002    }
2003
2004    #[test]
2005    fn test_joint_driver_high_speed_feedback_torque_with_custom_current() {
2006        // 测试使用自定义电流值计算力矩
2007        let current_val = 2000u16; // 2.0 A(反馈中的电流)
2008        let custom_current = 2.5; // 自定义电流值(A)
2009
2010        let mut data = [0u8; 8];
2011        data[2..4].copy_from_slice(&current_val.to_be_bytes());
2012
2013        // 关节 1:使用反馈中的电流值
2014        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16, &data);
2015        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
2016        let torque_from_feedback = feedback.torque(None);
2017        let expected_from_feedback = 2.0 * JointDriverHighSpeedFeedback::COEFFICIENT_1_3;
2018        assert!((torque_from_feedback - expected_from_feedback).abs() < 0.0001);
2019
2020        // 关节 1:使用自定义电流值
2021        let torque_from_custom = feedback.torque(Some(custom_current));
2022        let expected_from_custom = custom_current * JointDriverHighSpeedFeedback::COEFFICIENT_1_3;
2023        assert!((torque_from_custom - expected_from_custom).abs() < 0.0001);
2024
2025        // 关节 4:使用自定义电流值
2026        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16 + 3, &data);
2027        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
2028        let torque_from_custom = feedback.torque(Some(custom_current));
2029        let expected_from_custom = custom_current * JointDriverHighSpeedFeedback::COEFFICIENT_4_6;
2030        assert!((torque_from_custom - expected_from_custom).abs() < 0.0001);
2031    }
2032
2033    #[test]
2034    fn test_joint_driver_high_speed_feedback_torque_coefficients() {
2035        // 验证系数值与官方参考实现一致
2036        assert_eq!(JointDriverHighSpeedFeedback::COEFFICIENT_1_3, 1.18125);
2037        assert_eq!(JointDriverHighSpeedFeedback::COEFFICIENT_4_6, 0.95844);
2038
2039        // 测试具体计算值(与官方参考实现的 cal_effort 方法一致)
2040        // 示例:current = 1000 (0.001A 单位) = 1.0 A
2041        // 示例:effort = 1000 * 1.18125 = 1181.25 (0.001N·m 单位) = 1.18125 N·m
2042        let current_val = 1000u16; // 1.0 A
2043        let mut data = [0u8; 8];
2044        data[2..4].copy_from_slice(&current_val.to_be_bytes());
2045
2046        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_HIGH_SPEED_BASE as u16, &data);
2047        let feedback = JointDriverHighSpeedFeedback::try_from(frame).unwrap();
2048        let torque = feedback.torque(None);
2049        assert!((torque - 1.18125).abs() < 0.0001);
2050        assert_eq!(feedback.torque_raw(), 1181); // 四舍五入到整数
2051    }
2052
2053    // ========================================================================
2054    // 夹爪反馈测试
2055    // ========================================================================
2056
2057    #[test]
2058    fn test_gripper_status_bit_order() {
2059        // 测试:只有 Bit 0 和 Bit 6 被设置
2060        // Bit 0 = 1: 电压过低
2061        // Bit 6 = 1: 使能(注意:反向逻辑,1表示使能)
2062        // 期望字节值:0b0100_0001 = 0x41
2063        let byte = 0x41;
2064        let status = GripperStatus::from(u8::new(byte));
2065
2066        assert!(status.voltage_low(), "电压应该过低");
2067        assert!(!status.motor_over_temp(), "电机应该正常");
2068        assert!(status.enabled(), "应该使能(Bit 6 = 1)");
2069        assert!(!status.homed(), "应该没有回零");
2070    }
2071
2072    #[test]
2073    fn test_gripper_status_encode() {
2074        let mut status = GripperStatus::from(u8::new(0));
2075        status.set_voltage_low(true);
2076        status.set_enabled(true);
2077        status.set_homed(true);
2078
2079        let encoded = u8::from(status).value();
2080        // Bit 0, 6, 7 = 1: 0b1100_0001 = 0xC1
2081        assert_eq!(encoded, 0xC1);
2082    }
2083
2084    #[test]
2085    fn test_gripper_feedback_parse() {
2086        // 测试数据:
2087        // - 行程: 50.0mm = 50000 (0.001mm 单位)
2088        // - 扭矩: 2.5N·m = 2500 (0.001N·m 单位)
2089        // - 状态: 0b0100_0001 (电压过低,使能)
2090        let travel_val = 50000i32;
2091        let torque_val = 2500i16;
2092        let status_byte = 0x41u8;
2093
2094        let mut data = [0u8; 8];
2095        data[0..4].copy_from_slice(&travel_val.to_be_bytes());
2096        data[4..6].copy_from_slice(&torque_val.to_be_bytes());
2097        data[6] = status_byte;
2098
2099        let frame = PiperFrame::new_standard(ID_GRIPPER_FEEDBACK as u16, &data);
2100        let feedback = GripperFeedback::try_from(frame).unwrap();
2101
2102        assert_eq!(feedback.travel_raw(), 50000);
2103        assert_eq!(feedback.torque_raw(), 2500);
2104        assert!((feedback.travel() - 50.0).abs() < 0.0001);
2105        assert!((feedback.torque() - 2.5).abs() < 0.0001);
2106        assert!(feedback.status.voltage_low());
2107        assert!(feedback.status.enabled());
2108    }
2109
2110    #[test]
2111    fn test_gripper_feedback_invalid_id() {
2112        let frame = PiperFrame::new_standard(0x999, &[0; 8]);
2113        let result = GripperFeedback::try_from(frame);
2114        assert!(result.is_err());
2115    }
2116
2117    #[test]
2118    fn test_gripper_feedback_invalid_length() {
2119        let frame = PiperFrame::new_standard(ID_GRIPPER_FEEDBACK as u16, &[0; 4]);
2120        let result = GripperFeedback::try_from(frame);
2121        assert!(result.is_err());
2122    }
2123
2124    #[test]
2125    fn test_gripper_status_all_flags() {
2126        // 测试所有状态位
2127        let mut status = GripperStatus::from(u8::new(0));
2128        status.set_voltage_low(true);
2129        status.set_motor_over_temp(true);
2130        status.set_driver_over_current(true);
2131        status.set_driver_over_temp(true);
2132        status.set_sensor_error(true);
2133        status.set_driver_error(true);
2134        status.set_enabled(true);
2135        status.set_homed(true);
2136
2137        let encoded = u8::from(status).value();
2138        assert_eq!(encoded, 0xFF); // 所有位都是1
2139    }
2140
2141    // ========================================================================
2142    // 关节驱动器低速反馈测试
2143    // ========================================================================
2144
2145    #[test]
2146    fn test_driver_status_bit_order() {
2147        // 测试:Bit 0, 2, 4, 6 被设置
2148        // Bit 0 = 1: 电源电压过低
2149        // Bit 2 = 1: 驱动器过流
2150        // Bit 4 = 1: 碰撞保护触发
2151        // Bit 6 = 1: 驱动器使能
2152        // 期望字节值:0b0101_0101 = 0x55
2153        let byte = 0x55;
2154        let status = DriverStatus::from(u8::new(byte));
2155
2156        assert!(status.voltage_low(), "电源电压应该过低");
2157        assert!(!status.motor_over_temp(), "电机应该正常温度");
2158        assert!(status.driver_over_current(), "驱动器应该过流");
2159        assert!(status.collision_protection(), "碰撞保护应该触发");
2160        assert!(status.enabled(), "驱动器应该使能");
2161    }
2162
2163    #[test]
2164    fn test_driver_status_encode() {
2165        let mut status = DriverStatus::from(u8::new(0));
2166        status.set_voltage_low(true);
2167        status.set_driver_over_current(true);
2168        status.set_collision_protection(true);
2169        status.set_enabled(true);
2170
2171        let encoded = u8::from(status).value();
2172        // Bit 0, 2, 4, 6 = 1: 0b0101_0101 = 0x55
2173        assert_eq!(encoded, 0x55);
2174    }
2175
2176    #[test]
2177    fn test_joint_driver_low_speed_feedback_parse() {
2178        // 测试关节 1 (0x261)
2179        // 电压: 24.0V = 240 (0.1V 单位)
2180        // 驱动器温度: 45℃ = 45 (1℃ 单位)
2181        // 电机温度: 50℃ = 50 (1℃ 单位)
2182        // 状态: 0x44 (Bit 2=过流, Bit 6=使能)
2183        // 母线电流: 5.0A = 5000 (0.001A 单位)
2184        let voltage_val = 240u16;
2185        let driver_temp_val = 45i16;
2186        let motor_temp_val = 50i8;
2187        let status_byte = 0x44u8; // Bit 2=过流, Bit 6=使能
2188        let bus_current_val = 5000u16;
2189
2190        let mut data = [0u8; 8];
2191        data[0..2].copy_from_slice(&voltage_val.to_be_bytes());
2192        data[2..4].copy_from_slice(&driver_temp_val.to_be_bytes());
2193        data[4] = motor_temp_val as u8;
2194        data[5] = status_byte;
2195        data[6..8].copy_from_slice(&bus_current_val.to_be_bytes());
2196
2197        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_LOW_SPEED_BASE as u16, &data);
2198        let feedback = JointDriverLowSpeedFeedback::try_from(frame).unwrap();
2199
2200        assert_eq!(feedback.joint_index, 1);
2201        assert_eq!(feedback.voltage, 240);
2202        assert_eq!(feedback.driver_temp, 45);
2203        assert_eq!(feedback.motor_temp, 50);
2204        assert_eq!(feedback.bus_current, 5000);
2205        assert!(feedback.status.driver_over_current());
2206        assert!(feedback.status.enabled());
2207    }
2208
2209    #[test]
2210    fn test_joint_driver_low_speed_feedback_all_joints() {
2211        // 测试所有 6 个关节
2212        for i in 1..=6 {
2213            let id = ID_JOINT_DRIVER_LOW_SPEED_BASE + (i - 1) as u32;
2214            let mut data = [0u8; 8];
2215            data[0..2].copy_from_slice(&240u16.to_be_bytes()); // 24.0V
2216            data[2..4].copy_from_slice(&45i16.to_be_bytes()); // 45℃
2217            data[4] = 50; // 50℃
2218            data[5] = 0x40; // Bit 6=使能
2219
2220            let frame = PiperFrame::new_standard(id as u16, &data);
2221            let feedback = JointDriverLowSpeedFeedback::try_from(frame).unwrap();
2222            assert_eq!(feedback.joint_index, i);
2223        }
2224    }
2225
2226    #[test]
2227    fn test_joint_driver_low_speed_feedback_conversions() {
2228        let mut data = [0u8; 8];
2229        data[0..2].copy_from_slice(&240u16.to_be_bytes()); // 24.0V
2230        data[2..4].copy_from_slice(&45i16.to_be_bytes()); // 45℃
2231        data[4] = 50; // 50℃
2232        data[5] = 0x40; // Bit 6=使能
2233        data[6..8].copy_from_slice(&5000u16.to_be_bytes()); // 5.0A
2234
2235        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_LOW_SPEED_BASE as u16, &data);
2236        let feedback = JointDriverLowSpeedFeedback::try_from(frame).unwrap();
2237
2238        assert!((feedback.voltage() - 24.0).abs() < 0.01);
2239        assert!((feedback.driver_temp() - 45.0).abs() < 0.01);
2240        assert!((feedback.motor_temp() - 50.0).abs() < 0.01);
2241        assert!((feedback.bus_current() - 5.0).abs() < 0.001);
2242    }
2243
2244    #[test]
2245    fn test_joint_driver_low_speed_feedback_invalid_id() {
2246        let frame = PiperFrame::new_standard(0x999, &[0; 8]);
2247        let result = JointDriverLowSpeedFeedback::try_from(frame);
2248        assert!(result.is_err());
2249    }
2250
2251    #[test]
2252    fn test_joint_driver_low_speed_feedback_invalid_length() {
2253        let frame = PiperFrame::new_standard(ID_JOINT_DRIVER_LOW_SPEED_BASE as u16, &[0; 4]);
2254        let result = JointDriverLowSpeedFeedback::try_from(frame);
2255        assert!(result.is_err());
2256    }
2257
2258    // ========================================================================
2259    // 关节末端速度/加速度反馈测试
2260    // ========================================================================
2261
2262    #[test]
2263    fn test_joint_end_velocity_accel_feedback_parse() {
2264        // 测试关节 1 (0x481)
2265        let linear_vel = 1000u16; // 单位:0.001m/s = 1.0 m/s
2266        let angular_vel = 5000u16; // 单位:0.001rad/s = 5.0 rad/s
2267        let linear_accel = 2000u16; // 单位:0.001m/s² = 2.0 m/s²
2268        let angular_accel = 3000u16; // 单位:0.001rad/s² = 3.0 rad/s²
2269
2270        let mut data = [0u8; 8];
2271        data[0..2].copy_from_slice(&linear_vel.to_be_bytes());
2272        data[2..4].copy_from_slice(&angular_vel.to_be_bytes());
2273        data[4..6].copy_from_slice(&linear_accel.to_be_bytes());
2274        data[6..8].copy_from_slice(&angular_accel.to_be_bytes());
2275
2276        let frame = PiperFrame::new_standard(ID_JOINT_END_VELOCITY_ACCEL_BASE as u16, &data);
2277        let feedback = JointEndVelocityAccelFeedback::try_from(frame).unwrap();
2278
2279        assert_eq!(feedback.joint_index, 1);
2280        assert_eq!(feedback.linear_velocity_m_s_raw, 1000);
2281        assert_eq!(feedback.angular_velocity_rad_s_raw, 5000);
2282        assert_eq!(feedback.linear_accel_m_s2_raw, 2000);
2283        assert_eq!(feedback.angular_accel_rad_s2_raw, 3000);
2284    }
2285
2286    #[test]
2287    fn test_joint_end_velocity_accel_feedback_all_joints() {
2288        // 测试所有 6 个关节
2289        for i in 1..=6 {
2290            let id = ID_JOINT_END_VELOCITY_ACCEL_BASE + (i - 1) as u32;
2291            let mut data = [0u8; 8];
2292            data[0..2].copy_from_slice(&1000u16.to_be_bytes());
2293            data[2..4].copy_from_slice(&2000u16.to_be_bytes());
2294            data[4..6].copy_from_slice(&3000u16.to_be_bytes());
2295            data[6..8].copy_from_slice(&4000u16.to_be_bytes());
2296
2297            let frame = PiperFrame::new_standard(id as u16, &data);
2298            let feedback = JointEndVelocityAccelFeedback::try_from(frame).unwrap();
2299            assert_eq!(feedback.joint_index, i);
2300        }
2301    }
2302
2303    #[test]
2304    fn test_joint_end_velocity_accel_feedback_conversions() {
2305        let mut data = [0u8; 8];
2306        data[0..2].copy_from_slice(&1000u16.to_be_bytes()); // 1.0 m/s
2307        data[2..4].copy_from_slice(&2000u16.to_be_bytes()); // 2.0 rad/s
2308        data[4..6].copy_from_slice(&3000u16.to_be_bytes()); // 3.0 m/s²
2309        data[6..8].copy_from_slice(&4000u16.to_be_bytes()); // 4.0 rad/s²
2310
2311        let frame = PiperFrame::new_standard(ID_JOINT_END_VELOCITY_ACCEL_BASE as u16, &data);
2312        let feedback = JointEndVelocityAccelFeedback::try_from(frame).unwrap();
2313
2314        assert!((feedback.linear_velocity() - 1.0).abs() < 0.0001);
2315        assert!((feedback.angular_velocity() - 2.0).abs() < 0.0001);
2316        assert!((feedback.linear_accel() - 3.0).abs() < 0.0001);
2317        assert!((feedback.angular_accel() - 4.0).abs() < 0.0001);
2318    }
2319
2320    #[test]
2321    fn test_joint_end_velocity_accel_feedback_zero() {
2322        // 测试零值
2323        let data = [0u8; 8];
2324        let frame = PiperFrame::new_standard(ID_JOINT_END_VELOCITY_ACCEL_BASE as u16, &data);
2325        let feedback = JointEndVelocityAccelFeedback::try_from(frame).unwrap();
2326
2327        assert_eq!(feedback.linear_velocity_m_s_raw, 0);
2328        assert_eq!(feedback.angular_velocity_rad_s_raw, 0);
2329        assert_eq!(feedback.linear_accel_m_s2_raw, 0);
2330        assert_eq!(feedback.angular_accel_rad_s2_raw, 0);
2331        assert!((feedback.linear_velocity() - 0.0).abs() < 0.0001);
2332        assert!((feedback.angular_velocity() - 0.0).abs() < 0.0001);
2333    }
2334
2335    #[test]
2336    fn test_joint_end_velocity_accel_feedback_invalid_id() {
2337        let frame = PiperFrame::new_standard(0x999, &[0; 8]);
2338        let result = JointEndVelocityAccelFeedback::try_from(frame);
2339        assert!(result.is_err());
2340    }
2341
2342    #[test]
2343    fn test_joint_end_velocity_accel_feedback_invalid_length() {
2344        // 测试长度不足(需要 8 字节)
2345        let frame = PiperFrame::new_standard(ID_JOINT_END_VELOCITY_ACCEL_BASE as u16, &[0; 7]);
2346        let result = JointEndVelocityAccelFeedback::try_from(frame);
2347        assert!(result.is_err());
2348    }
2349}
2350
2351// ============================================================================
2352// 固件版本读取反馈结构体
2353// ============================================================================
2354
2355/// 固件版本读取反馈 (0x4AF)
2356///
2357/// 用于接收机械臂固件版本信息。
2358/// 注意:固件版本数据可能是分多个 CAN 帧传输的,需要累积接收。
2359#[derive(Debug, Clone, Default)]
2360pub struct FirmwareReadFeedback {
2361    pub firmware_data: [u8; 8],
2362}
2363
2364impl FirmwareReadFeedback {
2365    /// 获取固件数据原始字节
2366    pub fn firmware_data(&self) -> &[u8; 8] {
2367        &self.firmware_data
2368    }
2369
2370    /// 尝试从累积的固件数据中解析版本字符串
2371    ///
2372    /// 固件版本字符串通常以 "S-V" 开头,后面跟版本号。
2373    /// 此方法会在累积数据中查找版本字符串。
2374    ///
2375    /// # 参数
2376    /// - `accumulated_data`: 累积的固件数据(可能包含多个 CAN 帧的数据)
2377    ///
2378    /// # 返回值
2379    /// 如果找到版本字符串,返回 `Some(String)`,否则返回 `None`
2380    pub fn parse_version_string(accumulated_data: &[u8]) -> Option<String> {
2381        // 查找 "S-V" 标记
2382        if let Some(version_start) = accumulated_data.windows(3).position(|w| w == b"S-V") {
2383            // 从 "S-V" 后开始,查找版本字符串的结束位置(通常是换行符或字符串结束)
2384            let version_start = version_start + 3;
2385            let version_end = accumulated_data[version_start..]
2386                .iter()
2387                .position(|&b| b == b'\n' || b == b'\r' || b == 0)
2388                .map(|pos| version_start + pos)
2389                .unwrap_or(accumulated_data.len().min(version_start + 20)); // 最多读取20个字符
2390
2391            let version_bytes = &accumulated_data[version_start..version_end];
2392            String::from_utf8(version_bytes.to_vec()).ok().map(|s| s.trim().to_string())
2393        } else {
2394            None
2395        }
2396    }
2397}
2398
2399impl TryFrom<PiperFrame> for FirmwareReadFeedback {
2400    type Error = ProtocolError;
2401
2402    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
2403        // 验证 CAN ID
2404        if frame.id != ID_FIRMWARE_READ {
2405            return Err(ProtocolError::InvalidCanId { id: frame.id });
2406        }
2407
2408        // 验证数据长度(至少需要 1 字节,最多 8 字节)
2409        if frame.len == 0 {
2410            return Err(ProtocolError::InvalidLength {
2411                expected: 1,
2412                actual: 0,
2413            });
2414        }
2415
2416        let mut firmware_data = [0u8; 8];
2417        let copy_len = (frame.len as usize).min(8);
2418        firmware_data[..copy_len].copy_from_slice(&frame.data[..copy_len]);
2419
2420        Ok(Self { firmware_data })
2421    }
2422}
2423
2424#[cfg(test)]
2425mod firmware_read_tests {
2426    use super::*;
2427
2428    #[test]
2429    fn test_firmware_read_feedback_parse() {
2430        // 测试数据:包含 "S-V1.6-3" 版本字符串
2431        let data = b"S-V1.6-3";
2432        let frame = PiperFrame::new_standard(ID_FIRMWARE_READ as u16, data);
2433        let feedback = FirmwareReadFeedback::try_from(frame).unwrap();
2434
2435        assert_eq!(&feedback.firmware_data[..8], data);
2436    }
2437
2438    #[test]
2439    fn test_firmware_read_feedback_parse_version_string() {
2440        // 测试解析版本字符串
2441        let accumulated_data = b"Some prefix S-V1.6-3\nOther data";
2442        let version = FirmwareReadFeedback::parse_version_string(accumulated_data);
2443        assert_eq!(version, Some("1.6-3".to_string()));
2444    }
2445
2446    #[test]
2447    fn test_firmware_read_feedback_parse_version_string_not_found() {
2448        // 测试未找到版本字符串
2449        let accumulated_data = b"Some data without version";
2450        let version = FirmwareReadFeedback::parse_version_string(accumulated_data);
2451        assert_eq!(version, None);
2452    }
2453
2454    #[test]
2455    fn test_firmware_read_feedback_invalid_id() {
2456        let frame = PiperFrame::new_standard(0x999, &[0; 8]);
2457        let result = FirmwareReadFeedback::try_from(frame);
2458        assert!(result.is_err());
2459    }
2460
2461    #[test]
2462    fn test_firmware_read_feedback_empty_data() {
2463        let frame = PiperFrame::new_standard(ID_FIRMWARE_READ as u16, &[]);
2464        let result = FirmwareReadFeedback::try_from(frame);
2465        assert!(result.is_err());
2466    }
2467}
2468
2469// ============================================================================
2470// 主从模式控制指令反馈(用于接收主臂发送的控制指令)
2471// ============================================================================
2472
2473/// 主从模式控制模式指令反馈 (0x151)
2474///
2475/// 在主从模式下,示教输入臂会发送控制指令给运动输出臂。
2476/// 此反馈用于解析从示教输入臂接收到的控制模式指令。
2477///
2478/// 注意:此结构与 `ControlModeCommandFrame` 相同,但用于接收而非发送。
2479#[derive(Debug, Clone, Copy, Default)]
2480pub struct ControlModeCommandFeedback {
2481    pub control_mode: ControlModeCommand,
2482    pub move_mode: MoveMode,
2483    pub speed_percent: u8,
2484    pub mit_mode: MitMode,
2485    pub trajectory_stay_time: u8,
2486    pub install_position: InstallPosition,
2487}
2488
2489impl TryFrom<PiperFrame> for ControlModeCommandFeedback {
2490    type Error = ProtocolError;
2491
2492    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
2493        // 验证 CAN ID
2494        if frame.id != ID_CONTROL_MODE {
2495            return Err(ProtocolError::InvalidCanId { id: frame.id });
2496        }
2497
2498        // 验证数据长度
2499        if frame.len < 6 {
2500            return Err(ProtocolError::InvalidLength {
2501                expected: 6,
2502                actual: frame.len as usize,
2503            });
2504        }
2505
2506        Ok(Self {
2507            control_mode: ControlModeCommand::try_from(frame.data[0])?,
2508            move_mode: MoveMode::from(frame.data[1]),
2509            speed_percent: frame.data[2],
2510            mit_mode: MitMode::try_from(frame.data[3])?,
2511            trajectory_stay_time: frame.data[4],
2512            install_position: InstallPosition::try_from(frame.data[5])?,
2513        })
2514    }
2515}
2516
2517/// 主从模式关节控制指令反馈 (0x155-0x157)
2518///
2519/// 在主从模式下,示教输入臂会发送关节控制指令给运动输出臂。
2520/// 此反馈用于解析从示教输入臂接收到的关节控制指令。
2521#[derive(Debug, Clone, Copy, Default)]
2522pub struct JointControlFeedback {
2523    pub j1_deg: i32,
2524    pub j2_deg: i32,
2525    pub j3_deg: i32,
2526    pub j4_deg: i32,
2527    pub j5_deg: i32,
2528    pub j6_deg: i32,
2529}
2530
2531impl JointControlFeedback {
2532    /// 从 0x155 (J1-J2) 帧更新
2533    pub fn update_from_12(&mut self, feedback: JointControl12Feedback) {
2534        self.j1_deg = feedback.j1_deg;
2535        self.j2_deg = feedback.j2_deg;
2536    }
2537
2538    /// 从 0x156 (J3-J4) 帧更新
2539    pub fn update_from_34(&mut self, feedback: JointControl34Feedback) {
2540        self.j3_deg = feedback.j3_deg;
2541        self.j4_deg = feedback.j4_deg;
2542    }
2543
2544    /// 从 0x157 (J5-J6) 帧更新
2545    pub fn update_from_56(&mut self, feedback: JointControl56Feedback) {
2546        self.j5_deg = feedback.j5_deg;
2547        self.j6_deg = feedback.j6_deg;
2548    }
2549}
2550
2551/// 主从模式关节控制指令反馈12 (0x155)
2552#[derive(Debug, Clone, Copy, Default)]
2553pub struct JointControl12Feedback {
2554    pub j1_deg: i32,
2555    pub j2_deg: i32,
2556}
2557
2558impl TryFrom<PiperFrame> for JointControl12Feedback {
2559    type Error = ProtocolError;
2560
2561    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
2562        if frame.id != ID_JOINT_CONTROL_12 {
2563            return Err(ProtocolError::InvalidCanId { id: frame.id });
2564        }
2565
2566        if frame.len < 8 {
2567            return Err(ProtocolError::InvalidLength {
2568                expected: 8,
2569                actual: frame.len as usize,
2570            });
2571        }
2572
2573        let j1_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
2574        let j1_deg = bytes_to_i32_be(j1_bytes);
2575
2576        let j2_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
2577        let j2_deg = bytes_to_i32_be(j2_bytes);
2578
2579        Ok(Self { j1_deg, j2_deg })
2580    }
2581}
2582
2583/// 主从模式关节控制指令反馈34 (0x156)
2584#[derive(Debug, Clone, Copy, Default)]
2585pub struct JointControl34Feedback {
2586    pub j3_deg: i32,
2587    pub j4_deg: i32,
2588}
2589
2590impl TryFrom<PiperFrame> for JointControl34Feedback {
2591    type Error = ProtocolError;
2592
2593    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
2594        if frame.id != ID_JOINT_CONTROL_34 {
2595            return Err(ProtocolError::InvalidCanId { id: frame.id });
2596        }
2597
2598        if frame.len < 8 {
2599            return Err(ProtocolError::InvalidLength {
2600                expected: 8,
2601                actual: frame.len as usize,
2602            });
2603        }
2604
2605        let j3_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
2606        let j3_deg = bytes_to_i32_be(j3_bytes);
2607
2608        let j4_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
2609        let j4_deg = bytes_to_i32_be(j4_bytes);
2610
2611        Ok(Self { j3_deg, j4_deg })
2612    }
2613}
2614
2615/// 主从模式关节控制指令反馈56 (0x157)
2616#[derive(Debug, Clone, Copy, Default)]
2617pub struct JointControl56Feedback {
2618    pub j5_deg: i32,
2619    pub j6_deg: i32,
2620}
2621
2622impl TryFrom<PiperFrame> for JointControl56Feedback {
2623    type Error = ProtocolError;
2624
2625    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
2626        if frame.id != ID_JOINT_CONTROL_56 {
2627            return Err(ProtocolError::InvalidCanId { id: frame.id });
2628        }
2629
2630        if frame.len < 8 {
2631            return Err(ProtocolError::InvalidLength {
2632                expected: 8,
2633                actual: frame.len as usize,
2634            });
2635        }
2636
2637        let j5_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
2638        let j5_deg = bytes_to_i32_be(j5_bytes);
2639
2640        let j6_bytes = [frame.data[4], frame.data[5], frame.data[6], frame.data[7]];
2641        let j6_deg = bytes_to_i32_be(j6_bytes);
2642
2643        Ok(Self { j5_deg, j6_deg })
2644    }
2645}
2646
2647/// 主从模式夹爪控制指令反馈 (0x159)
2648///
2649/// 在主从模式下,示教输入臂会发送夹爪控制指令给运动输出臂。
2650#[derive(Debug, Clone, Copy, Default)]
2651pub struct GripperControlFeedback {
2652    pub travel_mm: i32,
2653    pub torque_nm: i16,
2654    pub status_code: u8,
2655    pub set_zero: u8,
2656}
2657
2658impl TryFrom<PiperFrame> for GripperControlFeedback {
2659    type Error = ProtocolError;
2660
2661    fn try_from(frame: PiperFrame) -> Result<Self, Self::Error> {
2662        if frame.id != ID_GRIPPER_CONTROL {
2663            return Err(ProtocolError::InvalidCanId { id: frame.id });
2664        }
2665
2666        if frame.len < 8 {
2667            return Err(ProtocolError::InvalidLength {
2668                expected: 8,
2669                actual: frame.len as usize,
2670            });
2671        }
2672
2673        let travel_bytes = [frame.data[0], frame.data[1], frame.data[2], frame.data[3]];
2674        let travel_mm = bytes_to_i32_be(travel_bytes);
2675
2676        let torque_bytes = [frame.data[4], frame.data[5]];
2677        let torque_nm = bytes_to_i16_be(torque_bytes);
2678
2679        Ok(Self {
2680            travel_mm,
2681            torque_nm,
2682            status_code: frame.data[6],
2683            set_zero: frame.data[7],
2684        })
2685    }
2686}