openrr_planner/collision/
robot_collision_detector.rs
1use std::path::Path;
2
3use k::nalgebra as na;
4use na::RealField;
5use ncollide3d::shape::{Compound, Shape};
6use schemars::JsonSchema;
7use serde::{Deserialize, Serialize};
8
9use crate::collision::{CollisionDetector, EnvCollisionNames, SelfCollisionPairs};
10
11pub struct RobotCollisionDetector<N>
12where
13 N: RealField + Copy + k::SubsetOf<f64>,
14{
15 pub robot: k::Chain<N>,
17 pub collision_detector: CollisionDetector<N>,
19 pub self_collision_pairs: Vec<(String, String)>,
21}
22
23impl<N> RobotCollisionDetector<N>
25where
26 N: RealField + Copy + k::SubsetOf<f64>,
27{
28 pub fn new(
29 robot: k::Chain<N>,
30 collision_detector: CollisionDetector<N>,
31 self_collision_pairs: Vec<(String, String)>,
32 ) -> Self {
33 RobotCollisionDetector {
34 robot,
35 collision_detector,
36 self_collision_pairs,
37 }
38 }
39
40 pub fn detect_env<'a>(
45 &'a self,
46 target_shape: &'a dyn Shape<N>,
47 target_pose: &'a na::Isometry3<N>,
48 ) -> EnvCollisionNames<'a, 'a, N> {
49 self.robot.update_transforms();
50
51 EnvCollisionNames::new(
52 &self.collision_detector,
53 &self.robot,
54 target_shape,
55 target_pose,
56 )
57 }
58
59 pub fn detect_self(&self) -> SelfCollisionPairs<'_, N> {
61 self.robot.update_transforms();
62
63 SelfCollisionPairs::new(
64 &self.collision_detector,
65 &self.robot,
66 &self.self_collision_pairs,
67 )
68 }
69
70 pub fn env_collision_link_names(&self, objects: &Compound<N>) -> Vec<String> {
73 let mut ret = Vec::new();
74 for shape in objects.shapes() {
75 let mut colliding_names = self.detect_env(&*shape.1, &shape.0).collect();
76 ret.append(&mut colliding_names);
77 }
78 ret
79 }
80
81 pub fn self_collision_link_pairs(&self) -> Vec<(String, String)> {
83 self.detect_self().collect()
84 }
85
86 pub fn is_env_collision_detected(&self, objects: &Compound<N>) -> bool {
89 for shape in objects.shapes() {
90 if self.detect_env(&*shape.1, &shape.0).next().is_some() {
91 return true;
92 }
93 }
94 false
95 }
96
97 pub fn is_self_collision_detected(&self) -> bool {
99 self.detect_self().next().is_some()
100 }
101
102 pub fn is_collision_detected(&self, objects: &Compound<N>) -> bool {
105 self.is_env_collision_detected(objects) | self.is_self_collision_detected()
106 }
107}
108
109#[derive(Clone, Serialize, Deserialize, Debug, JsonSchema)]
110#[serde(deny_unknown_fields)]
111pub struct RobotCollisionDetectorConfig {
113 #[serde(default = "default_prediction")]
114 pub prediction: f64,
115}
116
117fn default_prediction() -> f64 {
118 0.001
119}
120
121impl RobotCollisionDetectorConfig {
122 pub fn new(prediction: f64) -> Self {
123 RobotCollisionDetectorConfig { prediction }
124 }
125}
126
127impl Default for RobotCollisionDetectorConfig {
128 fn default() -> Self {
129 Self {
130 prediction: default_prediction(),
131 }
132 }
133}
134
135pub fn create_robot_collision_detector<P: AsRef<Path>>(
136 urdf_path: P,
137 config: RobotCollisionDetectorConfig,
138 self_collision_pairs: Vec<(String, String)>,
139) -> RobotCollisionDetector<f64> {
140 let urdf_robot = urdf_rs::read_file(&urdf_path).unwrap();
141 let robot = k::Chain::<f64>::from(&urdf_robot);
142 let collision_detector = CollisionDetector::from_urdf_robot_with_base_dir(
143 &urdf_robot,
144 urdf_path.as_ref().parent(),
145 config.prediction,
146 );
147
148 RobotCollisionDetector::new(robot, collision_detector, self_collision_pairs)
149}
150
151#[test]
152fn test_robot_collision_detector() {
153 let urdf_path = Path::new("sample.urdf");
154 let self_collision_pairs = vec![("root".into(), "l_shoulder_roll".into())];
155 let robot_collision_detector = create_robot_collision_detector(
156 urdf_path,
157 RobotCollisionDetectorConfig::default(),
158 self_collision_pairs,
159 );
160
161 robot_collision_detector
162 .robot
163 .set_joint_positions_clamped(&[0.0; 16]);
164 assert!(!robot_collision_detector.is_self_collision_detected());
165
166 robot_collision_detector
167 .robot
168 .set_joint_positions_clamped(&[
169 -1.57, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
170 ]);
171 assert!(robot_collision_detector.is_self_collision_detected());
172}
173
174pub fn create_all_collision_pairs<N>(robot: &k::Chain<N>) -> Vec<(String, String)>
178where
179 N: RealField + Copy + k::SubsetOf<f64>,
180{
181 let mut pairs: Vec<(String, String)> = Vec::new();
182
183 for node1 in robot.iter() {
184 let joint1_name = node1.joint().name.clone();
185 for node2 in robot.iter() {
186 let joint2_name = node2.joint().name.clone();
187
188 let is_this_pair_valid = !(joint1_name == joint2_name
190 || (node1.parent().is_some()
191 && node1.parent().unwrap().joint().name == joint2_name)
192 || (node2.parent().is_some()
193 && node2.parent().unwrap().joint().name == joint1_name));
194
195 if is_this_pair_valid {
197 let pair = if joint1_name < joint2_name {
198 (
199 joint1_name.clone().to_owned(),
200 joint2_name.clone().to_owned(),
201 )
202 } else {
203 (
204 joint2_name.clone().to_owned(),
205 joint1_name.clone().to_owned(),
206 )
207 };
208 pairs.push(pair);
209 }
210 }
211 }
212
213 pairs.sort();
215 pairs.dedup();
216
217 pairs
218}
219
220#[test]
221fn test_create_all_collision_pairs() {
222 let urdf_robot = urdf_rs::read_file("sample.urdf").unwrap();
223 let robot = k::Chain::<f32>::from(&urdf_robot);
224
225 let node = robot.iter().take(1).cloned().collect();
226 let trivial_chain = k::Chain::from_nodes(node);
227 assert_eq!(create_all_collision_pairs(&trivial_chain).len(), 0);
228
229 let nodes = robot.iter().take(5).cloned().collect();
230 let sub_chain = k::Chain::from_nodes(nodes);
231
232 assert_eq!(create_all_collision_pairs(&sub_chain).len(), 6);
237}
238
239#[test]
240fn test_create_all_collision_pairs_without_urdf() {
241 use k::{joint::*, node::*};
242
243 let joint0 = NodeBuilder::new()
244 .name("joint0")
245 .translation(na::Translation3::new(0.1, 0.0, 0.0))
246 .joint_type(JointType::Rotational {
247 axis: na::Vector3::y_axis(),
248 })
249 .into_node();
250 let joint1 = NodeBuilder::new()
251 .name("joint1")
252 .translation(na::Translation3::new(0.1, 0.0, 0.0))
253 .joint_type(JointType::Rotational {
254 axis: na::Vector3::y_axis(),
255 })
256 .into_node();
257 let joint2 = NodeBuilder::new()
258 .name("joint2")
259 .translation(na::Translation3::new(0.1, 0.0, 0.0))
260 .joint_type(JointType::Rotational {
261 axis: na::Vector3::y_axis(),
262 })
263 .into_node();
264 let joint3 = NodeBuilder::new()
265 .name("joint3")
266 .translation(na::Translation3::new(0.1, 0.0, 0.0))
267 .joint_type(JointType::Rotational {
268 axis: na::Vector3::y_axis(),
269 })
270 .into_node();
271 joint1.set_parent(&joint0);
272 joint2.set_parent(&joint1);
273 joint3.set_parent(&joint2);
274
275 let chain = k::Chain::from_root(joint0);
276
277 assert_eq!(create_all_collision_pairs(&chain).len(), 3);
280}