1use std::sync::Arc;
2
3use arci::{Error, JointTrajectoryClient, TrajectoryPoint, WaitFuture};
4use k::{nalgebra as na, Constraints, Isometry3};
5use schemars::{gen::SchemaGenerator, schema::Schema, JsonSchema};
6use serde::{Deserialize, Serialize};
7
8pub fn isometry(x: f64, y: f64, z: f64, roll: f64, pitch: f64, yaw: f64) -> k::Isometry3<f64> {
9 k::Isometry3::from_parts(
10 k::Translation3::new(x, y, z),
11 k::UnitQuaternion::from_euler_angles(roll, pitch, yaw),
12 )
13}
14
15#[derive(Debug)]
16pub struct IkSolverParameters {
17 pub allowable_position_error: f64, pub allowable_angle_error: f64, pub jacobian_multiplier: f64,
20 pub num_max_try: usize,
21}
22
23pub fn create_jacobian_ik_solver(parameters: &IkSolverParameters) -> k::JacobianIkSolver<f64> {
24 k::JacobianIkSolver::new(
25 parameters.allowable_position_error,
26 parameters.allowable_angle_error,
27 parameters.jacobian_multiplier,
28 parameters.num_max_try,
29 )
30}
31
32pub fn create_random_jacobian_ik_solver(
33 parameters: &IkSolverParameters,
34) -> openrr_planner::RandomInitializeIkSolver<f64, k::JacobianIkSolver<f64>> {
35 openrr_planner::RandomInitializeIkSolver::new(
36 create_jacobian_ik_solver(parameters),
37 parameters.num_max_try,
38 )
39}
40
41pub struct IkSolverWithChain {
42 ik_arm: k::SerialChain<f64>,
43 ik_solver: Arc<dyn k::InverseKinematicsSolver<f64> + Send + Sync>,
44 constraints: Constraints,
45}
46
47impl IkSolverWithChain {
48 pub fn end_transform(&self) -> k::Isometry3<f64> {
49 self.ik_arm.end_transform()
50 }
51
52 pub fn joint_names(&self) -> Vec<String> {
53 self.ik_arm
54 .iter_joints()
55 .map(|joint| joint.name.clone())
56 .collect()
57 }
58
59 pub fn joint_positions(&self) -> Vec<f64> {
60 self.ik_arm.joint_positions()
61 }
62
63 pub fn solve_with_constraints(
64 &self,
65 target_pose: &k::Isometry3<f64>,
66 constraints: &Constraints,
67 ) -> Result<(), Error> {
68 self.ik_solver
69 .solve_with_constraints(&self.ik_arm, target_pose, constraints)
70 .map_err(|e| Error::Other(e.into()))
71 }
72
73 pub fn solve(&self, target_pose: &k::Isometry3<f64>) -> Result<(), Error> {
74 self.solve_with_constraints(target_pose, &self.constraints)
75 }
76
77 pub fn set_joint_positions_clamped(&self, positions: &[f64]) {
78 self.ik_arm.set_joint_positions_clamped(positions)
79 }
80
81 pub fn new(
82 arm: k::SerialChain<f64>,
83 ik_solver: Arc<dyn k::InverseKinematicsSolver<f64> + Send + Sync>,
84 constraints: Constraints,
85 ) -> Self {
86 Self {
87 ik_arm: arm,
88 ik_solver,
89 constraints,
90 }
91 }
92
93 pub fn constraints(&self) -> &Constraints {
94 &self.constraints
95 }
96
97 pub fn generate_trajectory_with_interpolation(
98 &self,
99 current_pose: &Isometry3<f64>,
100 target_pose: &Isometry3<f64>,
101 duration_sec: f64,
102 max_resolution: f64,
103 min_number_of_points: i32,
104 ) -> Result<Vec<TrajectoryPoint>, Error> {
105 self.generate_trajectory_with_interpolation_and_constraints(
106 current_pose,
107 target_pose,
108 &self.constraints,
109 duration_sec,
110 max_resolution,
111 min_number_of_points,
112 )
113 }
114
115 pub fn generate_trajectory_with_interpolation_and_constraints(
116 &self,
117 current_pose: &Isometry3<f64>,
118 target_pose: &Isometry3<f64>,
119 constraints: &Constraints,
120 duration_sec: f64,
121 max_resolution: f64,
122 min_number_of_points: i32,
123 ) -> Result<Vec<TrajectoryPoint>, Error> {
124 let target_position = target_pose.translation.vector;
125 let target_rotation = target_pose.rotation;
126 let current_position = current_pose.translation.vector;
127 let current_rotation = current_pose.rotation;
128
129 let position_diff = target_position - current_position;
130 let n = std::cmp::max(
131 min_number_of_points,
132 (position_diff.norm() / max_resolution) as i32,
133 );
134 let mut traj = vec![];
135 if n == 0 {
136 self.solve_with_constraints(target_pose, constraints)?;
137 let trajectory = TrajectoryPoint::new(
138 self.joint_positions(),
139 std::time::Duration::from_secs_f64(duration_sec),
140 );
141 traj.push(trajectory);
142 } else {
143 for i in 1..n + 1 {
144 let t = i as f64 / n as f64;
145 let tar_pos = current_position.lerp(&target_position, t);
146 let tar_rot = current_rotation.slerp(&target_rotation, t);
147 self.solve_with_constraints(
148 &k::Isometry3::from_parts(na::Translation3::from(tar_pos), tar_rot),
149 constraints,
150 )?;
151 let trajectory = TrajectoryPoint::new(
152 self.joint_positions(),
153 std::time::Duration::from_secs_f64(t * duration_sec),
154 );
155 traj.push(trajectory);
156 }
157 }
158 Ok(traj)
159 }
160}
161
162pub struct IkClient<T>
163where
164 T: JointTrajectoryClient,
165{
166 pub client: T,
167 pub ik_solver_with_chain: Arc<IkSolverWithChain>,
168}
169
170impl<T> IkClient<T>
171where
172 T: JointTrajectoryClient + Send,
173{
174 pub fn new(client: T, ik_solver_with_chain: Arc<IkSolverWithChain>) -> Self {
175 if ik_solver_with_chain.ik_arm.dof() != client.joint_names().len() {
176 panic!(
177 "Invalid configuration : ik arm dof {} {:?} != joint_names length {} ({:?})",
178 ik_solver_with_chain.ik_arm.dof(),
179 ik_solver_with_chain
180 .ik_arm
181 .iter_joints()
182 .map(|j| j.name.to_owned())
183 .collect::<Vec<_>>(),
184 client.joint_names().len(),
185 client.joint_names()
186 );
187 }
188 Self {
189 client,
190 ik_solver_with_chain,
191 }
192 }
193
194 pub fn current_end_transform(&self) -> Result<k::Isometry3<f64>, Error> {
195 let current_joint_angles = self.client.current_joint_positions()?;
196 self.set_joint_positions_clamped(¤t_joint_angles);
197 Ok(self.ik_solver_with_chain.end_transform())
198 }
199
200 pub fn move_ik_with_constraints(
201 &self,
202 target_pose: &k::Isometry3<f64>,
203 constraints: &Constraints,
204 duration_sec: f64,
205 ) -> Result<WaitFuture, Error> {
206 self.ik_solver_with_chain
207 .solve_with_constraints(target_pose, constraints)?;
208
209 let positions = self.ik_solver_with_chain.joint_positions();
210 let duration = std::time::Duration::from_secs_f64(duration_sec);
211 self.client.send_joint_positions(positions, duration)
212 }
213
214 pub fn move_ik_with_interpolation_and_constraints(
215 &self,
216 target_pose: &k::Isometry3<f64>,
217 constraints: &Constraints,
218 duration_sec: f64,
219 max_resolution: f64,
220 min_number_of_points: i32,
221 ) -> Result<WaitFuture, Error> {
222 self.client.send_joint_trajectory(
223 self.ik_solver_with_chain
224 .generate_trajectory_with_interpolation_and_constraints(
225 &self.current_end_transform()?,
226 target_pose,
227 constraints,
228 duration_sec,
229 max_resolution,
230 min_number_of_points,
231 )?,
232 )
233 }
234
235 pub fn move_ik(
236 &self,
237 target_pose: &k::Isometry3<f64>,
238 duration_sec: f64,
239 ) -> Result<WaitFuture, Error> {
240 self.ik_solver_with_chain.solve(target_pose)?;
241
242 let positions = self.ik_solver_with_chain.joint_positions();
243 let duration = std::time::Duration::from_secs_f64(duration_sec);
244 self.client.send_joint_positions(positions, duration)
245 }
246
247 pub fn move_ik_with_interpolation(
248 &self,
249 target_pose: &k::Isometry3<f64>,
250 duration_sec: f64,
251 max_resolution: f64,
252 min_number_of_points: i32,
253 ) -> Result<WaitFuture, Error> {
254 self.client.send_joint_trajectory(
255 self.ik_solver_with_chain
256 .generate_trajectory_with_interpolation(
257 &self.current_end_transform()?,
258 target_pose,
259 duration_sec,
260 max_resolution,
261 min_number_of_points,
262 )?,
263 )
264 }
265
266 pub fn transform(&self, relative_pose: &k::Isometry3<f64>) -> Result<k::Isometry3<f64>, Error> {
268 Ok(self.current_end_transform()? * relative_pose)
269 }
270
271 pub fn set_zero_pose_for_kinematics(&self) -> Result<(), Error> {
273 let zero_angles = vec![0.0; self.ik_solver_with_chain.ik_arm.dof()];
274 self.ik_solver_with_chain
275 .ik_arm
276 .set_joint_positions(&zero_angles)
277 .map_err(|e| Error::Other(e.into()))?;
278 Ok(())
279 }
280
281 pub fn constraints(&self) -> &Constraints {
282 self.ik_solver_with_chain.constraints()
283 }
284
285 pub fn set_joint_positions_clamped(&self, positions: &[f64]) {
286 self.ik_solver_with_chain
287 .set_joint_positions_clamped(positions)
288 }
289}
290
291impl<T> JointTrajectoryClient for IkClient<T>
292where
293 T: JointTrajectoryClient,
294{
295 fn joint_names(&self) -> Vec<String> {
296 self.client.joint_names()
297 }
298
299 fn current_joint_positions(&self) -> Result<Vec<f64>, Error> {
300 self.client.current_joint_positions()
301 }
302
303 fn send_joint_positions(
304 &self,
305 positions: Vec<f64>,
306 duration: std::time::Duration,
307 ) -> Result<WaitFuture, Error> {
308 self.client.send_joint_positions(positions, duration)
309 }
310
311 fn send_joint_trajectory(&self, trajectory: Vec<TrajectoryPoint>) -> Result<WaitFuture, Error> {
312 self.client.send_joint_trajectory(trajectory)
313 }
314}
315
316#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
317#[serde(deny_unknown_fields)]
318pub struct IkSolverConfig {
319 pub root_node_name: Option<String>,
320 pub ik_target: String,
321 #[serde(default)]
322 pub use_random_ik: bool,
323 #[serde(default = "default_allowable_position_error_m")]
324 pub allowable_position_error_m: f64,
325 #[serde(default = "default_allowable_angle_error_rad")]
326 pub allowable_angle_error_rad: f64,
327 #[serde(default = "default_jacobian_multiplier")]
328 pub jacobian_multiplier: f64,
329 #[serde(default = "default_num_max_try")]
330 pub num_max_try: usize,
331 #[serde(default)]
332 #[schemars(schema_with = "constraints_schema")]
333 pub constraints: Constraints,
334}
335
336fn default_allowable_position_error_m() -> f64 {
337 0.005
338}
339fn default_allowable_angle_error_rad() -> f64 {
340 0.005
341}
342fn default_jacobian_multiplier() -> f64 {
343 0.1
344}
345fn default_num_max_try() -> usize {
346 300
347}
348
349fn constraints_schema(gen: &mut SchemaGenerator) -> Schema {
350 fn default_true() -> bool {
351 true
352 }
353 #[allow(dead_code)]
356 #[derive(Serialize, JsonSchema)]
357 struct ConstraintsSchema {
358 #[serde(default = "default_true")]
361 position_x: bool,
362 #[serde(default = "default_true")]
363 position_y: bool,
364 #[serde(default = "default_true")]
365 position_z: bool,
366 #[serde(default = "default_true")]
367 rotation_x: bool,
368 #[serde(default = "default_true")]
369 rotation_y: bool,
370 #[serde(default = "default_true")]
371 rotation_z: bool,
372 }
373 impl Default for ConstraintsSchema {
374 fn default() -> Self {
375 Self {
376 position_x: default_true(),
377 position_y: default_true(),
378 position_z: default_true(),
379 rotation_x: default_true(),
380 rotation_y: default_true(),
381 rotation_z: default_true(),
382 }
383 }
384 }
385
386 ConstraintsSchema::json_schema(gen)
387}
388
389pub fn create_ik_solver_with_chain(
390 full_chain: &k::Chain<f64>,
391 config: &IkSolverConfig,
392) -> IkSolverWithChain {
393 let chain = if let Some(root_node_name) = &config.root_node_name {
394 k::SerialChain::from_end_to_root(
395 full_chain
396 .find(&config.ik_target)
397 .unwrap_or_else(|| panic!("ik_target: {} not found", config.ik_target)),
398 full_chain
399 .find(root_node_name)
400 .unwrap_or_else(|| panic!("root_node_name: {root_node_name} not found")),
401 )
402 } else {
403 k::SerialChain::from_end(
404 full_chain
405 .find(&config.ik_target)
406 .unwrap_or_else(|| panic!("ik_target: {} not found", config.ik_target)),
407 )
408 };
409
410 let parameters = IkSolverParameters {
411 allowable_position_error: config.allowable_position_error_m,
412 allowable_angle_error: config.allowable_angle_error_rad,
413 jacobian_multiplier: config.jacobian_multiplier,
414 num_max_try: config.num_max_try,
415 };
416
417 IkSolverWithChain::new(
418 chain,
419 if config.use_random_ik {
420 Arc::new(create_random_jacobian_ik_solver(¶meters))
421 } else {
422 Arc::new(create_jacobian_ik_solver(¶meters))
423 },
424 config.constraints.clone(),
425 )
426}