$search
00001 /********************************************************************* 00002 * Software License Agreement (BSD License) 00003 * 00004 * Copyright (c) 2008, Willow Garage, Inc. 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 00011 * * Redistributions of source code must retain the above copyright 00012 * notice, this list of conditions and the following disclaimer. 00013 * * Redistributions in binary form must reproduce the above 00014 * copyright notice, this list of conditions and the following 00015 * disclaimer in the documentation and/or other materials provided 00016 * with the distribution. 00017 * * Neither the name of the Willow Garage nor the names of its 00018 * contributors may be used to endorse or promote products derived 00019 * from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00022 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00023 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00024 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00025 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00026 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00027 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00028 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00029 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00030 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00031 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00032 * POSSIBILITY OF SUCH DAMAGE. 00033 *********************************************************************/ 00034 00037 #include <ros/time.h> 00038 #include <gtest/gtest.h> 00039 #include <iostream> 00040 #include <sstream> 00041 #include <ros/package.h> 00042 00043 #include <planning_environment/monitors/planning_monitor.h> 00044 #include <planning_environment/models/collision_models_interface.h> 00045 #include <actionlib/client/simple_action_client.h> 00046 00047 static const double VERY_SMALL = .0001; 00048 00049 class PlanningMonitorTest : public testing::Test { 00050 public: 00051 00052 // void actionFeedbackCallback(const arm_navigation_msgs::SetPlanningSceneFeedbackConstPtr& feedback) { 00053 // ready_ = true; 00054 // } 00055 00056 // void actionDoneCallback(const actionlib::SimpleClientGoalState& state, 00057 // const arm_navigation_msgs::SetPlanningSceneResultConstPtr& result) 00058 // { 00059 // EXPECT_TRUE(state == actionlib::SimpleClientGoalState::PREEMPTED); 00060 // ROS_INFO("Got preempted"); 00061 // } 00062 00063 void setPlanningSceneCallback(const arm_navigation_msgs::PlanningScene& scene) { 00064 got_set_callback_ = true; 00065 } 00066 00067 void revertPlanningSceneCallback() { 00068 got_revert_callback_ = true; 00069 } 00070 00071 protected: 00072 00073 virtual void SetUp() { 00074 00075 got_set_callback_ = false; 00076 got_revert_callback_ = false; 00077 ready_ = false; 00078 00079 group_name_ = "right_arm"; 00080 00081 std::string robot_description_name = nh_.resolveName("robot_description", true); 00082 00083 ros::WallRate h(10.0); 00084 00085 while(nh_.ok() && !nh_.hasParam(robot_description_name)) { 00086 ros::spinOnce(); 00087 h.sleep(); 00088 } 00089 00090 collision_models_ = new planning_environment::CollisionModels(robot_description_name); 00091 planning_monitor_ = new planning_environment::PlanningMonitor(collision_models_, &tf_); 00092 planning_monitor_->setUseCollisionMap(false); 00093 planning_monitor_->waitForState(); 00094 planning_monitor_->startEnvironmentMonitor(); 00095 } 00096 00097 virtual void TearDown() 00098 { 00099 delete collision_models_; 00100 delete planning_monitor_; 00101 } 00102 00103 bool CallPlanningScene() { 00104 return planning_monitor_->getCompletePlanningScene(planning_scene_diff_, 00105 operations_, 00106 planning_scene_); 00107 } 00108 00109 protected: 00110 00111 bool ready_; 00112 bool got_set_callback_; 00113 bool got_revert_callback_; 00114 00115 std::string group_name_; 00116 ros::NodeHandle nh_; 00117 tf::TransformListener tf_; 00118 planning_environment::CollisionModels *collision_models_; 00119 planning_environment::PlanningMonitor *planning_monitor_; 00120 00121 arm_navigation_msgs::PlanningScene planning_scene_diff_; 00122 arm_navigation_msgs::PlanningScene planning_scene_; 00123 00124 arm_navigation_msgs::OrderedCollisionOperations operations_; 00125 00126 }; 00127 00128 TEST_F(PlanningMonitorTest, ChangingObjects) 00129 { 00130 planning_environment::CollisionModels test_collision_models("robot_description"); 00131 00132 planning_scene_diff_.robot_state.multi_dof_joint_state.stamp = ros::Time::now(); 00133 planning_scene_diff_.robot_state.multi_dof_joint_state.joint_names.push_back("base_joint"); 00134 planning_scene_diff_.robot_state.multi_dof_joint_state.frame_ids.push_back("odom_combined"); 00135 planning_scene_diff_.robot_state.multi_dof_joint_state.child_frame_ids.push_back("base_footprint"); 00136 planning_scene_diff_.robot_state.multi_dof_joint_state.poses.resize(1); 00137 planning_scene_diff_.robot_state.multi_dof_joint_state.poses[0].position.x = 4.0; 00138 planning_scene_diff_.robot_state.multi_dof_joint_state.poses[0].orientation.w = 1.0; 00139 00140 arm_navigation_msgs::CollisionObject obj1; 00141 obj1.header.stamp = ros::Time::now(); 00142 obj1.header.frame_id = "map_to_stapler"; 00143 obj1.id = "obj1"; 00144 obj1.operation.operation = arm_navigation_msgs::CollisionObjectOperation::ADD; 00145 obj1.shapes.resize(1); 00146 obj1.shapes[0].type = arm_navigation_msgs::Shape::BOX; 00147 obj1.shapes[0].dimensions.resize(3); 00148 obj1.shapes[0].dimensions[0] = .1; 00149 obj1.shapes[0].dimensions[1] = .1; 00150 obj1.shapes[0].dimensions[2] = .75; 00151 obj1.poses.resize(1); 00152 obj1.poses[0].position.x = .5; 00153 obj1.poses[0].position.y = .5; 00154 obj1.poses[0].position.z = 0; 00155 obj1.poses[0].orientation.w = 1.0; 00156 00157 arm_navigation_msgs::AttachedCollisionObject att_obj; 00158 att_obj.object = obj1; 00159 att_obj.object.header.stamp = ros::Time::now(); 00160 att_obj.object.header.frame_id = "odom_combined"; 00161 att_obj.link_name = "r_gripper_palm_link"; 00162 att_obj.touch_links.push_back("r_gripper_palm_link"); 00163 att_obj.touch_links.push_back("r_gripper_r_finger_link"); 00164 att_obj.touch_links.push_back("r_gripper_l_finger_link"); 00165 att_obj.touch_links.push_back("r_gripper_r_finger_tip_link"); 00166 att_obj.touch_links.push_back("r_gripper_l_finger_tip_link"); 00167 att_obj.touch_links.push_back("r_wrist_roll_link"); 00168 att_obj.touch_links.push_back("r_wrist_flex_link"); 00169 att_obj.touch_links.push_back("r_forearm_link"); 00170 att_obj.touch_links.push_back("r_gripper_motor_accelerometer_link"); 00171 att_obj.object.id = "obj2"; 00172 att_obj.object.shapes[0].type = arm_navigation_msgs::Shape::CYLINDER; 00173 att_obj.object.shapes[0].dimensions.resize(2); 00174 att_obj.object.shapes[0].dimensions[0] = .025; 00175 att_obj.object.shapes[0].dimensions[1] = .5; 00176 att_obj.object.poses.resize(1); 00177 att_obj.object.poses[0].position.x = 0.0; 00178 att_obj.object.poses[0].position.y = 0.0; 00179 att_obj.object.poses[0].position.z = 0.0; 00180 att_obj.object.poses[0].orientation.w = 1.0; 00181 00182 planning_scene_diff_.collision_objects.push_back(obj1); 00183 planning_scene_diff_.attached_collision_objects.push_back(att_obj); 00184 00185 att_obj.object.header.frame_id = "map_to_stapler"; 00186 planning_scene_diff_.attached_collision_objects.push_back(att_obj); 00187 00188 CallPlanningScene(); 00189 00190 ASSERT_EQ(planning_scene_.collision_objects.size(), 1); 00191 //extra object with same id should have overwritten first 00192 ASSERT_EQ(planning_scene_.attached_collision_objects.size(), 1); 00193 EXPECT_EQ(planning_scene_.attached_collision_objects[0].object.header.frame_id,std::string("map_to_stapler")); 00194 00195 planning_models::KinematicState* state = test_collision_models.setPlanningScene(planning_scene_); 00196 ASSERT_TRUE(state != NULL); 00197 00198 EXPECT_TRUE(test_collision_models.convertAttachedCollisionObjectToNewWorldFrame(*state, att_obj)); 00199 EXPECT_EQ(att_obj.object.header.frame_id, "r_gripper_palm_link"); 00200 00201 att_obj.object.header.frame_id = "stapler_to_monkey"; 00202 EXPECT_FALSE(test_collision_models.convertAttachedCollisionObjectToNewWorldFrame(*state, att_obj)); 00203 00204 EXPECT_TRUE(test_collision_models.convertCollisionObjectToNewWorldFrame(*state, obj1)); 00205 EXPECT_EQ(obj1.header.frame_id, test_collision_models.getWorldFrameId()); 00206 //.5 in x in map_to_stapler to map,-.5 to odom_combined = -3.5 00207 EXPECT_LE(fabs(obj1.poses[0].position.x+3.5), VERY_SMALL); 00208 //.5 in y in map_to_stapler to map, 3.5 to odom_combined = 3.5 00209 EXPECT_LE(fabs(obj1.poses[0].position.y-3.5), VERY_SMALL); 00210 00211 att_obj.link_name = "base_footprint"; 00212 att_obj.object.header.frame_id = "base_footprint"; 00213 att_obj.object.id = "obj3"; 00214 att_obj.object.poses[0].position.x = 0.12; 00215 att_obj.object.poses[0].position.y = 0.0; 00216 att_obj.object.poses[0].position.z = 0.0; 00217 att_obj.object.poses[0].orientation.w = 1.0; 00218 00219 planning_scene_diff_.attached_collision_objects.pop_back(); 00220 planning_scene_diff_.attached_collision_objects.push_back(att_obj); 00221 00222 CallPlanningScene(); 00223 00224 //now they should be different 00225 EXPECT_EQ(planning_scene_.attached_collision_objects[0].object.header.frame_id, "odom_combined"); 00226 EXPECT_EQ(planning_scene_.attached_collision_objects[1].object.header.frame_id, "base_footprint"); 00227 00228 test_collision_models.revertPlanningScene(state); 00229 00230 //now we mess with ordered collision operations 00231 arm_navigation_msgs::CollisionOperation cop; 00232 cop.object1 = "l_end_effector"; 00233 cop.object2 = "obj3"; 00234 cop.operation = cop.DISABLE; 00235 operations_.collision_operations.push_back(cop); 00236 00237 cop.object1 = "up_end_effector"; 00238 cop.object2 = "obj3"; 00239 cop.operation = cop.DISABLE; 00240 operations_.collision_operations.push_back(cop); 00241 00242 CallPlanningScene(); 00243 00244 state = test_collision_models.setPlanningScene(planning_scene_); 00245 ASSERT_TRUE(state != NULL); 00246 00247 const collision_space::EnvironmentModel::AllowedCollisionMatrix& acm = test_collision_models.getCollisionSpace()->getCurrentAllowedCollisionMatrix(); 00248 00249 bool allowed; 00250 EXPECT_TRUE(acm.getAllowedCollision("l_gripper_l_finger_tip_link", "obj3", allowed)); 00251 EXPECT_TRUE(allowed); 00252 00253 EXPECT_TRUE(acm.getAllowedCollision("l_gripper_l_finger_tip_link", "obj2", allowed)); 00254 EXPECT_FALSE(allowed); 00255 00256 //defaults shouldn't have changed 00257 const collision_space::EnvironmentModel::AllowedCollisionMatrix& acm2 = test_collision_models.getCollisionSpace()->getDefaultAllowedCollisionMatrix(); 00258 00259 EXPECT_TRUE(acm2.getAllowedCollision("l_gripper_l_finger_tip_link", "obj3", allowed)); 00260 EXPECT_FALSE(allowed); 00261 00262 EXPECT_TRUE(acm2.getAllowedCollision("l_gripper_l_finger_tip_link", "obj2", allowed)); 00263 EXPECT_FALSE(allowed); 00264 00265 00266 test_collision_models.revertPlanningScene(state); 00267 } 00268 00269 TEST_F(PlanningMonitorTest, ChangingRobotState) 00270 { 00271 00272 planning_environment::CollisionModels test_collision_models("robot_description"); 00273 00274 arm_navigation_msgs::CollisionObject obj1; 00275 obj1.header.stamp = ros::Time::now(); 00276 obj1.header.frame_id = "odom_combined"; 00277 obj1.id = "table"; 00278 obj1.operation.operation = arm_navigation_msgs::CollisionObjectOperation::ADD; 00279 obj1.shapes.resize(1); 00280 obj1.shapes[0].type = arm_navigation_msgs::Shape::BOX; 00281 obj1.shapes[0].dimensions.resize(3); 00282 obj1.shapes[0].dimensions[0] = 1.0; 00283 obj1.shapes[0].dimensions[1] = 1.0; 00284 obj1.shapes[0].dimensions[2] = .2; 00285 obj1.poses.resize(1); 00286 obj1.poses[0].position.x = 4.25; 00287 obj1.poses[0].position.y = 0.0; 00288 obj1.poses[0].position.z = .8; 00289 obj1.poses[0].orientation.w = 1.0; 00290 00291 planning_scene_diff_.collision_objects.push_back(obj1); 00292 00293 CallPlanningScene(); 00294 00295 planning_models::KinematicState* state = test_collision_models.setPlanningScene(planning_scene_); 00296 00297 //without transforming state nowhere near the table 00298 ASSERT_TRUE(state != NULL); 00299 EXPECT_FALSE(test_collision_models.isKinematicStateInCollision(*state)); 00300 00301 test_collision_models.revertPlanningScene(state); 00302 00303 planning_scene_diff_.robot_state.multi_dof_joint_state.stamp = ros::Time::now(); 00304 planning_scene_diff_.robot_state.multi_dof_joint_state.joint_names.push_back("base_joint"); 00305 planning_scene_diff_.robot_state.multi_dof_joint_state.frame_ids.push_back("odom_combined"); 00306 planning_scene_diff_.robot_state.multi_dof_joint_state.child_frame_ids.push_back("base_footprint"); 00307 planning_scene_diff_.robot_state.multi_dof_joint_state.poses.resize(1); 00308 planning_scene_diff_.robot_state.multi_dof_joint_state.poses[0].position.x = 4.0; 00309 planning_scene_diff_.robot_state.multi_dof_joint_state.poses[0].orientation.w = 1.0; 00310 00311 CallPlanningScene(); 00312 00313 state = test_collision_models.setPlanningScene(planning_scene_); 00314 00315 //expect collisions with table 00316 ASSERT_TRUE(state != NULL); 00317 std::map<std::string, double> joint_state_values; 00318 state->getKinematicStateValues(joint_state_values); 00319 EXPECT_EQ(joint_state_values["floating_trans_x"], 4.0); 00320 EXPECT_TRUE(test_collision_models.isKinematicStateInCollision(*state)); 00321 EXPECT_FALSE(test_collision_models.isKinematicStateInSelfCollision(*state)); 00322 EXPECT_TRUE(test_collision_models.isKinematicStateInEnvironmentCollision(*state)); 00323 00324 test_collision_models.revertPlanningScene(state); 00325 00326 //bad multi-dof 00327 planning_scene_diff_.robot_state.multi_dof_joint_state.stamp = ros::Time::now(); 00328 planning_scene_diff_.robot_state.multi_dof_joint_state.joint_names[0] = "base_joint"; 00329 planning_scene_diff_.robot_state.multi_dof_joint_state.frame_ids[0] = ""; 00330 planning_scene_diff_.robot_state.multi_dof_joint_state.child_frame_ids[0] = "base_footprint"; 00331 planning_scene_diff_.robot_state.multi_dof_joint_state.poses.resize(1); 00332 planning_scene_diff_.robot_state.multi_dof_joint_state.poses[0].position.x = 4.0; 00333 planning_scene_diff_.robot_state.multi_dof_joint_state.poses[0].orientation.w = 1.0; 00334 00335 CallPlanningScene(); 00336 00337 //but now we shouldn't be in collision 00338 state = test_collision_models.setPlanningScene(planning_scene_); 00339 00340 ASSERT_TRUE(state != NULL); 00341 //expect collisions with table 00342 state->getKinematicStateValues(joint_state_values); 00343 EXPECT_EQ(joint_state_values["floating_trans_x"], 0.0); 00344 EXPECT_FALSE(test_collision_models.isKinematicStateInCollision(*state)); 00345 00346 test_collision_models.revertPlanningScene(state); 00347 00348 planning_scene_diff_.robot_state.multi_dof_joint_state.joint_names.clear(); 00349 planning_scene_diff_.robot_state.multi_dof_joint_state.poses.clear(); 00350 planning_scene_diff_.robot_state.multi_dof_joint_state.frame_ids.clear(); 00351 planning_scene_diff_.robot_state.multi_dof_joint_state.child_frame_ids.clear(); 00352 00353 planning_scene_diff_.robot_state.joint_state.name.push_back("floating_trans_x"); 00354 planning_scene_diff_.robot_state.joint_state.position.push_back(3.3); 00355 00356 CallPlanningScene(); 00357 00358 //back in collision 00359 state = test_collision_models.setPlanningScene(planning_scene_); 00360 00361 ASSERT_TRUE(state != NULL); 00362 state->getKinematicStateValues(joint_state_values); 00363 EXPECT_EQ(joint_state_values["floating_trans_x"], 3.3); 00364 EXPECT_TRUE(test_collision_models.isKinematicStateInCollision(*state)); 00365 EXPECT_FALSE(test_collision_models.isKinematicStateInSelfCollision(*state)); 00366 EXPECT_TRUE(test_collision_models.isKinematicStateInEnvironmentCollision(*state)); 00367 00368 // test_collision_models.writePlanningSceneBag(ros::package::getPath("planning_environment")+"/test.bag", 00369 // complete_robot_state, 00370 // allowed_collision_matrix, 00371 // transformed_allowed_contacts, 00372 // all_link_paddings, 00373 // all_collision_objects, 00374 // all_attached_collision_objects, 00375 // unmasked_collision_map); 00376 00377 test_collision_models.revertPlanningScene(state); 00378 00379 //now we turn out of collision 00380 planning_scene_diff_.robot_state.joint_state.name.push_back("floating_rot_z"); 00381 planning_scene_diff_.robot_state.joint_state.name.push_back("floating_rot_w"); 00382 planning_scene_diff_.robot_state.joint_state.position.push_back(.7071); 00383 planning_scene_diff_.robot_state.joint_state.position.push_back(.7071); 00384 00385 CallPlanningScene(); 00386 00387 state = test_collision_models.setPlanningScene(planning_scene_); 00388 00389 ASSERT_TRUE(state != NULL); 00390 EXPECT_FALSE(test_collision_models.isKinematicStateInCollision(*state)); 00391 00392 test_collision_models.revertPlanningScene(state); 00393 } 00394 00395 TEST_F(PlanningMonitorTest, PlanningMonitorWithCollisionInterface) 00396 { 00397 00398 ros::AsyncSpinner async(2); 00399 async.start(); 00400 00401 std::string robot_description_name = nh_.resolveName("robot_description", true); 00402 planning_environment::CollisionModelsInterface test_collision_models(robot_description_name, false); 00403 00404 //this test is important because calling the service calls collision checking from a different thread 00405 test_collision_models.addSetPlanningSceneCallback(boost::bind(&PlanningMonitorTest::setPlanningSceneCallback, this, _1)); 00406 test_collision_models.addRevertPlanningSceneCallback(boost::bind(&PlanningMonitorTest::revertPlanningSceneCallback, this)); 00407 00408 CallPlanningScene(); 00409 00410 ros::NodeHandle priv_nh("~"); 00411 00412 actionlib::SimpleActionClient<arm_navigation_msgs::SyncPlanningSceneAction> ac(priv_nh, "sync_planning_scene", true); 00413 00414 arm_navigation_msgs::SyncPlanningSceneGoal goal; 00415 00416 goal.planning_scene = planning_scene_; 00417 00418 ASSERT_TRUE(ac.waitForServer()); 00419 00420 //ac.sendGoal(goal, boost::bind(&PlanningMonitorTest::actionDoneCallback, this, _1, _2), NULL, boost::bind(&PlanningMonitorTest::actionFeedbackCallback, this, _1)); 00421 00422 actionlib::SimpleClientGoalState gs = ac.sendGoalAndWait(goal); 00423 00424 EXPECT_TRUE(gs == actionlib::SimpleClientGoalState::SUCCEEDED); 00425 00426 EXPECT_TRUE(got_set_callback_); 00427 EXPECT_FALSE(test_collision_models.isKinematicStateInCollision(*(test_collision_models.getPlanningSceneState()))); 00428 00429 gs = ac.sendGoalAndWait(goal); 00430 00431 EXPECT_TRUE(gs == actionlib::SimpleClientGoalState::SUCCEEDED); 00432 00433 EXPECT_TRUE(got_revert_callback_); 00434 00435 EXPECT_FALSE(test_collision_models.isKinematicStateInCollision(*(test_collision_models.getPlanningSceneState()))); 00436 00437 EXPECT_TRUE(test_collision_models.getPlanningSceneState() != NULL); 00438 00439 } 00440 00441 int main(int argc, char** argv) 00442 { 00443 testing::InitGoogleTest(&argc, argv); 00444 ros::init(argc, argv, "test_planning_monitor"); 00445 return RUN_ALL_TESTS(); 00446 }