moveit2
The MoveIt Motion Planning Framework for ROS 2.
test_bullet_continuous_collision_checking.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2019, Jens Petit
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Jens Petit */
36 
37 #include <gtest/gtest.h>
38 #include <rclcpp/rclcpp.hpp>
39 
43 
47 
50 
51 #include <urdf_parser/urdf_parser.h>
52 #include <geometric_shapes/shape_operations.h>
53 
54 namespace cb = collision_detection_bullet;
55 
56 static const rclcpp::Logger TEST_LOGGER = rclcpp::get_logger("collision_detection.bullet_test");
57 
59 inline void setToHome(moveit::core::RobotState& panda_state)
60 {
61  panda_state.setToDefaultValues();
62  double joint2 = -0.785;
63  double joint4 = -2.356;
64  double joint6 = 1.571;
65  double joint7 = 0.785;
66  panda_state.setJointPositions("panda_joint2", &joint2);
67  panda_state.setJointPositions("panda_joint4", &joint4);
68  panda_state.setJointPositions("panda_joint6", &joint6);
69  panda_state.setJointPositions("panda_joint7", &joint7);
70  panda_state.update();
71 }
72 
73 class BulletCollisionDetectionTester : public testing::Test
74 {
75 protected:
76  void SetUp() override
77  {
79  robot_model_ok_ = static_cast<bool>(robot_model_);
80 
81  acm_ = std::make_shared<collision_detection::AllowedCollisionMatrix>(*robot_model_->getSRDF());
82 
83  cenv_ = std::make_shared<collision_detection::CollisionEnvBullet>(robot_model_);
84 
85  robot_state_ = std::make_shared<moveit::core::RobotState>(robot_model_);
86 
88  }
89 
90  void TearDown() override
91  {
92  }
93 
94 protected:
96 
97  moveit::core::RobotModelPtr robot_model_;
98 
99  collision_detection::CollisionEnvPtr cenv_;
100 
101  collision_detection::AllowedCollisionMatrixPtr acm_;
102 
103  moveit::core::RobotStatePtr robot_state_;
104 };
105 
107 {
109  // Add static box to checker
111  shapes::ShapePtr static_box = std::make_shared<shapes::Box>(1, 1, 1);
112  Eigen::Isometry3d static_box_pose;
113  static_box_pose.setIdentity();
114 
115  std::vector<shapes::ShapeConstPtr> obj1_shapes;
117  std::vector<cb::CollisionObjectType> obj1_types;
118  obj1_shapes.push_back(static_box);
119  obj1_poses.push_back(static_box_pose);
120  obj1_types.push_back(cb::CollisionObjectType::USE_SHAPE_TYPE);
121 
122  cb::CollisionObjectWrapperPtr cow_1 = std::make_shared<cb::CollisionObjectWrapper>(
123  "static_box_link", collision_detection::BodyType::WORLD_OBJECT, obj1_shapes, obj1_poses, obj1_types);
124  checker.addCollisionObject(cow_1);
125 
127  // Add moving box to checker
129  shapes::ShapePtr moving_box = std::make_shared<shapes::Box>(0.2, 0.2, 0.2);
130  Eigen::Isometry3d moving_box_pose;
131 
132  moving_box_pose.setIdentity();
133  moving_box_pose.translation() = Eigen::Vector3d(0.5, -0.5, 0);
134 
135  std::vector<shapes::ShapeConstPtr> obj2_shapes;
137  std::vector<cb::CollisionObjectType> obj2_types;
138  obj2_shapes.push_back(moving_box);
139  obj2_poses.push_back(moving_box_pose);
140  obj2_types.push_back(cb::CollisionObjectType::USE_SHAPE_TYPE);
141 
142  cb::CollisionObjectWrapperPtr cow_2 = std::make_shared<cb::CollisionObjectWrapper>(
143  "moving_box_link", collision_detection::BodyType::WORLD_OBJECT, obj2_shapes, obj2_poses, obj2_types);
144  checker.addCollisionObject(cow_2);
145 }
146 
148 {
150  // Add static box to checker
152  shapes::ShapePtr static_box = std::make_shared<shapes::Box>(0.3, 0.3, 0.3);
153  Eigen::Isometry3d static_box_pose;
154  static_box_pose.setIdentity();
155 
156  std::vector<shapes::ShapeConstPtr> obj1_shapes;
158  std::vector<cb::CollisionObjectType> obj1_types;
159  obj1_shapes.push_back(static_box);
160  obj1_poses.push_back(static_box_pose);
161  obj1_types.push_back(cb::CollisionObjectType::USE_SHAPE_TYPE);
162 
163  cb::CollisionObjectWrapperPtr cow_1 = std::make_shared<cb::CollisionObjectWrapper>(
164  "static_box_link", collision_detection::BodyType::WORLD_OBJECT, obj1_shapes, obj1_poses, obj1_types);
165  checker.addCollisionObject(cow_1);
167  // Add moving mesh to checker
169 
170  std::vector<shapes::ShapeConstPtr> obj2_shapes;
172  std::vector<cb::CollisionObjectType> obj2_types;
173 
174  obj1_poses.push_back(static_box_pose);
175  obj1_types.push_back(cb::CollisionObjectType::USE_SHAPE_TYPE);
176 
177  Eigen::Isometry3d s_pose;
178  s_pose.setIdentity();
179 
180  std::string kinect = "package://moveit_resources_panda_description/meshes/collision/hand.stl";
181  auto s = std::shared_ptr<shapes::Shape>{ shapes::createMeshFromResource(kinect) };
182  obj2_shapes.push_back(s);
183  obj2_types.push_back(cb::CollisionObjectType::CONVEX_HULL);
184  obj2_poses.push_back(s_pose);
185 
186  cb::CollisionObjectWrapperPtr cow_2 = std::make_shared<cb::CollisionObjectWrapper>(
187  "moving_box_link", collision_detection::BodyType::WORLD_OBJECT, obj2_shapes, obj2_poses, obj2_types);
188  checker.addCollisionObject(cow_2);
189 }
190 
192  std::vector<collision_detection::Contact>& result_vector, Eigen::Isometry3d& start_pos,
193  Eigen::Isometry3d& end_pos)
194 {
196  // Test when object is inside another
198  checker.setActiveCollisionObjects({ "moving_box_link" });
199  checker.setContactDistanceThreshold(0.1);
200 
201  // Set the collision object transforms
202  checker.setCollisionObjectsTransform("static_box_link", Eigen::Isometry3d::Identity());
203  checker.setCastCollisionObjectsTransform("moving_box_link", start_pos, end_pos);
204 
205  // Perform collision check
207  request.contacts = true;
208  // cb::ContactResultMap result;
209  checker.contactTest(result, request, nullptr, false);
210 
211  for (const auto& contacts_all : result.contacts)
212  {
213  for (const auto& contact : contacts_all.second)
214  {
215  result_vector.push_back(contact);
216  }
217  }
218 }
219 
220 // TODO(j-petit): Add continuous to continuous collision checking
222 TEST_F(BulletCollisionDetectionTester, DISABLED_ContinuousCollisionSelf)
223 {
226 
227  moveit::core::RobotState state1(robot_model_);
228  moveit::core::RobotState state2(robot_model_);
229 
230  setToHome(state1);
231  double joint2 = 0.15;
232  double joint4 = -3.0;
233  double joint5 = -0.8;
234  double joint7 = -0.785;
235  state1.setJointPositions("panda_joint2", &joint2);
236  state1.setJointPositions("panda_joint4", &joint4);
237  state1.setJointPositions("panda_joint5", &joint5);
238  state1.setJointPositions("panda_joint7", &joint7);
239  state1.update();
240 
241  cenv_->checkSelfCollision(req, res, state1, *acm_);
242  ASSERT_FALSE(res.collision);
243  res.clear();
244 
245  setToHome(state2);
246  double joint_5_other = 0.8;
247  state2.setJointPositions("panda_joint2", &joint2);
248  state2.setJointPositions("panda_joint4", &joint4);
249  state2.setJointPositions("panda_joint5", &joint_5_other);
250  state2.setJointPositions("panda_joint7", &joint7);
251  state2.update();
252 
253  cenv_->checkSelfCollision(req, res, state2, *acm_);
254  ASSERT_FALSE(res.collision);
255  res.clear();
256 
257  RCLCPP_INFO(TEST_LOGGER, "Continuous to continuous collisions are not supported yet, therefore fail here.");
258  ASSERT_TRUE(res.collision);
259  res.clear();
260 }
261 
263 TEST_F(BulletCollisionDetectionTester, ContinuousCollisionWorld)
264 {
266  req.contacts = true;
267  req.max_contacts = 10;
269 
270  moveit::core::RobotState state1(robot_model_);
271  moveit::core::RobotState state2(robot_model_);
272 
273  setToHome(state1);
274  state1.update();
275 
276  setToHome(state2);
277  double joint_2{ 0.05 };
278  double joint_4{ -1.6 };
279  state2.setJointPositions("panda_joint2", &joint_2);
280  state2.setJointPositions("panda_joint4", &joint_4);
281  state2.update();
282 
283  cenv_->checkRobotCollision(req, res, state1, state2, *acm_);
284  ASSERT_FALSE(res.collision);
285  res.clear();
286 
287  // Adding the box which is not in collision with the individual states but with the casted one.
288  shapes::Shape* shape = new shapes::Box(0.1, 0.1, 0.1);
289  shapes::ShapeConstPtr shape_ptr(shape);
290 
291  Eigen::Isometry3d pos{ Eigen::Isometry3d::Identity() };
292  pos.translation().x() = 0.43;
293  pos.translation().y() = 0;
294  pos.translation().z() = 0.55;
295  cenv_->getWorld()->addToObject("box", shape_ptr, pos);
296 
297  cenv_->checkRobotCollision(req, res, state1, *acm_);
298  ASSERT_FALSE(res.collision);
299  res.clear();
300 
301  cenv_->checkRobotCollision(req, res, state2, *acm_);
302  ASSERT_FALSE(res.collision);
303  res.clear();
304 
305  cenv_->checkRobotCollision(req, res, state1, state2, *acm_);
306  ASSERT_TRUE(res.collision);
307  ASSERT_EQ(res.contact_count, 4u);
308  // test contact types
309  for (auto& contact_pair : res.contacts)
310  {
311  for (collision_detection::Contact& contact : contact_pair.second)
312  {
313  collision_detection::BodyType contact_type1 = contact.body_name_1 == "box" ?
316  collision_detection::BodyType contact_type2 = contact.body_name_2 == "box" ?
319  ASSERT_EQ(contact.body_type_1, contact_type1);
320  ASSERT_EQ(contact.body_type_2, contact_type2);
321  }
322  }
323  res.clear();
324 }
325 
326 TEST(ContinuousCollisionUnit, BulletCastBVHCollisionBoxBoxUnit)
327 {
329  std::vector<collision_detection::Contact> result_vector;
330 
331  Eigen::Isometry3d start_pos, end_pos;
332  start_pos.setIdentity();
333  start_pos.translation().x() = -2;
334  end_pos.setIdentity();
335  end_pos.translation().x() = 2;
336 
337  cb::BulletCastBVHManager checker;
338  addCollisionObjects(checker);
339  runTest(checker, result, result_vector, start_pos, end_pos);
340 
341  ASSERT_TRUE(result.collision);
342  EXPECT_NEAR(result_vector[0].depth, -0.6, 0.001);
343  EXPECT_NEAR(result_vector[0].percent_interpolation, 0.6, 0.001);
344 }
345 
346 TEST(ContinuousCollisionUnit, BulletCastMeshVsBox)
347 {
348  cb::BulletCastBVHManager checker;
349  addCollisionObjectsMesh(checker);
350 
351  Eigen::Isometry3d start_pos, end_pos;
352  start_pos.setIdentity();
353  start_pos.translation().x() = -1.9;
354  end_pos.setIdentity();
355  end_pos.translation().x() = 1.9;
356 
358  std::vector<collision_detection::Contact> result_vector;
359 
360  runTest(checker, result, result_vector, start_pos, end_pos);
361 
362  ASSERT_TRUE(result.collision);
363 }
364 
365 int main(int argc, char** argv)
366 {
367  testing::InitGoogleTest(&argc, argv);
368  return RUN_ALL_TESTS();
369 }
collision_detection::AllowedCollisionMatrixPtr acm_
void setCollisionObjectsTransform(const std::string &name, const Eigen::Isometry3d &pose)
Set a single static collision object's tansform.
void setContactDistanceThreshold(double contact_distance)
Set the contact distance threshold for which collision should be considered through expanding the AAB...
void setActiveCollisionObjects(const std::vector< std::string > &names)
Set which collision objects are active.
A bounding volume hierarchy (BVH) implementation of a tesseract contact manager.
void setCastCollisionObjectsTransform(const std::string &name, const Eigen::Isometry3d &pose1, const Eigen::Isometry3d &pose2)
Set a single cast (moving) collision object's tansforms.
void contactTest(collision_detection::CollisionResult &collisions, const collision_detection::CollisionRequest &req, const collision_detection::AllowedCollisionMatrix *acm, bool self) override
Perform a contact test for all objects.
void addCollisionObject(const CollisionObjectWrapperPtr &cow) override
Add a tesseract collision object to the manager.
Representation of a robot's state. This includes position, velocity, acceleration and effort.
Definition: robot_state.h:90
void update(bool force=false)
Update all transforms.
void setToDefaultValues()
Set all joints to their default positions. The default position is 0, or if that is not within bounds...
void setJointPositions(const std::string &joint_name, const double *position)
Definition: robot_state.h:515
Type
The types of bodies that are considered for collision.
@ ROBOT_LINK
A link on the robot.
@ WORLD_OBJECT
A body in the environment.
std::vector< T, Eigen::aligned_allocator< T > > AlignedVector
Definition: basic_types.h:37
Vec3fX< details::Vec3Data< double > > Vector3d
Definition: fcl_compat.h:89
moveit::core::RobotModelPtr loadTestingRobotModel(const std::string &robot_name)
Loads a robot from moveit_resources.
Representation of a collision checking request.
bool contacts
If true, compute contacts. Otherwise only a binary collision yes/no is reported.
std::size_t max_contacts
Overall maximum number of contacts to compute.
Representation of a collision checking result.
ContactMap contacts
A map returning the pairs of body ids in contact, plus their contact details.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW void clear()
Clear a previously stored result.
bool collision
True if collision was found, false otherwise.
std::size_t contact_count
Number of contacts returned.
Definition of a contact point.
std::string body_name_2
The id of the second body involved in the contact.
std::string body_name_1
The id of the first body involved in the contact.
BodyType body_type_1
The type of the first body involved in the contact.
BodyType body_type_2
The type of the second body involved in the contact.
int main(int argc, char **argv)
void addCollisionObjectsMesh(cb::BulletCastBVHManager &checker)
TEST(ContinuousCollisionUnit, BulletCastBVHCollisionBoxBoxUnit)
void runTest(cb::BulletCastBVHManager &checker, collision_detection::CollisionResult &result, std::vector< collision_detection::Contact > &result_vector, Eigen::Isometry3d &start_pos, Eigen::Isometry3d &end_pos)
void setToHome(moveit::core::RobotState &panda_state)
Brings the panda robot in user defined home position.
TEST_F(BulletCollisionDetectionTester, DISABLED_ContinuousCollisionSelf)
Continuous self collision checks are not supported yet by the bullet integration.
void addCollisionObjects(cb::BulletCastBVHManager &checker)