router.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2017, <copyright holder> <email>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the <organization> nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY <copyright holder> <email> ''AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL <copyright holder> <email> BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
30 #include <chrono>
31 #include <unordered_set>
32 
33 #include <time.h>
34 #include <thread>
35 #include <ros/ros.h>
36 
37 namespace multi_robot_router
38 {
39 
41 {
42 }
43 
44 Router::Router(const uint32_t _nr_robots) : starts_(_nr_robots),
45  goals_(_nr_robots),
46  mrr_(_nr_robots),
47  mrrTs_(_nr_robots, 8)
48 {
49  robot_nr_ = _nr_robots;
50  std::vector<uint32_t> robotRadius(robot_nr_, 0);
52 }
53 
55 {
57 }
58 
59 void Router::setPlannerType(Router::routerType _type, uint32_t _nr_threads)
60 {
61  if (_type == routerType::multiThreadSrr)
63  else
65 }
66 
67 void Router::resize(const uint32_t _nr_robots)
68 {
69  robot_nr_ = _nr_robots;
70  starts_.resize(_nr_robots);
71  goals_.resize(_nr_robots);
72 
73  startSegments_.resize(_nr_robots);
74  goalSegments_.resize(_nr_robots);
75 
76  voronoiGoals_.resize(_nr_robots);
77  voronoiStart_.resize(_nr_robots);
78 
79  realGoals_.resize(_nr_robots);
80  realStart_.resize(_nr_robots);
81 }
82 
83 bool Router::preprocessEndpoints(const std::vector<float> &_radius, const float &resolution, const Eigen::Vector2d &origin, const std::vector<Segment> &_graph)
84 {
85  for (uint32_t i = 0; i < goals_.size(); i++)
86  {
87  //Find Start and Goal Poses On the map
88  realStart_[i] = {(starts_[i][0] - origin[0]) / resolution, (starts_[i][1] - origin[1]) / resolution};
89  realGoals_[i] = {(goals_[i][0] - origin[0]) / resolution, (goals_[i][1] - origin[1]) / resolution};
90 
91  float radius = _radius[i];
93  ROS_DEBUG("Multi Robot Router: robot %i \"%s\" @ <%f, %f >", i, robot_names_[i].c_str(), starts_[i][0], starts_[i][1]);
94  if ( d_start < radius / 2)
95  {
96  ROS_INFO("Multi Robot Router: Start of robot %i \"%s\" @ <%f, %f > is to close to an obstacle", i, robot_names_[i].c_str(), starts_[i][0], starts_[i][1]);
97  return false;
98  }
100  if (d_goal < radius / 2)
101  {
102  ROS_INFO("Multi Robot Router: Goal of robot%i \"%s\" @ <%f, %f > is to close to an obstacle", i, robot_names_[i].c_str(), starts_[i][0], starts_[i][1]);
103  return false;
104  }
105  }
106 
107  return true;
108 }
109 
110 bool Router::processEndpointsExpander(const cv::Mat &_map, const std::vector<Segment> &_graph, const Eigen::Vector2d &_realStart, const Eigen::Vector2d &_realGoal, Eigen::Vector2d &_voronoiStart, Eigen::Vector2d &_voronoiGoal, uint32_t &_segmentStart, uint32_t &_segmentGoal, const uint32_t _diameter, const uint32_t _index) const
111 {
112 
113  int32_t segIdStart = -1;
114  int32_t segIdGoal = -1;
115 
116  //check if start and goal pose have enough clearance to obstacles
117  uint32_t size_x = _map.cols;
118  uint32_t size_y = _map.rows;
119 
120  //No algorithm checks free space to obstacle because it is allready checked
122  {
123  //Find Start and Goal (with distance to Segment (more performance but robot has to be inside a segment)
124  segIdStart = getSegment(_graph, _realStart);
125  segIdGoal = getSegment(_graph, _realGoal);
126 
127  if (segIdStart != -1 && segIdGoal != -1)
128  {
129  _voronoiStart = (_graph[segIdStart].getStart() + _graph[segIdStart].getEnd()) / 2;
130  _voronoiGoal = (_graph[segIdGoal].getStart() + _graph[segIdGoal].getEnd()) / 2;
131  }
132  }
133  else // if(graphMode_ == graphType::random)
134  {
135  PointExpander _expander;
136  _expander.initialize(_map);
137 
138  //Save all segment Points into map to find them using point Expander
139  std::map<uint32_t, Eigen::Vector2d> points;
140 
141  for (const Segment &seg : _graph)
142  {
143  std::pair<uint32_t, Eigen::Vector2d> p(seg.getSegmentId(), (seg.getStart() + seg.getEnd()) / 2);
144  points.insert(p);
145  }
146 
147  //find Segment using Dijkstra (less performance but find segment for sure)
148  std::vector<float> potential;
149  potential.resize(size_x * size_y);
150  float *p = &potential[0];
151  //potential_.reset(new float[]);
152 
153  _expander.findGoalOnMap(_realStart, size_x * size_y, p, points, 0, _voronoiStart, segIdStart, _diameter / 2); //It is allready checked if there is enough free space
154 
155  std::vector<float> potential2;
156  potential2.resize(size_x * size_y);
157  float *p2 = &potential2[0];
158  _expander.findGoalOnMap(_realGoal, size_x * size_y, p2, points, 0, _voronoiGoal, segIdGoal, _diameter / 2); //It is allready checked if there is enough free space
159  }
160 
161  if (segIdStart == -1)
162  {
163  ROS_INFO("Multi Robot Router: Start of robot %i \"%s\" was not found", _index, robot_names_[_index].c_str());
164  return false;
165  }
166 
167  if (segIdGoal == -1)
168  {
169  ROS_INFO("Multi Robot Router: Goal of robot %i \"%s\" was not found", _index, robot_names_[_index].c_str());
170  return false;
171  }
172 
173  _segmentStart = segIdStart;
174  _segmentGoal = segIdGoal;
175 
176  //Optimize found segments for errors
177  if (!resolveSegment(_graph, _segmentStart, _realStart, _diameter, _segmentStart))
178  {
179  ROS_INFO("Multi Robot Router: Start of robot %i \"%s\" is not valid", _index, robot_names_[_index].c_str());
180  return false;
181  }
182 
183  if (!resolveSegment(_graph, _segmentGoal, _realGoal, _diameter, _segmentGoal))
184  {
185  ROS_INFO("Multi Robot Router: Goal of robot %i \"%s\" is not valid", _index, robot_names_[_index].c_str());
186  return false;
187  }
188 
189  return true;
190 }
191 
192 bool Router::calculateStartPoints(const std::vector<float> &_radius, const cv::Mat &_map, const float &resolution, const Eigen::Vector2d &origin, const std::vector<Segment> &_graph)
193 {
194  if (!preprocessEndpoints(_radius, resolution, origin, _graph))
195  return false;
196 
197  std::vector<std::thread> t;
198  t.resize(robot_nr_);
199 
200  std::vector<uint32_t> result;
201  result.resize(robot_nr_);
202 
203  for (uint32_t i = 0; i < goals_.size(); i++)
204  {
205  uint32_t &res = result[i];
206  Eigen::Vector2d &realS = realStart_[i];
207  Eigen::Vector2d &realG = realGoals_[i];
208  Eigen::Vector2d &voronS = voronoiStart_[i];
209  Eigen::Vector2d &voronG = voronoiGoals_[i];
210  uint32_t &segS = startSegments_[i];
211  uint32_t &segG = goalSegments_[i];
212  uint32_t diam = 2 * ((float)_radius[i]) / resolution;
213 
214  t[i] = std::thread(
215  [this, &res, _map, _graph, realS, realG, &voronS, &voronG, &segS, &segG, diam, i]() {
216  res = (uint32_t)processEndpointsExpander(_map, _graph, realS, realG, voronS, voronG, segS, segG, diam, i);
217  });
218 
219  // if(!processEndpointsExpander(_map, _graph, realStart_[i], realGoals_[i], voronoiStart_[i], voronoiGoals_[i], startSegments_[i], goalSegments_[i], 2 * ((float) _radius[i]) / resolution, i))
220  // return false;
221  }
222 
223  for (uint32_t i = 0; i < goals_.size(); i++)
224  {
225  t[i].join();
226  }
227 
228  for (uint32_t i = 0; i < goals_.size(); i++)
229  {
230 
231  if (!result[i])
232  return false;
233  }
234  return true;
235 }
236 
237 int32_t Router::getSegment(const std::vector<Segment> &_graph, const Eigen::Vector2d &_odom) const
238 {
239  float minDist = FLT_MAX;
240  int32_t segment = -1;
241 
242  //Select the segment which contains the robot center
243  for (uint32_t i = 0; i < _graph.size(); i++)
244  {
245  float d = distanceToSegment(_graph[i], _odom);
246 
247  if (d < minDist && d <= _graph[i].width())
248  {
249  segment = i;
250  minDist = d;
251  }
252  }
253 
254  return segment;
255 }
256 
257 float Router::distanceToSegment(const Segment &_s, const Eigen::Vector2d &_p) const
258 {
259  Eigen::Vector2d n = _s.getEnd() - _s.getStart();
260  Eigen::Vector2d pa = _s.getStart() - _p;
261 
262  float c = n.dot(pa);
263 
264  // Closest point is a
265  if (c > 0.0f)
266  return std::sqrt(pa.dot(pa));
267 
268  Eigen::Vector2d bp = _p - _s.getEnd();
269 
270  // Closest point is b
271  if (n.dot(bp) > 0.0f)
272  return std::sqrt(bp.dot(bp));
273 
274  // Closest point is between a and b
275  Eigen::Vector2d e = pa - n * (c / n.dot(n));
276 
277  return std::sqrt(e.dot(e));
278 }
279 
280 bool Router::resolveSegment(const std::vector<Segment> &_graph, const uint32_t &_segId, const Eigen::Vector2d &_originPoint, const float &_diameter, uint32_t &_foundSeg) const
281 {
282  const Segment seg = _graph[_segId];
283 
284  if ((seg.getPredecessors().size() == 0 || seg.getSuccessors().size() == 0) && seg.width() < _diameter)
285  {
286  //If we are on a leave Segment we are allowed to move the robot one segment in the graph if its radius is to big.
287  //Because it can happen, that a leave segment has a triangular shape and thus wrong width value.
288  std::vector<uint32_t> neighbours;
289 
290  if (seg.getPredecessors().size() != 0)
291  neighbours = seg.getPredecessors();
292  else
293  neighbours = seg.getSuccessors();
294 
295  float dist = std::numeric_limits<float>::max();
296 
297  //Find the closest neighbour
298  for (const uint32_t &neighbour : neighbours)
299  {
300  float ds_x = _originPoint[0] - _graph[neighbour].getStart()[0];
301  float ds_y = _originPoint[1] - _graph[neighbour].getStart()[1];
302  float de_x = _originPoint[0] - _graph[neighbour].getEnd()[0];
303  float de_y = _originPoint[1] - _graph[neighbour].getEnd()[1];
304  float d = (std::sqrt(ds_x * ds_x + ds_y * ds_y) + std::sqrt(de_x * de_x + de_y * de_y)) / 2;
305 
306  if (d < dist && _diameter <= _graph[neighbour].width())
307  {
308  _foundSeg = neighbour;
309  dist = d;
310  }
311  }
312 
313  //Return only true if a valid Segment is found, where the radius of the robot is smaller
314  //than the segment width
315  if (_diameter <= _graph[_foundSeg].width())
316  return true;
317  }
318  else if (_diameter <= seg.width())
319  {
320  //if the radius is smaller than the segment width a valid segment is found
321  return true;
322  }
323 
324  //No valid wait segment is found
325  return false;
326 }
327 
328 bool Router::makePlan(const std::vector<Eigen::Vector3d> &_starts, const std::vector<Eigen::Vector3d> &_goals, const std::vector<float> &_radius, const cv::Mat &_map, const float &_resolution, const Eigen::Vector2d &_origin, const std::vector<Segment> &_graph, const std::vector<std::string> &_robot_names)
329 {
330  robot_names_ = _robot_names;
331  auto t1 = std::chrono::high_resolution_clock::now();
332  std::clock_t startcputime = std::clock();
333 
334  if (_goals.size() != _starts.size() || _goals.size() != _radius.size())
335  {
336  ROS_INFO("Multi Robot Router: Wrong nr of goals, starts or radii %lu %lu %lu", _starts.size(), goals_.size(), _radius.size());
337  auto t2 = std::chrono::high_resolution_clock::now();
338  duration_ = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
339  return false;
340  }
341 
342  //Set nr robots
343  robot_nr_ = _goals.size();
344  resize(robot_nr_);
345 
346  ROS_INFO("=========================================================");
348  goals_ = _goals;
349  starts_ = _starts;
350 
351  if (!calculateStartPoints(_radius, _map, _resolution, _origin, _graph))
352  {
353  ROS_INFO("Multi Robot Router: Failed to find Endpoints !!!");
354  auto t2 = std::chrono::high_resolution_clock::now();
355  duration_ = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
356  return false;
357  }
358 
360  std::vector<uint32_t> diameter;
361 
362  for (int i = 0; i < _radius.size(); i++)
363  {
364  diameter.push_back(2 * ((float)_radius[i]) / _resolution);
365  }
366 
370  routingTable_.clear();
371 
373  {
374  ROS_INFO("Multi Robot Router: Failed to find Routing Table !!!");
375  auto t2 = std::chrono::high_resolution_clock::now();
376  duration_ = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
377  return false;
378  }
379 
381  optimizePaths(_graph);
382 
384 
385  //DEBUG STATS
386  longestPatLength_ = 0;
387  overallPathLength_ = 0;
388 
389  for (std::vector<Checkpoint> &path : routingTable_)
390  {
391  float lengthPath = 0;
392 
393  for (Checkpoint &seg : path)
394  {
395  Eigen::Vector3d vec = (seg.end - seg.start);
396  float lengthVertex = std::sqrt(vec[0] * vec[0] + vec[1] * vec[1]);
397  overallPathLength_ += lengthVertex;
398  lengthPath += lengthVertex;
399  }
400 
401  longestPatLength_ = std::max<int>(longestPatLength_, lengthPath);
402  }
403 
404  longestPatLength_ *= _resolution;
405  overallPathLength_ *= _resolution;
406 
407  auto t2 = std::chrono::high_resolution_clock::now();
408  duration_ = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
409  //DEBUG STATS
410 
411  return true;
412 }
413 
414 void Router::optimizePaths(const std::vector<Segment> &_graph)
415 {
416  if (routingTable_.size() > 1)
417  return;
418 
419  if (routingTable_.size() > 2)
420  {
421  routingTable_[0].erase(routingTable_[0].begin(), routingTable_[0].begin() + 1);
422  routingTable_[0].erase(routingTable_[0].end() - 1, routingTable_[0].end());
423  }
424 }
425 
427 {
429  {
430  for (int i = 0; i < routingTable_.size(); i++)
431  {
432  routingTable_[i].front().start[0] = voronoiStart_[i][0];
433  routingTable_[i].front().start[1] = voronoiStart_[i][1];
434  routingTable_[i].back().end[0] = voronoiGoals_[i][0];
435  routingTable_[i].back().end[1] = voronoiGoals_[i][1];
436  routingTable_[i].back().end[2] = goals_[i][2];
437  }
438  }
439  else if (goalMode_ == goalMode::use_map_goal)
440  {
441  for (int i = 0; i < routingTable_.size(); i++)
442  {
443  routingTable_[i].front().start[0] = realStart_[i][0];
444  routingTable_[i].front().start[1] = realStart_[i][1];
445  routingTable_[i].back().end[0] = realGoals_[i][0];
446  routingTable_[i].back().end[1] = realGoals_[i][1];
447  routingTable_[i].back().end[2] = goals_[i][2];
448  }
449  }
450  else
451  {
452  for (int i = 0; i < routingTable_.size(); i++)
453  {
454  routingTable_[i].back().end[2] = goals_[i][2];
455  }
456  }
457 }
458 
459 const std::vector<Checkpoint> &Router::getRoute(const uint32_t _robot) const
460 {
461  return routingTable_[_robot];
462 }
463 
464 uint32_t Router::getDuration_ms() const
465 {
466  return duration_;
467 }
468 
470 {
471  return longestPatLength_;
472 }
473 
475 {
476  return overallPathLength_;
477 }
478 
480 {
482 }
483 
485 {
487 }
488 } // namespace multi_robot_router
int32_t getSegment(const std::vector< Segment > &_graph, const Eigen::Vector2d &_pose) const
Definition: router.cpp:237
d
std::vector< Eigen::Vector2d > realStart_
Definition: router.h:120
float getOverallPathLength() const
getter
Definition: router.cpp:474
bool preprocessEndpoints(const std::vector< float > &_radius, const float &resolution, const Eigen::Vector2d &origin, const std::vector< Segment > &_graph)
Definition: router.cpp:83
f
MultiRobotRouterThreadedSrr mrrTs_
Definition: router.h:130
virtual const uint32_t getPriorityScheduleAttempts() const
returns the number of attemps to reschedul the priorities taken
void setPlannerType(routerType _type, uint32_t _nr_threads)
Definition: router.cpp:59
std::vector< Eigen::Vector2d > realGoals_
Definition: router.h:119
bool findGoalOnMap(const Eigen::Vector2d &_start, const uint32_t &_cycles, float *_potential, const std::map< uint32_t, Eigen::Vector2d > &_goals, const uint32_t &_optimizationSteps, Eigen::Vector2d &_foundPoint, int32_t &_segIdx, const uint32_t &_radius)
searches the first occurence of a point in the goals_ list and returns the index
std::vector< Eigen::Vector2d > voronoiGoals_
Definition: router.h:121
void resize(const uint32_t _nr_robots)
resizes the planner to a different nr of _nr_robots
Definition: router.cpp:67
virtual void setSpeedRescheduling(const bool _status)
enables or disables speed rescheduling
float getDistanceToObstacle(const Eigen::Vector2d &vec)
returns the distance to the closest obstacle for a point
virtual void setCollisionResolver(const SegmentExpander::CollisionResolverType cRes)
sets the CollisionResolverType used to resolve occured robot collisions
void initialize(const cv::Mat &_map)
initializes the point expander with a distance map
PointExpander pointExpander_
with the robot id one can access the robot name
Definition: router.h:127
virtual void setRobotDiameter(const std::vector< uint32_t > &_diameter)
sets the robot diameter for every robot
const std::vector< Checkpoint > & getRoute(const uint32_t _robot) const
returns the found Routing Table
Definition: router.cpp:459
float getLongestPathLength() const
getter
Definition: router.cpp:469
#define ROS_INFO(...)
const Eigen::Vector2d & getEnd() const
Definition: srr_utils.cpp:45
void optimizePaths(const std::vector< Segment > &_graph)
Definition: router.cpp:414
bool processEndpointsExpander(const cv::Mat &_map, const std::vector< Segment > &_graph, const Eigen::Vector2d &_realStart, const Eigen::Vector2d &_realGoal, Eigen::Vector2d &_voronoiStart, Eigen::Vector2d &_voronoiGoal, uint32_t &_segmentStart, uint32_t &_segmentGoal, const uint32_t _diameter, const uint32_t _index) const
Definition: router.cpp:110
MultiRobotRouter mrr_
Definition: router.h:129
bool makePlan(const std::vector< Eigen::Vector3d > &_starts, const std::vector< Eigen::Vector3d > &_goals, const std::vector< float > &_radius, const cv::Mat &_map, const float &_resolution, const Eigen::Vector2d &_origin, const std::vector< Segment > &_graph, const std::vector< std::string > &_robot_names)
generates the plan from (Vertex[odom robotPose] to Vertex[_goals]
Definition: router.cpp:328
bool resolveSegment(const std::vector< Segment > &_graph, const uint32_t &_segId, const Eigen::Vector2d &_originPoint, const float &_radius, uint32_t &_foundSeg) const
Definition: router.cpp:280
virtual bool getRoutingTable(const std::vector< Segment > &_graph, const std::vector< uint32_t > &_startSegments, const std::vector< uint32_t > &_goalSegments, std::vector< std::vector< Checkpoint >> &_routingTable, const float &_timeLimit)
computes the routing table according to the given start and goal _goalSegments
const std::vector< uint32_t > & getSuccessors() const
Definition: srr_utils.cpp:69
uint32_t getPriorityScheduleAttemps() const
getter
Definition: router.cpp:479
std::vector< Eigen::Vector2d > voronoiStart_
Definition: router.h:122
std::vector< Eigen::Vector3d > starts_
Definition: router.h:117
const Eigen::Vector2d & getStart() const
Definition: srr_utils.cpp:64
virtual void setPriorityRescheduling(const bool _status)
enables or disables priority rescheduling
float distanceToSegment(const Segment &_s, const Eigen::Vector2d &_p) const
Definition: router.cpp:257
void setCollisionResolutionType(const SegmentExpander::CollisionResolverType _cr)
sets the CollisionResolverType used
Definition: router.cpp:54
virtual const uint32_t getSpeedScheduleAttempts() const
returns the number of attemps to limit the maximum speed of a robot taken
std::vector< uint32_t > goalSegments_
Definition: router.h:124
std::vector< uint32_t > startSegments_
Definition: router.h:123
const std::vector< uint32_t > & getPredecessors() const
Definition: srr_utils.cpp:55
uint32_t getSpeedScheduleAttemps() const
getter
Definition: router.cpp:484
std::vector< std::vector< Checkpoint > > routingTable_
Definition: router.h:131
std::vector< std::string > robot_names_
Definition: router.h:125
std::vector< Eigen::Vector3d > goals_
Definition: router.h:118
uint32_t getDuration_ms() const
getter
Definition: router.cpp:464
bool calculateStartPoints(const std::vector< float > &_radius, const cv::Mat &_map, const float &resolution, const Eigen::Vector2d &origin, const std::vector< Segment > &_graph)
Definition: router.cpp:192
MultiRobotRouter * multiRobotRouter_
Definition: router.h:128
#define ROS_DEBUG(...)
virtual void setRobotNr(const uint32_t _nr_robots)
sets the number of robots used


tuw_multi_robot_router
Author(s): Benjamin Binder
autogenerated on Mon Jun 10 2019 15:42:49