1use {
2 super::{
3 auxiliary::{Kinematics, Matrix3x7},
4 gen_six_dof, spherical, spherical_two_intersecting, spherical_two_parallel, three_parallel,
5 three_parallel_two_intersecting, two_intersecting, two_parallel,
6 },
7 crate::subproblems::{
8 auxiliary::{random_angle, random_norm_vector3, random_vector3},
9 setups::SetupStatic,
10 },
11 nalgebra::{Matrix3, Matrix3x6, Vector3, Vector6},
12 std::f64::NAN,
13};
14
15pub trait SetupIk {
16 fn setup(&mut self);
17 fn setup_from_str(&mut self, raw: &str);
18 fn write_output(&self) -> String;
19 fn run(&mut self);
20 fn error(&self) -> f64;
21 fn ls_count(&self) -> usize;
22 fn solution_count(&self) -> usize;
23 fn name(&self) -> &'static str;
24 fn debug(&self, i: usize);
25}
26
27macro_rules! define_struct {
28 ($name:ident) => {
29 pub struct $name {
30 kin: Kinematics<6, 7>,
31 r: Matrix3<f64>,
32 t: Vector3<f64>,
33
34 q: Vec<Vector6<f64>>,
35 is_ls: Vec<bool>,
36 }
37 };
38}
39
40define_struct!(SphericalTwoParallelSetup);
42define_struct!(SphericalTwoIntersectingSetup);
43define_struct!(SphericalSetup);
44define_struct!(ThreeParallelTwoIntersectingSetup);
45define_struct!(ThreeParallelSetup);
46define_struct!(TwoParallelSetup);
47define_struct!(TwoIntersectingSetup);
48define_struct!(GenSixDofSetup);
49
50pub fn calculate_ik_error(
51 kin: &Kinematics<6, 7>,
52 r: &Matrix3<f64>,
53 t: &Vector3<f64>,
54 q: &Vector6<f64>,
55) -> f64 {
56 let (r_t, t_t) = kin.forward_kinematics(q);
57 (r_t - r).norm() + (t_t - t).norm()
58}
59
60fn ik_setup_from_string(
61 raw: &str,
62 kin: &mut Kinematics<6, 7>,
63 r: &mut Matrix3<f64>,
64 t: &mut Vector3<f64>,
65) {
66 let data: Vec<f64> = raw.split(',').map(|s| s.parse().unwrap()).collect();
67
68 kin.h = Matrix3x6::from_columns(&[
69 Vector3::new(data[0], data[1], data[2]),
70 Vector3::new(data[3], data[4], data[5]),
71 Vector3::new(data[6], data[7], data[8]),
72 Vector3::new(data[9], data[10], data[11]),
73 Vector3::new(data[12], data[13], data[14]),
74 Vector3::new(data[15], data[16], data[17]),
75 ]);
76
77 kin.p = Matrix3x7::from_columns(&[
78 Vector3::new(data[18], data[19], data[20]),
79 Vector3::new(data[21], data[22], data[23]),
80 Vector3::new(data[24], data[25], data[26]),
81 Vector3::new(data[27], data[28], data[29]),
82 Vector3::new(data[30], data[31], data[32]),
83 Vector3::new(data[33], data[34], data[35]),
84 Vector3::new(data[36], data[37], data[38]),
85 ]);
86
87 *r = Matrix3::new(
88 data[39], data[40], data[41], data[42], data[43], data[44], data[45], data[46], data[47],
89 );
90
91 *t = Vector3::new(data[48], data[49], data[50]);
92}
93
94pub fn ik_write_output(q: &Vec<Vector6<f64>>) -> String {
95 q.iter()
96 .map(|q| {
97 q.iter()
98 .map(|x| x.to_string())
99 .collect::<Vec<String>>()
100 .join(",")
101 })
102 .collect::<Vec<String>>()
103 .join(",")
104}
105
106macro_rules! impl_setup_static {
108 ($name:ident, $long_name:expr) => {
109 impl SetupStatic for $name {
110 fn new() -> Self {
111 Self {
112 kin: Kinematics::new(),
113 r: Matrix3::zeros(),
114 t: Vector3::zeros(),
115
116 q: Vec::new(),
117 is_ls: Vec::new(),
118 }
119 }
120
121 fn name() -> &'static str {
122 $long_name
123 }
124 }
125 };
126}
127
128impl_setup_static!(SphericalTwoParallelSetup, "Spherical two Parallel");
129impl_setup_static!(SphericalTwoIntersectingSetup, "Spherical Two Intersecting");
130impl_setup_static!(SphericalSetup, "Spherical");
131impl_setup_static!(
132 ThreeParallelTwoIntersectingSetup,
133 "Three Parallel Two Intersecting"
134);
135impl_setup_static!(ThreeParallelSetup, "Three Parallel");
136impl_setup_static!(TwoParallelSetup, "Two Parallel");
137impl_setup_static!(TwoIntersectingSetup, "Two Intersecting");
138impl_setup_static!(GenSixDofSetup, "Gen Six DOF");
139
140macro_rules! impl_setup_ik {
142 ($name:ident) => {
144 fn setup_from_str(&mut self, raw: &str) {
145 ik_setup_from_string(raw, &mut self.kin, &mut self.r, &mut self.t);
146 }
147
148 fn write_output(&self) -> String {
149 ik_write_output(&self.q)
150 }
151
152 fn error(&self) -> f64 {
153 self.q
154 .iter()
155 .map(|q| calculate_ik_error(&self.kin, &self.r, &self.t, q))
156 .reduce(f64::min)
157 .unwrap_or(NAN)
158 }
159
160 fn ls_count(&self) -> usize {
161 self.is_ls.iter().filter(|b| **b).count()
162 }
163
164 fn solution_count(&self) -> usize {
165 self.is_ls.len()
166 }
167
168 fn name(&self) -> &'static str {
169 <Self as SetupStatic>::name()
170 }
171
172 fn debug(&self, i: usize) {
173 println!("{i}\nr{}t{}h{}p{}", self.r, self.t, self.kin.h, self.kin.p);
174 }
175 };
176}
177
178impl SetupIk for SphericalTwoParallelSetup {
179 fn setup(&mut self) {
180 for i in 0..self.kin.h.ncols() {
181 self.kin.h.set_column(i, &random_norm_vector3());
182 }
183
184 let q = Vector6::zeros().map(|_: f64| random_angle());
185
186 let h_column_1: Vector3<f64> = self.kin.h.column(1).into();
187 self.kin.h.set_column(2, &h_column_1);
188
189 self.kin.p = Matrix3x7::from_columns(&[
190 random_vector3(),
191 random_vector3(),
192 random_vector3(),
193 random_vector3(),
194 Vector3::zeros(),
195 Vector3::zeros(),
196 random_vector3(),
197 ]);
198
199 (self.r, self.t) = self.kin.forward_kinematics(&q);
200 }
201
202 fn run(&mut self) {
203 (self.q, self.is_ls) = spherical_two_parallel(&self.r, &self.t, &self.kin);
204 }
205
206 impl_setup_ik!(SphericalTwoParallelSetup);
207}
208
209impl SetupIk for SphericalTwoIntersectingSetup {
210 fn setup(&mut self) {
211 for i in 0..self.kin.h.ncols() {
212 self.kin.h.set_column(i, &random_norm_vector3());
213 }
214
215 let q = Vector6::zeros().map(|_: f64| random_angle());
216
217 self.kin.p = Matrix3x7::from_columns(&[
218 random_vector3(),
219 Vector3::zeros(),
220 random_vector3(),
221 random_vector3(),
222 Vector3::zeros(),
223 Vector3::zeros(),
224 random_vector3(),
225 ]);
226
227 (self.r, self.t) = self.kin.forward_kinematics(&q);
228 }
229
230 fn run(&mut self) {
231 (self.q, self.is_ls) = spherical_two_intersecting(&self.r, &self.t, &self.kin);
232 }
233
234 impl_setup_ik!(SphericalTwoParallelSetup);
235}
236
237impl SetupIk for SphericalSetup {
238 fn setup(&mut self) {
239 for i in 0..self.kin.h.ncols() {
240 self.kin.h.set_column(i, &random_norm_vector3());
241 }
242
243 let q = Vector6::zeros().map(|_: f64| random_angle());
244
245 self.kin.p = Matrix3x7::from_columns(&[
246 random_vector3(),
247 random_vector3(),
248 random_vector3(),
249 random_vector3(),
250 Vector3::zeros(),
251 Vector3::zeros(),
252 random_vector3(),
253 ]);
254
255 (self.r, self.t) = self.kin.forward_kinematics(&q);
256 }
257
258 fn run(&mut self) {
259 (self.q, self.is_ls) = spherical(&self.r, &self.t, &self.kin);
260 }
261
262 impl_setup_ik!(SphericalTwoParallelSetup);
263}
264
265impl SetupIk for ThreeParallelTwoIntersectingSetup {
266 fn setup(&mut self) {
267 for i in 0..self.kin.h.ncols() {
268 self.kin.h.set_column(i, &random_norm_vector3());
269 }
270
271 let q = Vector6::zeros().map(|_: f64| random_angle());
272
273 let h_1: Vector3<f64> = self.kin.h.column(1).into();
274 self.kin.h.set_column(2, &h_1);
275 self.kin.h.set_column(3, &h_1);
276
277 self.kin.p = Matrix3x7::from_columns(&[
278 random_vector3(),
279 random_vector3(),
280 random_vector3(),
281 random_vector3(),
282 random_vector3(),
283 Vector3::zeros(),
284 random_vector3(),
285 ]);
286
287 (self.r, self.t) = self.kin.forward_kinematics(&q);
288 }
289
290 fn run(&mut self) {
291 (self.q, self.is_ls) = three_parallel_two_intersecting(&self.r, &self.t, &self.kin);
292 }
293
294 impl_setup_ik!(SphericalTwoParallelSetup);
295}
296
297impl SetupIk for ThreeParallelSetup {
298 fn setup(&mut self) {
299 for i in 0..self.kin.h.ncols() {
300 self.kin.h.set_column(i, &random_norm_vector3());
301 }
302
303 let q = Vector6::zeros().map(|_: f64| random_angle());
304
305 let h_1: Vector3<f64> = self.kin.h.column(1).into();
306 self.kin.h.set_column(2, &h_1);
307 self.kin.h.set_column(3, &h_1);
308
309 self.kin.p = Matrix3x7::from_columns(&[
310 random_vector3(),
311 random_vector3(),
312 random_vector3(),
313 random_vector3(),
314 random_vector3(),
315 random_vector3(),
316 random_vector3(),
317 ]);
318
319 (self.r, self.t) = self.kin.forward_kinematics(&q);
320 }
321
322 fn run(&mut self) {
323 (self.q, self.is_ls) = three_parallel(&self.r, &self.t, &self.kin);
324 }
325
326 impl_setup_ik!(SphericalTwoParallelSetup);
327}
328
329impl SetupIk for TwoParallelSetup {
330 fn setup(&mut self) {
331 for i in 0..self.kin.h.ncols() {
332 self.kin.h.set_column(i, &random_norm_vector3());
333 }
334
335 let q = Vector6::zeros().map(|_: f64| random_angle());
336
337 let h_1: Vector3<f64> = self.kin.h.column(1).into();
338 self.kin.h.set_column(2, &h_1);
339
340 self.kin.p = Matrix3x7::from_columns(&[
341 random_vector3(),
342 random_vector3(),
343 random_vector3(),
344 random_vector3(),
345 random_vector3(),
346 random_vector3(),
347 random_vector3(),
348 ]);
349
350 (self.r, self.t) = self.kin.forward_kinematics(&q);
351 }
352
353 fn run(&mut self) {
354 (self.q, self.is_ls) = two_parallel(&self.r, &self.t, &self.kin);
355 }
356
357 impl_setup_ik!(SphericalTwoParallelSetup);
358}
359
360impl SetupIk for TwoIntersectingSetup {
361 fn setup(&mut self) {
362 for i in 0..self.kin.h.ncols() {
363 self.kin.h.set_column(i, &random_norm_vector3());
364 }
365
366 let q = Vector6::zeros().map(|_: f64| random_angle());
367
368 self.kin.p = Matrix3x7::from_columns(&[
369 random_vector3(),
370 random_vector3(),
371 random_vector3(),
372 random_vector3(),
373 random_vector3(),
374 Vector3::zeros(),
375 random_vector3(),
376 ]);
377
378 (self.r, self.t) = self.kin.forward_kinematics(&q);
379 }
380
381 fn run(&mut self) {
382 (self.q, self.is_ls) = two_intersecting(&self.r, &self.t, &self.kin);
383 }
384
385 impl_setup_ik!(SphericalTwoParallelSetup);
386}
387
388impl SetupIk for GenSixDofSetup {
389 fn setup(&mut self) {
390 let q = Vector6::zeros().map(|_: f64| random_angle());
391
392 for i in 0..self.kin.h.ncols() {
393 self.kin.h.set_column(i, &random_norm_vector3());
394 }
395
396 for i in 0..self.kin.p.ncols() {
397 self.kin.p.set_column(i, &random_vector3());
398 }
399
400 (self.r, self.t) = self.kin.forward_kinematics(&q);
401 }
402
403 fn run(&mut self) {
404 (self.q, self.is_ls) = gen_six_dof(&self.r, &self.t, &self.kin);
405 }
406
407 impl_setup_ik!(SphericalTwoParallelSetup);
408}