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