00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include <moveit/setup_assistant/tools/compute_default_collisions.h>
00038 #include <boost/math/special_functions/binomial.hpp>
00039 #include <boost/thread.hpp>
00040 #include <boost/lexical_cast.hpp>
00041 #include <boost/unordered_map.hpp>
00042 #include <boost/assign.hpp>
00043 #include <ros/console.h>
00044
00045 namespace moveit_setup_assistant
00046 {
00047
00048
00049
00050
00051
00052 const boost::unordered_map<DisabledReason, std::string> reasonsToString = boost::assign::map_list_of(NEVER, "Never")(
00053 DEFAULT, "Default")(ADJACENT, "Adjacent")(ALWAYS, "Always")(USER, "User")(NOT_DISABLED, "Not Disabled");
00054
00055 const boost::unordered_map<std::string, DisabledReason> reasonsFromString = boost::assign::map_list_of("Never", NEVER)(
00056 "Default", DEFAULT)("Adjacent", ADJACENT)("Always", ALWAYS)("User", USER)("Not Disabled", NOT_DISABLED);
00057
00058
00059 typedef std::set<std::pair<std::string, std::string> > StringPairSet;
00060
00061
00062 struct ThreadComputation
00063 {
00064 ThreadComputation(planning_scene::PlanningScene& scene, const collision_detection::CollisionRequest& req,
00065 int thread_id, int num_trials, StringPairSet* links_seen_colliding, boost::mutex* lock,
00066 unsigned int* progress)
00067 : scene_(scene)
00068 , req_(req)
00069 , thread_id_(thread_id)
00070 , num_trials_(num_trials)
00071 , links_seen_colliding_(links_seen_colliding)
00072 , lock_(lock)
00073 , progress_(progress)
00074 {
00075 }
00076 planning_scene::PlanningScene& scene_;
00077 const collision_detection::CollisionRequest& req_;
00078 int thread_id_;
00079 unsigned int num_trials_;
00080 StringPairSet* links_seen_colliding_;
00081 boost::mutex* lock_;
00082 unsigned int* progress_;
00083 };
00084
00085
00086 typedef std::map<const robot_model::LinkModel*, std::set<const robot_model::LinkModel*> > LinkGraph;
00087
00088
00089
00090
00091
00100 static bool setLinkPair(const std::string& linkA, const std::string& linkB, const DisabledReason reason,
00101 LinkPairMap& link_pairs);
00102
00108 static void computeConnectionGraph(const robot_model::LinkModel* link, LinkGraph& link_graph);
00109
00115 static void computeConnectionGraphRec(const robot_model::LinkModel* link, LinkGraph& link_graph);
00116
00124 static unsigned int disableAdjacentLinks(planning_scene::PlanningScene& scene, LinkGraph& link_graph,
00125 LinkPairMap& link_pairs);
00126
00134 static unsigned int disableDefaultCollisions(planning_scene::PlanningScene& scene, LinkPairMap& link_pairs,
00135 collision_detection::CollisionRequest& req);
00136
00147 static unsigned int disableAlwaysInCollision(planning_scene::PlanningScene& scene, LinkPairMap& link_pairs,
00148 collision_detection::CollisionRequest& req,
00149 StringPairSet& links_seen_colliding, double min_collision_faction = 0.95);
00150
00159 static unsigned int disableNeverInCollision(const unsigned int num_trials, planning_scene::PlanningScene& scene,
00160 LinkPairMap& link_pairs, const collision_detection::CollisionRequest& req,
00161 StringPairSet& links_seen_colliding, unsigned int* progress);
00162
00167 static void disableNeverInCollisionThread(ThreadComputation tc);
00168
00169
00170
00171
00172 LinkPairMap computeDefaultCollisions(const planning_scene::PlanningSceneConstPtr& parent_scene, unsigned int* progress,
00173 const bool include_never_colliding, const unsigned int num_trials,
00174 const double min_collision_fraction, const bool verbose)
00175 {
00176
00177 planning_scene::PlanningScenePtr scene = parent_scene->diff();
00178
00179
00180 LinkPairMap link_pairs;
00181
00182
00183 StringPairSet links_seen_colliding;
00184
00185
00186 LinkGraph link_graph;
00187
00188
00189
00190
00191
00192
00193 computeLinkPairs(*scene, link_pairs);
00194 *progress = 1;
00195
00196
00197
00198
00199
00200
00201 computeConnectionGraph(scene->getRobotModel()->getRootLink(), link_graph);
00202 *progress = 2;
00203
00204
00205
00206 unsigned int num_adjacent = disableAdjacentLinks(*scene, link_graph, link_pairs);
00207 *progress = 4;
00208
00209
00210
00211 collision_detection::CollisionRequest req;
00212 req.contacts = true;
00213
00214 req.max_contacts = int(link_graph.size());
00215 req.max_contacts_per_pair = 1;
00216 req.verbose = false;
00217
00218
00219
00220 unsigned int num_default = disableDefaultCollisions(*scene, link_pairs, req);
00221 *progress = 6;
00222
00223
00224
00225 unsigned int num_always =
00226 disableAlwaysInCollision(*scene, link_pairs, req, links_seen_colliding, min_collision_fraction);
00227
00228 *progress = 8;
00229
00230
00231
00232 unsigned int num_never = 0;
00233 if (include_never_colliding)
00234 {
00235 num_never = disableNeverInCollision(num_trials, *scene, link_pairs, req, links_seen_colliding, progress);
00236 }
00237
00238
00239
00240 if (verbose)
00241 {
00242
00243 unsigned int num_disabled = 0;
00244 for (LinkPairMap::const_iterator pair_it = link_pairs.begin(); pair_it != link_pairs.end(); ++pair_it)
00245 {
00246 if (pair_it->second.disable_check)
00247 ++num_disabled;
00248 }
00249
00250 ROS_INFO("-------------------------------------------------------------------------------");
00251 ROS_INFO("Statistics:");
00252 unsigned int num_links = int(link_graph.size());
00253 double num_possible = boost::math::binomial_coefficient<double>(num_links, 2);
00254 unsigned int num_sometimes = num_possible - num_disabled;
00255
00256 ROS_INFO("%6d : %s", num_links, "Total Links");
00257 ROS_INFO("%6.0f : %s", num_possible, "Total possible collisions");
00258 ROS_INFO("%6d : %s", num_always, "Always in collision");
00259 ROS_INFO("%6d : %s", num_never, "Never in collision");
00260 ROS_INFO("%6d : %s", num_default, "Default in collision");
00261 ROS_INFO("%6d : %s", num_adjacent, "Adjacent links disabled");
00262 ROS_INFO("%6d : %s", num_sometimes, "Sometimes in collision");
00263 ROS_INFO("%6d : %s", num_disabled, "TOTAL DISABLED");
00264
00265
00266
00267
00268
00269
00270 }
00271
00272 *progress = 100;
00273
00274 return link_pairs;
00275 }
00276
00277
00278
00279
00280 bool setLinkPair(const std::string& linkA, const std::string& linkB, const DisabledReason reason,
00281 LinkPairMap& link_pairs)
00282 {
00283 bool isUnique = false;
00284
00285
00286 std::pair<std::string, std::string> link_pair;
00287
00288
00289 if (linkA < linkB)
00290 {
00291 link_pair = std::pair<std::string, std::string>(linkA, linkB);
00292 }
00293 else
00294 {
00295 link_pair = std::pair<std::string, std::string>(linkB, linkA);
00296 }
00297
00298
00299 LinkPairData* link_pair_ptr = &link_pairs[link_pair];
00300
00301
00302 if (link_pairs[link_pair].disable_check == false)
00303 {
00304 isUnique = true;
00305 link_pair_ptr->reason = reason;
00306 }
00307
00308
00309 link_pair_ptr->disable_check = (reason != NOT_DISABLED);
00310
00311 return isUnique;
00312 }
00313
00314
00315
00316
00317 void computeLinkPairs(const planning_scene::PlanningScene& scene, LinkPairMap& link_pairs)
00318 {
00319
00320 const std::vector<std::string>& names = scene.getRobotModel()->getLinkModelNamesWithCollisionGeometry();
00321
00322 std::pair<std::string, std::string> temp_pair;
00323
00324
00325 for (std::size_t i = 0; i < names.size(); ++i)
00326 {
00327 for (std::size_t j = i + 1; j < names.size(); ++j)
00328 {
00329
00330 setLinkPair(names[i], names[j], NOT_DISABLED, link_pairs);
00331 }
00332 }
00333 }
00334
00335
00336
00337 void computeConnectionGraph(const robot_model::LinkModel* start_link, LinkGraph& link_graph)
00338 {
00339 link_graph.clear();
00340
00341
00342 computeConnectionGraphRec(start_link, link_graph);
00343
00344
00345 bool update = true;
00346 while (update)
00347 {
00348 update = false;
00349
00350
00351 for (LinkGraph::const_iterator edge_it = link_graph.begin(); edge_it != link_graph.end(); ++edge_it)
00352 {
00353 if (edge_it->first->getShapes().empty())
00354 {
00355
00356 std::vector<const robot_model::LinkModel*> temp_list;
00357
00358
00359 for (std::set<const robot_model::LinkModel*>::const_iterator adj_it = edge_it->second.begin();
00360 adj_it != edge_it->second.end(); ++adj_it)
00361 {
00362 temp_list.push_back(*adj_it);
00363 }
00364
00365
00366
00367 for (std::size_t i = 0; i < temp_list.size(); ++i)
00368 {
00369 for (std::size_t j = i + 1; j < temp_list.size(); ++j)
00370 {
00371
00372
00373
00374 if (link_graph[temp_list[i]].insert(temp_list[j]).second)
00375 update = true;
00376 if (link_graph[temp_list[j]].insert(temp_list[i]).second)
00377 update = true;
00378 }
00379 }
00380 }
00381 }
00382 }
00383
00384 }
00385
00386
00387
00388
00389 void computeConnectionGraphRec(const robot_model::LinkModel* start_link, LinkGraph& link_graph)
00390 {
00391 if (start_link)
00392 {
00393
00394 for (std::size_t i = 0; i < start_link->getChildJointModels().size(); ++i)
00395 {
00396 const robot_model::LinkModel* next = start_link->getChildJointModels()[i]->getChildLinkModel();
00397
00398
00399 link_graph[next].insert(start_link);
00400 link_graph[start_link].insert(next);
00401
00402
00403 computeConnectionGraphRec(next, link_graph);
00404 }
00405 }
00406 else
00407 {
00408 ROS_ERROR("Joint exists in URDF with no link!");
00409 }
00410 }
00411
00412
00413
00414
00415 unsigned int disableAdjacentLinks(planning_scene::PlanningScene& scene, LinkGraph& link_graph, LinkPairMap& link_pairs)
00416 {
00417 int num_disabled = 0;
00418 for (LinkGraph::const_iterator link_graph_it = link_graph.begin(); link_graph_it != link_graph.end(); ++link_graph_it)
00419 {
00420
00421 for (std::set<const robot_model::LinkModel*>::const_iterator adj_it = link_graph_it->second.begin();
00422 adj_it != link_graph_it->second.end(); ++adj_it)
00423 {
00424
00425
00426
00427 if (!link_graph_it->first->getShapes().empty() && !(*adj_it)->getShapes().empty())
00428 {
00429 num_disabled += setLinkPair(link_graph_it->first->getName(), (*adj_it)->getName(), ADJACENT, link_pairs);
00430
00431
00432 scene.getAllowedCollisionMatrixNonConst().setEntry(link_graph_it->first->getName(), (*adj_it)->getName(), true);
00433 }
00434 }
00435 }
00436
00437
00438 return num_disabled;
00439 }
00440
00441
00442
00443
00444 unsigned int disableDefaultCollisions(planning_scene::PlanningScene& scene, LinkPairMap& link_pairs,
00445 collision_detection::CollisionRequest& req)
00446 {
00447
00448 collision_detection::CollisionResult res;
00449 scene.getCurrentStateNonConst().setToDefaultValues();
00450
00451 scene.checkSelfCollision(req, res);
00452
00453
00454 int num_disabled = 0;
00455 for (collision_detection::CollisionResult::ContactMap::const_iterator it = res.contacts.begin();
00456 it != res.contacts.end(); ++it)
00457 {
00458 num_disabled += setLinkPair(it->first.first, it->first.second, DEFAULT, link_pairs);
00459
00460
00461 scene.getAllowedCollisionMatrixNonConst().setEntry(it->first.first, it->first.second, true);
00462 }
00463
00464
00465
00466 return num_disabled;
00467 }
00468
00469
00470
00471
00472 unsigned int disableAlwaysInCollision(planning_scene::PlanningScene& scene, LinkPairMap& link_pairs,
00473 collision_detection::CollisionRequest& req, StringPairSet& links_seen_colliding,
00474 double min_collision_faction)
00475 {
00476
00477 static const unsigned int small_trial_count = 200;
00478 static const unsigned int small_trial_limit = (unsigned int)((double)small_trial_count * min_collision_faction);
00479
00480 bool done = false;
00481 unsigned int num_disabled = 0;
00482
00483 while (!done)
00484 {
00485
00486 std::map<std::pair<std::string, std::string>, unsigned int> collision_count;
00487
00488
00489 for (unsigned int i = 0; i < small_trial_count; ++i)
00490 {
00491
00492 collision_detection::CollisionResult res;
00493 scene.getCurrentStateNonConst().setToRandomPositions();
00494 scene.checkSelfCollision(req, res);
00495
00496
00497 unsigned int nc = 0;
00498 for (collision_detection::CollisionResult::ContactMap::const_iterator it = res.contacts.begin();
00499 it != res.contacts.end(); ++it)
00500 {
00501 collision_count[it->first]++;
00502 links_seen_colliding.insert(it->first);
00503 nc += it->second.size();
00504 }
00505
00506
00507 if (nc >= req.max_contacts)
00508 {
00509 req.max_contacts *= 2;
00510
00511 }
00512 }
00513
00514
00515
00516 int found = 0;
00517
00518
00519 for (std::map<std::pair<std::string, std::string>, unsigned int>::const_iterator it = collision_count.begin();
00520 it != collision_count.end(); ++it)
00521 {
00522
00523 if (it->second > small_trial_limit)
00524 {
00525 num_disabled += setLinkPair(it->first.first, it->first.second, ALWAYS, link_pairs);
00526
00527
00528 scene.getAllowedCollisionMatrixNonConst().setEntry(it->first.first, it->first.second, true);
00529
00530 found++;
00531 }
00532 }
00533
00534
00535 if (found == 0)
00536 done = true;
00537
00538
00539 }
00540
00541 return num_disabled;
00542 }
00543
00544
00545
00546
00547 unsigned int disableNeverInCollision(const unsigned int num_trials, planning_scene::PlanningScene& scene,
00548 LinkPairMap& link_pairs, const collision_detection::CollisionRequest& req,
00549 StringPairSet& links_seen_colliding, unsigned int* progress)
00550 {
00551 unsigned int num_disabled = 0;
00552
00553 boost::thread_group bgroup;
00554 boost::mutex lock;
00555
00556 int num_threads = boost::thread::hardware_concurrency();
00557
00558
00559
00560 for (int i = 0; i < num_threads; ++i)
00561 {
00562 ThreadComputation tc(scene, req, i, num_trials / num_threads, &links_seen_colliding, &lock, progress);
00563 bgroup.create_thread(boost::bind(&disableNeverInCollisionThread, tc));
00564 }
00565
00566 bgroup.join_all();
00567
00568
00569 for (LinkPairMap::iterator pair_it = link_pairs.begin(); pair_it != link_pairs.end(); ++pair_it)
00570 {
00571 if (!pair_it->second.disable_check)
00572 {
00573
00574
00575 if (links_seen_colliding.find(pair_it->first) == links_seen_colliding.end())
00576 {
00577
00578 pair_it->second.reason = NEVER;
00579 pair_it->second.disable_check = true;
00580
00581
00582 ++num_disabled;
00583 }
00584 }
00585 }
00586
00587
00588 return num_disabled;
00589 }
00590
00591
00592
00593
00594 void disableNeverInCollisionThread(ThreadComputation tc)
00595 {
00596
00597
00598
00599 const unsigned int progress_interval = tc.num_trials_ / 20;
00600
00601
00602 robot_state::RobotState kstate(tc.scene_.getRobotModel());
00603
00604
00605 for (unsigned int i = 0; i < tc.num_trials_; ++i)
00606 {
00607
00608 if (i % progress_interval == 0 && tc.thread_id_ == 0)
00609 {
00610
00611 (*tc.progress_) = i * 92 / tc.num_trials_ + 8;
00612 }
00613
00614 collision_detection::CollisionResult res;
00615 kstate.setToRandomPositions();
00616 tc.scene_.checkSelfCollision(tc.req_, res, kstate);
00617
00618
00619 for (collision_detection::CollisionResult::ContactMap::const_iterator it = res.contacts.begin();
00620 it != res.contacts.end(); ++it)
00621 {
00622
00623 if (tc.links_seen_colliding_->find(it->first) == tc.links_seen_colliding_->end())
00624 {
00625
00626
00627 boost::mutex::scoped_lock slock(*tc.lock_);
00628 tc.links_seen_colliding_->insert(it->first);
00629
00630 tc.scene_.getAllowedCollisionMatrixNonConst().setEntry(it->first.first, it->first.second,
00631 true);
00632 }
00633 }
00634 }
00635 }
00636
00637
00638
00639
00640 const std::string disabledReasonToString(DisabledReason reason)
00641 {
00642 return reasonsToString.at(reason);
00643 }
00644
00645
00646
00647
00648 DisabledReason disabledReasonFromString(const std::string& reason)
00649 {
00650 DisabledReason r;
00651 try
00652 {
00653 r = reasonsFromString.at(reason);
00654 }
00655 catch (std::out_of_range)
00656 {
00657 r = USER;
00658 }
00659
00660 return r;
00661 }
00662
00663 }