Skip to main content

piper_protocol/
feedback.rs

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