lanelet2_map_server v1.2.3
Loading...
Searching...
No Matches
lanelet2_map_interface.cpp
Go to the documentation of this file.
1// Copyright Institute for Automotive Engineering (ika), RWTH Aachen University
2// SPDX-License-Identifier: Apache-2.0
3
4#include <cctype>
5#include <cstdlib>
6#include <filesystem>
7#include <utility>
8
10
20std::filesystem::path resolveFilepath(const std::string& path_string) {
21 std::filesystem::path path(path_string);
22 if (path_string.empty()) return path;
23 if (!path.has_root_path()) {
24 const char* ros_home_ptr = std::getenv("ROS_HOME");
25 if (ros_home_ptr != nullptr && !std::string(ros_home_ptr).empty()) {
26 path = std::filesystem::path(std::string(ros_home_ptr));
27 } else {
28 const char* home_dir = std::getenv("HOME");
29 if (home_dir != nullptr && !std::string(home_dir).empty()) {
30 path = std::filesystem::path(std::string(home_dir) + "/.ros");
31 } else {
32 path = std::filesystem::current_path();
33 }
34 }
35 path.append(path_string);
36 }
37 path = path.lexically_normal();
38 return path;
39}
40
41Lanelet2MapInterface::Lanelet2MapInterface(rclcpp::Node& parent_node, std::string map_server_name)
42 : parent_node_(&parent_node),
43 map_filepath_(std::string(".lanelet2_map_interface/") + std::string(parent_node.get_fully_qualified_name()) + "/map.osm"),
44 map_server_name_(map_server_name) {
45 rcl_interfaces::msg::ParameterDescriptor param_desc;
46 param_desc.description = "Local filepath to where map from map server is written to (relative to $ROS_HOME)";
47 try {
48 parent_node_->declare_parameter("map_filepath", map_filepath_, param_desc);
49 } catch (const rclcpp::exceptions::ParameterAlreadyDeclaredException& ex) {
50 RCLCPP_WARN(parent_node_->get_logger(), "Parameter 'map_filepath' already declared: %s", ex.what());
51 }
52 map_filepath_ = parent_node_->get_parameter("map_filepath").as_string();
54 RCLCPP_INFO(parent_node_->get_logger(), "Loaded parameter 'map_filepath': %s", map_filepath_.c_str());
55
56 // Initialize parameter client and event handler
57 parameter_client_ = std::make_shared<rclcpp::AsyncParametersClient>(parent_node_, map_server_name);
58 parameter_sub_ = std::make_shared<rclcpp::ParameterEventHandler>(parent_node_);
59
60 // Periodically check if the parameter server is available
62 parent_node_->create_wall_timer(std::chrono::seconds(1), std::bind(&Lanelet2MapInterface::findMapServer, this));
63}
64
66 if (!parameter_client_->wait_for_service(std::chrono::milliseconds(10))) {
67 RCLCPP_WARN(parent_node_->get_logger(), "Waiting for map server ('%s') parameter service ...", map_server_name_.c_str());
68 return;
69 }
70
71 startup_timer_->cancel();
72 auto parameters_future =
73 parameter_client_->get_parameters({"map_frame_id", "map_contents", "origin_lat", "origin_lon"},
74 std::bind(&Lanelet2MapInterface::serviceParamsCallback, this, std::placeholders::_1));
75 RCLCPP_INFO(parent_node_->get_logger(), "Connected to map server ('%s') parameter service", map_server_name_.c_str());
76
77 // Only declare parameters once
78 if (!params_declared_) {
79 frame_id_callback_handle_ = parameter_sub_->add_parameter_callback(
80 "map_frame_id", std::bind(&Lanelet2MapInterface::updateParamsCallback, this, std::placeholders::_1), map_server_name_);
81 contents_callback_handle_ = parameter_sub_->add_parameter_callback(
82 "map_contents", std::bind(&Lanelet2MapInterface::updateParamsCallback, this, std::placeholders::_1), map_server_name_);
83 origin_lat_callback_handle_ = parameter_sub_->add_parameter_callback(
84 "origin_lat", std::bind(&Lanelet2MapInterface::updateParamsCallback, this, std::placeholders::_1), map_server_name_);
85 origin_lon_callback_handle_ = parameter_sub_->add_parameter_callback(
86 "origin_lon", std::bind(&Lanelet2MapInterface::updateParamsCallback, this, std::placeholders::_1), map_server_name_);
87 params_declared_ = true;
88 }
89}
90
91void Lanelet2MapInterface::updateParamsCallback(const rclcpp::Parameter& p) {
92 RCLCPP_INFO_STREAM(parent_node_->get_logger(), "Parameter '" << p.get_name() << "' changed, reloading map");
94 std::ignore = loadMap();
95}
96
97void Lanelet2MapInterface::serviceParamsCallback(std::shared_future<std::vector<rclcpp::Parameter>> future) {
98 auto result = future.get();
99 for (auto& parameter : result) {
100 updateMapParam(parameter);
101 }
102 std::ignore = loadMap();
103}
104
106 if (map_frame_id_.empty()) {
107 RCLCPP_ERROR_STREAM(parent_node_->get_logger(), "Parameter 'map_frame_id_' is empty");
108 return false;
109 }
110 if (map_filepath_.empty()) {
111 RCLCPP_ERROR_STREAM(parent_node_->get_logger(), "Parameter 'map_filepath_' is empty");
112 return false;
113 }
114 if (map_contents_.empty()) {
115 RCLCPP_ERROR_STREAM(parent_node_->get_logger(), "Parameter 'map_contents_' is empty");
116 return false;
117 }
118 if (origin_lat_ == std::numeric_limits<double>::quiet_NaN()) {
119 RCLCPP_WARN_STREAM(parent_node_->get_logger(), "Parameter 'origin_lat_' is not set");
120 return false;
121 }
122 if (origin_lon_ == std::numeric_limits<double>::quiet_NaN()) {
123 RCLCPP_WARN_STREAM(parent_node_->get_logger(), "Parameter 'origin_lon_' is not set");
124 return false;
125 }
126 return true;
127}
128
130 if (!map_loaded_) {
131 return nullptr;
132 }
133 return mapPtr_;
134}
135
136lanelet::LaneletMapConstPtr Lanelet2MapInterface::getMapPtr() { return getNonConstMapPtr(); }
137
138std::shared_ptr<lanelet::Projector> Lanelet2MapInterface::getProjectorPtr() {
139 if (!map_loaded_) {
140 return nullptr;
141 }
142 return utmProjectorPtr_;
143}
144
145void Lanelet2MapInterface::updateMapParam(rclcpp::Parameter param) {
146 if (param.get_name() == "map_frame_id") {
147 map_frame_id_ = param.value_to_string();
148 }
149 if (param.get_name() == "map_contents") {
150 map_contents_ = param.value_to_string();
151 }
152 if (param.get_name() == "origin_lat") {
153 origin_lat_ = param.as_double();
154 }
155 if (param.get_name() == "origin_lon") {
156 origin_lon_ = param.as_double();
157 }
158}
159
161 // Validate parameters
162 if (!validateParams()) {
163 return false;
164 }
165
166 // Check if location of map file exists, if not create all folders
167 std::string map_directory = map_filepath_.substr(0, map_filepath_.find_last_of("/"));
168 if (!std::filesystem::exists(map_directory)) {
169 if (!std::filesystem::create_directories(map_directory)) {
170 RCLCPP_ERROR_STREAM(parent_node_->get_logger(), "Failed to create directory '" << map_directory << "'");
171 return false;
172 }
173 }
174
175 // Save map_contents to file
176 std::ofstream map_file;
177 map_file.open(map_filepath_);
178 map_file << map_contents_;
179 map_file.close();
180
181 try {
182 // Load map from file
183 utmProjectorPtr_ = std::make_shared<lanelet::projection::UtmProjector>(lanelet::Origin({origin_lat_, origin_lon_}));
184 mapPtr_ = lanelet::load(map_filepath_, *utmProjectorPtr_);
185 map_loaded_ = true;
186 RCLCPP_INFO_STREAM(parent_node_->get_logger(), "Loaded map '" + map_filepath_ + "'");
187 update_pending_ = true;
188 } catch (const std::exception& exc) {
189 RCLCPP_ERROR_STREAM(parent_node_->get_logger(), "Failed to load map '" + map_filepath_ + "': " + exc.what());
190 return false;
191 }
192
193 return true;
194}
std::shared_ptr< lanelet::Projector > getProjectorPtr()
Returns the projector used to interpret the loaded map coordinates.
void serviceParamsCallback(std::shared_future< std::vector< rclcpp::Parameter > > future)
Handles the asynchronous response of an initial parameter fetch.
bool validateParams()
Validates that the required map parameters are available and usable.
Lanelet2MapInterface(rclcpp::Node &parent_node, std::string map_server_name)
Creates a client-side interface for retrieving Lanelet2 map parameters from a map server node.
lanelet::LaneletMapPtr getNonConstMapPtr()
Returns the currently loaded mutable Lanelet2 map.
bool loadMap()
Loads and parses the map from the currently cached parameters.
std::shared_ptr< rclcpp::AsyncParametersClient > parameter_client_
void updateParamsCallback(const rclcpp::Parameter &p)
Reacts to a single parameter event from the map server.
lanelet::LaneletMapPtr mapPtr_
std::shared_ptr< rclcpp::ParameterCallbackHandle > origin_lon_callback_handle_
void findMapServer()
Checks for the configured map server and, once available, requests initial parameters and installs su...
std::shared_ptr< rclcpp::ParameterCallbackHandle > origin_lat_callback_handle_
std::shared_ptr< lanelet::Projector > utmProjectorPtr_
void updateMapParam(rclcpp::Parameter param)
Updates one cached map parameter from a value received from the map server.
std::shared_ptr< rclcpp::ParameterCallbackHandle > contents_callback_handle_
std::shared_ptr< rclcpp::ParameterCallbackHandle > frame_id_callback_handle_
std::shared_ptr< rclcpp::ParameterEventHandler > parameter_sub_
rclcpp::TimerBase::SharedPtr startup_timer_
lanelet::LaneletMapConstPtr getMapPtr()
Returns the currently loaded immutable Lanelet2 map.
std::filesystem::path resolveFilepath(const std::string &path_string)
Resolves a relative string filepath.