rs_opw_kinematics/utils/
utils.rs1use crate::kinematic_traits::{Joints, Solutions};
4use nalgebra::{Isometry3, UnitQuaternion, Vector6};
5
6pub(crate) mod opw_kinematics {
9 use crate::kinematic_traits::Joints;
10
11 pub fn is_valid(qs: &Joints) -> bool {
13 qs.iter().all(|&q| q.is_finite())
14 }
15}
16
17pub fn joints(angles: &[f32; 6]) -> Joints {
20 [
21 (angles[0] as f64).to_radians(),
22 (angles[1] as f64).to_radians(),
23 (angles[2] as f64).to_radians(),
24 (angles[3] as f64).to_radians(),
25 (angles[4] as f64).to_radians(),
26 (angles[5] as f64).to_radians(),
27 ]
28}
29
30pub fn to_degrees(angles: &Joints) -> [f32; 6] {
33 [
34 angles[0].to_degrees() as f32,
35 angles[1].to_degrees() as f32,
36 angles[2].to_degrees() as f32,
37 angles[3].to_degrees() as f32,
38 angles[4].to_degrees() as f32,
39 angles[5].to_degrees() as f32,
40 ]
41}
42
43pub fn dump_solutions(solutions: &Solutions) {
45 if solutions.is_empty() {
46 println!("No solutions");
47 }
48 for sol_idx in 0..solutions.len() {
49 let mut row_str = String::new();
50 for joint_idx in 0..6 {
51 let computed = solutions[sol_idx][joint_idx];
52 row_str.push_str(&format!("{:5.2} ", computed.to_degrees()));
53 }
54 println!("[{}]", row_str.trim_end());
55 }
56}
57
58pub fn dump_solutions_degrees(solutions: &Solutions) {
59 if solutions.is_empty() {
60 println!("No solutions");
61 }
62 for sol_idx in 0..solutions.len() {
63 let mut row_str = String::new();
64 for joint_idx in 0..6 {
65 let computed = solutions[sol_idx][joint_idx];
66 row_str.push_str(&format!("{:5.2} ", computed));
67 }
68 println!("[{}]", row_str.trim_end());
69 }
70}
71
72pub fn dump_joints(joints: &Joints) {
74 let mut row_str = String::new();
75 for joint_idx in 0..6 {
76 let computed = joints[joint_idx];
77 row_str.push_str(&format!("{:5.2} ", computed.to_degrees()));
78 }
79 println!("[{}]", row_str.trim_end());
80}
81
82pub fn dump_pose(isometry: &Isometry3<f64>) {
83 let translation = isometry.translation.vector;
85
86 let rotation: UnitQuaternion<f64> = isometry.rotation;
88
89 println!(
91 "x: {:.5}, y: {:.5}, z: {:.5}, quat: {:.5},{:.5},{:.5},{:.5}",
92 translation.x, translation.y, translation.z, rotation.i, rotation.j, rotation.k, rotation.w
93 );
94}
95
96pub fn as_radians(degrees: [i32; 6]) -> Joints {
98 std::array::from_fn(|i| (degrees[i] as f64).to_radians())
99}
100
101pub(crate) fn deg(x: &f64) -> String {
103 if *x == 0.0 {
104 return "0".to_string();
105 }
106 format!("deg({:.4})", x.to_degrees())
107}
108
109pub fn vector6_to_joints(v: Vector6<f64>) -> Joints {
111 [v[0], v[1], v[2], v[3], v[4], v[5]]
112}
113
114pub fn joints_to_vector6(j: Joints) -> nalgebra::Vector6<f64> {
116 Vector6::new(j[0], j[1], j[2], j[3], j[4], j[5])
117}
118
119pub fn transition_costs(from: &Joints, to: &Joints, coefficients: &Joints) -> f64 {
123 [(from[0] - to[0]).abs() * coefficients[0]
124 + (from[1] - to[1]).abs() * coefficients[1]
125 + (from[2] - to[2]).abs() * coefficients[2]
126 + (from[3] - to[3]).abs() * coefficients[3]
127 + (from[4] - to[4]).abs() * coefficients[4]
128 + (from[5] - to[5]).abs() * coefficients[5]]
129 .iter()
130 .fold(f64::NEG_INFINITY, |a, &b| a.max(b))
131}
132
133pub fn assert_pose_eq(ta: &Isometry3<f64>, tb: &Isometry3<f64>,
134 distance_tolerance: f64, angular_tolerance: f64) -> bool {
135 fn bad(ta: &Isometry3<f64>, tb: &Isometry3<f64>) {
136 dump_pose(ta);
137 dump_pose(tb);
138 }
139
140 let translation_distance = (ta.translation.vector - tb.translation.vector).norm();
141 let angular_distance = ta.rotation.angle_to(&tb.rotation);
142
143 if translation_distance.abs() > distance_tolerance {
144 bad(ta, tb);
145 panic!("Poses have too different translations");
146 }
147
148 if angular_distance.abs() > angular_tolerance {
149 bad(ta, tb);
150 panic!("Poses have too different angles");
151 }
152 true
153}
154
155#[cfg(test)]
156mod tests {
157 use super::opw_kinematics::*;
158 use std::f64::consts::PI;
159
160 #[test]
161 fn test_is_valid_with_all_finite() {
162 let qs = [0.0, 1.0, -1.0, 0.5, -0.5, PI];
163 assert!(is_valid(&qs));
164 }
165
166 #[test]
167 fn test_is_valid_with_nan() {
168 let qs = [0.0, f64::NAN, 1.0, -1.0, 0.5, -0.5];
169 assert!(!is_valid(&qs));
170 }
171
172 #[test]
173 fn test_is_valid_with_infinity() {
174 let qs = [0.0, f64::INFINITY, 1.0, -1.0, 0.5, -0.5];
175 assert!(!is_valid(&qs));
176 }
177}