32 #include "nav2_map_server/map_saver.hpp"
40 using namespace std::placeholders;
42 namespace nav2_map_server
44 MapSaver::MapSaver(
const rclcpp::NodeOptions & options)
45 : nav2::LifecycleNode(
"map_saver",
"", options)
47 RCLCPP_INFO(get_logger(),
"Creating");
57 RCLCPP_INFO(get_logger(),
"Configuring");
61 const std::string service_prefix = get_name() + std::string(
"/");
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);
74 save_map_service_ = create_service<nav2_msgs::srv::SaveMap>(
75 service_prefix + save_map_service_name_,
78 return nav2::CallbackReturn::SUCCESS;
84 RCLCPP_INFO(get_logger(),
"Activating");
89 return nav2::CallbackReturn::SUCCESS;
95 RCLCPP_INFO(get_logger(),
"Deactivating");
100 return nav2::CallbackReturn::SUCCESS;
106 RCLCPP_INFO(get_logger(),
"Cleaning up");
108 save_map_service_.reset();
110 return nav2::CallbackReturn::SUCCESS;
116 RCLCPP_INFO(get_logger(),
"Shutting down");
117 return nav2::CallbackReturn::SUCCESS;
121 const std::shared_ptr<rmw_request_id_t>,
122 const std::shared_ptr<nav2_msgs::srv::SaveMap::Request> request,
123 std::shared_ptr<nav2_msgs::srv::SaveMap::Response> response)
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;
132 save_parameters.mode = map_mode_from_string(request->map_mode);
133 }
catch (std::invalid_argument &) {
134 save_parameters.mode = MapMode::Trinary;
136 get_logger(),
"Map mode parameter not recognized: '%s', using default value (trinary)",
137 request->map_mode.c_str());
144 const std::string & map_topic,
148 std::string map_topic_loc = map_topic;
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());
157 if (map_topic_loc ==
"") {
158 map_topic_loc =
"map";
160 get_logger(),
"Map topic unspecified. Map messages will be read from \'%s\' topic",
161 map_topic_loc.c_str());
165 if (save_parameters_loc.free_thresh == 0.0) {
168 "Free threshold unspecified. Setting it to default value: %f",
169 free_thresh_default_);
170 save_parameters_loc.free_thresh = free_thresh_default_;
172 if (save_parameters_loc.occupied_thresh == 0.0) {
175 "Occupied threshold unspecified. Setting it to default value: %f",
176 occupied_thresh_default_);
177 save_parameters_loc.occupied_thresh = occupied_thresh_default_;
180 std::promise<nav_msgs::msg::OccupancyGrid::ConstSharedPtr> prom;
181 std::future<nav_msgs::msg::OccupancyGrid::ConstSharedPtr> future_result = prom.get_future();
183 auto mapCallback = [&prom](
184 const nav_msgs::msg::OccupancyGrid::ConstSharedPtr & msg) ->
void {
189 if (map_subscribe_transient_local_) {
194 auto callback_group = create_callback_group(
195 rclcpp::CallbackGroupType::MutuallyExclusive,
198 auto map_sub = create_subscription<nav_msgs::msg::OccupancyGrid>(
199 map_topic_loc, mapCallback, map_qos, callback_group);
202 rclcpp::executors::SingleThreadedExecutor executor;
203 executor.add_callback_group(callback_group, get_node_base_interface());
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");
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");
219 RCLCPP_ERROR(get_logger(),
"Failed to save the map");
222 }
catch (std::exception & e) {
223 RCLCPP_ERROR(get_logger(),
"Failed to save the map: %s", e.what());
232 #include "rclcpp_components/register_node_macro.hpp"
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.
nav2::CallbackReturn on_cleanup(const rclcpp_lifecycle::State &state) override
Called when it is required node clean-up.
nav2::CallbackReturn on_configure(const rclcpp_lifecycle::State &state) override
Sets up map saving service.
~MapSaver()
Destructor for the nav2_map_server::MapServer.
nav2::CallbackReturn on_activate(const rclcpp_lifecycle::State &state) override
Called when node switched to active state.
nav2::CallbackReturn on_shutdown(const rclcpp_lifecycle::State &state) override
Called when in Shutdown state.
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.
bool saveMapTopicToFile(const std::string &map_topic, const SaveParameters &save_parameters)
Read a message from incoming map topic and save map to a file.
nav2::CallbackReturn on_deactivate(const rclcpp_lifecycle::State &state) override
Called when node switched to inactive state.