Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
map_server.cpp
1 /* Copyright (c) 2018 Intel Corporation
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 /* Copyright 2019 Rover Robotics
17  * Copyright 2010 Brian Gerkey
18  * Copyright (c) 2008, Willow Garage, Inc.
19  *
20  * All rights reserved.
21  *
22  * Redistribution and use in source and binary forms, with or without
23  * modification, are permitted provided that the following conditions are met:
24  *
25  * * Redistributions of source code must retain the above copyright
26  * notice, this list of conditions and the following disclaimer.
27  * * Redistributions in binary form must reproduce the above copyright
28  * notice, this list of conditions and the following disclaimer in the
29  * documentation and/or other materials provided with the distribution.
30  * * Neither the name of the Willow Garage, Inc. nor the names of its
31  * contributors may be used to endorse or promote products derived from
32  * this software without specific prior written permission.
33  *
34  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
35  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
38  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
39  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
40  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
41  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
42  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
43  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
44  * POSSIBILITY OF SUCH DAMAGE.
45  */
46 
47 #include "nav2_map_server/map_server.hpp"
48 
49 #include <string>
50 #include <memory>
51 #include <fstream>
52 #include <stdexcept>
53 #include <utility>
54 
55 #include "yaml-cpp/yaml.h"
56 #include "lifecycle_msgs/msg/state.hpp"
57 #include "nav2_map_server/map_io.hpp"
58 
59 using namespace std::chrono_literals;
60 using namespace std::placeholders;
61 
62 namespace nav2_map_server
63 {
64 
65 MapServer::MapServer(const rclcpp::NodeOptions & options)
66 : nav2::LifecycleNode("map_server", "", options), map_available_(false)
67 {
68  RCLCPP_INFO(get_logger(), "Creating");
69 }
70 
72 {
73 }
74 
75 nav2::CallbackReturn
76 MapServer::on_configure(const rclcpp_lifecycle::State & /*state*/)
77 {
78  RCLCPP_INFO(get_logger(), "Configuring");
79  auto node = shared_from_this();
80 
81  // Get the name of the YAML file to use (can be empty if no initial map should be used)
82  std::string yaml_filename = node->declare_or_get_parameter(
83  "yaml_filename", std::string(""));
84  std::string topic_name = node->declare_or_get_parameter(
85  "topic_name", std::string("map"));
86  frame_id_ = node->declare_or_get_parameter(
87  "frame_id", std::string("map"));
88 
89  // only try to load map if parameter was set
90  if (!yaml_filename.empty()) {
91  // Shared pointer to LoadMap::Response is also should be initialized
92  // in order to avoid null-pointer dereference
93  std::shared_ptr<nav2_msgs::srv::LoadMap::Response> rsp =
94  std::make_shared<nav2_msgs::srv::LoadMap::Response>();
95 
96  if (!loadMapResponseFromYaml(yaml_filename, rsp)) {
97  throw std::runtime_error("Failed to load map yaml file: " + yaml_filename);
98  }
99  } else {
100  RCLCPP_INFO(
101  get_logger(),
102  "yaml-filename parameter is empty, set map through '%s'-service",
103  load_map_service_name_.c_str());
104  }
105 
106  // Make name prefix for services
107  const std::string service_prefix = get_name() + std::string("/");
108 
109  // Create a service that provides the occupancy grid
110  occ_service_ = create_service<nav_msgs::srv::GetMap>(
111  service_prefix + std::string(service_name_),
112  std::bind(&MapServer::getMapCallback, this, _1, _2, _3));
113 
114  // Create a publisher using the QoS settings to emulate a ROS1 latched topic
115  occ_pub_ = create_publisher<nav_msgs::msg::OccupancyGrid>(
116  topic_name,
118 
119  // Create a service that loads the occupancy grid from a file
120  load_map_service_ = create_service<nav2_msgs::srv::LoadMap>(
121  service_prefix + std::string(load_map_service_name_),
122  std::bind(&MapServer::loadMapCallback, this, _1, _2, _3));
123 
124  return nav2::CallbackReturn::SUCCESS;
125 }
126 
127 nav2::CallbackReturn
128 MapServer::on_activate(const rclcpp_lifecycle::State & /*state*/)
129 {
130  RCLCPP_INFO(get_logger(), "Activating");
131 
132  // Publish the map using the latched topic
133  occ_pub_->on_activate();
134  if (map_available_) {
135  auto occ_grid = std::make_unique<nav_msgs::msg::OccupancyGrid>(msg_);
136  occ_pub_->publish(std::move(occ_grid));
137  }
138 
139  // create bond connection
140  createBond();
141 
142  return nav2::CallbackReturn::SUCCESS;
143 }
144 
145 nav2::CallbackReturn
146 MapServer::on_deactivate(const rclcpp_lifecycle::State & /*state*/)
147 {
148  RCLCPP_INFO(get_logger(), "Deactivating");
149 
150  occ_pub_->on_deactivate();
151 
152  // destroy bond connection
153  destroyBond();
154 
155  return nav2::CallbackReturn::SUCCESS;
156 }
157 
158 nav2::CallbackReturn
159 MapServer::on_cleanup(const rclcpp_lifecycle::State & /*state*/)
160 {
161  RCLCPP_INFO(get_logger(), "Cleaning up");
162 
163  occ_pub_.reset();
164  occ_service_.reset();
165  load_map_service_.reset();
166  map_available_ = false;
167  msg_ = nav_msgs::msg::OccupancyGrid();
168 
169  return nav2::CallbackReturn::SUCCESS;
170 }
171 
172 nav2::CallbackReturn
173 MapServer::on_shutdown(const rclcpp_lifecycle::State & /*state*/)
174 {
175  RCLCPP_INFO(get_logger(), "Shutting down");
176  return nav2::CallbackReturn::SUCCESS;
177 }
178 
180  const std::shared_ptr<rmw_request_id_t>/*request_header*/,
181  const std::shared_ptr<nav_msgs::srv::GetMap::Request>/*request*/,
182  std::shared_ptr<nav_msgs::srv::GetMap::Response> response)
183 {
184  // if not in ACTIVE state, ignore request
185  if (get_current_state().id() != lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE) {
186  RCLCPP_WARN(
187  get_logger(),
188  "Received GetMap request but not in ACTIVE state, ignoring!");
189  return;
190  }
191  RCLCPP_INFO(get_logger(), "Handling GetMap request");
192  response->map = msg_;
193 }
194 
196  const std::shared_ptr<rmw_request_id_t>/*request_header*/,
197  const std::shared_ptr<nav2_msgs::srv::LoadMap::Request> request,
198  std::shared_ptr<nav2_msgs::srv::LoadMap::Response> response)
199 {
200  // if not in ACTIVE state, ignore request
201  if (get_current_state().id() != lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE) {
202  RCLCPP_WARN(
203  get_logger(),
204  "Received LoadMap request but not in ACTIVE state, ignoring!");
205  response->result = response->RESULT_UNDEFINED_FAILURE;
206  return;
207  }
208  RCLCPP_INFO(get_logger(), "Handling LoadMap request");
209  // Load from file
210  if (loadMapResponseFromYaml(request->map_url, response)) {
211  auto occ_grid = std::make_unique<nav_msgs::msg::OccupancyGrid>(msg_);
212  occ_pub_->publish(std::move(occ_grid)); // publish new map
213  }
214 }
215 
217  const std::string & yaml_file,
218  std::shared_ptr<nav2_msgs::srv::LoadMap::Response> response)
219 {
220  switch (loadMapFromYaml(yaml_file, msg_)) {
221  case MAP_DOES_NOT_EXIST:
222  response->result = nav2_msgs::srv::LoadMap::Response::RESULT_MAP_DOES_NOT_EXIST;
223  return false;
224  case INVALID_MAP_METADATA:
225  response->result = nav2_msgs::srv::LoadMap::Response::RESULT_INVALID_MAP_METADATA;
226  return false;
227  case INVALID_MAP_DATA:
228  response->result = nav2_msgs::srv::LoadMap::Response::RESULT_INVALID_MAP_DATA;
229  return false;
230  case LOAD_MAP_SUCCESS:
231  // Correcting msg_ header when it belongs to specific node
232  updateMsgHeader();
233 
234  map_available_ = true;
235  response->map = msg_;
236  response->result = nav2_msgs::srv::LoadMap::Response::RESULT_SUCCESS;
237  }
238 
239  return true;
240 }
241 
243 {
244  msg_.info.map_load_time = now();
245  msg_.header.frame_id = frame_id_;
246  msg_.header.stamp = now();
247 }
248 
249 } // namespace nav2_map_server
250 
251 #include "rclcpp_components/register_node_macro.hpp"
252 
253 // Register the component with class_loader.
254 // This acts as a sort of entry point, allowing the component to be discoverable when its library
255 // is being loaded into a running process.
256 RCLCPP_COMPONENTS_REGISTER_NODE(nav2_map_server::MapServer)
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 1 messages.
Parses the map yaml file and creates a service and a publisher that provides occupancy grid.
Definition: map_server.hpp:38
nav2::CallbackReturn on_activate(const rclcpp_lifecycle::State &state) override
Start publishing the map using the latched topic.
Definition: map_server.cpp:128
void loadMapCallback(const std::shared_ptr< rmw_request_id_t > request_header, const std::shared_ptr< nav2_msgs::srv::LoadMap::Request > request, std::shared_ptr< nav2_msgs::srv::LoadMap::Response > response)
Map loading service callback.
Definition: map_server.cpp:195
void getMapCallback(const std::shared_ptr< rmw_request_id_t > request_header, const std::shared_ptr< nav_msgs::srv::GetMap::Request > request, std::shared_ptr< nav_msgs::srv::GetMap::Response > response)
Map getting service callback.
Definition: map_server.cpp:179
void updateMsgHeader()
Method correcting msg_ header when it belongs to instantiated object.
Definition: map_server.cpp:242
~MapServer()
A Destructor for nav2_map_server::MapServer.
Definition: map_server.cpp:71
bool loadMapResponseFromYaml(const std::string &yaml_file, std::shared_ptr< nav2_msgs::srv::LoadMap::Response > response)
Load the map YAML, image from map file name and generate output response containing an OccupancyGrid....
Definition: map_server.cpp:216
nav2::CallbackReturn on_shutdown(const rclcpp_lifecycle::State &state) override
Called when in Shutdown state.
Definition: map_server.cpp:173
nav2::CallbackReturn on_configure(const rclcpp_lifecycle::State &state) override
Sets up required params and services. Loads map and its parameters from the file.
Definition: map_server.cpp:76
nav2::CallbackReturn on_deactivate(const rclcpp_lifecycle::State &state) override
Stops publishing the latched topic.
Definition: map_server.cpp:146
nav2::CallbackReturn on_cleanup(const rclcpp_lifecycle::State &state) override
Resets the member variables.
Definition: map_server.cpp:159