1#![allow(clippy::trivially_copy_pass_by_ref)]
17
18use k::{nalgebra as na, InverseKinematicsSolver, SubsetOf};
19use na::RealField;
20use parking_lot::Mutex;
21use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
22
23use crate::funcs::*;
24
25#[derive(Debug)]
27pub struct RandomInitializeIkSolver<T, I>
28where
29 I: InverseKinematicsSolver<T>,
30 T: RealField,
31{
32 pub solver: I,
34 pub num_max_try: usize,
36 phantom: ::std::marker::PhantomData<T>,
37}
38
39impl<T, I> RandomInitializeIkSolver<T, I>
40where
41 T: RealField,
42 I: InverseKinematicsSolver<T>,
43{
44 pub fn new(solver: I, num_max_try: usize) -> Self {
45 RandomInitializeIkSolver {
46 solver,
47 num_max_try,
48 phantom: ::std::marker::PhantomData,
49 }
50 }
51}
52
53impl<T, I> InverseKinematicsSolver<T> for RandomInitializeIkSolver<T, I>
54where
55 T: RealField + Copy + SubsetOf<f64>,
56 I: InverseKinematicsSolver<T>,
57{
58 fn solve_with_constraints(
59 &self,
60 arm: &k::SerialChain<T>,
61 target_pose: &na::Isometry3<T>,
62 constraints: &k::Constraints,
63 ) -> ::std::result::Result<(), k::Error> {
64 let mut result = Err(k::Error::NotConvergedError {
65 num_tried: 0,
66 position_diff: na::Vector3::new(0.0, 0.0, 0.0),
67 rotation_diff: na::Vector3::new(0.0, 0.0, 0.0),
68 });
69 let limits = arm.iter_joints().map(|j| j.limits).collect();
70 let initial_angles = arm.joint_positions();
71
72 for _ in 0..self.num_max_try {
73 result = self
74 .solver
75 .solve_with_constraints(arm, target_pose, constraints);
76 if result.is_ok() {
77 return result;
78 }
79 let mut new_angles = generate_random_joint_positions_from_limits(&limits);
80 modify_to_nearest_angle(&initial_angles, &mut new_angles, &limits);
81 arm.set_joint_positions(&new_angles)?;
82 }
83 arm.set_joint_positions(&initial_angles)?;
85 result
86 }
87}
88
89pub fn get_reachable_region<T, I>(
91 ik_solver: &I,
92 arm: &k::SerialChain<T>,
93 initial_pose: &na::Isometry3<T>,
94 constraints: &k::Constraints,
95 max_point: na::Vector3<T>,
96 min_point: na::Vector3<T>,
97 unit_check_length: T,
98) -> Vec<na::Isometry3<T>>
99where
100 T: RealField + Copy + k::SubsetOf<f64> + Send + Sync,
101 I: InverseKinematicsSolver<T> + Send + Sync,
102{
103 let initial_angles = arm.joint_positions();
104 let solved_poses = Mutex::new(Vec::new());
105 let target_pose = *initial_pose;
106
107 let mut z_points = vec![];
108 let mut z = min_point[2];
109 while z < max_point[2] {
110 z_points.push(z);
111 z += unit_check_length;
112 }
113
114 z_points.par_iter().for_each(|&z| {
115 let arm = arm.clone();
116 let mut target_pose = target_pose;
117 target_pose.translation.vector[2] = z;
118 let mut y = min_point[1];
119 while y < max_point[1] {
120 target_pose.translation.vector[1] = y;
121 let mut x = min_point[0];
122 while x < max_point[0] {
123 target_pose.translation.vector[0] = x;
124 arm.set_joint_positions_unchecked(&initial_angles);
125 if ik_solver
126 .solve_with_constraints(&arm, &target_pose, constraints)
127 .is_ok()
128 {
129 solved_poses.lock().push(target_pose);
130 }
131 x += unit_check_length;
132 }
133 y += unit_check_length;
134 }
135 });
136 solved_poses.into_inner()
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn get_region() {
145 let robot = k::Chain::<f32>::from_urdf_file("sample.urdf").unwrap();
146 let target_link = robot.find("l_tool_fixed").unwrap();
147 let chain = k::SerialChain::from_end(target_link);
148
149 let angles = vec![0.2, 0.2, 0.0, -1.0, 0.0, 0.0];
151
152 chain.set_joint_positions(&angles).unwrap();
153 println!("initial angles={:?}", chain.joint_positions());
154
155 chain.update_transforms();
157 let target = target_link.world_transform().unwrap();
158 println!("{:?}", target.translation);
159 let solver = k::JacobianIkSolver::default();
161
162 let arm = k::SerialChain::from_end(target_link);
164 let regions = get_reachable_region(
165 &solver,
166 &arm,
167 &target,
168 &k::Constraints::default(),
169 na::Vector3::new(0.8, 0.9, 0.9),
170 na::Vector3::new(0.0, -0.9, 0.0),
171 0.1,
172 );
173 assert_eq!(regions.len(), 114);
174 }
175}