38#include <gtest/gtest.h>
43#include <urdf_parser/urdf_parser.h>
47#include <tf2_eigen/tf2_eigen.hpp>
48#include <octomap_msgs/conversions.h>
49#include <octomap/octomap.h>
55TEST(PlanningScene, TestOneShapeObjectPose)
58 srdf::ModelSharedPtr srdf_model = std::make_shared<srdf::Model>();
61 const std::string object_name =
"object";
62 const Eigen::Isometry3d expected_transfrom = Eigen::Isometry3d::Identity() * Eigen::Translation3d(0.5, -0.25, 0.0);
64 moveit_msgs::msg::CollisionObject co;
65 co.header.frame_id =
"base_footprint";
67 co.operation = moveit_msgs::msg::CollisionObject::ADD;
68 co.primitives.push_back([] {
69 shape_msgs::msg::SolidPrimitive primitive;
70 primitive.type = shape_msgs::msg::SolidPrimitive::CYLINDER;
71 primitive.dimensions = { 0.25, 0.02 };
74 co.primitive_poses.push_back(tf2::toMsg(expected_transfrom));
81TEST(PlanningScene, LoadRestore)
84 srdf::ModelSharedPtr srdf_model = std::make_shared<srdf::Model>();
86 moveit_msgs::msg::PlanningScene ps_msg;
88 EXPECT_EQ(ps.
getName(), ps_msg.name);
89 EXPECT_EQ(ps.
getRobotModel()->getName(), ps_msg.robot_model_name);
91 EXPECT_EQ(ps.
getName(), ps_msg.name);
92 EXPECT_EQ(ps.
getRobotModel()->getName(), ps_msg.robot_model_name);
95TEST(PlanningScene, LoadOctomap)
98 srdf::ModelSharedPtr srdf_model(
new srdf::Model());
102 octomap_msgs::msg::OctomapWithPose msg;
104 EXPECT_TRUE(msg.octomap.id.empty());
105 EXPECT_TRUE(msg.octomap.data.empty());
110 octomap::point3d origin(0, 0, 0);
111 octomap::point3d end(0, 1, 2);
112 octomap.insertRay(origin, end);
115 moveit_msgs::msg::PlanningScene msg;
117 octomap_msgs::fullMapToMsg(
octomap, msg.world.octomap.octomap);
121 octomap_msgs::msg::OctomapWithPose octomap_msg;
123 EXPECT_EQ(octomap_msg.octomap.id,
"OcTree");
124 EXPECT_EQ(octomap_msg.octomap.data.size(), msg.world.octomap.octomap.data.size());
129 moveit_msgs::msg::PlanningScene msg;
133 octomap_msgs::msg::OctomapWithPose octomap_msg;
135 EXPECT_EQ(octomap_msg.octomap.id,
"OcTree");
136 EXPECT_FALSE(octomap_msg.octomap.data.empty());
140 moveit_msgs::msg::PlanningScene msg;
142 msg.world.octomap.octomap.id =
"xxx";
148TEST(PlanningScene, LoadRestoreDiff)
151 srdf::ModelSharedPtr srdf_model = std::make_shared<srdf::Model>();
152 auto ps = std::make_shared<planning_scene::PlanningScene>(urdf_model, srdf_model);
157 Eigen::Isometry3d
id = Eigen::Isometry3d::Identity();
158 world.
addToObject(
"sphere", std::make_shared<const shapes::Sphere>(0.4),
id);
161 moveit_msgs::msg::PlanningScene ps_msg;
162 ps_msg.robot_state.is_diff =
true;
164 ps->getPlanningSceneMsg(ps_msg);
165 ps->setPlanningSceneMsg(ps_msg);
166 EXPECT_EQ(ps_msg.world.collision_objects.size(), 1u);
167 EXPECT_EQ(ps_msg.world.collision_objects[0].id,
"sphere");
171 planning_scene::PlanningScenePtr next = ps->diff();
173 EXPECT_TRUE(next->getWorld()->hasObject(
"sphere"));
176 next->getWorldNonConst()->addToObject(
"sphere_in_next_only", std::make_shared<const shapes::Sphere>(0.5),
id);
177 EXPECT_EQ(next->getWorld()->size(), 2u);
178 EXPECT_EQ(ps->getWorld()->size(), 1u);
181 EXPECT_EQ(ps->getCollisionEnv()->getWorld()->size(), 1u);
182 EXPECT_EQ(ps->getCollisionEnvUnpadded()->getWorld()->size(), 1u);
184 EXPECT_EQ(next->getCollisionEnv()->getWorld()->size(), 2u);
185 EXPECT_EQ(next->getCollisionEnvUnpadded()->getWorld()->size(), 2u);
188 next->getPlanningSceneDiffMsg(ps_msg);
189 EXPECT_EQ(ps_msg.world.collision_objects.size(), 1u);
192 next->decoupleParent();
193 moveit_msgs::msg::PlanningScene ps_msg2;
196 next->getPlanningSceneDiffMsg(ps_msg2);
197 EXPECT_EQ(ps_msg2.world.collision_objects.size(), 0u);
200 next->getPlanningSceneMsg(ps_msg);
201 EXPECT_EQ(ps_msg.world.collision_objects.size(), 2u);
202 ps->setPlanningSceneMsg(ps_msg);
203 EXPECT_EQ(ps->getWorld()->size(), 2u);
204 EXPECT_EQ(ps->getCollisionEnv()->getWorld()->size(), 2u);
205 EXPECT_EQ(ps->getCollisionEnvUnpadded()->getWorld()->size(), 2u);
208TEST(PlanningScene, MakeAttachedDiff)
211 srdf::ModelSharedPtr srdf_model = std::make_shared<srdf::Model>();
212 auto ps = std::make_shared<planning_scene::PlanningScene>(urdf_model, srdf_model);
216 Eigen::Isometry3d
id = Eigen::Isometry3d::Identity();
217 world.
addToObject(
"sphere", std::make_shared<const shapes::Sphere>(0.4),
id);
220 planning_scene::PlanningScenePtr attached_object_diff_scene = ps->diff();
222 moveit_msgs::msg::AttachedCollisionObject att_obj;
223 att_obj.link_name =
"r_wrist_roll_link";
224 att_obj.object.operation = moveit_msgs::msg::CollisionObject::ADD;
225 att_obj.object.id =
"sphere";
226 attached_object_diff_scene->processAttachedCollisionObjectMsg(att_obj);
229 EXPECT_EQ(attached_object_diff_scene->getWorld()->size(), 0u);
231 EXPECT_TRUE(attached_object_diff_scene->getCurrentState().hasAttachedBody(
"sphere"));
235 attached_object_diff_scene->checkCollision(req, res);
236 ps->checkCollision(req, res);
239TEST(PlanningScene, isStateValid)
242 auto ps = std::make_shared<planning_scene::PlanningScene>(robot_model->getURDF(), robot_model->getSRDF());
244 if (ps->isStateColliding(current_state,
"left_arm"))
246 EXPECT_FALSE(ps->isStateValid(current_state,
"left_arm"));
250TEST(PlanningScene, loadGoodSceneGeometryNewFormat)
253 auto ps = std::make_shared<planning_scene::PlanningScene>(robot_model->getURDF(), robot_model->getSRDF());
255 std::istringstream good_scene_geometry;
256 good_scene_geometry.str(
"foobar_scene\n"
263 "1.49257 1.00222 0.170051\n"
264 "0 0 4.16377e-05 1\n"
273 "0.453709 0.499136 0.355051\n"
274 "0 0 4.16377e-05 1\n"
278 EXPECT_TRUE(ps->loadGeometryFromStream(good_scene_geometry));
279 EXPECT_EQ(ps->getName(),
"foobar_scene");
280 EXPECT_TRUE(ps->getWorld()->hasObject(
"foo"));
281 EXPECT_TRUE(ps->getWorld()->hasObject(
"bar"));
282 EXPECT_FALSE(ps->getWorld()->hasObject(
"baz"));
285TEST(PlanningScene, loadGoodSceneGeometryOldFormat)
288 auto ps = std::make_shared<planning_scene::PlanningScene>(robot_model->getURDF(), robot_model->getSRDF());
290 std::istringstream good_scene_geometry;
291 good_scene_geometry.str(
"foobar_scene\n"
305 EXPECT_TRUE(ps->loadGeometryFromStream(good_scene_geometry));
306 EXPECT_EQ(ps->getName(),
"foobar_scene");
307 EXPECT_TRUE(ps->getWorld()->hasObject(
"foo"));
308 EXPECT_FALSE(ps->getWorld()->hasObject(
"baz"));
311TEST(PlanningScene, loadBadSceneGeometry)
314 auto ps = std::make_shared<planning_scene::PlanningScene>(robot_model->getURDF(), robot_model->getSRDF());
315 std::istringstream empty_scene_geometry;
318 EXPECT_FALSE(ps->loadGeometryFromStream(empty_scene_geometry));
320 std::istringstream malformed_scene_geometry;
321 malformed_scene_geometry.str(
"malformed_scene_geometry\n"
328 "1.49257 1.00222 0.170051\n"
329 "0 0 4.16377e-05 1\n"
332 EXPECT_FALSE(ps->loadGeometryFromStream(malformed_scene_geometry));
337TEST(PlanningScene, switchCollisionDetectorType)
340 auto ps = std::make_shared<planning_scene::PlanningScene>(robot_model->getURDF(), robot_model->getSRDF());
342 if (ps->isStateColliding(current_state,
"left_arm"))
344 EXPECT_FALSE(ps->isStateValid(current_state,
"left_arm"));
348 if (ps->isStateColliding(current_state,
"left_arm"))
350 EXPECT_FALSE(ps->isStateValid(current_state,
"left_arm"));
354TEST(PlanningScene, FailRetrievingNonExistentObject)
358 moveit_msgs::msg::CollisionObject obj;
367 const std::string plugin_name = GetParam();
368 SCOPED_TRACE(plugin_name);
371 srdf::ModelSharedPtr srdf_model = std::make_shared<srdf::Model>();
373 planning_scene::PlanningScenePtr parent = std::make_shared<planning_scene::PlanningScene>(urdf_model, srdf_model);
376 if (!loader.
activate(plugin_name, parent))
378#if defined(GTEST_SKIP_)
379 GTEST_SKIP_(
"Failed to load collision plugin");
386 planning_scene::PlanningScenePtr child = parent->diff();
397 parent->getCollisionEnv()->checkRobotCollision(req, res, *state, parent->getAllowedCollisionMatrix());
400 child->getCollisionEnv()->checkRobotCollision(req, res, *state, child->getAllowedCollisionMatrix());
404 moveit_msgs::msg::PlanningScene ps_msg;
405 ps_msg.is_diff =
false;
406 moveit_msgs::msg::CollisionObject co;
407 co.header.frame_id =
"base_link";
408 co.operation = moveit_msgs::msg::CollisionObject::ADD;
410 co.pose.orientation.w = 1.0;
412 shape_msgs::msg::SolidPrimitive sp;
413 sp.type = shape_msgs::msg::SolidPrimitive::BOX;
414 sp.dimensions = { 1., 1., 1. };
415 co.primitives.push_back(sp);
416 geometry_msgs::msg::Pose sp_pose;
417 sp_pose.orientation.w = 1.0;
418 co.primitive_poses.push_back(sp_pose);
420 ps_msg.world.collision_objects.push_back(co);
423 parent->usePlanningSceneMsg(ps_msg);
427 parent->getCollisionEnv()->checkRobotCollision(req, res, *state, parent->getAllowedCollisionMatrix());
432 child->getCollisionEnv()->checkRobotCollision(req, res, *state, child->getAllowedCollisionMatrix());
440 parent->getCollisionEnv()->checkRobotCollision(req, res, *state, parent->getAllowedCollisionMatrix());
443 child->getCollisionEnv()->checkRobotCollision(req, res, *state, child->getAllowedCollisionMatrix());
452 const std::string& object_name,
const int8_t operation,
453 const bool attach_object =
false,
454 const bool create_object =
true)
457 auto add_object = [](
const std::string& object_name,
const int8_t operation) {
458 moveit_msgs::msg::CollisionObject co;
459 co.header.frame_id =
"panda_link0";
461 co.operation = operation;
462 co.primitives.push_back([] {
463 shape_msgs::msg::SolidPrimitive primitive;
464 primitive.type = shape_msgs::msg::SolidPrimitive::SPHERE;
465 primitive.dimensions.push_back(1.0);
468 co.primitive_poses.push_back([] {
469 geometry_msgs::msg::Pose pose;
470 pose.orientation.w = 1.0;
473 co.pose = co.primitive_poses[0];
477 auto add_attached_object = [](
const std::string& object_name,
const int8_t operation) {
478 moveit_msgs::msg::AttachedCollisionObject aco;
479 aco.object.operation = operation;
480 aco.object.id = object_name;
481 aco.link_name =
"panda_link0";
485 auto new_ps = ps.
diff();
486 if ((operation == moveit_msgs::msg::CollisionObject::REMOVE && !attach_object) ||
487 (operation == moveit_msgs::msg::CollisionObject::ADD && create_object))
488 new_ps->processCollisionObjectMsg(add_object(object_name, operation));
490 new_ps->processAttachedCollisionObjectMsg(add_attached_object(object_name, operation));
491 moveit_msgs::msg::PlanningScene scene_msg;
492 new_ps->getPlanningSceneDiffMsg(scene_msg);
499 std::vector<moveit_msgs::msg::CollisionObject> collision_objects;
501 std::set<std::string> collision_objects_names;
502 for (
const auto& collision_object : collision_objects)
503 collision_objects_names.emplace(collision_object.id);
504 return collision_objects_names;
510 std::vector<moveit_msgs::msg::AttachedCollisionObject> collision_objects;
512 std::set<std::string> collision_objects_names;
513 for (
const auto& collision_object : collision_objects)
514 collision_objects_names.emplace(collision_object.object.id);
515 return collision_objects_names;
518TEST(PlanningScene, RobotStateDiffBug)
521 auto srdf_model = std::make_shared<srdf::Model>();
522 auto ps = std::make_shared<planning_scene::PlanningScene>(urdf_model, srdf_model);
529 ps->usePlanningSceneMsg(ps1);
530 ps->usePlanningSceneMsg(ps2);
539 ps->usePlanningSceneMsg(ps1);
544 ps = std::make_shared<planning_scene::PlanningScene>(urdf_model, srdf_model);
549 ps->usePlanningSceneMsg(ps1);
550 ps->usePlanningSceneMsg(ps2);
558 ps->usePlanningSceneMsg(ps1);
567 ps->usePlanningSceneMsg(ps1);
575 auto ps1 = ps->diff();
576 moveit_msgs::msg::CollisionObject co;
578 co.operation = moveit_msgs::msg::CollisionObject::REMOVE;
579 moveit_msgs::msg::AttachedCollisionObject aco;
582 ps1->processAttachedCollisionObjectMsg(aco);
583 ps1->processCollisionObjectMsg(co);
585 moveit_msgs::msg::PlanningScene msg;
586 ps1->getPlanningSceneDiffMsg(msg);
587 ps->usePlanningSceneMsg(msg);
594TEST(PlanningScene, UpdateACMAfterObjectRemoval)
597 auto ps = std::make_shared<planning_scene::PlanningScene>(robot_model);
599 const auto object_name =
"object";
602 collision_request.
verbose =
true;
605 auto add_object = [&] {
607 ps->usePlanningSceneMsg(ps1);
612 auto attach_object = [&] {
614 ps->usePlanningSceneMsg(ps1);
619 auto detach_object = [&] {
621 ps->usePlanningSceneMsg(ps1);
626 auto modify_acm = [&] {
628 acm.
setEntry(object_name, ps->getRobotModel()->getJointModelGroup(
"hand")->getLinkModelNamesWithCollisionGeometry(),
630 EXPECT_TRUE(ps->getAllowedCollisionMatrix().hasEntry(object_name));
634 auto check_collision = [&] {
636 ps->checkCollision(collision_request, res);
642 EXPECT_TRUE(check_collision());
644 EXPECT_FALSE(check_collision());
647 EXPECT_FALSE(check_collision());
649 EXPECT_FALSE(check_collision());
652 ps->usePlanningSceneMsg(ps1);
654 EXPECT_FALSE(ps->getAllowedCollisionMatrix().hasEntry(object_name));
660 EXPECT_TRUE(check_collision());
662 EXPECT_FALSE(check_collision());
663 ps->removeAllCollisionObjects();
665 EXPECT_FALSE(ps->getAllowedCollisionMatrix().hasEntry(object_name));
668#ifndef INSTANTIATE_TEST_SUITE_P
669#define INSTANTIATE_TEST_SUITE_P(...) INSTANTIATE_TEST_CASE_P(__VA_ARGS__)
677 testing::InitGoogleTest(&argc, argv);
678 return RUN_ALL_TESTS();
Definition of a structure for the allowed collision matrix. All elements in the collision world are r...
void setEntry(const std::string &name1, const std::string &name2, bool allowed)
Set an entry corresponding to a pair of elements.
static CollisionDetectorAllocatorPtr create()
bool activate(const std::string &name, const planning_scene::PlanningScenePtr &scene)
Activate a specific collision plugin for the given planning scene instance.
Maintain a representation of the environment.
bool hasObject(const std::string &object_id) const
Check if a particular object exists in the collision world.
void addToObject(const std::string &object_id, const Eigen::Isometry3d &pose, const std::vector< shapes::ShapeConstPtr > &shapes, const EigenSTL::vector_Isometry3d &shape_poses)
Add a pose and shapes to an object in the map. This function makes repeated calls to addToObjectInter...
Representation of a robot's state. This includes position, velocity, acceleration and effort.
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...
This class maintains the representation of the environment as seen by a planning instance....
void getAttachedCollisionObjectMsgs(std::vector< moveit_msgs::msg::AttachedCollisionObject > &attached_collision_objs) const
Construct a vector of messages (attached_collision_objects) with the attached collision object data f...
void getPlanningSceneMsg(moveit_msgs::msg::PlanningScene &scene) const
Construct a message (scene) with all the necessary data so that the scene can be later reconstructed ...
const moveit::core::RobotModelConstPtr & getRobotModel() const
Get the kinematic model for which the planning scene is maintained.
bool processCollisionObjectMsg(const moveit_msgs::msg::CollisionObject &object)
const Eigen::Isometry3d & getFrameTransform(const std::string &id) const
Get the transform corresponding to the frame id. This will be known if id is a link name,...
bool getCollisionObjectMsg(moveit_msgs::msg::CollisionObject &collision_obj, const std::string &ns) const
Construct a message (collision_object) with the collision object data from the planning_scene for the...
void getCollisionObjectMsgs(std::vector< moveit_msgs::msg::CollisionObject > &collision_objs) const
Construct a vector of messages (collision_objects) with the collision object data for all objects in ...
PlanningScenePtr diff() const
Return a new child PlanningScene that uses this one as parent.
const collision_detection::WorldConstPtr & getWorld() const
Get the representation of the world.
bool setPlanningSceneDiffMsg(const moveit_msgs::msg::PlanningScene &scene)
Apply changes to this planning scene as diffs, even if the message itself is not marked as being a di...
bool getOctomapMsg(octomap_msgs::msg::OctomapWithPose &octomap) const
Construct a message (octomap) with the octomap data from the planning_scene.
const std::string & getName() const
Get the name of the planning scene. This is empty by default.
bool setPlanningSceneMsg(const moveit_msgs::msg::PlanningScene &scene)
Set this instance of a planning scene to be the same as the one serialized in the scene message,...
static const std::string OCTOMAP_NS
bool isEmpty(const moveit_msgs::msg::PlanningScene &msg)
Check if a message includes any information about a planning scene, or whether it is empty.
moveit::core::RobotModelPtr loadTestingRobotModel(const std::string &package_name, const std::string &urdf_relative_path, const std::string &srdf_relative_path)
Loads a robot model given a URDF and SRDF file in a package.
urdf::ModelInterfaceSharedPtr loadModelInterface(const std::string &robot_name)
Loads a URDF Model Interface from moveit_resources.
Representation of a collision checking request.
std::string group_name
The group name to check collisions for (optional; if empty, assume the complete robot)....
bool verbose
Flag indicating whether information about detected collisions should be reported.
Representation of a collision checking result.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW void clear()
Clear a previously stored result.
bool collision
True if collision was found, false otherwise.
int main(int argc, char **argv)
TEST(PlanningScene, TestOneShapeObjectPose)
#define INSTANTIATE_TEST_SUITE_P(...)
moveit_msgs::msg::PlanningScene createPlanningSceneDiff(const planning_scene::PlanningScene &ps, const std::string &object_name, const int8_t operation, const bool attach_object=false, const bool create_object=true)
TEST_P(CollisionDetectorTests, ClearDiff)
std::set< std::string > getAttachedCollisionObjectsNames(const planning_scene::PlanningScene &ps)
std::set< std::string > getCollisionObjectsNames(const planning_scene::PlanningScene &ps)