Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
map_saver.cpp
1 /*
2  * Copyright (c) 2020 Samsung Research Russia
3  * Copyright 2019 Rover Robotics
4  * Copyright (c) 2008, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  * * Neither the name of the <ORGANIZATION> nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "nav2_map_server/map_saver.hpp"
33 
34 #include <string>
35 #include <memory>
36 #include <stdexcept>
37 #include <functional>
38 #include <mutex>
39 
40 using namespace std::placeholders;
41 
42 namespace nav2_map_server
43 {
44 MapSaver::MapSaver(const rclcpp::NodeOptions & options)
45 : nav2::LifecycleNode("map_saver", "", options)
46 {
47  RCLCPP_INFO(get_logger(), "Creating");
48 }
49 
51 {
52 }
53 
54 nav2::CallbackReturn
55 MapSaver::on_configure(const rclcpp_lifecycle::State & /*state*/)
56 {
57  RCLCPP_INFO(get_logger(), "Configuring");
58  auto node = shared_from_this();
59 
60  // Make name prefix for services
61  const std::string service_prefix = get_name() + std::string("/");
62 
63  save_map_timeout_ = std::make_shared<rclcpp::Duration>(
64  rclcpp::Duration::from_seconds(
65  node->declare_or_get_parameter("save_map_timeout", 2.0)));
66  free_thresh_default_ = node->declare_or_get_parameter(
67  "free_thresh_default", 0.25);
68  occupied_thresh_default_ = node->declare_or_get_parameter(
69  "occupied_thresh_default", 0.65);
70  map_subscribe_transient_local_ = node->declare_or_get_parameter(
71  "map_subscribe_transient_local", true);
72 
73  // Create a service that saves the occupancy grid from map topic to a file
74  save_map_service_ = create_service<nav2_msgs::srv::SaveMap>(
75  service_prefix + save_map_service_name_,
76  std::bind(&MapSaver::saveMapCallback, this, _1, _2, _3));
77 
78  return nav2::CallbackReturn::SUCCESS;
79 }
80 
81 nav2::CallbackReturn
82 MapSaver::on_activate(const rclcpp_lifecycle::State & /*state*/)
83 {
84  RCLCPP_INFO(get_logger(), "Activating");
85 
86  // create bond connection
87  createBond();
88 
89  return nav2::CallbackReturn::SUCCESS;
90 }
91 
92 nav2::CallbackReturn
93 MapSaver::on_deactivate(const rclcpp_lifecycle::State & /*state*/)
94 {
95  RCLCPP_INFO(get_logger(), "Deactivating");
96 
97  // destroy bond connection
98  destroyBond();
99 
100  return nav2::CallbackReturn::SUCCESS;
101 }
102 
103 nav2::CallbackReturn
104 MapSaver::on_cleanup(const rclcpp_lifecycle::State & /*state*/)
105 {
106  RCLCPP_INFO(get_logger(), "Cleaning up");
107 
108  save_map_service_.reset();
109 
110  return nav2::CallbackReturn::SUCCESS;
111 }
112 
113 nav2::CallbackReturn
114 MapSaver::on_shutdown(const rclcpp_lifecycle::State & /*state*/)
115 {
116  RCLCPP_INFO(get_logger(), "Shutting down");
117  return nav2::CallbackReturn::SUCCESS;
118 }
119 
121  const std::shared_ptr<rmw_request_id_t>/*request_header*/,
122  const std::shared_ptr<nav2_msgs::srv::SaveMap::Request> request,
123  std::shared_ptr<nav2_msgs::srv::SaveMap::Response> response)
124 {
125  // Set input arguments and call saveMapTopicToFile()
126  SaveParameters save_parameters;
127  save_parameters.map_file_name = request->map_url;
128  save_parameters.image_format = request->image_format;
129  save_parameters.free_thresh = request->free_thresh;
130  save_parameters.occupied_thresh = request->occupied_thresh;
131  try {
132  save_parameters.mode = map_mode_from_string(request->map_mode);
133  } catch (std::invalid_argument &) {
134  save_parameters.mode = MapMode::Trinary;
135  RCLCPP_WARN(
136  get_logger(), "Map mode parameter not recognized: '%s', using default value (trinary)",
137  request->map_mode.c_str());
138  }
139 
140  response->result = saveMapTopicToFile(request->map_topic, save_parameters);
141 }
142 
144  const std::string & map_topic,
145  const SaveParameters & save_parameters)
146 {
147  // Local copies of map_topic and save_parameters that could be changed
148  std::string map_topic_loc = map_topic;
149  SaveParameters save_parameters_loc = save_parameters;
150 
151  RCLCPP_INFO(
152  get_logger(), "Saving map from \'%s\' topic to \'%s\' file",
153  map_topic_loc.c_str(), save_parameters_loc.map_file_name.c_str());
154 
155  try {
156  // Correct map_topic_loc if necessary
157  if (map_topic_loc == "") {
158  map_topic_loc = "map";
159  RCLCPP_WARN(
160  get_logger(), "Map topic unspecified. Map messages will be read from \'%s\' topic",
161  map_topic_loc.c_str());
162  }
163 
164  // Set default for MapSaver node thresholds parameters
165  if (save_parameters_loc.free_thresh == 0.0) {
166  RCLCPP_WARN(
167  get_logger(),
168  "Free threshold unspecified. Setting it to default value: %f",
169  free_thresh_default_);
170  save_parameters_loc.free_thresh = free_thresh_default_;
171  }
172  if (save_parameters_loc.occupied_thresh == 0.0) {
173  RCLCPP_WARN(
174  get_logger(),
175  "Occupied threshold unspecified. Setting it to default value: %f",
176  occupied_thresh_default_);
177  save_parameters_loc.occupied_thresh = occupied_thresh_default_;
178  }
179 
180  std::promise<nav_msgs::msg::OccupancyGrid::ConstSharedPtr> prom;
181  std::future<nav_msgs::msg::OccupancyGrid::ConstSharedPtr> future_result = prom.get_future();
182  // A callback function that receives map message from subscribed topic
183  auto mapCallback = [&prom](
184  const nav_msgs::msg::OccupancyGrid::ConstSharedPtr & msg) -> void {
185  prom.set_value(msg);
186  };
187 
188  rclcpp::QoS map_qos = nav2::qos::StandardTopicQoS(); // initialize to default
189  if (map_subscribe_transient_local_) {
191  }
192 
193  // Create new CallbackGroup for map_sub
194  auto callback_group = create_callback_group(
195  rclcpp::CallbackGroupType::MutuallyExclusive,
196  false);
197 
198  auto map_sub = create_subscription<nav_msgs::msg::OccupancyGrid>(
199  map_topic_loc, mapCallback, map_qos, callback_group);
200 
201  // Create SingleThreadedExecutor to spin map_sub in callback_group
202  rclcpp::executors::SingleThreadedExecutor executor;
203  executor.add_callback_group(callback_group, get_node_base_interface());
204  // Spin until map message received
205  auto timeout = save_map_timeout_->to_chrono<std::chrono::nanoseconds>();
206  auto status = executor.spin_until_future_complete(future_result, timeout);
207  if (status != rclcpp::FutureReturnCode::SUCCESS) {
208  RCLCPP_ERROR(get_logger(), "Failed to spin map subscription");
209  return false;
210  }
211  // map_sub is no more needed
212  map_sub.reset();
213  // Map message received. Saving it to file
214  nav_msgs::msg::OccupancyGrid::ConstSharedPtr map_msg = future_result.get();
215  if (saveMapToFile(*map_msg, save_parameters_loc)) {
216  RCLCPP_INFO(get_logger(), "Map saved successfully");
217  return true;
218  } else {
219  RCLCPP_ERROR(get_logger(), "Failed to save the map");
220  return false;
221  }
222  } catch (std::exception & e) {
223  RCLCPP_ERROR(get_logger(), "Failed to save the map: %s", e.what());
224  return false;
225  }
226 
227  return false;
228 }
229 
230 } // namespace nav2_map_server
231 
232 #include "rclcpp_components/register_node_macro.hpp"
233 
234 // Register the component with class_loader.
235 // This acts as a sort of entry point, allowing the component to be discoverable when its library
236 // is being loaded into a running process.
237 RCLCPP_COMPONENTS_REGISTER_NODE(nav2_map_server::MapSaver)
void destroyBond()
Destroy bond connection to lifecycle manager.
nav2::LifecycleNode::SharedPtr shared_from_this()
Get a shared pointer of this.
void createBond()
Create bond connection to lifecycle manager.
A QoS profile for latched, reliable topics with a history of 10 messages.
A QoS profile for standard reliable topics with a history of 10 messages.
A class that provides map saving methods and services.
Definition: map_saver.hpp:38
nav2::CallbackReturn on_cleanup(const rclcpp_lifecycle::State &state) override
Called when it is required node clean-up.
Definition: map_saver.cpp:104
nav2::CallbackReturn on_configure(const rclcpp_lifecycle::State &state) override
Sets up map saving service.
Definition: map_saver.cpp:55
~MapSaver()
Destructor for the nav2_map_server::MapServer.
Definition: map_saver.cpp:50
nav2::CallbackReturn on_activate(const rclcpp_lifecycle::State &state) override
Called when node switched to active state.
Definition: map_saver.cpp:82
nav2::CallbackReturn on_shutdown(const rclcpp_lifecycle::State &state) override
Called when in Shutdown state.
Definition: map_saver.cpp:114
void saveMapCallback(const std::shared_ptr< rmw_request_id_t > request_header, const std::shared_ptr< nav2_msgs::srv::SaveMap::Request > request, std::shared_ptr< nav2_msgs::srv::SaveMap::Response > response)
Map saving service callback.
Definition: map_saver.cpp:120
bool saveMapTopicToFile(const std::string &map_topic, const SaveParameters &save_parameters)
Read a message from incoming map topic and save map to a file.
Definition: map_saver.cpp:143
nav2::CallbackReturn on_deactivate(const rclcpp_lifecycle::State &state) override
Called when node switched to inactive state.
Definition: map_saver.cpp:93