1use nalgebra::{Matrix3, Matrix4, Rotation3, UnitQuaternion, Vector3};
8
9use super::{DELTA_T, FACTOR_CARTESIAN_ROTATION_POSE_INTERFACE, NORM_EPS};
10use crate::control_types::is_homogeneous_transformation;
11use crate::error::{FrankaError, FrankaResult};
12use crate::math_utils::{
13 cmax, cmin, linear_of, orthonormalized_rotation, pose_to_array, translation_of,
14};
15
16fn limit_rate_vector3(
21 max_velocity: f64,
22 max_acceleration: f64,
23 max_jerk: f64,
24 commanded_velocity: &Vector3<f64>,
25 last_commanded_velocity: &Vector3<f64>,
26 last_commanded_acceleration: &Vector3<f64>,
27) -> Vector3<f64> {
28 let commanded_jerk = (((commanded_velocity - last_commanded_velocity) / DELTA_T)
30 - last_commanded_acceleration)
31 / DELTA_T;
32
33 let mut commanded_acceleration = *last_commanded_acceleration;
35 let jerk_norm = commanded_jerk.norm();
36 if jerk_norm > NORM_EPS {
37 commanded_acceleration +=
38 (commanded_jerk / jerk_norm) * cmax(cmin(jerk_norm, max_jerk), -max_jerk) * DELTA_T;
39 }
40
41 let unit_commanded_acceleration = commanded_acceleration / commanded_acceleration.norm();
44 let dot_product = unit_commanded_acceleration.dot(last_commanded_velocity);
45 let distance_to_max_velocity = -dot_product
46 + (dot_product.powi(2) - last_commanded_velocity.norm_squared() + max_velocity.powi(2))
47 .sqrt();
48
49 let safe_max_acceleration = cmin(
51 (max_jerk / max_acceleration) * distance_to_max_velocity,
52 max_acceleration,
53 );
54
55 let mut limited_commanded_velocity = *last_commanded_velocity;
57 let acceleration_norm = commanded_acceleration.norm();
58 if acceleration_norm > NORM_EPS {
59 limited_commanded_velocity +=
60 unit_commanded_acceleration * cmin(acceleration_norm, safe_max_acceleration) * DELTA_T;
61 }
62
63 limited_commanded_velocity
64}
65
66#[allow(clippy::too_many_arguments)]
76pub fn limit_rate_cartesian_velocity(
77 max_translational_velocity: f64,
78 max_translational_acceleration: f64,
79 max_translational_jerk: f64,
80 max_rotational_velocity: f64,
81 max_rotational_acceleration: f64,
82 max_rotational_jerk: f64,
83 O_dP_EE_c: &[f64; 6],
84 last_O_dP_EE_c: &[f64; 6],
85 last_O_ddP_EE_c: &[f64; 6],
86) -> FrankaResult<[f64; 6]> {
87 if !O_dP_EE_c.iter().all(|v| v.is_finite()) {
88 return Err(FrankaError::InvalidArgument(
89 "O_dP_EE_c is infinite or NaN.".to_string(),
90 ));
91 }
92 let head = |v: &[f64; 6]| Vector3::new(v[0], v[1], v[2]);
93 let tail = |v: &[f64; 6]| Vector3::new(v[3], v[4], v[5]);
94
95 let translation = limit_rate_vector3(
96 max_translational_velocity,
97 max_translational_acceleration,
98 max_translational_jerk,
99 &head(O_dP_EE_c),
100 &head(last_O_dP_EE_c),
101 &head(last_O_ddP_EE_c),
102 );
103 let rotation = limit_rate_vector3(
104 max_rotational_velocity,
105 max_rotational_acceleration,
106 max_rotational_jerk,
107 &tail(O_dP_EE_c),
108 &tail(last_O_dP_EE_c),
109 &tail(last_O_ddP_EE_c),
110 );
111
112 Ok([
113 translation[0],
114 translation[1],
115 translation[2],
116 rotation[0],
117 rotation[1],
118 rotation[2],
119 ])
120}
121
122#[allow(clippy::too_many_arguments)]
134pub fn limit_rate_cartesian_pose(
135 max_translational_velocity: f64,
136 max_translational_acceleration: f64,
137 max_translational_jerk: f64,
138 max_rotational_velocity: f64,
139 max_rotational_acceleration: f64,
140 max_rotational_jerk: f64,
141 O_T_EE_c: &[f64; 16],
142 last_O_T_EE_c: &[f64; 16],
143 last_O_dP_EE_c: &[f64; 6],
144 last_O_ddP_EE_c: &[f64; 6],
145) -> FrankaResult<[f64; 16]> {
146 if !O_T_EE_c.iter().all(|v| v.is_finite()) {
147 return Err(FrankaError::InvalidArgument(
148 "O_T_EE_c is infinite or NaN.".to_string(),
149 ));
150 }
151 if !is_homogeneous_transformation(O_T_EE_c) {
152 return Err(FrankaError::InvalidArgument(
153 "O_T_EE_c is invalid transformation matrix. Has to be column major!".to_string(),
154 ));
155 }
156
157 let commanded_pose = Matrix4::from_column_slice(O_T_EE_c);
158 let last_commanded_pose = Matrix4::from_column_slice(last_O_T_EE_c);
159 let commanded_translation = translation_of(&commanded_pose);
160 let last_commanded_translation = translation_of(&last_commanded_pose);
161 let commanded_rotation = orthonormalized_rotation(&linear_of(&commanded_pose));
164 let last_commanded_rotation = orthonormalized_rotation(&linear_of(&last_commanded_pose));
165
166 let translational_velocity = (commanded_translation - last_commanded_translation) / DELTA_T;
168
169 let rot_difference = commanded_rotation * last_commanded_rotation.transpose();
171 let rotational_velocity = scaled_axis(&rot_difference) / DELTA_T;
172
173 let commanded_twist = [
175 translational_velocity[0],
176 translational_velocity[1],
177 translational_velocity[2],
178 rotational_velocity[0],
179 rotational_velocity[1],
180 rotational_velocity[2],
181 ];
182 let limited_twist = limit_rate_cartesian_velocity(
183 max_translational_velocity,
184 max_translational_acceleration,
185 max_translational_jerk,
186 FACTOR_CARTESIAN_ROTATION_POSE_INTERFACE * max_rotational_velocity,
187 FACTOR_CARTESIAN_ROTATION_POSE_INTERFACE * max_rotational_acceleration,
188 FACTOR_CARTESIAN_ROTATION_POSE_INTERFACE * max_rotational_jerk,
189 &commanded_twist,
190 last_O_dP_EE_c,
191 last_O_ddP_EE_c,
192 )?;
193 let dx_head = Vector3::new(limited_twist[0], limited_twist[1], limited_twist[2]);
194 let dx_tail = Vector3::new(limited_twist[3], limited_twist[4], limited_twist[5]);
195
196 let limited_translation = last_commanded_translation + dx_head * DELTA_T;
198 let mut limited_rotation = last_commanded_rotation;
199 let angular_speed = dx_tail.norm();
200 if angular_speed > NORM_EPS {
201 let w_norm = dx_tail / angular_speed;
202 let theta = DELTA_T * angular_speed;
203 let omega_skew = Matrix3::new(
204 0.0, -w_norm[2], w_norm[1], w_norm[2], 0.0, -w_norm[0], -w_norm[1], w_norm[0], 0.0,
207 );
208 let rotation = Matrix3::identity()
209 + theta.sin() * omega_skew
210 + (1.0 - theta.cos()) * (omega_skew * omega_skew);
211 limited_rotation = rotation * last_commanded_rotation;
212 }
213
214 Ok(pose_to_array(&limited_rotation, &limited_translation))
215}
216
217pub(crate) fn scaled_axis(rotation: &Matrix3<f64>) -> Vector3<f64> {
222 let q = UnitQuaternion::from_rotation_matrix(&Rotation3::from_matrix_unchecked(*rotation));
223 let vec = Vector3::new(q.i, q.j, q.k);
224 let mut n = vec.norm();
225 if n == 0.0 {
226 return Vector3::zeros();
227 }
228 let angle = 2.0 * n.atan2(q.w.abs());
229 if q.w < 0.0 {
230 n = -n;
231 }
232 (vec / n) * angle
233}