Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
layered_costmap.cpp
1 /*********************************************************************
2  *
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2008, 2013, Willow Garage, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * * Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * * Redistributions in binary form must reproduce the above
15  * copyright notice, this list of conditions and the following
16  * disclaimer in the documentation and/or other materials provided
17  * with the distribution.
18  * * Neither the name of Willow Garage, Inc. nor the names of its
19  * contributors may be used to endorse or promote products derived
20  * from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33  * POSSIBILITY OF SUCH DAMAGE.
34  *
35  * Author: Eitan Marder-Eppstein
36  * David V. Lu!!
37  *********************************************************************/
38 #include "nav2_costmap_2d/layered_costmap.hpp"
39 
40 #include <algorithm>
41 #include <cstdio>
42 #include <memory>
43 #include <string>
44 #include <vector>
45 #include <limits>
46 
47 #include <rclcpp/clock.hpp>
48 
49 #include "nav2_costmap_2d/footprint.hpp"
50 
51 
52 using std::vector;
53 
54 namespace nav2_costmap_2d
55 {
56 
57 LayeredCostmap::LayeredCostmap(std::string global_frame, bool rolling_window, bool track_unknown)
58 : primary_costmap_(), combined_costmap_(),
59  global_frame_(global_frame),
60  rolling_window_(rolling_window),
61  minx_(0.0),
62  miny_(0.0),
63  maxx_(0.0),
64  maxy_(0.0),
65  bx0_(0),
66  bxn_(0),
67  by0_(0),
68  byn_(0),
69  initialized_(false),
70  size_locked_(false),
71  circumscribed_radius_(1.0),
72  inscribed_radius_(0.1),
73  footprint_(std::make_shared<std::vector<geometry_msgs::msg::Point>>())
74 {
75  if (track_unknown) {
76  primary_costmap_.setDefaultValue(NO_INFORMATION);
77  combined_costmap_.setDefaultValue(NO_INFORMATION);
78  } else {
79  primary_costmap_.setDefaultValue(FREE_SPACE);
80  combined_costmap_.setDefaultValue(FREE_SPACE);
81  }
82 }
83 
85 {
86  while (plugins_.size() > 0) {
87  plugins_.pop_back();
88  }
89  while (filters_.size() > 0) {
90  filters_.pop_back();
91  }
92 }
93 
94 void LayeredCostmap::addPlugin(std::shared_ptr<Layer> plugin)
95 {
96  std::unique_lock<Costmap2D::mutex_t> lock(*(combined_costmap_.getMutex()));
97  plugins_.push_back(plugin);
98 }
99 
100 void LayeredCostmap::addFilter(std::shared_ptr<Layer> filter)
101 {
102  std::unique_lock<Costmap2D::mutex_t> lock(*(combined_costmap_.getMutex()));
103  filters_.push_back(filter);
104 }
105 
107  unsigned int size_x, unsigned int size_y, double resolution,
108  double origin_x,
109  double origin_y,
110  bool size_locked)
111 {
112  std::unique_lock<Costmap2D::mutex_t> lock(*(combined_costmap_.getMutex()));
113  size_locked_ = size_locked;
114  primary_costmap_.resizeMap(size_x, size_y, resolution, origin_x, origin_y);
115  combined_costmap_.resizeMap(size_x, size_y, resolution, origin_x, origin_y);
116  for (vector<std::shared_ptr<Layer>>::iterator plugin = plugins_.begin();
117  plugin != plugins_.end(); ++plugin)
118  {
119  if (*plugin) {
120  (*plugin)->matchSize();
121  }
122  }
123  for (vector<std::shared_ptr<Layer>>::iterator filter = filters_.begin();
124  filter != filters_.end(); ++filter)
125  {
126  (*filter)->matchSize();
127  }
128 }
129 
130 bool LayeredCostmap::isOutofBounds(double robot_x, double robot_y)
131 {
132  unsigned int mx, my;
133  return !combined_costmap_.worldToMap(robot_x, robot_y, mx, my);
134 }
135 
136 void LayeredCostmap::updateMap(double robot_x, double robot_y, double robot_yaw)
137 {
138  // Lock for the remainder of this function, some plugins (e.g. VoxelLayer)
139  // implement thread unsafe updateBounds() functions.
140  std::unique_lock<Costmap2D::mutex_t> lock(*(combined_costmap_.getMutex()));
141 
142  // if we're using a rolling buffer costmap...
143  // we need to update the origin using the robot's position
144  if (rolling_window_) {
145  double new_origin_x = robot_x - combined_costmap_.getSizeInMetersX() / 2;
146  double new_origin_y = robot_y - combined_costmap_.getSizeInMetersY() / 2;
147  primary_costmap_.updateOrigin(new_origin_x, new_origin_y);
148  combined_costmap_.updateOrigin(new_origin_x, new_origin_y);
149  }
150 
151  if (isOutofBounds(robot_x, robot_y)) {
152  rclcpp::Clock clock{RCL_ROS_TIME};
153  RCLCPP_WARN_THROTTLE(
154  rclcpp::get_logger("nav2_costmap_2d"),
155  clock, 5000,
156  "Robot is out of bounds of the costmap");
157  }
158 
159  if (plugins_.size() == 0 && filters_.size() == 0) {
160  return;
161  }
162 
163  minx_ = miny_ = std::numeric_limits<double>::max();
164  maxx_ = maxy_ = std::numeric_limits<double>::lowest();
165 
166  for (vector<std::shared_ptr<Layer>>::iterator plugin = plugins_.begin();
167  plugin != plugins_.end(); ++plugin)
168  {
169  double prev_minx = minx_;
170  double prev_miny = miny_;
171  double prev_maxx = maxx_;
172  double prev_maxy = maxy_;
173  (*plugin)->updateBounds(robot_x, robot_y, robot_yaw, &minx_, &miny_, &maxx_, &maxy_);
174  if (minx_ > prev_minx || miny_ > prev_miny || maxx_ < prev_maxx || maxy_ < prev_maxy) {
175  RCLCPP_WARN(
176  rclcpp::get_logger(
177  "nav2_costmap_2d"), "Illegal bounds change, was [tl: (%f, %f), br: (%f, %f)], but "
178  "is now [tl: (%f, %f), br: (%f, %f)]. The offending layer is %s",
179  prev_minx, prev_miny, prev_maxx, prev_maxy,
180  minx_, miny_, maxx_, maxy_,
181  (*plugin)->getName().c_str());
182  }
183  }
184  for (vector<std::shared_ptr<Layer>>::iterator filter = filters_.begin();
185  filter != filters_.end(); ++filter)
186  {
187  double prev_minx = minx_;
188  double prev_miny = miny_;
189  double prev_maxx = maxx_;
190  double prev_maxy = maxy_;
191  (*filter)->updateBounds(robot_x, robot_y, robot_yaw, &minx_, &miny_, &maxx_, &maxy_);
192  if (minx_ > prev_minx || miny_ > prev_miny || maxx_ < prev_maxx || maxy_ < prev_maxy) {
193  RCLCPP_WARN(
194  rclcpp::get_logger(
195  "nav2_costmap_2d"), "Illegal bounds change, was [tl: (%f, %f), br: (%f, %f)], but "
196  "is now [tl: (%f, %f), br: (%f, %f)]. The offending filter is %s",
197  prev_minx, prev_miny, prev_maxx, prev_maxy,
198  minx_, miny_, maxx_, maxy_,
199  (*filter)->getName().c_str());
200  }
201  }
202 
203  int x0, xn, y0, yn;
204  combined_costmap_.worldToMapEnforceBounds(minx_, miny_, x0, y0);
205  combined_costmap_.worldToMapEnforceBounds(maxx_, maxy_, xn, yn);
206 
207  x0 = std::max(0, x0);
208  xn = std::min(static_cast<int>(combined_costmap_.getSizeInCellsX()), xn + 1);
209  y0 = std::max(0, y0);
210  yn = std::min(static_cast<int>(combined_costmap_.getSizeInCellsY()), yn + 1);
211 
212  RCLCPP_DEBUG(
213  rclcpp::get_logger(
214  "nav2_costmap_2d"), "Updating area x: [%d, %d] y: [%d, %d]", x0, xn, y0, yn);
215 
216  if (xn >= x0 && yn >= y0) {
217  if (filters_.size() == 0) {
218  // If there are no filters enabled just update costmap sequentially by each plugin
219  combined_costmap_.resetMap(x0, y0, xn, yn);
220  for (vector<std::shared_ptr<Layer>>::iterator plugin = plugins_.begin();
221  plugin != plugins_.end(); ++plugin)
222  {
223  (*plugin)->updateCosts(combined_costmap_, x0, y0, xn, yn);
224  }
225  } else {
226  // Costmap Filters enabled
227  // 1. Update costmap by plugins
228  primary_costmap_.resetMap(x0, y0, xn, yn);
229  for (vector<std::shared_ptr<Layer>>::iterator plugin = plugins_.begin();
230  plugin != plugins_.end(); ++plugin)
231  {
232  (*plugin)->updateCosts(primary_costmap_, x0, y0, xn, yn);
233  }
234 
235  // 2. Copy processed costmap window to a final costmap.
236  // primary_costmap_ remain to be untouched for further usage by plugins.
237  if (!combined_costmap_.copyWindow(primary_costmap_, x0, y0, xn, yn, x0, y0)) {
238  RCLCPP_ERROR(
239  rclcpp::get_logger("nav2_costmap_2d"),
240  "Can not copy costmap (%i,%i)..(%i,%i) window",
241  x0, y0, xn, yn);
242  throw std::runtime_error{"Can not copy costmap"};
243  }
244 
245  // 3. Apply filters over the plugins in order to make filters' work
246  // not being considered by plugins on next updateMap() calls
247  for (vector<std::shared_ptr<Layer>>::iterator filter = filters_.begin();
248  filter != filters_.end(); ++filter)
249  {
250  (*filter)->updateCosts(combined_costmap_, x0, y0, xn, yn);
251  }
252  }
253 
254  bx0_ = x0;
255  bxn_ = xn;
256  by0_ = y0;
257  byn_ = yn;
258 
259  initialized_ = true;
260  }
261 
262  // Set current_ = true for all disabled plugins
263  for (vector<std::shared_ptr<Layer>>::iterator plugin = plugins_.begin();
264  plugin != plugins_.end(); ++plugin)
265  {
266  if (*plugin && !(*plugin)->isEnabled()) {
267  (*plugin)->setCurrent(true);
268  }
269  }
270  for (vector<std::shared_ptr<Layer>>::iterator filter = filters_.begin();
271  filter != filters_.end(); ++filter)
272  {
273  if (!(*filter)->isEnabled()) {
274  (*filter)->setCurrent(true);
275  }
276  }
277 }
278 
280 {
281  for (vector<std::shared_ptr<Layer>>::iterator plugin = plugins_.begin();
282  plugin != plugins_.end(); ++plugin)
283  {
284  if (!(*plugin)->isCurrent()) {
285  return false;
286  }
287  }
288  for (vector<std::shared_ptr<Layer>>::iterator filter = filters_.begin();
289  filter != filters_.end(); ++filter)
290  {
291  if (!(*filter)->isCurrent()) {
292  return false;
293  }
294  }
295  return true;
296 }
297 
298 void LayeredCostmap::setFootprint(const std::vector<geometry_msgs::msg::Point> & footprint_spec)
299 {
300  std::pair<double, double> inside_outside = nav2_costmap_2d::calculateMinAndMaxDistances(
301  footprint_spec);
302  // use atomic store here since footprint is used by various planners/controllers
303  // and not otherwise locked
304  footprint_.store(
305  std::make_shared<std::vector<geometry_msgs::msg::Point>>(footprint_spec));
306  inscribed_radius_.store(std::get<0>(inside_outside));
307  circumscribed_radius_.store(std::get<1>(inside_outside));
308 
309  for (vector<std::shared_ptr<Layer>>::iterator plugin = plugins_.begin();
310  plugin != plugins_.end();
311  ++plugin)
312  {
313  (*plugin)->onFootprintChanged();
314  }
315  for (vector<std::shared_ptr<Layer>>::iterator filter = filters_.begin();
316  filter != filters_.end();
317  ++filter)
318  {
319  (*filter)->onFootprintChanged();
320  }
321 }
322 
323 } // namespace nav2_costmap_2d
void resetMap(unsigned int x0, unsigned int y0, unsigned int xn, unsigned int yn)
Reset the costmap in bounds.
Definition: costmap_2d.cpp:131
void resizeMap(unsigned int size_x, unsigned int size_y, double resolution, double origin_x, double origin_y)
Resize the costmap.
Definition: costmap_2d.cpp:111
bool copyWindow(const Costmap2D &source, unsigned int sx0, unsigned int sy0, unsigned int sxn, unsigned int syn, unsigned int dx0, unsigned int dy0)
Copies the (x0,y0)..(xn,yn) window from source costmap into a current costmap.
Definition: costmap_2d.cpp:185
void worldToMapEnforceBounds(double wx, double wy, int &mx, int &my) const
Convert from world coordinates to map coordinates, constraining results to legal bounds.
Definition: costmap_2d.cpp:328
bool worldToMap(double wx, double wy, unsigned int &mx, unsigned int &my) const
Convert from world coordinates to map coordinates.
Definition: costmap_2d.cpp:292
void setDefaultValue(unsigned char c)
Set the default background value of the costmap.
Definition: costmap_2d.hpp:300
virtual void updateOrigin(double new_origin_x, double new_origin_y)
Move the origin of the costmap to a new location.... keeping data when it can.
Definition: costmap_2d.cpp:350
double getSizeInMetersY() const
Accessor for the y size of the costmap in meters.
Definition: costmap_2d.cpp:563
double getSizeInMetersX() const
Accessor for the x size of the costmap in meters.
Definition: costmap_2d.cpp:558
unsigned int getSizeInCellsX() const
Accessor for the x size of the costmap in cells.
Definition: costmap_2d.cpp:548
unsigned int getSizeInCellsY() const
Accessor for the y size of the costmap in cells.
Definition: costmap_2d.cpp:553
void addPlugin(std::shared_ptr< Layer > plugin)
Add a new plugin to the plugins vector to process.
void addFilter(std::shared_ptr< Layer > filter)
Add a new costmap filter plugin to the filters vector to process.
void resizeMap(unsigned int size_x, unsigned int size_y, double resolution, double origin_x, double origin_y, bool size_locked=false)
Resize the map to a new size, resolution, or origin.
bool isOutofBounds(double robot_x, double robot_y)
Checks if the robot is outside the bounds of its costmap in the case of poorly configured setups.
void updateMap(double robot_x, double robot_y, double robot_yaw)
Update the underlying costmap with new data. If you want to update the map outside of the update loop...
LayeredCostmap(std::string global_frame, bool rolling_window, bool track_unknown)
Constructor for a costmap.
void setFootprint(const std::vector< geometry_msgs::msg::Point > &footprint_spec)
Updates the stored footprint, updates the circumscribed and inscribed radii, and calls onFootprintCha...
bool isCurrent()
If the costmap is current, e.g. are all the layers processing recent data and not stale information f...
std::pair< double, double > calculateMinAndMaxDistances(const std::vector< geometry_msgs::msg::Point > &footprint)
Calculate the extreme distances for the footprint.
Definition: footprint.cpp:43