1use crate::chains::Chain;
18use crate::geometry::{Frame, Introspection, Twist};
19use crate::joint::JointType;
20
21pub fn reference_frame(
25 total_twist: Twist,
26 segment_twist: Twist,
27 total_pose: Frame,
28 segment_pose: Frame,
29) -> Twist {
30 let rotation = total_pose.get_rotation();
31 let rot = rotation * segment_twist.fixed_rows::<3>(3);
32 let tmp = rotation * segment_pose.get_translation();
33 let trans =
34 rotation * segment_twist.fixed_rows::<3>(0) + total_twist.fixed_rows::<3>(3).cross(&tmp);
35
36 Twist::new(trans[0], trans[1], trans[2], rot[0], rot[1], rot[2])
37}
38
39#[derive(Clone, Debug)]
42pub struct ForwardDiffKinematicsSolver {
43 chain: Chain,
44}
45
46impl ForwardDiffKinematicsSolver {
47 pub fn default() -> Self {
49 Self {
50 chain: Chain::default(),
51 }
52 }
53
54 pub fn new(in_chain: Chain) -> Self {
56 Self { chain: in_chain }
57 }
58
59 pub fn solve_at_segment(
67 &self,
68 angles: &Vec<f64>,
69 qdots: &Vec<f64>,
70 segment_index: usize,
71 ) -> Twist {
72 let num_joints = self.chain.get_num_joints();
73 let num_segments = self.chain.get_num_segments();
74 if num_joints != angles.len() {
75 panic!(
76 "Got {} angles, but the chain has {} joints",
77 angles.len(),
78 num_joints
79 );
80 }
81
82 if num_joints != qdots.len() {
83 panic!(
84 "Got {} angle differentials, but the chain has {} joints",
85 qdots.len(),
86 num_joints
87 );
88 }
89
90 if segment_index >= num_segments {
91 panic!(
92 "Asked for pose at segment {}, but the chain has {} segments",
93 segment_index, num_segments
94 );
95 }
96 let mut counter = 0;
97 let mut result_pose = Frame::identity();
98 let mut result_twist = Twist::zeros();
99
100 for i in 0..segment_index + 1 {
101 let segment = self.chain.get_segment(i);
102 let pose = segment.pose(angles[counter]);
103 let twist = segment.twist(angles[counter], qdots[counter]);
104 result_twist += reference_frame(result_twist, twist, result_pose, pose);
105 result_pose *= pose;
106 if segment.get_joint_type() != JointType::NoJoint {
107 counter += 1;
108 }
109 }
110 result_twist
111 }
112
113 pub fn solve(&self, angles: &Vec<f64>, qdots: &Vec<f64>) -> Twist {
116 self.solve_at_segment(angles, qdots, self.chain.get_num_segments() - 1)
117 }
118}
119
120#[cfg(test)]
121mod test {
122 use crate::chains::tests::create_testing_chain;
123 use crate::forward_diff_kinematics::ForwardDiffKinematicsSolver;
124 use crate::geometry::{get_twist_error, Twist};
125
126 #[test]
127 fn base_twist_correct() {
128 let chain = create_testing_chain();
129 let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
130 let qdots = vec![1.0, -0.65, 0.87, 0.01, -0.41, -0.98, 0.24];
131 let solver = ForwardDiffKinematicsSolver::new(chain);
132 let base_twist = solver.solve_at_segment(&angles, &qdots, 0);
133 assert_eq!(base_twist, Twist::zeros())
134 }
135
136 #[test]
137 fn end_twist_correct() {
138 let chain = create_testing_chain();
139 let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
140 let qdots = vec![1.0, -0.65, 0.87, 0.01, -0.41, -0.98, 0.24];
141 let solver = ForwardDiffKinematicsSolver::new(chain);
142 let end_twist = solver.solve(&angles, &qdots);
143 let error = get_twist_error(
144 end_twist,
145 Twist::new(-0.423878, -1.01074, 0.123592, -2.28297, 0.209941, 1.80897),
146 );
147 assert!(error < 0.00001)
148 }
149
150 #[test]
151 fn middle_twist_correct() {
152 let chain = create_testing_chain();
153 let angles = vec![0.1, -0.95, 0.57, 0.68, -0.27, 0.39, 0.47];
154 let qdots = vec![1.0, -0.65, 0.87, 0.01, -0.41, -0.98, 0.24];
155 let solver = ForwardDiffKinematicsSolver::new(chain);
156 let middle_twist = solver.solve_at_segment(&angles, &qdots, 4);
157 let error = get_twist_error(
158 middle_twist,
159 Twist::new(-0.344006, 0.591387, 0.0751308, -1.1035, -0.0710371, 1.45781),
160 );
161 assert!(error < 0.00001)
162 }
163}