Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
costmap_2d_publisher.cpp
1 /*********************************************************************
2  *
3  * Software License Agreement (BSD License)
4  *
5  * Copyright (c) 2008, 2013, Willow Garage, Inc.
6  * Copyright (c) 2019, Samsung Research America, Inc.
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 Willow Garage, Inc. 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: Eitan Marder-Eppstein
37  * David V. Lu!!
38  *********************************************************************/
39 #include "nav2_costmap_2d/costmap_2d_publisher.hpp"
40 #include "nav2_costmap_2d/costmap_layer.hpp"
41 
42 #include <string>
43 #include <memory>
44 #include <utility>
45 
46 #include "nav2_costmap_2d/cost_values.hpp"
47 
48 namespace nav2_costmap_2d
49 {
50 
51 char * Costmap2DPublisher::cost_translation_table_ = NULL;
52 
54  const nav2::LifecycleNode::WeakPtr & parent,
55  Costmap2D * costmap,
56  std::string global_frame,
57  std::string topic_name,
58  bool always_send_full_costmap,
59  double map_vis_z)
60 : costmap_(costmap),
61  global_frame_(global_frame),
62  topic_name_(topic_name),
63  always_send_full_costmap_(always_send_full_costmap),
64  map_vis_z_(map_vis_z)
65 {
66  auto node = parent.lock();
67  clock_ = node->get_clock();
68  logger_ = node->get_logger();
69 
70  auto matched_callback = [this](rclcpp::MatchedInfo & status) {
71  if (status.total_count_change > 0) {
72  republish_costmap_ = true;
73  }
74  };
75  costmap_pub_ = node->create_publisher<nav_msgs::msg::OccupancyGrid>(
76  topic_name,
77  nav2::qos::LatchedPublisherQoS(), nullptr, matched_callback);
78  costmap_raw_pub_ = node->create_publisher<nav2_msgs::msg::Costmap>(
79  topic_name + "_raw",
80  nav2::qos::LatchedPublisherQoS(), nullptr, matched_callback);
81  costmap_update_pub_ = node->create_publisher<map_msgs::msg::OccupancyGridUpdate>(
82  topic_name + "_updates", nav2::qos::LatchedPublisherQoS());
83  costmap_raw_update_pub_ = node->create_publisher<nav2_msgs::msg::CostmapUpdate>(
84  topic_name + "_raw_updates", nav2::qos::LatchedPublisherQoS());
85 
86  // Create a service that will use the callback function to handle requests.
87  costmap_service_ = node->create_service<nav2_msgs::srv::GetCostmap>(
88  std::string("get_") + topic_name,
89  std::bind(
90  &Costmap2DPublisher::costmap_service_callback, this,
91  std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
92 
93  if (cost_translation_table_ == NULL) {
94  cost_translation_table_ = new char[256];
95 
96  // special values:
97  cost_translation_table_[0] = 0; // NO obstacle
98  cost_translation_table_[253] = 99; // INSCRIBED obstacle
99  cost_translation_table_[254] = 100; // LETHAL obstacle
100  cost_translation_table_[255] = -1; // UNKNOWN
101 
102  // regular cost values scale the range 1 to 252 (inclusive) to fit
103  // into 1 to 98 (inclusive).
104  for (int i = 1; i < 253; i++) {
105  cost_translation_table_[i] = static_cast<char>(1 + (97 * (i - 1)) / 251);
106  }
107  }
108 
109  xn_ = yn_ = 0;
110  x0_ = costmap_->getSizeInCellsX();
111  y0_ = costmap_->getSizeInCellsY();
112 }
113 
115 
116 void Costmap2DPublisher::updateGridParams()
117 {
118  saved_origin_x_ = costmap_->getOriginX();
119  saved_origin_y_ = costmap_->getOriginY();
120  grid_resolution_ = costmap_->getResolution();
121  grid_width_ = costmap_->getSizeInCellsX();
122  grid_height_ = costmap_->getSizeInCellsY();
123 }
124 
125 // prepare grid_ message for publication.
126 void Costmap2DPublisher::prepareGrid()
127 {
128  std::unique_lock<Costmap2D::mutex_t> lock(*(costmap_->getMutex()));
129 
130  grid_ = std::make_unique<nav_msgs::msg::OccupancyGrid>();
131 
132  grid_->header.frame_id = global_frame_;
133  grid_->header.stamp = clock_->now();
134 
135  grid_->info.resolution = grid_resolution_;
136 
137  grid_->info.width = grid_width_;
138  grid_->info.height = grid_height_;
139 
140  double wx, wy;
141  costmap_->mapToWorld(0, 0, wx, wy);
142  grid_->info.origin.position.x = wx - grid_resolution_ / 2;
143  grid_->info.origin.position.y = wy - grid_resolution_ / 2;
144  grid_->info.origin.position.z = map_vis_z_;
145  grid_->info.origin.orientation.w = 1.0;
146 
147  grid_->data.resize(grid_->info.width * grid_->info.height);
148 
149  unsigned char * data = costmap_->getCharMap();
150  std::transform(
151  data, data + grid_->data.size(), grid_->data.begin(),
152  [](unsigned char c) {return cost_translation_table_[c];});
153 }
154 
155 void Costmap2DPublisher::prepareCostmap()
156 {
157  std::unique_lock<Costmap2D::mutex_t> lock(*(costmap_->getMutex()));
158  double resolution = costmap_->getResolution();
159 
160  costmap_raw_ = std::make_unique<nav2_msgs::msg::Costmap>();
161 
162  costmap_raw_->header.frame_id = global_frame_;
163  costmap_raw_->header.stamp = clock_->now();
164 
165  costmap_raw_->metadata.layer = "master";
166  costmap_raw_->metadata.resolution = resolution;
167 
168  costmap_raw_->metadata.size_x = costmap_->getSizeInCellsX();
169  costmap_raw_->metadata.size_y = costmap_->getSizeInCellsY();
170 
171  double wx, wy;
172  costmap_->mapToWorld(0, 0, wx, wy);
173  costmap_raw_->metadata.origin.position.x = wx - resolution / 2;
174  costmap_raw_->metadata.origin.position.y = wy - resolution / 2;
175  costmap_raw_->metadata.origin.position.z = 0.0;
176  costmap_raw_->metadata.origin.orientation.w = 1.0;
177 
178  costmap_raw_->data.resize(costmap_raw_->metadata.size_x * costmap_raw_->metadata.size_y);
179 
180  unsigned char * data = costmap_->getCharMap();
181  memcpy(costmap_raw_->data.data(), data, costmap_raw_->data.size());
182 }
183 
184 std::unique_ptr<map_msgs::msg::OccupancyGridUpdate> Costmap2DPublisher::createGridUpdateMsg()
185 {
186  auto update = std::make_unique<map_msgs::msg::OccupancyGridUpdate>();
187 
188  update->header.stamp = clock_->now();
189  update->header.frame_id = global_frame_;
190  update->x = x0_;
191  update->y = y0_;
192  update->width = xn_ - x0_;
193  update->height = yn_ - y0_;
194  update->data.resize(update->width * update->height);
195  const std::uint32_t map_width = costmap_->getSizeInCellsX();
196  unsigned char * costmap_data = costmap_->getCharMap();
197  std::uint32_t i = 0;
198  for (std::uint32_t y = y0_; y < yn_; y++) {
199  std::uint32_t row_start = y * map_width + x0_;
200  std::transform(
201  costmap_data + row_start, costmap_data + row_start + update->width,
202  update->data.begin() + i,
203  [](unsigned char c) {return cost_translation_table_[c];});
204  i += update->width;
205  }
206  return update;
207 }
208 
209 std::unique_ptr<nav2_msgs::msg::CostmapUpdate> Costmap2DPublisher::createCostmapUpdateMsg()
210 {
211  auto msg = std::make_unique<nav2_msgs::msg::CostmapUpdate>();
212 
213  msg->header.stamp = clock_->now();
214  msg->header.frame_id = global_frame_;
215  msg->x = x0_;
216  msg->y = y0_;
217  msg->size_x = xn_ - x0_;
218  msg->size_y = yn_ - y0_;
219  msg->data.resize(msg->size_x * msg->size_y);
220  const std::uint32_t map_width = costmap_->getSizeInCellsX();
221  unsigned char * costmap_data = costmap_->getCharMap();
222 
223  std::uint32_t i = 0;
224  for (std::uint32_t y = y0_; y < yn_; y++) {
225  std::uint32_t row_start = y * map_width + x0_;
226  std::copy_n(costmap_data + row_start, msg->size_x, msg->data.begin() + i);
227  i += msg->size_x;
228  }
229  return msg;
230 }
231 
233 {
234  auto const costmap_layer = dynamic_cast<CostmapLayer *>(costmap_);
235  if (costmap_layer != nullptr && !costmap_layer->isEnabled()) {
236  return;
237  }
238 
239  const bool republish = republish_costmap_.exchange(false);
240  float resolution = costmap_->getResolution();
241  if (always_send_full_costmap_ || grid_resolution_ != resolution ||
242  grid_width_ != costmap_->getSizeInCellsX() ||
243  grid_height_ != costmap_->getSizeInCellsY() ||
244  saved_origin_x_ != costmap_->getOriginX() ||
245  saved_origin_y_ != costmap_->getOriginY() ||
246  !costmap_published_once_ || republish)
247  {
248  updateGridParams();
249  if (costmap_pub_->get_subscription_count() > 0 || !costmap_published_once_) {
250  prepareGrid();
251  costmap_pub_->publish(std::move(grid_));
252  }
253  if (costmap_raw_pub_->get_subscription_count() > 0 || !costmap_published_once_) {
254  prepareCostmap();
255  costmap_raw_pub_->publish(std::move(costmap_raw_));
256  }
257  costmap_published_once_ = true;
258  } else if (x0_ < xn_) {
259  // Publish just update msgs
260  std::unique_lock<Costmap2D::mutex_t> lock(*(costmap_->getMutex()));
261  if (costmap_update_pub_->get_subscription_count() > 0) {
262  costmap_update_pub_->publish(createGridUpdateMsg());
263  }
264  if (costmap_raw_update_pub_->get_subscription_count() > 0) {
265  costmap_raw_update_pub_->publish(createCostmapUpdateMsg());
266  }
267  }
268 
269  xn_ = yn_ = 0;
270  x0_ = costmap_->getSizeInCellsX();
271  y0_ = costmap_->getSizeInCellsY();
272 }
273 
274 void
275 Costmap2DPublisher::costmap_service_callback(
276  const std::shared_ptr<rmw_request_id_t>/*request_header*/,
277  const std::shared_ptr<nav2_msgs::srv::GetCostmap::Request>/*request*/,
278  const std::shared_ptr<nav2_msgs::srv::GetCostmap::Response> response)
279 {
280  RCLCPP_DEBUG(logger_, "Received costmap service request");
281 
282  // TODO(bpwilcox): Grab correct orientation information
283  tf2::Quaternion quaternion;
284  quaternion.setRPY(0.0, 0.0, 0.0);
285 
286  std::unique_lock<Costmap2D::mutex_t> lock(*(costmap_->getMutex()));
287 
288  auto size_x = costmap_->getSizeInCellsX();
289  auto size_y = costmap_->getSizeInCellsY();
290  auto data_length = size_x * size_y;
291  unsigned char * data = costmap_->getCharMap();
292  auto current_time = clock_->now();
293 
294  response->map.header.stamp = current_time;
295  response->map.header.frame_id = global_frame_;
296  response->map.metadata.size_x = size_x;
297  response->map.metadata.size_y = size_y;
298  response->map.metadata.resolution = costmap_->getResolution();
299  response->map.metadata.layer = "master";
300  response->map.metadata.map_load_time = current_time;
301  response->map.metadata.update_time = current_time;
302  response->map.metadata.origin.position.x = costmap_->getOriginX();
303  response->map.metadata.origin.position.y = costmap_->getOriginY();
304  response->map.metadata.origin.position.z = 0.0;
305  response->map.metadata.origin.orientation = tf2::toMsg(quaternion);
306  response->map.data.resize(data_length);
307  response->map.data.assign(data, data + data_length);
308 }
309 
310 } // end namespace nav2_costmap_2d
A QoS profile for latched, reliable topics with a history of 1 messages.
Costmap2DPublisher(const nav2::LifecycleNode::WeakPtr &parent, Costmap2D *costmap, std::string global_frame, std::string topic_name, bool always_send_full_costmap=false, double map_vis_z=0.0)
Constructor for the Costmap2DPublisher.
void publishCostmap()
Publishes the visualization data over ROS.
A 2D costmap provides a mapping between points in the world and their associated "costs".
Definition: costmap_2d.hpp:69
void mapToWorld(unsigned int mx, unsigned int my, double &wx, double &wy) const
Convert from map coordinates to world coordinates.
Definition: costmap_2d.cpp:280
unsigned char * getCharMap() const
Will return a pointer to the underlying unsigned char array used as the costmap.
Definition: costmap_2d.cpp:260
double getResolution() const
Accessor for the resolution of the costmap.
Definition: costmap_2d.cpp:578
unsigned int getSizeInCellsX() const
Accessor for the x size of the costmap in cells.
Definition: costmap_2d.cpp:548
double getOriginY() const
Accessor for the y origin of the costmap.
Definition: costmap_2d.cpp:573
unsigned int getSizeInCellsY() const
Accessor for the y size of the costmap in cells.
Definition: costmap_2d.cpp:553
double getOriginX() const
Accessor for the x origin of the costmap.
Definition: costmap_2d.cpp:568
A costmap layer base class for costmap plugin layers. Rather than just a layer, this object also cont...