costmap_prohibition_layer.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2016,
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  * Author: Stephan Kurzawe
37  *********************************************************************/
38 
41 
43 
44 using costmap_2d::LETHAL_OBSTACLE;
45 
47 {
48 
49 CostmapProhibitionLayer::CostmapProhibitionLayer() : _dsrv(NULL)
50 {
51 }
52 
54 {
55  if (_dsrv!=NULL)
56  delete _dsrv;
57 }
58 
60 {
61  ros::NodeHandle nh("~/" + name_);
62  current_ = true;
63 
64  _dsrv = new dynamic_reconfigure::Server<CostmapProhibitionLayerConfig>(nh);
65  dynamic_reconfigure::Server<CostmapProhibitionLayerConfig>::CallbackType cb =
66  boost::bind(&CostmapProhibitionLayer::reconfigureCB, this, _1, _2);
67  _dsrv->setCallback(cb);
68 
69  // get a pointer to the layered costmap and save resolution
72 
73  // set initial bounds
74  _min_x = _min_y = _max_x = _max_y = 0;
75 
76  // reading the prohibition areas out of the namespace of this plugin!
77  // e.g.: "move_base/global_costmap/prohibition_layer/prohibition_areas"
78  std::string params = "prohibition_areas";
79  if (!parseProhibitionListFromYaml(&nh, params))
80  ROS_ERROR_STREAM("Reading prohibition areas from '" << nh.getNamespace() << "/" << params << "' failed!");
81 
82  _fill_polygons = true;
83  nh.param("fill_polygons", _fill_polygons, _fill_polygons);
84 
85  // compute map bounds for the current set of prohibition areas.
87 
88  ROS_INFO("CostmapProhibitionLayer initialized.");
89 }
90 
91 void CostmapProhibitionLayer::reconfigureCB(CostmapProhibitionLayerConfig &config, uint32_t level)
92 {
93  enabled_ = config.enabled;
94  _fill_polygons = config.fill_polygons;
95 }
96 
97 
98 void CostmapProhibitionLayer::updateBounds(double robot_x, double robot_y, double robot_yaw,
99  double *min_x, double *min_y, double *max_x, double *max_y)
100 {
101  if (!enabled_)
102  return;
103 
104  std::lock_guard<std::mutex> l(_data_mutex);
105 
106  if (_prohibition_points.empty() && _prohibition_polygons.empty())
107  return;
108 
109  *min_x = std::min(*min_x, _min_x);
110  *min_y = std::min(*min_y, _min_y);
111  *max_x = std::max(*max_x, _max_x);
112  *max_y = std::max(*max_y, _max_y);
113 
114 }
115 
116 void CostmapProhibitionLayer::updateCosts(costmap_2d::Costmap2D &master_grid, int min_i, int min_j, int max_i, int max_j)
117 {
118  if (!enabled_)
119  return;
120 
121  std::lock_guard<std::mutex> l(_data_mutex);
122 
123  // set costs of polygons
124  for (int i = 0; i < _prohibition_polygons.size(); ++i)
125  {
126  setPolygonCost(master_grid, _prohibition_polygons[i], LETHAL_OBSTACLE, min_i, min_j, max_i, max_j, _fill_polygons);
127  }
128 
129  // set cost of points
130  for (int i = 0; i < _prohibition_points.size(); ++i)
131  {
132  unsigned int mx;
133  unsigned int my;
134  if (master_grid.worldToMap(_prohibition_points[i].x, _prohibition_points[i].y, mx, my))
135  {
136  master_grid.setCost(mx, my, LETHAL_OBSTACLE);
137  }
138  }
139 }
140 
142 {
143  std::lock_guard<std::mutex> l(_data_mutex);
144 
145  // reset bounds
146  _min_x = _min_y = _max_x = _max_y = 0;
147 
148  // iterate polygons
149  for (int i = 0; i < _prohibition_polygons.size(); ++i)
150  {
151  for (int j=0; j < _prohibition_polygons.at(i).size(); ++j)
152  {
153  double px = _prohibition_polygons.at(i).at(j).x;
154  double py = _prohibition_polygons.at(i).at(j).y;
155  _min_x = std::min(px, _min_x);
156  _min_y = std::min(py, _min_y);
157  _max_x = std::max(px, _max_x);
158  _max_y = std::max(py, _max_y);
159  }
160  }
161 
162  // iterate points
163  for (int i = 0; i < _prohibition_points.size(); ++i)
164  {
165  double px = _prohibition_points.at(i).x;
166  double py = _prohibition_points.at(i).y;
167  _min_x = std::min(px, _min_x);
168  _min_y = std::min(py, _min_y);
169  _max_x = std::max(px, _max_x);
170  _max_y = std::max(py, _max_y);
171  }
172 }
173 
174 
175 void CostmapProhibitionLayer::setPolygonCost(costmap_2d::Costmap2D &master_grid, const std::vector<geometry_msgs::Point>& polygon, unsigned char cost,
176  int min_i, int min_j, int max_i, int max_j, bool fill_polygon)
177 {
178  std::vector<PointInt> map_polygon;
179  for (unsigned int i = 0; i < polygon.size(); ++i)
180  {
181  PointInt loc;
182  master_grid.worldToMapNoBounds(polygon[i].x, polygon[i].y, loc.x, loc.y);
183  map_polygon.push_back(loc);
184  }
185 
186  std::vector<PointInt> polygon_cells;
187 
188  // get the cells that fill the polygon
189  rasterizePolygon(map_polygon, polygon_cells, fill_polygon);
190 
191  // set the cost of those cells
192  for (unsigned int i = 0; i < polygon_cells.size(); ++i)
193  {
194  int mx = polygon_cells[i].x;
195  int my = polygon_cells[i].y;
196  // check if point is outside bounds
197  if (mx < min_i || mx >= max_i)
198  continue;
199  if (my < min_j || my >= max_j)
200  continue;
201  master_grid.setCost(mx, my, cost);
202  }
203 }
204 
205 
206 void CostmapProhibitionLayer::polygonOutlineCells(const std::vector<PointInt>& polygon, std::vector<PointInt>& polygon_cells)
207  {
208  for (unsigned int i = 0; i < polygon.size() - 1; ++i)
209  {
210  raytrace(polygon[i].x, polygon[i].y, polygon[i + 1].x, polygon[i + 1].y, polygon_cells);
211  }
212  if (!polygon.empty())
213  {
214  unsigned int last_index = polygon.size() - 1;
215  // we also need to close the polygon by going from the last point to the first
216  raytrace(polygon[last_index].x, polygon[last_index].y, polygon[0].x, polygon[0].y, polygon_cells);
217  }
218  }
219 
220 void CostmapProhibitionLayer::raytrace(int x0, int y0, int x1, int y1, std::vector<PointInt>& cells)
221 {
222  int dx = abs(x1 - x0);
223  int dy = abs(y1 - y0);
224  PointInt pt;
225  pt.x = x0;
226  pt.y = y0;
227  int n = 1 + dx + dy;
228  int x_inc = (x1 > x0) ? 1 : -1;
229  int y_inc = (y1 > y0) ? 1 : -1;
230  int error = dx - dy;
231  dx *= 2;
232  dy *= 2;
233 
234  for (; n > 0; --n)
235  {
236  cells.push_back(pt);
237 
238  if (error > 0)
239  {
240  pt.x += x_inc;
241  error -= dy;
242  }
243  else
244  {
245  pt.y += y_inc;
246  error += dx;
247  }
248  }
249 }
250 
251 
252 void CostmapProhibitionLayer::rasterizePolygon(const std::vector<PointInt>& polygon, std::vector<PointInt>& polygon_cells, bool fill)
253 {
254  // this implementation is a slighly modified version of Costmap2D::convexFillCells(...)
255 
256  //we need a minimum polygon of a traingle
257  if(polygon.size() < 3)
258  return;
259 
260  //first get the cells that make up the outline of the polygon
261  polygonOutlineCells(polygon, polygon_cells);
262 
263  if (!fill)
264  return;
265 
266  //quick bubble sort to sort points by x
267  PointInt swap;
268  unsigned int i = 0;
269  while(i < polygon_cells.size() - 1)
270  {
271  if(polygon_cells[i].x > polygon_cells[i + 1].x)
272  {
273  swap = polygon_cells[i];
274  polygon_cells[i] = polygon_cells[i + 1];
275  polygon_cells[i + 1] = swap;
276 
277  if(i > 0)
278  --i;
279  }
280  else
281  ++i;
282  }
283 
284  i = 0;
285  PointInt min_pt;
286  PointInt max_pt;
287  int min_x = polygon_cells[0].x;
288  int max_x = polygon_cells[(int)polygon_cells.size() -1].x;
289 
290  //walk through each column and mark cells inside the polygon
291  for(int x = min_x; x <= max_x; ++x)
292  {
293  if(i >= (int)polygon_cells.size() - 1)
294  break;
295 
296  if(polygon_cells[i].y < polygon_cells[i + 1].y)
297  {
298  min_pt = polygon_cells[i];
299  max_pt = polygon_cells[i + 1];
300  }
301  else
302  {
303  min_pt = polygon_cells[i + 1];
304  max_pt = polygon_cells[i];
305  }
306 
307  i += 2;
308  while(i < polygon_cells.size() && polygon_cells[i].x == x)
309  {
310  if(polygon_cells[i].y < min_pt.y)
311  min_pt = polygon_cells[i];
312  else if(polygon_cells[i].y > max_pt.y)
313  max_pt = polygon_cells[i];
314  ++i;
315  }
316 
317  PointInt pt;
318  //loop though cells in the column
319  for(int y = min_pt.y; y < max_pt.y; ++y)
320  {
321  pt.x = x;
322  pt.y = y;
323  polygon_cells.push_back(pt);
324  }
325  }
326  }
327 
328 // load prohibition positions out of the rosparam server
330 {
331  std::lock_guard<std::mutex> l(_data_mutex);
332  std::unordered_map<std::string, geometry_msgs::Pose> map_out;
333 
334  XmlRpc::XmlRpcValue param_yaml;
335 
336  bool ret_val = true;
337 
338  if (nhandle->getParam(param, param_yaml))
339  {
340  if (param_yaml.getType() == XmlRpc::XmlRpcValue::TypeArray) // list of goals
341  {
342  for (int i = 0; i < param_yaml.size(); ++i)
343  {
344  if (param_yaml[i].getType() == XmlRpc::XmlRpcValue::TypeArray)
345  {
346  std::vector<geometry_msgs::Point> vector_to_add;
347 
348  /* **************************************
349  * differ between points and polygons
350  * lines get to a polygon with the resolution
351  * of the costmap
352  **************************************** */
353 
354  // add a point
355  if (param_yaml[i].size() == 1)
356  {
357  geometry_msgs::Point point;
358  ret_val = getPoint(param_yaml[i][0], point);
359  _prohibition_points.push_back(point);
360  }
361  // add a line
362  else if (param_yaml[i].size() == 2)
363  {
364  if (param_yaml[i][0].getType() == XmlRpc::XmlRpcValue::TypeDouble ||
365  param_yaml[i][0].getType() == XmlRpc::XmlRpcValue::TypeInt)
366  {
367  // add a lonely point
368  geometry_msgs::Point point;
369  ret_val = getPoint(param_yaml[i], point);
370  _prohibition_points.push_back(point);
371  }
372  else
373  {
374  // add a line!
375  geometry_msgs::Point point_A;
376  ret_val = getPoint(param_yaml[i][0], point_A);
377  vector_to_add.push_back(point_A);
378 
379  geometry_msgs::Point point_B;
380  ret_val = getPoint(param_yaml[i][1], point_B);
381  vector_to_add.push_back(point_B);
382 
383  // calculate the normal vector for AB
384  geometry_msgs::Point point_N;
385  point_N.x = point_B.y - point_A.y;
386  point_N.y = point_A.x - point_B.x;
387 
388  // get the absolute value of N to normalize and get
389  // it to the length of the costmap resolution
390  double abs_N = sqrt(pow(point_N.x, 2) + pow(point_N.y, 2));
391  point_N.x = point_N.x / abs_N * _costmap_resolution;
392  point_N.y = point_N.y / abs_N * _costmap_resolution;
393 
394  // calculate the new points to get a polygon which can be filled
395  geometry_msgs::Point point;
396  point.x = point_A.x + point_N.x;
397  point.y = point_A.y + point_N.y;
398  vector_to_add.push_back(point);
399 
400  point.x = point_B.x + point_N.x;
401  point.y = point_B.y + point_N.y;
402  vector_to_add.push_back(point);
403 
404  _prohibition_polygons.push_back(vector_to_add);
405  }
406  }
407  // add a point or add a polygon
408  else if (param_yaml[i].size() >= 3)
409  {
410  // add a polygon with any number of points
411  for (int j = 0; j < param_yaml[i].size(); ++j)
412  {
413  geometry_msgs::Point point;
414  ret_val = getPoint(param_yaml[i][j], point);
415  vector_to_add.push_back(point);
416  }
417  _prohibition_polygons.push_back(vector_to_add);
418  }
419  }
420  else
421  {
422  ROS_ERROR_STREAM("Prohibition Layer:" << param << " with index " << i << " is not correct.");
423  ret_val = false;
424  }
425  }
426  }
427  else
428  {
429  ROS_ERROR_STREAM("Prohibition Layer: " << param << "struct is not correct.");
430  ret_val = false;
431  }
432  }
433  else
434  {
435  ROS_ERROR_STREAM("Prohibition Layer: Cannot read " << param << " from parameter server");
436  ret_val = false;
437  }
438  return ret_val;
439 }
440 
441 // get a point out of the XML Type into a geometry_msgs::Point
442 bool CostmapProhibitionLayer::getPoint(XmlRpc::XmlRpcValue &val, geometry_msgs::Point &point)
443 {
444  try
445  {
446  // check if there a two values for the coordinate
447  if (val.getType() == XmlRpc::XmlRpcValue::TypeArray && val.size() == 2)
448  {
449  auto convDouble = [](XmlRpc::XmlRpcValue &val) -> double
450  {
451  if (val.getType() == XmlRpc::XmlRpcValue::TypeInt) // XmlRpc cannot cast int to double
452  return int(val);
453  return val; // if not double, an exception is thrown;
454  };
455 
456  point.x = convDouble(val[0]);
457  point.y = convDouble(val[1]);
458  point.z = 0.0;
459  return true;
460  }
461  else
462  {
463  ROS_ERROR_STREAM("Prohibition_Layer: A point has to consist two values!");
464  return false;
465  }
466  }
467  catch (const XmlRpc::XmlRpcException &ex)
468  {
469  ROS_ERROR_STREAM("Prohibition Layer: Cannot add current point: " << ex.getMessage());
470  return false;
471  }
472 }
473 
474 } // end namespace
void setCost(unsigned int mx, unsigned int my, unsigned char cost)
const std::string & getMessage() const
bool parseProhibitionListFromYaml(ros::NodeHandle *nhandle, const std::string &param)
LayeredCostmap * layered_costmap_
virtual void updateBounds(double robot_x, double robot_y, double robot_yaw, double *min_x, double *min_y, double *max_x, double *max_y)
virtual void updateCosts(costmap_2d::Costmap2D &master_grid, int min_i, int min_j, int max_i, int max_j)
int size() const
PLUGINLIB_EXPORT_CLASS(BAGReader, nodelet::Nodelet)
std::vector< geometry_msgs::Point > _prohibition_points
vector to save the lonely points in source coordinates
Type const & getType() const
TFSIMD_FORCE_INLINE const tfScalar & y() const
std::string name_
void reconfigureCB(CostmapProhibitionLayerConfig &config, uint32_t level)
void rasterizePolygon(const std::vector< PointInt > &polygon, std::vector< PointInt > &polygon_cells, bool fill)
bool getPoint(XmlRpc::XmlRpcValue &val, geometry_msgs::Point &point)
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
bool _fill_polygons
if true, all cells that are located in the interior of polygons are marked as obstacle as well ...
std::mutex _data_mutex
mutex for the accessing _prohibition_points and _prohibition_polygons
const std::string & getNamespace() const
void raytrace(int x0, int y0, int x1, int y1, std::vector< PointInt > &cells)
TFSIMD_FORCE_INLINE const tfScalar & x() const
void worldToMapNoBounds(double wx, double wy, int &mx, int &my) const
bool getParam(const std::string &key, std::string &s) const
dynamic_reconfigure::Server< CostmapProhibitionLayerConfig > * _dsrv
dynamic_reconfigure server for the costmap
double getResolution() const
#define ROS_ERROR_STREAM(args)
double _costmap_resolution
resolution of the overlayed costmap to create the thinnest line out of two points ...
void polygonOutlineCells(const std::vector< PointInt > &polygon, std::vector< PointInt > &polygon_cells)
std::vector< std::vector< geometry_msgs::Point > > _prohibition_polygons
vector to save the polygons (including lines) in source coordinates
bool worldToMap(double wx, double wy, unsigned int &mx, unsigned int &my) const
void setPolygonCost(costmap_2d::Costmap2D &master_grid, const std::vector< geometry_msgs::Point > &polygon, unsigned char cost, int min_i, int min_j, int max_i, int max_j, bool fill_polygon)


costmap_prohibition_layer
Author(s): Stephan Kurzawe
autogenerated on Mon Jun 10 2019 13:05:00