1use crate::robot::control_types::{Finishable, JointPositions};
6use crate::robot::robot_state::RobotState;
7use nalgebra::{Isometry3, Matrix4, MatrixMN, MatrixN, Rotation3, Vector3, VectorN, U6, U7};
8use std::time::Duration;
9
10pub fn array_to_isometry(array: &[f64; 16]) -> Isometry3<f64> {
12 let rot = Rotation3::from_matrix(
13 &Matrix4::from_column_slice(array)
14 .remove_column(3)
15 .remove_row(3),
16 );
17 Isometry3::from_parts(
18 Vector3::new(array[12], array[13], array[14]).into(),
19 rot.into(),
20 )
21}
22pub type Vector7 = VectorN<f64, U7>;
24pub type Matrix6x7 = MatrixMN<f64, U6, U7>;
26pub type Matrix7 = MatrixN<f64, U7>;
28#[derive(Debug)]
32pub struct MotionGenerator {
33 q_goal: Vector7,
34 q_start: Vector7,
35 delta_q: Vector7,
36 dq_max_sync: Vector7,
37 t_1_sync: Vector7,
38 t_2_sync: Vector7,
39 t_f_sync: Vector7,
40 q_1: Vector7,
41
42 time: f64,
43 dq_max: Vector7,
44 ddq_max_start: Vector7,
45 ddq_max_goal: Vector7,
46}
47
48impl MotionGenerator {
49 const DELTA_Q_MOTION_FINISHED: f64 = 1e-6;
50 pub fn new(speed_factor: f64, q_goal: &[f64; 7]) -> Self {
56 let time = 0.;
57 let q_goal = Vector7::from_row_slice(q_goal);
58 let dq_max = Vector7::from_row_slice(&[2.0, 2.0, 2.0, 2.0, 2.5, 2.5, 2.5]) * speed_factor;
59 let ddq_max_start = Vector7::from_row_slice(&[5.; 7]) * speed_factor;
60 let ddq_max_goal = Vector7::from_row_slice(&[5.; 7]) * speed_factor;
61
62 let dq_max_sync = Vector7::zeros();
63 let q_start = Vector7::zeros();
64 let delta_q = Vector7::zeros();
65 let t_1_sync = Vector7::zeros();
66 let t_2_sync = Vector7::zeros();
67 let t_f_sync = Vector7::zeros();
68 let q_1 = Vector7::zeros();
69 MotionGenerator {
70 q_goal,
71 q_start,
72 delta_q,
73 dq_max_sync,
74 t_1_sync,
75 t_2_sync,
76 t_f_sync,
77 q_1,
78 time,
79 dq_max,
80 ddq_max_start,
81 ddq_max_goal,
82 }
83 }
84 fn calculate_desired_values(&self, t: f64, delta_q_d: &mut Vector7) -> bool {
85 let sign_delta_q = Vector7::from_iterator(self.delta_q.iter().map(|&x| x.signum()));
86 let t_d = self.t_2_sync - self.t_1_sync;
87 let delta_t_2_sync = self.t_f_sync - self.t_2_sync;
88 let mut joint_motion_finished = [false; 7];
89 for i in 0..7 {
90 if self.delta_q[i].abs() < MotionGenerator::DELTA_Q_MOTION_FINISHED {
91 delta_q_d[i] = 0.;
92 joint_motion_finished[i] = true;
93 } else if t < self.t_1_sync[i] {
94 delta_q_d[i] = -1. / self.t_1_sync[i].powi(3)
95 * self.dq_max_sync[i]
96 * sign_delta_q[i]
97 * (0.5 * t - self.t_1_sync[i])
98 * t.powi(3);
99 } else if t >= self.t_1_sync[i] && t < self.t_2_sync[i] {
100 delta_q_d[i] =
101 self.q_1[i] + (t - self.t_1_sync[i]) * self.dq_max_sync[i] * sign_delta_q[i];
102 } else if t >= self.t_2_sync[i] && t < self.t_f_sync[i] {
103 delta_q_d[i] = self.delta_q[i]
104 + 0.5
105 * (1. / delta_t_2_sync[i].powi(3)
106 * (t - self.t_1_sync[i] - 2.0 * delta_t_2_sync[i] - t_d[i])
107 * (t - self.t_1_sync[i] - t_d[i]).powi(3)
108 + (2. * t - 2. * self.t_1_sync[i] - delta_t_2_sync[i] - 2. * t_d[i]))
109 * self.dq_max_sync[i]
110 * sign_delta_q[i];
111 } else {
112 delta_q_d[i] = self.delta_q[i];
113 joint_motion_finished[i] = true;
114 }
115 }
116 joint_motion_finished.iter().all(|i| *i)
117 }
118 fn calculate_synchronized_values(&mut self) {
119 let mut dq_max_reach = self.dq_max;
120 let mut t_f: Vector7 = Vector7::zeros();
121 let mut delta_t_2 = Vector7::zeros();
122 let mut t_1 = Vector7::zeros();
123
124 let mut delta_t_2_sync = Vector7::zeros();
125 let sign_delta_q = Vector7::from_iterator(self.delta_q.iter().map(|&x| x.signum()));
126 for i in 0..7 {
127 if self.delta_q[i].abs() > MotionGenerator::DELTA_Q_MOTION_FINISHED {
128 if self.delta_q[i].abs()
129 < (3.0 / 4.0 * (self.dq_max[i].powi(2) / self.ddq_max_start[i])
130 + 3. / 4. * (self.dq_max[i].powi(2) / self.ddq_max_goal[i]))
131 {
132 dq_max_reach[i] = f64::sqrt(
133 4. / 3.
134 * self.delta_q[i]
135 * sign_delta_q[i]
136 * (self.ddq_max_start[i] * self.ddq_max_goal[i])
137 / (self.ddq_max_start[i] + self.ddq_max_goal[i]),
138 )
139 }
140 t_1[i] = 1.5 * dq_max_reach[i] / self.ddq_max_start[i];
141 delta_t_2[i] = 1.5 * dq_max_reach[i] / self.ddq_max_goal[i];
142 t_f[i] =
143 t_1[i] / 2. + delta_t_2[i] / 2. + f64::abs(self.delta_q[i]) / dq_max_reach[i];
144 }
145 }
146 let max_t_f = t_f.max();
147 for i in 0..7 {
148 if self.delta_q[i].abs() > MotionGenerator::DELTA_Q_MOTION_FINISHED {
149 let a = 1.5 / 2. * (self.ddq_max_goal[i] + self.ddq_max_start[i]);
150 let b = -1. * max_t_f * self.ddq_max_goal[i] * self.ddq_max_start[i];
151 let c = f64::abs(self.delta_q[i]) * self.ddq_max_goal[i] * self.ddq_max_start[i];
152 let delta = f64::max(b * b - 4. * a * c, 0.);
153 self.dq_max_sync[i] = (-1. * b - f64::sqrt(delta)) / (2. * a);
154 self.t_1_sync[i] = 1.5 * self.dq_max_sync[i] / self.ddq_max_start[i];
155 delta_t_2_sync[i] = 1.5 * self.dq_max_sync[i] / self.ddq_max_goal[i];
156 self.t_f_sync[i] = self.t_1_sync[i] / 2.
157 + delta_t_2_sync[i] / 2.
158 + f64::abs(self.delta_q[i] / self.dq_max_sync[i]);
159 self.t_2_sync[i] = self.t_f_sync[i] - delta_t_2_sync[i];
160 self.q_1[i] = self.dq_max_sync[i] * sign_delta_q[i] * (0.5 * self.t_1_sync[i])
161 }
162 }
163 }
164 pub fn generate_motion(
173 &mut self,
174 robot_state: &RobotState,
175 period: &Duration,
176 ) -> JointPositions {
177 self.time += period.as_secs_f64();
178
179 if self.time == 0. {
180 self.q_start = Vector7::from_column_slice(&robot_state.q_d);
181 self.delta_q = self.q_goal - self.q_start;
182 self.calculate_synchronized_values();
183 }
184 let mut delta_q_d = Vector7::zeros();
185 let motion_finished = self.calculate_desired_values(self.time, &mut delta_q_d);
186
187 let mut output = JointPositions::new((self.q_start + delta_q_d).into());
188 output.set_motion_finished(motion_finished);
189 output
190 }
191}
192
193#[cfg(test)]
194mod test {
195 use crate::{array_to_isometry, Finishable, MotionGenerator, RobotState};
196 use nalgebra::Rotation3;
197 use std::time::Duration;
198
199 fn slice_compare(a: &[f64], b: &[f64], thresh: f64) {
200 for i in 0..a.len() {
201 float_compare(a[i], b[i], thresh);
202 }
203 }
204
205 fn float_compare(a: f64, b: f64, thresh: f64) {
206 assert!((a - b).abs() < thresh);
207 }
208
209 #[test]
210 fn motion_generator() {
211 let q_des = [
212 [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
213 [
214 0.005530250638946291,
215 0.005530250638946291,
216 0.005530250638946291,
217 0.005530250638946291,
218 0.005530250638946291,
219 0.005530250638946291,
220 0.005530250638946291,
221 ],
222 [
223 0.039797560667125885,
224 0.039797560667125885,
225 0.039797560667125885,
226 0.039797560667125885,
227 0.039797560667125885,
228 0.039797560667125885,
229 0.039797560667125885,
230 ],
231 [
232 0.11931676725154987,
233 0.11931676725154987,
234 0.11931676725154987,
235 0.11931676725154987,
236 0.11931676725154987,
237 0.11931676725154987,
238 0.11931676725154987,
239 ],
240 [
241 0.24726937422589595,
242 0.24726937422589595,
243 0.24726937422589595,
244 0.24726937422589595,
245 0.24726937422589595,
246 0.24726937422589595,
247 0.24726937422589595,
248 ],
249 [
250 0.4135035520905085,
251 0.4135035520905085,
252 0.4135035520905085,
253 0.4135035520905085,
254 0.4135035520905085,
255 0.4135035520905085,
256 0.4135035520905085,
257 ],
258 [
259 0.5946171259214752,
260 0.5946171259214752,
261 0.5946171259214752,
262 0.5946171259214752,
263 0.5946171259214752,
264 0.5946171259214752,
265 0.5946171259214752,
266 ],
267 [
268 0.7595171113649393,
269 0.7595171113649393,
270 0.7595171113649393,
271 0.7595171113649393,
272 0.7595171113649393,
273 0.7595171113649393,
274 0.7595171113649393,
275 ],
276 [
277 0.8853832940789487,
278 0.8853832940789487,
279 0.8853832940789487,
280 0.8853832940789487,
281 0.8853832940789487,
282 0.8853832940789487,
283 0.8853832940789487,
284 ],
285 [
286 0.9626711625624701,
287 0.9626711625624701,
288 0.9626711625624701,
289 0.9626711625624701,
290 0.9626711625624701,
291 0.9626711625624701,
292 0.9626711625624701,
293 ],
294 [
295 0.9951695386478036,
296 0.9951695386478036,
297 0.9951695386478036,
298 0.9951695386478036,
299 0.9951695386478036,
300 0.9951695386478036,
301 0.9951695386478036,
302 ],
303 [1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0],
304 ];
305 let mut state = RobotState::default();
306 let mut motion_generator = MotionGenerator::new(1.0, &[1.; 7]);
307 let mut joint_pos = motion_generator.generate_motion(&state, &Duration::from_secs_f64(0.0));
308 slice_compare(&joint_pos.q, &q_des[0], 1e-10);
309 let mut counter = 1;
310 while !joint_pos.is_finished() {
311 state.q_d = joint_pos.q;
312 joint_pos = motion_generator.generate_motion(&state, &Duration::from_secs_f64(0.1));
313 slice_compare(&joint_pos.q, &q_des[counter], 1e-10);
314 counter += 1;
315 }
316 assert_eq!(counter, q_des.len())
317 }
318
319 #[test]
320 fn array_to_isometry_nan_test_1() {
321 let o_t_ee_c = [
322 1.0,
323 -0.000000011046552201160267,
324 0.000000008312911920110592,
325 0.0,
326 -0.000000011046552077288223,
327 -0.9999999999999999,
328 -0.000000014901161362226844,
329 0.0,
330 0.000000008312912084717049,
331 0.000000014901161270397825,
332 -0.9999999999999999,
333 0.0,
334 0.30689056578595225,
335 -0.000000003883240449999549,
336 0.486882056335292,
337 1.0,
338 ];
339 let last_o_t_ee_c = [
340 0.9999903734042683,
341 -0.000000011046444370332864,
342 0.00000000831299559264306,
343 0.0,
344 -0.000000011046444370332864,
345 -0.9999903734042683,
346 -0.0000000021131709957245164,
347 0.0,
348 0.000000008313075597526054,
349 0.0000000021131912467324254,
350 -0.9999999999999999,
351 0.0,
352 0.30689056578595225,
353 -0.000000003883240449999549,
354 0.486882056335292,
355 1.0,
356 ];
357 let commanded_pose = array_to_isometry(&o_t_ee_c);
358 let last_commanded_pose = array_to_isometry(&last_o_t_ee_c);
359
360 let mut rot_diff: Rotation3<f64> = commanded_pose.rotation.to_rotation_matrix()
361 * last_commanded_pose
362 .rotation
363 .to_rotation_matrix()
364 .transpose();
365 rot_diff.renormalize();
366 for i in rot_diff.matrix().iter() {
367 assert!(i.is_finite());
368 }
369 }
370
371 #[test]
372 fn array_to_isometry_nan_test_2() {
373 let y = [
374 0.9999903734042686,
375 0.0000000002540163079878255,
376 -0.00000000012581154368346085,
377 0.0,
378 0.0000000002540163079878255,
379 -0.9999903734042686,
380 0.00000000004614105974113725,
381 0.0,
382 -0.00000000012581275483128821,
383 -0.000000000046141503958700795,
384 -1.0,
385 0.0,
386 0.30689056659844144,
387 0.0000000000692086410879149,
388 0.4868820527992277,
389 1.0,
390 ];
391 assert!(array_to_isometry(&y).rotation.angle().is_finite())
392 }
393}