1use crate::duration::Duration;
7use crate::errors::Errors;
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub enum RobotMode {
13 Other,
15 Idle,
17 Move,
19 Guiding,
22 Reflex,
25 UserStopped,
27 AutomaticErrorRecovery,
30}
31
32impl RobotMode {
33 pub const fn from_u8(v: u8) -> Option<RobotMode> {
35 Some(match v {
36 0 => RobotMode::Other,
37 1 => RobotMode::Idle,
38 2 => RobotMode::Move,
39 3 => RobotMode::Guiding,
40 4 => RobotMode::Reflex,
41 5 => RobotMode::UserStopped,
42 6 => RobotMode::AutomaticErrorRecovery,
43 _ => return None,
44 })
45 }
46}
47
48impl std::fmt::Display for RobotMode {
50 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51 let s = match self {
52 RobotMode::Other => "Other",
53 RobotMode::Idle => "Idle",
54 RobotMode::Move => "Move",
55 RobotMode::Guiding => "Guiding",
56 RobotMode::Reflex => "Reflex",
57 RobotMode::UserStopped => "User stopped",
58 RobotMode::AutomaticErrorRecovery => "Automatic error recovery",
59 };
60 f.write_str(s)
61 }
62}
63
64pub const IDENTITY_TRANSFORM: [f64; 16] = [
66 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0,
67];
68
69#[derive(Debug, Clone, Copy, PartialEq)]
75#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
76pub struct RobotState {
77 pub O_T_EE: [f64; 16],
79 pub O_T_EE_d: [f64; 16],
81 pub F_T_EE: [f64; 16],
83 pub F_T_NE: [f64; 16],
85 pub NE_T_EE: [f64; 16],
87 pub EE_T_K: [f64; 16],
89 pub m_ee: f64,
91 pub I_ee: [f64; 9],
93 pub F_x_Cee: [f64; 3],
95 pub m_load: f64,
97 pub I_load: [f64; 9],
99 pub F_x_Cload: [f64; 3],
101 pub m_total: f64,
103 pub I_total: [f64; 9],
105 pub F_x_Ctotal: [f64; 3],
107 pub elbow: [f64; 2],
109 pub elbow_d: [f64; 2],
111 pub elbow_c: [f64; 2],
113 pub delbow_c: [f64; 2],
115 pub ddelbow_c: [f64; 2],
117 pub tau_J: [f64; 7],
119 pub tau_J_d: [f64; 7],
121 pub dtau_J: [f64; 7],
123 pub q: [f64; 7],
125 pub q_d: [f64; 7],
127 pub dq: [f64; 7],
129 pub dq_d: [f64; 7],
131 pub ddq_d: [f64; 7],
133 pub joint_contact: [f64; 7],
135 pub cartesian_contact: [f64; 6],
137 pub joint_collision: [f64; 7],
139 pub cartesian_collision: [f64; 6],
141 pub tau_ext_hat_filtered: [f64; 7],
143 pub O_F_ext_hat_K: [f64; 6],
145 pub K_F_ext_hat_K: [f64; 6],
147 pub O_dP_EE_d: [f64; 6],
149 pub O_ddP_O: [f64; 3],
151 pub O_T_EE_c: [f64; 16],
153 pub O_dP_EE_c: [f64; 6],
155 pub O_ddP_EE_c: [f64; 6],
157 pub theta: [f64; 7],
159 pub dtheta: [f64; 7],
161 pub accelerometer_top: [[f64; 3]; 6],
163 pub accelerometer_bottom: [[f64; 3]; 6],
165 pub current_errors: Errors,
167 pub last_motion_errors: Errors,
169 pub control_command_success_rate: f64,
171 pub robot_mode: RobotMode,
173 pub time: Duration,
175}
176
177impl Default for RobotState {
178 fn default() -> Self {
181 RobotState {
182 O_T_EE: IDENTITY_TRANSFORM,
183 O_T_EE_d: IDENTITY_TRANSFORM,
184 F_T_EE: IDENTITY_TRANSFORM,
185 F_T_NE: IDENTITY_TRANSFORM,
186 NE_T_EE: IDENTITY_TRANSFORM,
187 EE_T_K: IDENTITY_TRANSFORM,
188 m_ee: 0.0,
189 I_ee: [0.0; 9],
190 F_x_Cee: [0.0; 3],
191 m_load: 0.0,
192 I_load: [0.0; 9],
193 F_x_Cload: [0.0; 3],
194 m_total: 0.0,
195 I_total: [0.0; 9],
196 F_x_Ctotal: [0.0; 3],
197 elbow: [0.0; 2],
198 elbow_d: [0.0; 2],
199 elbow_c: [0.0; 2],
200 delbow_c: [0.0; 2],
201 ddelbow_c: [0.0; 2],
202 tau_J: [0.0; 7],
203 tau_J_d: [0.0; 7],
204 dtau_J: [0.0; 7],
205 q: [0.0; 7],
206 q_d: [0.0; 7],
207 dq: [0.0; 7],
208 dq_d: [0.0; 7],
209 ddq_d: [0.0; 7],
210 joint_contact: [0.0; 7],
211 cartesian_contact: [0.0; 6],
212 joint_collision: [0.0; 7],
213 cartesian_collision: [0.0; 6],
214 tau_ext_hat_filtered: [0.0; 7],
215 O_F_ext_hat_K: [0.0; 6],
216 K_F_ext_hat_K: [0.0; 6],
217 O_dP_EE_d: [0.0; 6],
218 O_ddP_O: [0.0, 0.0, -9.81],
219 O_T_EE_c: IDENTITY_TRANSFORM,
220 O_dP_EE_c: [0.0; 6],
221 O_ddP_EE_c: [0.0; 6],
222 theta: [0.0; 7],
223 dtheta: [0.0; 7],
224 accelerometer_top: [[0.0; 3]; 6],
225 accelerometer_bottom: [[0.0; 3]; 6],
226 current_errors: Errors::default(),
227 last_motion_errors: Errors::default(),
228 control_command_success_rate: 0.0,
229 robot_mode: RobotMode::Other,
230 time: Duration::default(),
231 }
232 }
233}
234
235pub fn combine_center_of_mass(
240 m_ee: f64,
241 F_x_Cee: &[f64; 3],
242 m_load: f64,
243 F_x_Cload: &[f64; 3],
244) -> [f64; 3] {
245 let mut F_x_Ctotal = [0.0; 3];
246 if (m_ee + m_load) > 0.0 {
247 for i in 0..3 {
248 F_x_Ctotal[i] = (m_ee * F_x_Cee[i] + m_load * F_x_Cload[i]) / (m_ee + m_load);
249 }
250 }
251 F_x_Ctotal
252}
253
254fn skew_symmetric(v: &[f64; 3]) -> nalgebra::Matrix3<f64> {
256 nalgebra::Matrix3::new(0.0, -v[2], v[1], v[2], 0.0, -v[0], -v[1], v[0], 0.0)
257}
258
259#[allow(clippy::too_many_arguments)]
267pub fn combine_inertia_tensor(
268 m_ee: f64,
269 F_x_Cee: &[f64; 3],
270 I_ee: &[f64; 9],
271 m_load: f64,
272 F_x_Cload: &[f64; 3],
273 I_load: &[f64; 9],
274 m_total: f64,
275 F_x_Ctotal: &[f64; 3],
276) -> [f64; 9] {
277 if m_total == 0.0 {
278 return [0.0; 9];
279 }
280
281 let mut inertia_ee = nalgebra::Matrix3::from_column_slice(I_ee);
282 let mut inertia_load = nalgebra::Matrix3::from_column_slice(I_load);
283 if m_ee == 0.0 {
284 inertia_ee = nalgebra::Matrix3::zeros();
285 }
286 if m_load == 0.0 {
287 inertia_load = nalgebra::Matrix3::zeros();
288 }
289
290 let skew_ee = skew_symmetric(F_x_Cee);
291 let skew_load = skew_symmetric(F_x_Cload);
292 let skew_total = skew_symmetric(F_x_Ctotal);
293
294 let inertia_ee_flange = inertia_ee - m_ee * (skew_ee * skew_ee);
295 let inertia_load_flange = inertia_load - m_load * (skew_load * skew_load);
296 let inertia_total =
297 inertia_ee_flange + inertia_load_flange + m_total * (skew_total * skew_total);
298
299 let mut out = [0.0; 9];
300 out.copy_from_slice(inertia_total.as_slice());
301 out
302}
303
304impl RobotState {
305 pub fn from_wire(w: &crate::wire::robot::RobotState) -> RobotState {
314 use crate::wire::{accel_to_f64, f32s_to_f64};
315
316 let m_ee = w.m_ee.get() as f64;
317 let m_load = w.m_load.get() as f64;
318 let I_ee = f32s_to_f64(&w.I_ee);
319 let I_load = f32s_to_f64(&w.I_load);
320 let F_x_Cee = f32s_to_f64(&w.F_x_Cee);
321 let F_x_Cload = f32s_to_f64(&w.F_x_Cload);
322
323 let m_total = f64::from(w.m_ee.get() + w.m_load.get());
327 let F_x_Ctotal = combine_center_of_mass(m_ee, &F_x_Cee, m_load, &F_x_Cload);
328 let I_total = combine_inertia_tensor(
329 m_ee,
330 &F_x_Cee,
331 &I_ee,
332 m_load,
333 &F_x_Cload,
334 &I_load,
335 m_total,
336 &F_x_Ctotal,
337 );
338
339 RobotState {
340 O_T_EE: f32s_to_f64(&w.O_T_EE),
341 O_T_EE_d: f32s_to_f64(&w.O_T_EE_d),
342 F_T_EE: f32s_to_f64(&w.F_T_EE),
343 F_T_NE: f32s_to_f64(&w.F_T_NE),
344 NE_T_EE: f32s_to_f64(&w.NE_T_EE),
345 EE_T_K: f32s_to_f64(&w.EE_T_K),
346 m_ee,
347 I_ee,
348 F_x_Cee,
349 m_load,
350 I_load,
351 F_x_Cload,
352 m_total,
353 I_total,
354 F_x_Ctotal,
355 elbow: f32s_to_f64(&w.elbow),
356 elbow_d: f32s_to_f64(&w.elbow_d),
357 elbow_c: f32s_to_f64(&w.elbow_c),
358 delbow_c: f32s_to_f64(&w.delbow_c),
359 ddelbow_c: f32s_to_f64(&w.ddelbow_c),
360 tau_J: f32s_to_f64(&w.tau_J),
361 tau_J_d: f32s_to_f64(&w.tau_J_d),
362 dtau_J: f32s_to_f64(&w.dtau_J),
363 q: f32s_to_f64(&w.q),
364 q_d: f32s_to_f64(&w.q_d),
365 dq: f32s_to_f64(&w.dq),
366 dq_d: f32s_to_f64(&w.dq_d),
367 ddq_d: f32s_to_f64(&w.ddq_d),
368 joint_contact: f32s_to_f64(&w.joint_contact),
369 cartesian_contact: f32s_to_f64(&w.cartesian_contact),
370 joint_collision: f32s_to_f64(&w.joint_collision),
371 cartesian_collision: f32s_to_f64(&w.cartesian_collision),
372 tau_ext_hat_filtered: f32s_to_f64(&w.tau_ext_hat_filtered),
373 O_F_ext_hat_K: f32s_to_f64(&w.O_F_ext_hat_K),
374 K_F_ext_hat_K: f32s_to_f64(&w.K_F_ext_hat_K),
375 O_dP_EE_d: f32s_to_f64(&w.O_dP_EE_d),
376 O_ddP_O: f32s_to_f64(&w.O_ddP_O),
377 O_T_EE_c: f32s_to_f64(&w.O_T_EE_c),
378 O_dP_EE_c: f32s_to_f64(&w.O_dP_EE_c),
379 O_ddP_EE_c: f32s_to_f64(&w.O_ddP_EE_c),
380 theta: f32s_to_f64(&w.theta),
381 dtheta: f32s_to_f64(&w.dtheta),
382 accelerometer_top: accel_to_f64(&w.accelerometer_top),
383 accelerometer_bottom: accel_to_f64(&w.accelerometer_bottom),
384 current_errors: Errors::from(w.errors),
385 last_motion_errors: Errors::from(w.reflex_reason),
386 control_command_success_rate: w.control_command_success_rate.get() as f64,
387 robot_mode: RobotMode::from_u8(w.robot_mode).unwrap_or(RobotMode::Other),
388 time: Duration::from_millis(w.message_id.get()),
389 }
390 }
391
392 pub fn from_wire_v5(w: &crate::wire::robot::v5::RobotState) -> RobotState {
403 use crate::wire::f64s_to_f64;
404
405 let m_ee = w.m_ee.get();
406 let m_load = w.m_load.get();
407 let I_ee = f64s_to_f64(&w.I_ee);
408 let I_load = f64s_to_f64(&w.I_load);
409 let F_x_Cee = f64s_to_f64(&w.F_x_Cee);
410 let F_x_Cload = f64s_to_f64(&w.F_x_Cload);
411
412 let m_total = m_ee + m_load;
413 let F_x_Ctotal = combine_center_of_mass(m_ee, &F_x_Cee, m_load, &F_x_Cload);
414 let I_total = combine_inertia_tensor(
415 m_ee,
416 &F_x_Cee,
417 &I_ee,
418 m_load,
419 &F_x_Cload,
420 &I_load,
421 m_total,
422 &F_x_Ctotal,
423 );
424
425 RobotState {
426 O_T_EE: f64s_to_f64(&w.O_T_EE),
427 O_T_EE_d: f64s_to_f64(&w.O_T_EE_d),
428 F_T_EE: f64s_to_f64(&w.F_T_EE),
429 F_T_NE: f64s_to_f64(&w.F_T_NE),
430 NE_T_EE: f64s_to_f64(&w.NE_T_EE),
431 EE_T_K: f64s_to_f64(&w.EE_T_K),
432 m_ee,
433 I_ee,
434 F_x_Cee,
435 m_load,
436 I_load,
437 F_x_Cload,
438 m_total,
439 I_total,
440 F_x_Ctotal,
441 elbow: f64s_to_f64(&w.elbow),
442 elbow_d: f64s_to_f64(&w.elbow_d),
443 elbow_c: f64s_to_f64(&w.elbow_c),
444 delbow_c: f64s_to_f64(&w.delbow_c),
445 ddelbow_c: f64s_to_f64(&w.ddelbow_c),
446 tau_J: f64s_to_f64(&w.tau_J),
447 tau_J_d: f64s_to_f64(&w.tau_J_d),
448 dtau_J: f64s_to_f64(&w.dtau_J),
449 q: f64s_to_f64(&w.q),
450 q_d: f64s_to_f64(&w.q_d),
451 dq: f64s_to_f64(&w.dq),
452 dq_d: f64s_to_f64(&w.dq_d),
453 ddq_d: f64s_to_f64(&w.ddq_d),
454 joint_contact: f64s_to_f64(&w.joint_contact),
455 cartesian_contact: f64s_to_f64(&w.cartesian_contact),
456 joint_collision: f64s_to_f64(&w.joint_collision),
457 cartesian_collision: f64s_to_f64(&w.cartesian_collision),
458 tau_ext_hat_filtered: f64s_to_f64(&w.tau_ext_hat_filtered),
459 O_F_ext_hat_K: f64s_to_f64(&w.O_F_ext_hat_K),
460 K_F_ext_hat_K: f64s_to_f64(&w.K_F_ext_hat_K),
461 O_dP_EE_d: f64s_to_f64(&w.O_dP_EE_d),
462 O_ddP_O: f64s_to_f64(&w.O_ddP_O),
463 O_T_EE_c: f64s_to_f64(&w.O_T_EE_c),
464 O_dP_EE_c: f64s_to_f64(&w.O_dP_EE_c),
465 O_ddP_EE_c: f64s_to_f64(&w.O_ddP_EE_c),
466 theta: f64s_to_f64(&w.theta),
467 dtheta: f64s_to_f64(&w.dtheta),
468 accelerometer_top: [[0.0; 3]; 6],
469 accelerometer_bottom: [[0.0; 3]; 6],
470 current_errors: Errors::from(w.errors),
471 last_motion_errors: Errors::from(w.reflex_reason),
472 control_command_success_rate: w.control_command_success_rate.get(),
473 robot_mode: RobotMode::from_u8(w.robot_mode).unwrap_or(RobotMode::Other),
474 time: Duration::from_millis(w.message_id.get()),
475 }
476 }
477}
478
479#[cfg(test)]
480mod tests;