1use crate::SRobotQ;
2
3use super::{AAffine3, AVec3, FKChain};
4
5#[derive(Debug, Clone)]
42pub struct FPDispatch<const N: usize, FK32, FK64>
43where
44 FK32: FKChain<N, f32>,
45 FK64: FKChain<N, f64>,
46{
47 f32_chain: FK32,
48 f64_chain: FK64,
49}
50
51impl<const N: usize, FK32, FK64> FPDispatch<N, FK32, FK64>
52where
53 FK32: FKChain<N, f32>,
54 FK64: FKChain<N, f64>,
55{
56 pub fn new(f32_chain: FK32, f64_chain: FK64) -> Self {
59 Self { f32_chain, f64_chain }
60 }
61
62 pub fn f32_chain(&self) -> &FK32 {
63 &self.f32_chain
64 }
65
66 pub fn f64_chain(&self) -> &FK64 {
67 &self.f64_chain
68 }
69}
70
71impl<const N: usize, FK32, FK64> FPDispatch<N, FK32, FK64>
72where
73 FK32: FKChain<N, f32> + From<FK64>,
74 FK64: FKChain<N, f64> + Clone,
75{
76 pub fn from_f64(f64_chain: FK64) -> Self {
80 let f32_chain = FK32::from(f64_chain.clone());
81 Self { f32_chain, f64_chain }
82 }
83}
84
85impl<const N: usize, FK32, FK64> FKChain<N, f32> for FPDispatch<N, FK32, FK64>
86where
87 FK32: FKChain<N, f32>,
88 FK64: FKChain<N, f64>,
89{
90 type Error = FK32::Error;
91
92 fn base_tf(&self) -> AAffine3<f32> {
93 self.f32_chain.base_tf()
94 }
95
96 fn max_reach(&self) -> Result<f32, Self::Error> {
97 self.f32_chain.max_reach()
98 }
99
100 fn fk(&self, q: &SRobotQ<N, f32>) -> Result<[AAffine3<f32>; N], Self::Error> {
101 self.f32_chain.fk(q)
102 }
103
104 fn fk_end(&self, q: &SRobotQ<N, f32>) -> Result<AAffine3<f32>, Self::Error> {
105 self.f32_chain.fk_end(q)
106 }
107
108 fn joint_axes_positions(
109 &self,
110 q: &SRobotQ<N, f32>,
111 ) -> Result<([AVec3<f32>; N], [AVec3<f32>; N], AVec3<f32>), Self::Error> {
112 self.f32_chain.joint_axes_positions(q)
113 }
114
115 fn jacobian(&self, q: &SRobotQ<N, f32>) -> Result<[[f32; N]; 6], Self::Error> {
116 self.f32_chain.jacobian(q)
117 }
118
119 fn jacobian_dot(
120 &self,
121 q: &SRobotQ<N, f32>,
122 qdot: &SRobotQ<N, f32>,
123 ) -> Result<[[f32; N]; 6], Self::Error> {
124 self.f32_chain.jacobian_dot(q, qdot)
125 }
126
127 fn jacobian_ddot(
128 &self,
129 q: &SRobotQ<N, f32>,
130 qdot: &SRobotQ<N, f32>,
131 qddot: &SRobotQ<N, f32>,
132 ) -> Result<[[f32; N]; 6], Self::Error> {
133 self.f32_chain.jacobian_ddot(q, qdot, qddot)
134 }
135}
136
137impl<const N: usize, FK32, FK64> FKChain<N, f64> for FPDispatch<N, FK32, FK64>
138where
139 FK32: FKChain<N, f32>,
140 FK64: FKChain<N, f64>,
141{
142 type Error = FK64::Error;
143
144 fn base_tf(&self) -> AAffine3<f64> {
145 self.f64_chain.base_tf()
146 }
147
148 fn max_reach(&self) -> Result<f64, Self::Error> {
149 self.f64_chain.max_reach()
150 }
151
152 fn fk(&self, q: &SRobotQ<N, f64>) -> Result<[AAffine3<f64>; N], Self::Error> {
153 self.f64_chain.fk(q)
154 }
155
156 fn fk_end(&self, q: &SRobotQ<N, f64>) -> Result<AAffine3<f64>, Self::Error> {
157 self.f64_chain.fk_end(q)
158 }
159
160 fn joint_axes_positions(
161 &self,
162 q: &SRobotQ<N, f64>,
163 ) -> Result<([AVec3<f64>; N], [AVec3<f64>; N], AVec3<f64>), Self::Error> {
164 self.f64_chain.joint_axes_positions(q)
165 }
166
167 fn jacobian(&self, q: &SRobotQ<N, f64>) -> Result<[[f64; N]; 6], Self::Error> {
168 self.f64_chain.jacobian(q)
169 }
170
171 fn jacobian_dot(
172 &self,
173 q: &SRobotQ<N, f64>,
174 qdot: &SRobotQ<N, f64>,
175 ) -> Result<[[f64; N]; 6], Self::Error> {
176 self.f64_chain.jacobian_dot(q, qdot)
177 }
178
179 fn jacobian_ddot(
180 &self,
181 q: &SRobotQ<N, f64>,
182 qdot: &SRobotQ<N, f64>,
183 qddot: &SRobotQ<N, f64>,
184 ) -> Result<[[f64; N]; 6], Self::Error> {
185 self.f64_chain.jacobian_ddot(q, qdot, qddot)
186 }
187}
188
189#[cfg(test)]
190mod tests {
191 use super::*;
192 use crate::{DHChain, DHJoint};
193 use glam_traits_ext::{TAffine3, TVec3};
194
195 #[test]
196 fn dispatch_routes_to_correct_precision() {
197 const F32_CHAIN: DHChain<2, f32> = DHChain::<2, f32>::new([
198 DHJoint { a: 1.0, alpha: 0.0, d: 0.0, theta_offset: 0.0 },
199 DHJoint { a: 1.0, alpha: 0.0, d: 0.0, theta_offset: 0.0 },
200 ]);
201 const F64_CHAIN: DHChain<2, f64> = DHChain::<2, f64>::new_f64([
202 DHJoint { a: 1.0, alpha: 0.0, d: 0.0, theta_offset: 0.0 },
203 DHJoint { a: 1.0, alpha: 0.0, d: 0.0, theta_offset: 0.0 },
204 ]);
205
206 let dispatch = FPDispatch::new(F32_CHAIN, F64_CHAIN);
207
208 let q32 = SRobotQ::<2, f32>::from_array([0.5, -0.3]);
209 let q64 = SRobotQ::<2, f64>::from_array([0.5, -0.3]);
210
211 let end32 = <FPDispatch<_, _, _> as FKChain<2, f32>>::fk_end(&dispatch, &q32)
212 .unwrap()
213 .translation();
214 let end64 = <FPDispatch<_, _, _> as FKChain<2, f64>>::fk_end(&dispatch, &q64)
215 .unwrap()
216 .translation();
217
218 assert!((end32.x() as f64 - end64.x()).abs() < 1e-5);
219 assert!((end32.y() as f64 - end64.y()).abs() < 1e-5);
220 }
221
222 #[test]
223 fn from_f64_derives_f32_chain() {
224 const F64_CHAIN: DHChain<2, f64> = DHChain::<2, f64>::new_f64([
225 DHJoint { a: 1.0, alpha: 0.0, d: 0.0, theta_offset: 0.0 },
226 DHJoint { a: 1.0, alpha: 0.0, d: 0.0, theta_offset: 0.0 },
227 ]);
228
229 let dispatch: FPDispatch<2, DHChain<2, f32>, DHChain<2, f64>> =
230 FPDispatch::from_f64(F64_CHAIN);
231
232 let q32 = SRobotQ::<2, f32>::from_array([0.5, -0.3]);
233 let q64 = SRobotQ::<2, f64>::from_array([0.5, -0.3]);
234 let end32 = <FPDispatch<_, _, _> as FKChain<2, f32>>::fk_end(&dispatch, &q32)
235 .unwrap()
236 .translation();
237 let end64 = <FPDispatch<_, _, _> as FKChain<2, f64>>::fk_end(&dispatch, &q64)
238 .unwrap()
239 .translation();
240 assert!((end32.x() as f64 - end64.x()).abs() < 1e-4);
241 assert!((end32.y() as f64 - end64.y()).abs() < 1e-4);
242 }
243}