1use glam_traits_ext::{FloatAffine, FloatVec, TAffine3, TVec3};
2
3use crate::SRobotQ;
4
5use super::{AAffine3, AVec3, FKChain, FKScalar};
6
7#[derive(Debug, Clone)]
21pub struct PrismaticFK<const M: usize, const N: usize, F: FKScalar, FK: FKChain<N, F>> {
22 inner: FK,
23 axis: AVec3<F>,
24 q_index_first: bool,
25}
26
27impl<const M: usize, const N: usize, F: FKScalar, FK: FKChain<N, F>> PrismaticFK<M, N, F, FK> {
28 pub fn new(inner: FK, axis: AVec3<F>, q_index_first: bool) -> Self {
29 const { assert!(M == N + 1, "M must equal N + 1") };
30 Self {
31 inner,
32 axis,
33 q_index_first,
34 }
35 }
36
37 pub fn inner(&self) -> &FK {
38 &self.inner
39 }
40
41 pub fn axis(&self) -> AVec3<F> {
42 self.axis
43 }
44
45 pub fn q_index_first(&self) -> bool {
46 self.q_index_first
47 }
48
49 fn split_q(&self, q: &SRobotQ<M, F>) -> (F, SRobotQ<N, F>) {
50 let mut inner = [F::zero(); N];
51 if self.q_index_first {
52 inner.copy_from_slice(&q.0[1..M]);
53 (q.0[0], SRobotQ(inner))
54 } else {
55 inner.copy_from_slice(&q.0[..N]);
56 (q.0[M - 1], SRobotQ(inner))
57 }
58 }
59
60 fn prismatic_col(&self) -> usize {
61 if self.q_index_first { 0 } else { N }
62 }
63
64 fn revolute_offset(&self) -> usize {
65 if self.q_index_first { 1 } else { 0 }
66 }
67}
68
69impl<const M: usize, const N: usize, F: FKScalar, FK: FKChain<N, F>> FKChain<M, F>
70 for PrismaticFK<M, N, F, FK>
71{
72 type Error = FK::Error;
73
74 fn base_tf(&self) -> AAffine3<F> {
75 self.inner.base_tf()
76 }
77
78 fn fk(&self, q: &SRobotQ<M, F>) -> Result<[AAffine3<F>; M], Self::Error> {
79 let (q_p, inner_q) = self.split_q(q);
80 let offset = self.axis * q_p;
81 let inner_frames = self.inner.fk(&inner_q)?;
82 let mut out = [AAffine3::<F>::IDENTITY; M];
83
84 out[0] = AAffine3::<F>::from_translation(offset);
85 for i in 0..N {
86 let mut f = inner_frames[i];
87 f = AAffine3::<F>::from_mat3_translation(f.matrix3(), f.translation() + offset);
90 out[i + 1] = f;
91 }
92
93 Ok(out)
94 }
95
96 fn fk_end(&self, q: &SRobotQ<M, F>) -> Result<AAffine3<F>, Self::Error> {
97 let (q_p, inner_q) = self.split_q(q);
98 let end = self.inner.fk_end(&inner_q)?;
99 let offset = self.axis * q_p;
100 Ok(AAffine3::<F>::from_mat3_translation(
101 end.matrix3(),
102 end.translation() + offset,
103 ))
104 }
105
106 fn all_fk(
107 &self,
108 q: &SRobotQ<M, F>,
109 ) -> Result<(AAffine3<F>, [AAffine3<F>; M], AAffine3<F>), Self::Error> {
110 let (q_p, inner_q) = self.split_q(q);
111 let offset = self.axis * q_p;
112 let (inner_base, inner_frames, inner_end) = self.inner.all_fk(&inner_q)?;
113
114 let mut frames = [AAffine3::<F>::IDENTITY; M];
115 frames[0] = AAffine3::<F>::from_translation(offset);
116 for i in 0..N {
117 let f = inner_frames[i];
118 frames[i + 1] = AAffine3::<F>::from_mat3_translation(
119 f.matrix3(),
120 f.translation() + offset,
121 );
122 }
123
124 let end = AAffine3::<F>::from_mat3_translation(
125 inner_end.matrix3(),
126 inner_end.translation() + offset,
127 );
128
129 Ok((inner_base, frames, end))
130 }
131
132 fn joint_axes_positions(
133 &self,
134 q: &SRobotQ<M, F>,
135 ) -> Result<([AVec3<F>; M], [AVec3<F>; M], AVec3<F>), Self::Error> {
136 let (q_p, inner_q) = self.split_q(q);
137 let offset = self.axis * q_p;
138 let (inner_axes, inner_pos, inner_p_ee) = self.inner.joint_axes_positions(&inner_q)?;
139
140 let mut axes = [AVec3::<F>::ZERO; M];
141 let mut positions = [AVec3::<F>::ZERO; M];
142
143 axes[0] = self.axis;
144 for i in 0..N {
145 axes[i + 1] = inner_axes[i];
146 positions[i + 1] = inner_pos[i] + offset;
147 }
148
149 Ok((axes, positions, inner_p_ee + offset))
150 }
151
152 fn jacobian(&self, q: &SRobotQ<M, F>) -> Result<[[F; M]; 6], Self::Error> {
153 let (_q_p, inner_q) = self.split_q(q);
154 let inner_j = self.inner.jacobian(&inner_q)?;
155 let p_col = self.prismatic_col();
156 let r_off = self.revolute_offset();
157
158 let mut j = [[F::zero(); M]; 6];
159 j[0][p_col] = self.axis.x();
160 j[1][p_col] = self.axis.y();
161 j[2][p_col] = self.axis.z();
162
163 for row in 0..6 {
164 for col in 0..N {
165 j[row][col + r_off] = inner_j[row][col];
166 }
167 }
168
169 Ok(j)
170 }
171
172 fn jacobian_dot(
173 &self,
174 q: &SRobotQ<M, F>,
175 qdot: &SRobotQ<M, F>,
176 ) -> Result<[[F; M]; 6], Self::Error> {
177 let (_q_p, inner_q) = self.split_q(q);
178 let (_qdot_p, inner_qdot) = self.split_q(qdot);
179 let inner_jd = self.inner.jacobian_dot(&inner_q, &inner_qdot)?;
180 let r_off = self.revolute_offset();
181
182 let mut jd = [[F::zero(); M]; 6];
183 for row in 0..6 {
184 for col in 0..N {
185 jd[row][col + r_off] = inner_jd[row][col];
186 }
187 }
188
189 Ok(jd)
190 }
191
192 fn jacobian_ddot(
193 &self,
194 q: &SRobotQ<M, F>,
195 qdot: &SRobotQ<M, F>,
196 qddot: &SRobotQ<M, F>,
197 ) -> Result<[[F; M]; 6], Self::Error> {
198 let (_q_p, inner_q) = self.split_q(q);
199 let (_qdot_p, inner_qdot) = self.split_q(qdot);
200 let (_qddot_p, inner_qddot) = self.split_q(qddot);
201 let inner_jdd = self
202 .inner
203 .jacobian_ddot(&inner_q, &inner_qdot, &inner_qddot)?;
204 let r_off = self.revolute_offset();
205
206 let mut jdd = [[F::zero(); M]; 6];
207 for row in 0..6 {
208 for col in 0..N {
209 jdd[row][col + r_off] = inner_jdd[row][col];
210 }
211 }
212
213 Ok(jdd)
214 }
215}
216
217impl<const M: usize, const N: usize, FK32, FK64> From<PrismaticFK<M, N, f32, FK32>>
218 for PrismaticFK<M, N, f64, FK64>
219where
220 FK32: FKChain<N, f32>,
221 FK64: FKChain<N, f64> + From<FK32>,
222{
223 #[inline]
224 fn from(p: PrismaticFK<M, N, f32, FK32>) -> Self {
225 PrismaticFK {
226 inner: FK64::from(p.inner),
227 axis: p.axis.as_dvec3(),
228 q_index_first: p.q_index_first,
229 }
230 }
231}
232
233impl<const M: usize, const N: usize, FK64, FK32> From<PrismaticFK<M, N, f64, FK64>>
234 for PrismaticFK<M, N, f32, FK32>
235where
236 FK64: FKChain<N, f64>,
237 FK32: FKChain<N, f32> + From<FK64>,
238{
239 #[inline]
240 fn from(p: PrismaticFK<M, N, f64, FK64>) -> Self {
241 PrismaticFK {
242 inner: FK32::from(p.inner),
243 axis: p.axis.as_vec3a(),
244 q_index_first: p.q_index_first,
245 }
246 }
247}