openrr_planner/collision/
robot_collision_detector.rs1use 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(&urdf_robot, config.prediction);
143
144 RobotCollisionDetector::new(robot, collision_detector, self_collision_pairs)
145}
146
147#[test]
148fn test_robot_collision_detector() {
149 let urdf_path = Path::new("sample.urdf");
150 let self_collision_pairs = vec![("root".into(), "l_shoulder_roll".into())];
151 let robot_collision_detector = create_robot_collision_detector(
152 urdf_path,
153 RobotCollisionDetectorConfig::default(),
154 self_collision_pairs,
155 );
156
157 robot_collision_detector
158 .robot
159 .set_joint_positions_clamped(&[0.0; 16]);
160 assert!(!robot_collision_detector.is_self_collision_detected());
161
162 robot_collision_detector
163 .robot
164 .set_joint_positions_clamped(&[
165 -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,
166 ]);
167 assert!(robot_collision_detector.is_self_collision_detected());
168}
169
170pub fn create_all_collision_pairs<N>(robot: &k::Chain<N>) -> Vec<(String, String)>
174where
175 N: RealField + Copy + k::SubsetOf<f64>,
176{
177 let mut pairs: Vec<(String, String)> = Vec::new();
178
179 for node1 in robot.iter() {
180 let joint1_name = node1.joint().name.clone();
181 for node2 in robot.iter() {
182 let joint2_name = node2.joint().name.clone();
183
184 let is_this_pair_valid = !(joint1_name == joint2_name
186 || (node1.parent().is_some()
187 && node1.parent().unwrap().joint().name == joint2_name)
188 || (node2.parent().is_some()
189 && node2.parent().unwrap().joint().name == joint1_name));
190
191 if is_this_pair_valid {
193 let pair = if joint1_name < joint2_name {
194 (
195 joint1_name.clone().to_owned(),
196 joint2_name.clone().to_owned(),
197 )
198 } else {
199 (
200 joint2_name.clone().to_owned(),
201 joint1_name.clone().to_owned(),
202 )
203 };
204 pairs.push(pair);
205 }
206 }
207 }
208
209 pairs.sort();
211 pairs.dedup();
212
213 pairs
214}
215
216#[test]
217fn test_create_all_collision_pairs() {
218 let urdf_robot = urdf_rs::read_file("sample.urdf").unwrap();
219 let robot = k::Chain::<f32>::from(&urdf_robot);
220
221 let node = robot.iter().take(1).cloned().collect();
222 let trivial_chain = k::Chain::from_nodes(node);
223 assert_eq!(create_all_collision_pairs(&trivial_chain).len(), 0);
224
225 let nodes = robot.iter().take(5).cloned().collect();
226 let sub_chain = k::Chain::from_nodes(nodes);
227
228 assert_eq!(create_all_collision_pairs(&sub_chain).len(), 6);
233}
234
235#[test]
236fn test_create_all_collision_pairs_without_urdf() {
237 use k::{joint::*, node::*};
238
239 let joint0 = NodeBuilder::new()
240 .name("joint0")
241 .translation(na::Translation3::new(0.1, 0.0, 0.0))
242 .joint_type(JointType::Rotational {
243 axis: na::Vector3::y_axis(),
244 })
245 .into_node();
246 let joint1 = NodeBuilder::new()
247 .name("joint1")
248 .translation(na::Translation3::new(0.1, 0.0, 0.0))
249 .joint_type(JointType::Rotational {
250 axis: na::Vector3::y_axis(),
251 })
252 .into_node();
253 let joint2 = NodeBuilder::new()
254 .name("joint2")
255 .translation(na::Translation3::new(0.1, 0.0, 0.0))
256 .joint_type(JointType::Rotational {
257 axis: na::Vector3::y_axis(),
258 })
259 .into_node();
260 let joint3 = NodeBuilder::new()
261 .name("joint3")
262 .translation(na::Translation3::new(0.1, 0.0, 0.0))
263 .joint_type(JointType::Rotational {
264 axis: na::Vector3::y_axis(),
265 })
266 .into_node();
267 joint1.set_parent(&joint0);
268 joint2.set_parent(&joint1);
269 joint3.set_parent(&joint2);
270
271 let chain = k::Chain::from_root(joint0);
272
273 assert_eq!(create_all_collision_pairs(&chain).len(), 3);
276}