graph_search.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2017,
6  * TU Dortmund - Institute of Control Theory and Systems Engineering.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * * Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * * Redistributions in binary form must reproduce the above
16  * copyright notice, this list of conditions and the following
17  * disclaimer in the documentation and/or other materials provided
18  * with the distribution.
19  * * Neither the name of the institute nor the names of its
20  * contributors may be used to endorse or promote products derived
21  * from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  * POSSIBILITY OF SUCH DAMAGE.
35  *
36  * Authors: Christoph Rösmann, Franz Albers
37  *********************************************************************/
38 
41 
42 namespace teb_local_planner
43 {
44 
45 void GraphSearchInterface::DepthFirst(HcGraph& g, std::vector<HcGraphVertexType>& visited, const HcGraphVertexType& goal, double start_orientation,
46  double goal_orientation, const geometry_msgs::Twist* start_velocity)
47 {
48  // see http://www.technical-recipes.com/2011/a-recursive-algorithm-to-find-all-paths-between-two-given-nodes/ for details on finding all simple paths
49 
50  if ((int)hcp_->getTrajectoryContainer().size() >= cfg_->hcp.max_number_classes)
51  return; // We do not need to search for further possible alternative homotopy classes.
52 
53  HcGraphVertexType back = visited.back();
54 
57  for ( boost::tie(it,end) = boost::adjacent_vertices(back,g); it!=end; ++it)
58  {
59  if ( std::find(visited.begin(), visited.end(), *it)!=visited.end() )
60  continue; // already visited
61 
62  if ( *it == goal ) // goal reached
63  {
64  visited.push_back(*it);
65 
66  // Add new TEB, if this path belongs to a new homotopy class
67  hcp_->addAndInitNewTeb(visited.begin(), visited.end(), boost::bind(getVector2dFromHcGraph, _1, boost::cref(graph_)),
68  start_orientation, goal_orientation, start_velocity);
69 
70  visited.pop_back();
71  break;
72  }
73  }
74 
76  for ( boost::tie(it,end) = boost::adjacent_vertices(back,g); it!=end; ++it)
77  {
78  if ( std::find(visited.begin(), visited.end(), *it)!=visited.end() || *it == goal)
79  continue; // already visited || goal reached
80 
81 
82  visited.push_back(*it);
83 
84  // recursion step
85  DepthFirst(g, visited, goal, start_orientation, goal_orientation, start_velocity);
86 
87  visited.pop_back();
88  }
89 }
90 
91 
92 
93 void lrKeyPointGraph::createGraph(const PoseSE2& start, const PoseSE2& goal, double dist_to_obst, double obstacle_heading_threshold, const geometry_msgs::Twist* start_velocity)
94 {
95  // Clear existing graph and paths
96  clearGraph();
98  return;
99  // Direction-vector between start and goal and normal-vector:
100  Eigen::Vector2d diff = goal.position()-start.position();
101 
102  if (diff.norm()<cfg_->goal_tolerance.xy_goal_tolerance)
103  {
104  ROS_DEBUG("HomotopyClassPlanner::createProbRoadmapGraph(): xy-goal-tolerance already reached.");
105  if (hcp_->getTrajectoryContainer().empty())
106  {
107  ROS_INFO("HomotopyClassPlanner::createProbRoadmapGraph(): Initializing a small straight line to just correct orientation errors.");
108  hcp_->addAndInitNewTeb(start, goal, start_velocity);
109  }
110  return;
111  }
112 
113  Eigen::Vector2d normal(-diff[1],diff[0]); // normal-vector
114  normal.normalize();
115  normal = normal*dist_to_obst; // scale with obstacle_distance;
116 
117  // Insert Vertices
118  HcGraphVertexType start_vtx = boost::add_vertex(graph_); // start vertex
119  graph_[start_vtx].pos = start.position();
120  diff.normalize();
121 
122  // store nearest obstacle keypoints -> only used if limit_obstacle_heading is enabled
123  std::pair<HcGraphVertexType,HcGraphVertexType> nearest_obstacle; // both vertices are stored
124  double min_dist = DBL_MAX;
125 
126  if (hcp_->obstacles()!=NULL)
127  {
128  for (ObstContainer::const_iterator it_obst = hcp_->obstacles()->begin(); it_obst != hcp_->obstacles()->end(); ++it_obst)
129  {
130  // check if obstacle is placed in front of start point
131  Eigen::Vector2d start2obst = (*it_obst)->getCentroid() - start.position();
132  double dist = start2obst.norm();
133  if (start2obst.dot(diff)/dist<0.1)
134  continue;
135 
136  // Add Keypoints
137  HcGraphVertexType u = boost::add_vertex(graph_);
138  graph_[u].pos = (*it_obst)->getCentroid() + normal;
139  HcGraphVertexType v = boost::add_vertex(graph_);
140  graph_[v].pos = (*it_obst)->getCentroid() - normal;
141 
142  // store nearest obstacle
143  if (obstacle_heading_threshold && dist<min_dist)
144  {
145  min_dist = dist;
146  nearest_obstacle.first = u;
147  nearest_obstacle.second = v;
148  }
149  }
150  }
151 
152  HcGraphVertexType goal_vtx = boost::add_vertex(graph_); // goal vertex
153  graph_[goal_vtx].pos = goal.position();
154 
155  // Insert Edges
156  HcGraphVertexIterator it_i, end_i, it_j, end_j;
157  for (boost::tie(it_i,end_i) = boost::vertices(graph_); it_i!=end_i-1; ++it_i) // ignore goal in this loop
158  {
159  for (boost::tie(it_j,end_j) = boost::vertices(graph_); it_j!=end_j; ++it_j) // check all forward connections
160  {
161  if (it_i==it_j)
162  continue;
163  // TODO: make use of knowing in which order obstacles are inserted and that for each obstacle 2 vertices are added,
164  // therefore we must only check one of them.
165  Eigen::Vector2d distij = graph_[*it_j].pos-graph_[*it_i].pos;
166  distij.normalize();
167  // Check if the direction is backwards:
168  if (distij.dot(diff)<=obstacle_heading_threshold)
169  continue;
170 
171 
172  // Check start angle to nearest obstacle
173  if (obstacle_heading_threshold && *it_i==start_vtx && min_dist!=DBL_MAX)
174  {
175  if (*it_j == nearest_obstacle.first || *it_j == nearest_obstacle.second)
176  {
177  Eigen::Vector2d keypoint_dist = graph_[*it_j].pos-start.position();
178  keypoint_dist.normalize();
179  Eigen::Vector2d start_orient_vec( cos(start.theta()), sin(start.theta()) ); // already normalized
180  // check angle
181  if (start_orient_vec.dot(keypoint_dist) <= obstacle_heading_threshold)
182  {
183  ROS_DEBUG("createGraph() - deleted edge: limit_obstacle_heading");
184  continue;
185  }
186  }
187  }
188 
189  // Collision Check
190 
191  if (hcp_->obstacles()!=NULL)
192  {
193  bool collision = false;
194  for (ObstContainer::const_iterator it_obst = hcp_->obstacles()->begin(); it_obst != hcp_->obstacles()->end(); ++it_obst)
195  {
196  if ( (*it_obst)->checkLineIntersection(graph_[*it_i].pos,graph_[*it_j].pos, 0.5*dist_to_obst) )
197  {
198  collision = true;
199  break;
200  }
201  }
202  if (collision)
203  continue;
204  }
205 
206  // Create Edge
207  boost::add_edge(*it_i,*it_j,graph_);
208  }
209  }
210 
211 
212  // Find all paths between start and goal!
213  std::vector<HcGraphVertexType> visited;
214  visited.push_back(start_vtx);
215  DepthFirst(graph_,visited,goal_vtx, start.theta(), goal.theta(), start_velocity);
216 }
217 
218 
219 
220 void ProbRoadmapGraph::createGraph(const PoseSE2& start, const PoseSE2& goal, double dist_to_obst, double obstacle_heading_threshold, const geometry_msgs::Twist* start_velocity)
221 {
222  // Clear existing graph and paths
223  clearGraph();
224  if((int)hcp_->getTrajectoryContainer().size() >= cfg_->hcp.max_number_classes)
225  return;
226  // Direction-vector between start and goal and normal-vector:
227  Eigen::Vector2d diff = goal.position()-start.position();
228  double start_goal_dist = diff.norm();
229 
230  if (start_goal_dist<cfg_->goal_tolerance.xy_goal_tolerance)
231  {
232  ROS_DEBUG("HomotopyClassPlanner::createProbRoadmapGraph(): xy-goal-tolerance already reached.");
233  if (hcp_->getTrajectoryContainer().empty())
234  {
235  ROS_INFO("HomotopyClassPlanner::createProbRoadmapGraph(): Initializing a small straight line to just correct orientation errors.");
236  hcp_->addAndInitNewTeb(start, goal, start_velocity);
237  }
238  return;
239  }
240  Eigen::Vector2d normal(-diff.coeffRef(1),diff.coeffRef(0)); // normal-vector
241  normal.normalize();
242 
243  // Now sample vertices between start, goal and a specified width between both sides
244  // Let's start with a square area between start and goal (maybe change it later to something like a circle or whatever)
245 
246  double area_width = cfg_->hcp.roadmap_graph_area_width;
247 
248  boost::random::uniform_real_distribution<double> distribution_x(0, start_goal_dist * cfg_->hcp.roadmap_graph_area_length_scale);
249  boost::random::uniform_real_distribution<double> distribution_y(0, area_width);
250 
251  double phi = atan2(diff.coeffRef(1),diff.coeffRef(0)); // rotate area by this angle
252  Eigen::Rotation2D<double> rot_phi(phi);
253 
254  Eigen::Vector2d area_origin;
256  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; // bottom left corner of the origin
257  else
258  area_origin = start.position() - 0.5*area_width*normal; // bottom left corner of the origin
259 
260  // Insert Vertices
261  HcGraphVertexType start_vtx = boost::add_vertex(graph_); // start vertex
262  graph_[start_vtx].pos = start.position();
263  diff.normalize(); // normalize in place
264 
265 
266  // Start sampling
267  for (int i=0; i < cfg_->hcp.roadmap_graph_no_samples; ++i)
268  {
269  Eigen::Vector2d sample;
270 // bool coll_free;
271 // do // sample as long as a collision free sample is found
272 // {
273  // Sample coordinates
274  sample = area_origin + rot_phi*Eigen::Vector2d(distribution_x(rnd_generator_), distribution_y(rnd_generator_));
275 
276  // Test for collision
277  // we do not care for collision checking here to improve efficiency, since we perform resampling repeatedly.
278  // occupied vertices are ignored in the edge insertion state since they always violate the edge-obstacle collision check.
279 // coll_free = true;
280 // for (ObstContainer::const_iterator it_obst = obstacles_->begin(); it_obst != obstacles_->end(); ++it_obst)
281 // {
282 // if ( (*it_obst)->checkCollision(sample, dist_to_obst)) // TODO really keep dist_to_obst here?
283 // {
284 // coll_free = false;
285 // break;
286 // }
287 // }
288 //
289 // } while (!coll_free && ros::ok());
290 
291  // Add new vertex
292  HcGraphVertexType v = boost::add_vertex(graph_);
293  graph_[v].pos = sample;
294  }
295 
296  // Now add goal vertex
297  HcGraphVertexType goal_vtx = boost::add_vertex(graph_); // goal vertex
298  graph_[goal_vtx].pos = goal.position();
299 
300 
301  // Insert Edges
302  HcGraphVertexIterator it_i, end_i, it_j, end_j;
303  for (boost::tie(it_i,end_i) = boost::vertices(graph_); it_i!=boost::prior(end_i); ++it_i) // ignore goal in this loop
304  {
305  for (boost::tie(it_j,end_j) = boost::vertices(graph_); it_j!=end_j; ++it_j) // check all forward connections
306  {
307  if (it_i==it_j) // same vertex found
308  continue;
309 
310  Eigen::Vector2d distij = graph_[*it_j].pos-graph_[*it_i].pos;
311  distij.normalize(); // normalize in place
312 
313  // Check if the direction is backwards:
314  if (distij.dot(diff)<=obstacle_heading_threshold)
315  continue; // diff is already normalized
316 
317 
318  // Collision Check
319  bool collision = false;
320  for (ObstContainer::const_iterator it_obst = hcp_->obstacles()->begin(); it_obst != hcp_->obstacles()->end(); ++it_obst)
321  {
322  if ( (*it_obst)->checkLineIntersection(graph_[*it_i].pos,graph_[*it_j].pos, dist_to_obst) )
323  {
324  collision = true;
325  break;
326  }
327  }
328  if (collision)
329  continue;
330 
331  // Create Edge
332  boost::add_edge(*it_i,*it_j,graph_);
333  }
334  }
335 
337  std::vector<HcGraphVertexType> visited;
338  visited.push_back(start_vtx);
339  DepthFirst(graph_,visited,goal_vtx, start.theta(), goal.theta(), start_velocity);
340 }
341 
342 } // end namespace
boost::graph_traits< HcGraph >::vertex_descriptor HcGraphVertexType
Abbrev. for vertex type descriptors in the homotopy class search-graph.
Definition: graph_search.h:82
Eigen::Vector2d & position()
Access the 2D position part.
Definition: pose_se2.h:145
double roadmap_graph_area_width
< Specify the number of samples generated for creating the roadmap graph, if simple_exploration is tu...
Definition: teb_config.h:183
const ObstContainer * obstacles() const
Access current obstacle container (read-only)
const TebConfig * cfg_
Config class that stores and manages all related parameters.
Definition: graph_search.h:144
double xy_goal_tolerance
Allowed final euclidean distance to the goal position.
Definition: teb_config.h:111
HcGraph graph_
Store the graph that is utilized to find alternative homotopy classes.
Definition: graph_search.h:120
IMETHOD Vector diff(const Vector &p_w_a, const Vector &p_w_b, double dt=1)
boost::graph_traits< HcGraph >::vertex_iterator HcGraphVertexIterator
Abbrev. for the vertices iterator of the homotopy class search-graph.
Definition: graph_search.h:86
void clearGraph()
Clear any existing graph of the homotopy class search.
Definition: graph_search.h:116
TebOptimalPlannerPtr addAndInitNewTeb(BidirIter path_start, BidirIter path_end, Fun fun_position, double start_orientation, double goal_orientation, const geometry_msgs::Twist *start_velocity)
Add a new Teb to the internal trajectory container, if this teb constitutes a new equivalence class...
HomotopyClassPlanner *const hcp_
Raw pointer to the HomotopyClassPlanner. The HomotopyClassPlanner itself is guaranteed to outlive the...
Definition: graph_search.h:145
void DepthFirst(HcGraph &g, std::vector< HcGraphVertexType > &visited, const HcGraphVertexType &goal, double start_orientation, double goal_orientation, const geometry_msgs::Twist *start_velocity)
Depth First Search implementation to find all paths between the start and the specified goal vertex...
#define DBL_MAX
struct teb_local_planner::TebConfig::GoalTolerance goal_tolerance
Goal tolerance related parameters.
virtual void createGraph(const PoseSE2 &start, const PoseSE2 &goal, double dist_to_obst, double obstacle_heading_threshold, const geometry_msgs::Twist *start_velocity)
Create a graph and sample points in the global frame that can be used to explore new possible paths b...
struct teb_local_planner::TebConfig::HomotopyClasses hcp
#define ROS_INFO(...)
const TebOptPlannerContainer & getTrajectoryContainer() const
Read-only access to the internal trajectory container.
boost::graph_traits< HcGraph >::adjacency_iterator HcGraphAdjecencyIterator
Abbrev. for the adjacency iterator that iterates vertices that are adjecent to the specified one...
Definition: graph_search.h:90
This class implements a pose in the domain SE2: The pose consist of the position x and y and an orie...
Definition: pose_se2.h:57
double & theta()
Access the orientation part (yaw angle) of the pose.
Definition: pose_se2.h:182
double roadmap_graph_area_length_scale
The length of the rectangular region is determined by the distance between start and goal...
Definition: teb_config.h:184
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
const Eigen::Vector2d & getVector2dFromHcGraph(HcGraphVertexType vert_descriptor, const HcGraph &graph)
Definition: graph_search.h:99
boost::adjacency_list< boost::listS, boost::vecS, boost::directedS, HcGraphVertex, boost::no_property > HcGraph
Abbrev. for the homotopy class search-graph type.
Definition: graph_search.h:80
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
int max_number_classes
Specify the maximum number of allowed alternative homotopy classes (limits computational effort) ...
Definition: teb_config.h:174
virtual void createGraph(const PoseSE2 &start, const PoseSE2 &goal, double dist_to_obst, double obstacle_heading_threshold, const geometry_msgs::Twist *start_velocity)
Create a graph containing points in the global frame that can be used to explore new possible paths b...
#define ROS_DEBUG(...)


teb_local_planner
Author(s): Christoph Rösmann
autogenerated on Wed Jun 3 2020 04:03:08