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
00038
00039 #include <teb_local_planner/homotopy_class_planner.h>
00040
00041 namespace teb_local_planner
00042 {
00043
00045 inline std::complex<long double> getCplxFromVertexPosePtr(const VertexPose* pose)
00046 {
00047 return std::complex<long double>(pose->x(), pose->y());
00048 };
00049
00051 inline std::complex<long double> getCplxFromHcGraph(HcGraphVertexType vert_descriptor, const HcGraph& graph)
00052 {
00053 return std::complex<long double>(graph[vert_descriptor].pos.x(), graph[vert_descriptor].pos.y());
00054 };
00055
00057 inline const Eigen::Vector2d& getVector2dFromHcGraph(HcGraphVertexType vert_descriptor, const HcGraph& graph)
00058 {
00059 return graph[vert_descriptor].pos;
00060 };
00061
00063 inline std::complex<long double> getCplxFromMsgPoseStamped(const geometry_msgs::PoseStamped& pose)
00064 {
00065 return std::complex<long double>(pose.pose.position.x, pose.pose.position.y);
00066 };
00067
00068
00069 HomotopyClassPlanner::HomotopyClassPlanner() : cfg_(NULL), obstacles_(NULL), via_points_(NULL), robot_model_(new PointRobotFootprint()), initial_plan_(NULL), initialized_(false)
00070 {
00071 }
00072
00073 HomotopyClassPlanner::HomotopyClassPlanner(const TebConfig& cfg, ObstContainer* obstacles, RobotFootprintModelPtr robot_model,
00074 TebVisualizationPtr visual, const ViaPointContainer* via_points) : initial_plan_(NULL)
00075 {
00076 initialize(cfg, obstacles, robot_model, visual, via_points);
00077 }
00078
00079 HomotopyClassPlanner::~HomotopyClassPlanner()
00080 {
00081 }
00082
00083 void HomotopyClassPlanner::initialize(const TebConfig& cfg, ObstContainer* obstacles, RobotFootprintModelPtr robot_model,
00084 TebVisualizationPtr visual, const ViaPointContainer* via_points)
00085 {
00086 cfg_ = &cfg;
00087 obstacles_ = obstacles;
00088 via_points_ = via_points;
00089 robot_model_ = robot_model;
00090 initialized_ = true;
00091
00092 setVisualization(visual);
00093 }
00094
00095
00096 void HomotopyClassPlanner::setVisualization(TebVisualizationPtr visualization)
00097 {
00098 visualization_ = visualization;
00099 }
00100
00101
00102
00103 bool HomotopyClassPlanner::plan(const std::vector<geometry_msgs::PoseStamped>& initial_plan, const geometry_msgs::Twist* start_vel, bool free_goal_vel)
00104 {
00105 ROS_ASSERT_MSG(initialized_, "Call initialize() first.");
00106
00107
00108 initial_plan_ = &initial_plan;
00109
00110 initial_plan_eq_class_ = calculateEquivalenceClass(initial_plan.begin(), initial_plan.end(), getCplxFromMsgPoseStamped, obstacles_);
00111
00112 PoseSE2 start(initial_plan.front().pose);
00113 PoseSE2 goal(initial_plan.back().pose);
00114
00115 return plan(start, goal, start_vel, free_goal_vel);
00116 }
00117
00118
00119 bool HomotopyClassPlanner::plan(const tf::Pose& start, const tf::Pose& goal, const geometry_msgs::Twist* start_vel, bool free_goal_vel)
00120 {
00121 ROS_ASSERT_MSG(initialized_, "Call initialize() first.");
00122 PoseSE2 start_pose(start);
00123 PoseSE2 goal_pose(goal);
00124 return plan(start_pose, goal_pose, start_vel, free_goal_vel);
00125 }
00126
00127 bool HomotopyClassPlanner::plan(const PoseSE2& start, const PoseSE2& goal, const geometry_msgs::Twist* start_vel, bool free_goal_vel)
00128 {
00129 ROS_ASSERT_MSG(initialized_, "Call initialize() first.");
00130
00131
00132 updateAllTEBs(&start, &goal, start_vel);
00133
00134
00135 exploreEquivalenceClassesAndInitTebs(start, goal, cfg_->obstacles.min_obstacle_dist, start_vel);
00136
00137 updateReferenceTrajectoryViaPoints(cfg_->hcp.viapoints_all_candidates);
00138
00139 optimizeAllTEBs(cfg_->optim.no_inner_iterations, cfg_->optim.no_outer_iterations);
00140
00141 deleteTebDetours(-0.1);
00142
00143 selectBestTeb();
00144
00145 initial_plan_ = nullptr;
00146 return true;
00147 }
00148
00149 bool HomotopyClassPlanner::getVelocityCommand(double& vx, double& vy, double& omega) const
00150 {
00151 TebOptimalPlannerConstPtr best_teb = bestTeb();
00152 if (!best_teb)
00153 {
00154 vx = 0;
00155 vy = 0;
00156 omega = 0;
00157 return false;
00158 }
00159
00160 return best_teb->getVelocityCommand(vx, vy, omega);
00161 }
00162
00163
00164
00165
00166 void HomotopyClassPlanner::visualize()
00167 {
00168 if (visualization_)
00169 {
00170
00171 if (cfg_->hcp.visualize_hc_graph)
00172 visualization_->publishGraph(graph_);
00173
00174
00175 visualization_->publishTebContainer(tebs_);
00176
00177
00178 TebOptimalPlannerConstPtr best_teb = bestTeb();
00179 if (best_teb)
00180 {
00181 visualization_->publishLocalPlanAndPoses(best_teb->teb());
00182
00183 if (best_teb->teb().sizePoses() > 0)
00184 visualization_->publishRobotFootprintModel(best_teb->teb().Pose(0), *robot_model_);
00185
00186
00187 if (cfg_->trajectory.publish_feedback)
00188 {
00189 int best_idx = bestTebIdx();
00190 if (best_idx>=0)
00191 visualization_->publishFeedbackMessage(tebs_, (unsigned int) best_idx, *obstacles_);
00192 }
00193 }
00194 }
00195 else ROS_DEBUG("Ignoring HomotopyClassPlanner::visualize() call, since no visualization class was instantiated before.");
00196 }
00197
00198
00199
00200
00201 void HomotopyClassPlanner::createGraph(const PoseSE2& start, const PoseSE2& goal, double dist_to_obst, double obstacle_heading_threshold, const geometry_msgs::Twist* start_velocity)
00202 {
00203
00204 clearGraph();
00205
00206
00207 Eigen::Vector2d diff = goal.position()-start.position();
00208
00209 if (diff.norm()<cfg_->goal_tolerance.xy_goal_tolerance)
00210 {
00211 ROS_DEBUG("HomotopyClassPlanner::createProbRoadmapGraph(): xy-goal-tolerance already reached.");
00212 if (tebs_.empty())
00213 {
00214 ROS_INFO("HomotopyClassPlanner::createProbRoadmapGraph(): Initializing a small straight line to just correct orientation errors.");
00215 addAndInitNewTeb(start, goal, start_velocity);
00216 }
00217 return;
00218 }
00219
00220 Eigen::Vector2d normal(-diff[1],diff[0]);
00221 normal.normalize();
00222 normal = normal*dist_to_obst;
00223
00224
00225 HcGraphVertexType start_vtx = boost::add_vertex(graph_);
00226 graph_[start_vtx].pos = start.position();
00227 diff.normalize();
00228
00229
00230 std::pair<HcGraphVertexType,HcGraphVertexType> nearest_obstacle;
00231 double min_dist = DBL_MAX;
00232
00233 if (obstacles_!=NULL)
00234 {
00235 for (ObstContainer::const_iterator it_obst = obstacles_->begin(); it_obst != obstacles_->end(); ++it_obst)
00236 {
00237
00238 Eigen::Vector2d start2obst = (*it_obst)->getCentroid() - start.position();
00239 double dist = start2obst.norm();
00240 if (start2obst.dot(diff)/dist<0.1)
00241 continue;
00242
00243
00244 HcGraphVertexType u = boost::add_vertex(graph_);
00245 graph_[u].pos = (*it_obst)->getCentroid() + normal;
00246 HcGraphVertexType v = boost::add_vertex(graph_);
00247 graph_[v].pos = (*it_obst)->getCentroid() - normal;
00248
00249
00250 if (obstacle_heading_threshold && dist<min_dist)
00251 {
00252 min_dist = dist;
00253 nearest_obstacle.first = u;
00254 nearest_obstacle.second = v;
00255 }
00256 }
00257 }
00258
00259 HcGraphVertexType goal_vtx = boost::add_vertex(graph_);
00260 graph_[goal_vtx].pos = goal.position();
00261
00262
00263 HcGraphVertexIterator it_i, end_i, it_j, end_j;
00264 for (boost::tie(it_i,end_i) = boost::vertices(graph_); it_i!=end_i-1; ++it_i)
00265 {
00266 for (boost::tie(it_j,end_j) = boost::vertices(graph_); it_j!=end_j; ++it_j)
00267 {
00268 if (it_i==it_j)
00269 continue;
00270
00271
00272 Eigen::Vector2d distij = graph_[*it_j].pos-graph_[*it_i].pos;
00273 distij.normalize();
00274
00275 if (distij.dot(diff)<=obstacle_heading_threshold)
00276 continue;
00277
00278
00279
00280 if (obstacle_heading_threshold && *it_i==start_vtx && min_dist!=DBL_MAX)
00281 {
00282 if (*it_j == nearest_obstacle.first || *it_j == nearest_obstacle.second)
00283 {
00284 Eigen::Vector2d keypoint_dist = graph_[*it_j].pos-start.position();
00285 keypoint_dist.normalize();
00286 Eigen::Vector2d start_orient_vec( cos(start.theta()), sin(start.theta()) );
00287
00288 if (start_orient_vec.dot(keypoint_dist) <= obstacle_heading_threshold)
00289 {
00290 ROS_DEBUG("createGraph() - deleted edge: limit_obstacle_heading");
00291 continue;
00292 }
00293 }
00294 }
00295
00296
00297
00298 if (obstacles_!=NULL)
00299 {
00300 bool collision = false;
00301 for (ObstContainer::const_iterator it_obst = obstacles_->begin(); it_obst != obstacles_->end(); ++it_obst)
00302 {
00303 if ( (*it_obst)->checkLineIntersection(graph_[*it_i].pos,graph_[*it_j].pos, 0.5*dist_to_obst) )
00304 {
00305 collision = true;
00306 break;
00307 }
00308 }
00309 if (collision)
00310 continue;
00311 }
00312
00313
00314 boost::add_edge(*it_i,*it_j,graph_);
00315 }
00316 }
00317
00318
00319
00320 std::vector<HcGraphVertexType> visited;
00321 visited.push_back(start_vtx);
00322 DepthFirst(graph_,visited,goal_vtx, start.theta(), goal.theta(), start_velocity);
00323 }
00324
00325
00326 void HomotopyClassPlanner::createProbRoadmapGraph(const PoseSE2& start, const PoseSE2& goal, double dist_to_obst, int no_samples, double obstacle_heading_threshold, const geometry_msgs::Twist* start_velocity)
00327 {
00328
00329 clearGraph();
00330
00331
00332 Eigen::Vector2d diff = goal.position()-start.position();
00333 double start_goal_dist = diff.norm();
00334
00335 if (start_goal_dist<cfg_->goal_tolerance.xy_goal_tolerance)
00336 {
00337 ROS_DEBUG("HomotopyClassPlanner::createProbRoadmapGraph(): xy-goal-tolerance already reached.");
00338 if (tebs_.empty())
00339 {
00340 ROS_INFO("HomotopyClassPlanner::createProbRoadmapGraph(): Initializing a small straight line to just correct orientation errors.");
00341 addAndInitNewTeb(start, goal, start_velocity);
00342 }
00343 return;
00344 }
00345 Eigen::Vector2d normal(-diff.coeffRef(1),diff.coeffRef(0));
00346 normal.normalize();
00347
00348
00349
00350
00351 double area_width = cfg_->hcp.roadmap_graph_area_width;
00352
00353 boost::random::uniform_real_distribution<double> distribution_x(0, start_goal_dist * cfg_->hcp.roadmap_graph_area_length_scale);
00354 boost::random::uniform_real_distribution<double> distribution_y(0, area_width);
00355
00356 double phi = atan2(diff.coeffRef(1),diff.coeffRef(0));
00357 Eigen::Rotation2D<double> rot_phi(phi);
00358
00359 Eigen::Vector2d area_origin;
00360 if (cfg_->hcp.roadmap_graph_area_length_scale != 1.0)
00361 area_origin = start.position() + 0.5*(1.0-cfg_->hcp.roadmap_graph_area_length_scale)*start_goal_dist*diff.normalized() - 0.5*area_width*normal;
00362 else
00363 area_origin = start.position() - 0.5*area_width*normal;
00364
00365
00366 HcGraphVertexType start_vtx = boost::add_vertex(graph_);
00367 graph_[start_vtx].pos = start.position();
00368 diff.normalize();
00369
00370
00371
00372 for (int i=0; i < no_samples; ++i)
00373 {
00374 Eigen::Vector2d sample;
00375
00376
00377
00378
00379 sample = area_origin + rot_phi*Eigen::Vector2d(distribution_x(rnd_generator_), distribution_y(rnd_generator_));
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397 HcGraphVertexType v = boost::add_vertex(graph_);
00398 graph_[v].pos = sample;
00399 }
00400
00401
00402 HcGraphVertexType goal_vtx = boost::add_vertex(graph_);
00403 graph_[goal_vtx].pos = goal.position();
00404
00405
00406
00407 HcGraphVertexIterator it_i, end_i, it_j, end_j;
00408 for (boost::tie(it_i,end_i) = boost::vertices(graph_); it_i!=boost::prior(end_i); ++it_i)
00409 {
00410 for (boost::tie(it_j,end_j) = boost::vertices(graph_); it_j!=end_j; ++it_j)
00411 {
00412 if (it_i==it_j)
00413 continue;
00414
00415 Eigen::Vector2d distij = graph_[*it_j].pos-graph_[*it_i].pos;
00416 distij.normalize();
00417
00418
00419 if (distij.dot(diff)<=obstacle_heading_threshold)
00420 continue;
00421
00422
00423
00424 bool collision = false;
00425 for (ObstContainer::const_iterator it_obst = obstacles_->begin(); it_obst != obstacles_->end(); ++it_obst)
00426 {
00427 if ( (*it_obst)->checkLineIntersection(graph_[*it_i].pos,graph_[*it_j].pos, dist_to_obst) )
00428 {
00429 collision = true;
00430 break;
00431 }
00432 }
00433 if (collision)
00434 continue;
00435
00436
00437 boost::add_edge(*it_i,*it_j,graph_);
00438 }
00439 }
00440
00442 std::vector<HcGraphVertexType> visited;
00443 visited.push_back(start_vtx);
00444 DepthFirst(graph_,visited,goal_vtx, start.theta(), goal.theta(), start_velocity);
00445 }
00446
00447
00448 void HomotopyClassPlanner::DepthFirst(HcGraph& g, std::vector<HcGraphVertexType>& visited, const HcGraphVertexType& goal, double start_orientation, double goal_orientation, const geometry_msgs::Twist* start_velocity)
00449 {
00450
00451
00452 if ((int)tebs_.size() >= cfg_->hcp.max_number_classes)
00453 return;
00454
00455 HcGraphVertexType back = visited.back();
00456
00458 HcGraphAdjecencyIterator it, end;
00459 for ( boost::tie(it,end) = boost::adjacent_vertices(back,g); it!=end; ++it)
00460 {
00461 if ( std::find(visited.begin(), visited.end(), *it)!=visited.end() )
00462 continue;
00463
00464 if ( *it == goal )
00465 {
00466 visited.push_back(*it);
00467
00468
00469
00470 EquivalenceClassPtr H = calculateEquivalenceClass(visited.begin(), visited.end(), boost::bind(getCplxFromHcGraph, _1, boost::cref(graph_)), obstacles_);
00471
00472
00473
00474 if ( addEquivalenceClassIfNew(H) )
00475 {
00476 addAndInitNewTeb(visited.begin(), visited.end(), boost::bind(getVector2dFromHcGraph, _1, boost::cref(graph_)), start_orientation, goal_orientation, start_velocity);
00477 }
00478
00479 visited.pop_back();
00480 break;
00481 }
00482 }
00483
00485 for ( boost::tie(it,end) = boost::adjacent_vertices(back,g); it!=end; ++it)
00486 {
00487 if ( std::find(visited.begin(), visited.end(), *it)!=visited.end() || *it == goal)
00488 continue;
00489
00490
00491 visited.push_back(*it);
00492
00493
00494 DepthFirst(g, visited, goal, start_orientation, goal_orientation, start_velocity);
00495
00496 visited.pop_back();
00497 }
00498 }
00499
00500
00501 bool HomotopyClassPlanner::hasEquivalenceClass(const EquivalenceClassPtr& eq_class) const
00502 {
00503
00504 for (const std::pair<EquivalenceClassPtr, bool>& eqrel : equivalence_classes_)
00505 {
00506 if (eq_class->isEqual(*eqrel.first))
00507 return true;
00508 }
00509 return false;
00510 }
00511
00512 bool HomotopyClassPlanner::addEquivalenceClassIfNew(const EquivalenceClassPtr& eq_class, bool lock)
00513 {
00514 if (!eq_class->isValid())
00515 {
00516 ROS_WARN("HomotopyClassPlanner: Ignoring invalid H-signature");
00517 return false;
00518 }
00519
00520 if (hasEquivalenceClass(eq_class))
00521 return false;
00522
00523
00524 equivalence_classes_.push_back(std::make_pair(eq_class,lock));
00525 return true;
00526 }
00527
00528
00529 void HomotopyClassPlanner::renewAndAnalyzeOldTebs(bool delete_detours)
00530 {
00531
00532 equivalence_classes_.clear();
00533
00534
00535
00536
00537
00538
00539 TebOptPlannerContainer::iterator it_teb = tebs_.begin();
00540 while(it_teb != tebs_.end())
00541 {
00542
00543 if (delete_detours && tebs_.size()>1 && it_teb->get()->teb().detectDetoursBackwards(-0.1))
00544 {
00545 it_teb = tebs_.erase(it_teb);
00546 continue;
00547 }
00548
00549
00550 EquivalenceClassPtr equivalence_class = calculateEquivalenceClass(it_teb->get()->teb().poses().begin(), it_teb->get()->teb().poses().end(), getCplxFromVertexPosePtr ,obstacles_);
00551
00552
00553
00554
00555
00556 bool new_flag = addEquivalenceClassIfNew(equivalence_class);
00557 if (!new_flag)
00558 {
00559 it_teb = tebs_.erase(it_teb);
00560 continue;
00561 }
00562
00563 ++it_teb;
00564 }
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610 }
00611
00612 void HomotopyClassPlanner::updateReferenceTrajectoryViaPoints(bool all_trajectories)
00613 {
00614 if ( (!all_trajectories && !initial_plan_) || !via_points_ || via_points_->empty() || cfg_->optim.weight_viapoint <= 0)
00615 return;
00616
00617 if(equivalence_classes_.size() < tebs_.size())
00618 {
00619 ROS_ERROR("HomotopyClassPlanner::updateReferenceTrajectoryWithViaPoints(): Number of h-signatures does not match number of trajectories.");
00620 return;
00621 }
00622
00623 if (all_trajectories)
00624 {
00625
00626 for (std::size_t i=0; i < equivalence_classes_.size(); ++i)
00627 {
00628 tebs_[i]->setViaPoints(via_points_);
00629 }
00630 }
00631 else
00632 {
00633
00634 for (std::size_t i=0; i < equivalence_classes_.size(); ++i)
00635 {
00636 if(initial_plan_eq_class_->isEqual(*equivalence_classes_[i].first))
00637 tebs_[i]->setViaPoints(via_points_);
00638 else
00639 tebs_[i]->setViaPoints(NULL);
00640 }
00641 }
00642 }
00643
00644
00645 void HomotopyClassPlanner::exploreEquivalenceClassesAndInitTebs(const PoseSE2& start, const PoseSE2& goal, double dist_to_obst, const geometry_msgs::Twist* start_vel)
00646 {
00647
00648 renewAndAnalyzeOldTebs(false);
00649
00650
00651 if (initial_plan_ && addEquivalenceClassIfNew(initial_plan_eq_class_, true))
00652 initial_plan_teb_ = addAndInitNewTeb(*initial_plan_, start_vel);
00653 else
00654 {
00655 initial_plan_teb_.reset();
00656 initial_plan_teb_ = getInitialPlanTEB();
00657 }
00658
00659
00660 if (cfg_->hcp.simple_exploration)
00661 createGraph(start,goal,dist_to_obst,cfg_->hcp.obstacle_heading_threshold, start_vel);
00662 else
00663 createProbRoadmapGraph(start,goal,dist_to_obst,cfg_->hcp.roadmap_graph_no_samples,cfg_->hcp.obstacle_heading_threshold, start_vel);
00664 }
00665
00666
00667 TebOptimalPlannerPtr HomotopyClassPlanner::addAndInitNewTeb(const PoseSE2& start, const PoseSE2& goal, const geometry_msgs::Twist* start_velocity)
00668 {
00669 tebs_.push_back( TebOptimalPlannerPtr( new TebOptimalPlanner(*cfg_, obstacles_, robot_model_) ) );
00670 tebs_.back()->teb().initTEBtoGoal(start, goal, 0, cfg_->trajectory.dt_ref, cfg_->trajectory.min_samples, cfg_->trajectory.allow_init_with_backwards_motion);
00671
00672 if (start_velocity)
00673 tebs_.back()->setVelocityStart(*start_velocity);
00674
00675 return tebs_.back();
00676 }
00677
00678 TebOptimalPlannerPtr HomotopyClassPlanner::addAndInitNewTeb(const std::vector<geometry_msgs::PoseStamped>& initial_plan, const geometry_msgs::Twist* start_velocity)
00679 {
00680 tebs_.push_back( TebOptimalPlannerPtr( new TebOptimalPlanner(*cfg_, obstacles_, robot_model_) ) );
00681 tebs_.back()->teb().initTEBtoGoal(*initial_plan_, cfg_->trajectory.dt_ref, true, cfg_->trajectory.min_samples, cfg_->trajectory.allow_init_with_backwards_motion);
00682
00683 if (start_velocity)
00684 tebs_.back()->setVelocityStart(*start_velocity);
00685
00686 return tebs_.back();
00687 }
00688
00689 void HomotopyClassPlanner::updateAllTEBs(const PoseSE2* start, const PoseSE2* goal, const geometry_msgs::Twist* start_velocity)
00690 {
00691
00692
00693 if (!tebs_.empty() && (goal->position() - tebs_.front()->teb().BackPose().position()).norm() >= cfg_->trajectory.force_reinit_new_goal_dist)
00694 {
00695 ROS_DEBUG("New goal: distance to existing goal is higher than the specified threshold. Reinitalizing trajectories.");
00696 tebs_.clear();
00697 equivalence_classes_.clear();
00698 }
00699
00700
00701 for (TebOptPlannerContainer::iterator it_teb = tebs_.begin(); it_teb != tebs_.end(); ++it_teb)
00702 {
00703 it_teb->get()->teb().updateAndPruneTEB(*start, *goal);
00704 if (start_velocity)
00705 it_teb->get()->setVelocityStart(*start_velocity);
00706 }
00707 }
00708
00709
00710 void HomotopyClassPlanner::optimizeAllTEBs(int iter_innerloop, int iter_outerloop)
00711 {
00712
00713 if (cfg_->hcp.enable_multithreading)
00714 {
00715 boost::thread_group teb_threads;
00716 for (TebOptPlannerContainer::iterator it_teb = tebs_.begin(); it_teb != tebs_.end(); ++it_teb)
00717 {
00718 teb_threads.create_thread( boost::bind(&TebOptimalPlanner::optimizeTEB, it_teb->get(), iter_innerloop, iter_outerloop,
00719 true, cfg_->hcp.selection_obst_cost_scale, cfg_->hcp.selection_viapoint_cost_scale,
00720 cfg_->hcp.selection_alternative_time_cost) );
00721 }
00722 teb_threads.join_all();
00723 }
00724 else
00725 {
00726 for (TebOptPlannerContainer::iterator it_teb = tebs_.begin(); it_teb != tebs_.end(); ++it_teb)
00727 {
00728 it_teb->get()->optimizeTEB(iter_innerloop,iter_outerloop, true, cfg_->hcp.selection_obst_cost_scale,
00729 cfg_->hcp.selection_viapoint_cost_scale, cfg_->hcp.selection_alternative_time_cost);
00730 }
00731 }
00732 }
00733
00734 void HomotopyClassPlanner::deleteTebDetours(double threshold)
00735 {
00736 TebOptPlannerContainer::iterator it_teb = tebs_.begin();
00737 EquivalenceClassContainer::iterator it_eqclasses = equivalence_classes_.begin();
00738
00739 if (tebs_.size() != equivalence_classes_.size())
00740 {
00741 ROS_ERROR("HomotopyClassPlanner::deleteTebDetours(): number of equivalence classes (%lu) and trajectories (%lu) does not match.", equivalence_classes_.size(), tebs_.size());
00742 return;
00743 }
00744
00745 bool modified;
00746
00747 while(it_teb != tebs_.end())
00748 {
00749 modified = false;
00750
00751 if (!it_eqclasses->second)
00752 {
00753
00754 if (tebs_.size()>1 && it_teb->get()->teb().detectDetoursBackwards(threshold))
00755 {
00756 it_teb = tebs_.erase(it_teb);
00757 it_eqclasses = equivalence_classes_.erase(it_eqclasses);
00758 modified = true;
00759 }
00760 }
00761
00762
00763
00764 if (!it_teb->get()->isOptimized())
00765 {
00766 it_teb = tebs_.erase(it_teb);
00767 it_eqclasses = equivalence_classes_.erase(it_eqclasses);
00768 modified = true;
00769 ROS_DEBUG("HomotopyClassPlanner::deleteTebDetours(): removing candidate that was not optimized successfully");
00770 }
00771
00772 if (!modified)
00773 {
00774 ++it_teb;
00775 ++it_eqclasses;
00776 }
00777 }
00778 }
00779
00780 TebOptimalPlannerPtr HomotopyClassPlanner::getInitialPlanTEB()
00781 {
00782
00783 if (initial_plan_teb_)
00784 {
00785
00786 if ( std::find(tebs_.begin(), tebs_.end(), initial_plan_teb_ ) != tebs_.end() )
00787 return initial_plan_teb_;
00788 else
00789 {
00790 initial_plan_teb_.reset();
00791 ROS_DEBUG("initial teb not found, trying to find a match according to the cached equivalence class");
00792 }
00793 }
00794
00795
00796 for (int i=0; i<equivalence_classes_.size(); ++i)
00797 {
00798 equivalence_classes_[i].second = false;
00799 }
00800
00801
00802 if (initial_plan_eq_class_ && initial_plan_eq_class_->isValid())
00803 {
00804 if (equivalence_classes_.size() == tebs_.size())
00805 {
00806 for (int i=0; i<equivalence_classes_.size(); ++i)
00807 {
00808 if (equivalence_classes_[i].first->isEqual(*initial_plan_eq_class_))
00809 {
00810 equivalence_classes_[i].second = true;
00811 return tebs_[i];
00812 }
00813 }
00814 }
00815 else
00816 ROS_ERROR("HomotopyClassPlanner::getInitialPlanTEB(): number of equivalence classes (%lu) and number of trajectories (%lu) does not match.", equivalence_classes_.size(), tebs_.size());
00817 }
00818 else
00819 ROS_DEBUG("HomotopyClassPlanner::getInitialPlanTEB(): initial TEB not found in the set of available trajectories.");
00820
00821 return TebOptimalPlannerPtr();
00822 }
00823
00824 TebOptimalPlannerPtr HomotopyClassPlanner::selectBestTeb()
00825 {
00826 double min_cost = std::numeric_limits<double>::max();
00827 double min_cost_last_best = std::numeric_limits<double>::max();
00828 double min_cost_initial_plan_teb = std::numeric_limits<double>::max();
00829 TebOptimalPlannerPtr last_best_teb;
00830 TebOptimalPlannerPtr initial_plan_teb = getInitialPlanTEB();
00831
00832
00833 if (std::find(tebs_.begin(), tebs_.end(), best_teb_) != tebs_.end())
00834 {
00835
00836 min_cost_last_best = best_teb_->getCurrentCost() * cfg_->hcp.selection_cost_hysteresis;
00837 last_best_teb = best_teb_;
00838 }
00839
00840
00841 if (initial_plan_teb)
00842 {
00843
00844 min_cost_initial_plan_teb = initial_plan_teb->getCurrentCost() * cfg_->hcp.selection_prefer_initial_plan;
00845 }
00846
00847
00848 best_teb_.reset();
00849
00850 for (TebOptPlannerContainer::iterator it_teb = tebs_.begin(); it_teb != tebs_.end(); ++it_teb)
00851 {
00852
00853
00854
00855
00856
00857
00858
00859 double teb_cost;
00860
00861 if (*it_teb == last_best_teb)
00862 teb_cost = min_cost_last_best;
00863 else if (*it_teb == initial_plan_teb)
00864 teb_cost = min_cost_initial_plan_teb;
00865 else
00866 teb_cost = it_teb->get()->getCurrentCost();
00867
00868 if (teb_cost < min_cost)
00869 {
00870
00871 best_teb_ = *it_teb;
00872 min_cost = teb_cost;
00873 }
00874 }
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902
00903
00904
00905
00906 return best_teb_;
00907 }
00908
00909 int HomotopyClassPlanner::bestTebIdx() const
00910 {
00911 if (tebs_.size() == 1)
00912 return 0;
00913
00914 if (!best_teb_)
00915 return -1;
00916
00917 int idx = 0;
00918 for (TebOptPlannerContainer::const_iterator it_teb = tebs_.begin(); it_teb != tebs_.end(); ++it_teb, ++idx)
00919 {
00920 if (*it_teb == best_teb_)
00921 return idx;
00922 }
00923 return -1;
00924 }
00925
00926 bool HomotopyClassPlanner::isTrajectoryFeasible(base_local_planner::CostmapModel* costmap_model, const std::vector<geometry_msgs::Point>& footprint_spec,
00927 double inscribed_radius, double circumscribed_radius, int look_ahead_idx)
00928 {
00929 TebOptimalPlannerPtr best = bestTeb();
00930 if (!best)
00931 return false;
00932
00933 return best->isTrajectoryFeasible(costmap_model,footprint_spec, inscribed_radius, circumscribed_radius, look_ahead_idx);
00934 }
00935
00936 bool HomotopyClassPlanner::isHorizonReductionAppropriate(const std::vector<geometry_msgs::PoseStamped>& initial_plan) const
00937 {
00938 TebOptimalPlannerPtr best = bestTeb();
00939 if (!best)
00940 return false;
00941
00942 return best->isHorizonReductionAppropriate(initial_plan);
00943 }
00944
00945 void HomotopyClassPlanner::computeCurrentCost(std::vector<double>& cost, double obst_cost_scale, double viapoint_cost_scale, bool alternative_time_cost)
00946 {
00947 for (TebOptPlannerContainer::iterator it_teb = tebs_.begin(); it_teb != tebs_.end(); ++it_teb)
00948 {
00949 it_teb->get()->computeCurrentCost(cost, obst_cost_scale, viapoint_cost_scale, alternative_time_cost);
00950 }
00951 }
00952
00953
00954 }