lanelet2_map_server v1.2.3
Loading...
Searching...
No Matches
Lanelet2MapServer Class Reference

#include <lanelet2_map_server.hpp>

Inheritance diagram for Lanelet2MapServer:

Public Member Functions

 Lanelet2MapServer ()
 Creates the Lanelet2 map server node and declares its parameters.
 

Private Member Functions

template<typename T >
bool declareAndLoadParameter (const std::string &name, T &param, const std::string &description, const bool add_to_auto_reconfigurable_params=true, const bool is_required=false, const bool read_only=false, const std::optional< double > &from_value=std::nullopt, const std::optional< double > &to_value=std::nullopt, const std::optional< double > &step_value=std::nullopt, const std::string &additional_constraints="")
 Declares and loads a ROS parameter.
 
rcl_interfaces::msg::SetParametersResult parametersCallback (const std::vector< rclcpp::Parameter > &parameters)
 Handles reconfiguration when a parameter value is changed.
 
void loadMapContents ()
 Loads the configured map file and caches its serialized contents.
 
void unsetMapParameters ()
 Clears map-specific parameters after an invalid or unloaded map state.
 
void updateMapParameters ()
 Writes the current map state into this node's exported ROS parameters.
 
void setup ()
 Sets up timers, callbacks, publishers, and initial map loading.
 
void find_available_maps (const std::string &directory, std::vector< Lanelet2MapMeta > &maps) const
 Recursively scans a directory for available Lanelet2 map files.
 
void derive_map_meta (Lanelet2MapMeta &map_meta) const
 Fills the derived metadata fields for a discovered map.
 
bool deriveOriginFromMap (const std::string &map_filepath, double &origin_lat, double &origin_lon) const
 Derives a south-west origin latitude and longitude from a Lanelet2 map file.
 
bool map_sanity_check (std::string map_filepath, double origin_lat, double origin_lon) const
 Tries to load a map with the provided origin to verify that it is usable.
 
void pub_tf () const
 Publishes the static transform from the derived UTM frame to the map frame.
 
void navSatFixCallback (const sensor_msgs::msg::NavSatFix::SharedPtr msg)
 Stores the latest GNSS fix for automatic map selection.
 
void automaticMapUpdateTimerCallback ()
 Periodically reevaluates the best map when automatic selection is enabled.
 

Static Private Member Functions

static void derive_utm_zone (const double latitude, const double longitude, int &zone, bool &northp)
 Derives the UTM zone and hemisphere from a geographic position.
 

Private Attributes

std::vector< std::tuple< std::string, std::function< void(const rclcpp::Parameter &)> > > auto_reconfigurable_params_
 Auto-reconfigurable parameters for dynamic reconfiguration.
 
OnSetParametersCallbackHandle::SharedPtr parameters_callback_
 Callback handle for dynamic parameter reconfiguration.
 
rclcpp::TimerBase::SharedPtr one_shot_timer_
 
rclcpp::TimerBase::SharedPtr automatic_map_timer_
 
bool use_automatic_map_selection_ = false
 
std::string map_directory_ = "/data/maps/default-maps"
 
std::vector< Lanelet2MapMeta > available_maps_
 
std::string map_filepath_
 
std::string map_frame_id_ = "map"
 
std::string map_contents_
 
double origin_lat_
 
double origin_lon_
 
bool origin_lat_set_ = false
 
bool origin_lon_set_ = false
 
std::shared_ptr< tf2_ros::StaticTransformBroadcaster > tf_static_broadcaster_
 
rclcpp::Subscription< sensor_msgs::msg::NavSatFix >::SharedPtr navsat_subscription_
 
double current_latitude_ = std::numeric_limits<double>::quiet_NaN()
 
double current_longitude_ = std::numeric_limits<double>::quiet_NaN()
 
bool gps_fix_received_ = false
 

Detailed Description

Definition at line 40 of file lanelet2_map_server.hpp.

Constructor & Destructor Documentation

◆ Lanelet2MapServer()

Lanelet2MapServer::Lanelet2MapServer ( )

Creates the Lanelet2 map server node and declares its parameters.

Definition at line 16 of file lanelet2_map_server.cpp.

16 : Node("lanelet2_map_server") {
17 // General parameters
18 this->declareAndLoadParameter("map_frame_id", map_frame_id_, "Frame ID of Lanelet2 map", true, false, false);
19 // Automatic map selection parameters
20 this->declareAndLoadParameter("use_automatic_map_selection", use_automatic_map_selection_, "Automatic map selection", false,
21 false, true);
22 this->declareAndLoadParameter("map_directory", map_directory_, "Directory containing Lanelet2 maps", true, false, false);
23 // Map-Server parameters (are not reconfigurable and not required if automatic map selection is enabled)
24 this->declareAndLoadParameter("map_filepath", map_filepath_, "Path to Lanelet2 map", !use_automatic_map_selection_,
26 origin_lat_set_ = this->declareAndLoadParameter("origin_lat", origin_lat_, "Latitude of origin of Lanelet2 map",
27 !use_automatic_map_selection_, false, false);
28 origin_lon_set_ = this->declareAndLoadParameter("origin_lon", origin_lon_, "Longitude of origin of Lanelet2 map",
29 !use_automatic_map_selection_, false, false);
30 // Map-Contents is never required and never reconfigurable
31 this->declareAndLoadParameter("map_contents", map_contents_, "Contents of Lanelet2 map", false, false, false);
32
33 this->setup();
34}
bool declareAndLoadParameter(const std::string &name, T &param, const std::string &description, const bool add_to_auto_reconfigurable_params=true, const bool is_required=false, const bool read_only=false, const std::optional< double > &from_value=std::nullopt, const std::optional< double > &to_value=std::nullopt, const std::optional< double > &step_value=std::nullopt, const std::string &additional_constraints="")
Declares and loads a ROS parameter.
void setup()
Sets up timers, callbacks, publishers, and initial map loading.

Member Function Documentation

◆ automaticMapUpdateTimerCallback()

void Lanelet2MapServer::automaticMapUpdateTimerCallback ( )
private

Periodically reevaluates the best map when automatic selection is enabled.

Definition at line 389 of file lanelet2_map_server.cpp.

389 {
390 if (!gps_fix_received_) {
391 RCLCPP_WARN(this->get_logger(), "No initial GPS fix received, unable to select map");
393 return;
394 }
395
396 const Lanelet2MapMeta* selected_map = nullptr;
397 for (const auto& map_meta : available_maps_) {
398 // check for invalid map
399 if (map_meta.diagonal_length <= 0.0) {
400 continue;
401 }
402 // check for maps outside current GPS location
403 if (current_latitude_ < map_meta.min_lat || current_latitude_ > map_meta.max_lat || current_longitude_ < map_meta.min_lon ||
404 current_longitude_ > map_meta.max_lon) {
405 continue;
406 }
407 if (selected_map == nullptr || map_meta.diagonal_length < selected_map->diagonal_length) {
408 if (map_sanity_check(map_meta.map_path, map_meta.min_lat, map_meta.min_lon)) {
409 RCLCPP_DEBUG(this->get_logger(), "Map sanity check passed for '%s'", map_meta.map_path.c_str());
410 selected_map = &map_meta;
411 } else {
412 RCLCPP_WARN(this->get_logger(), "Map sanity check failed for '%s'", map_meta.map_path.c_str());
413 continue;
414 }
415 }
416 }
417
418 if (selected_map == nullptr) {
419 RCLCPP_WARN(this->get_logger(), "No suitable map found for current GPS location (lat=%.9f, lon=%.9f)", current_latitude_,
422 return;
423 }
424
425 if (map_filepath_ == selected_map->map_path) {
426 RCLCPP_DEBUG(this->get_logger(), "Currently loaded map '%s' is still valid", map_filepath_.c_str());
427 return;
428 }
429
430 map_filepath_ = selected_map->map_path;
431 origin_lat_ = selected_map->min_lat;
432 origin_lon_ = selected_map->min_lon;
433 origin_lat_set_ = false;
434 origin_lon_set_ = false;
435 this->loadMapContents();
436 this->updateMapParameters();
437 this->pub_tf();
438}
void unsetMapParameters()
Clears map-specific parameters after an invalid or unloaded map state.
std::vector< Lanelet2MapMeta > available_maps_
void updateMapParameters()
Writes the current map state into this node's exported ROS parameters.
bool map_sanity_check(std::string map_filepath, double origin_lat, double origin_lon) const
Tries to load a map with the provided origin to verify that it is usable.
void loadMapContents()
Loads the configured map file and caches its serialized contents.
void pub_tf() const
Publishes the static transform from the derived UTM frame to the map frame.

◆ declareAndLoadParameter()

template<typename T >
bool Lanelet2MapServer::declareAndLoadParameter ( const std::string & name,
T & param,
const std::string & description,
const bool add_to_auto_reconfigurable_params = true,
const bool is_required = false,
const bool read_only = false,
const std::optional< double > & from_value = std::nullopt,
const std::optional< double > & to_value = std::nullopt,
const std::optional< double > & step_value = std::nullopt,
const std::string & additional_constraints = "" )
private

Declares and loads a ROS parameter.

Parameters
namename
paramparameter variable to load into
descriptiondescription
add_to_auto_reconfigurable_paramsenable reconfiguration of parameter
is_requiredwhether failure to load parameter will stop node
read_onlyset parameter to read-only
from_valueparameter range minimum
to_valueparameter range maximum
step_valueparameter range step
additional_constraintsadditional constraints description
Returns
true if the parameter was already initialized from an external source

Definition at line 37 of file lanelet2_map_server.cpp.

46 {
47 rcl_interfaces::msg::ParameterDescriptor param_desc;
48 param_desc.description = description;
49 param_desc.additional_constraints = additional_constraints;
50 param_desc.read_only = read_only;
51
52 auto type = rclcpp::ParameterValue(param).get_type();
53
54 if (from_value.has_value() && to_value.has_value()) {
55 if constexpr (std::is_integral_v<T>) {
56 rcl_interfaces::msg::IntegerRange range;
57 range.set__from_value(static_cast<T>(from_value.value())).set__to_value(static_cast<T>(to_value.value()));
58 if (step_value.has_value()) range.set__step(static_cast<T>(step_value.value()));
59 param_desc.integer_range = {range};
60 } else if constexpr (std::is_floating_point_v<T>) {
61 rcl_interfaces::msg::FloatingPointRange range;
62 range.set__from_value(static_cast<T>(from_value.value())).set__to_value(static_cast<T>(to_value.value()));
63 if (step_value.has_value()) range.set__step(static_cast<T>(step_value.value()));
64 param_desc.floating_point_range = {range};
65 } else {
66 RCLCPP_WARN(this->get_logger(), "Parameter type of parameter '%s' does not support specifying a range", name.c_str());
67 }
68 }
69
70 this->declare_parameter(name, type, param_desc);
71 bool initial_set = false;
72
73 try {
74 param = this->get_parameter(name).get_value<T>();
75 std::stringstream ss;
76 ss << "Loaded parameter '" << name << "': ";
77 if constexpr (is_vector_v<T>) {
78 ss << "[";
79 for (const auto& element : param) ss << element << (&element != &param.back() ? ", " : "");
80 ss << "]";
81 } else {
82 ss << param;
83 }
84 RCLCPP_INFO_STREAM(this->get_logger(), ss.str());
85 initial_set = true;
86 } catch (rclcpp::exceptions::ParameterUninitializedException&) {
87 if (is_required) {
88 RCLCPP_FATAL_STREAM(this->get_logger(), "Missing required parameter '" << name << "', exiting");
89 exit(EXIT_FAILURE);
90 } else {
91 std::stringstream ss;
92 ss << "Missing parameter '" << name << "', using default value: ";
93 if constexpr (is_vector_v<T>) {
94 ss << "[";
95 for (const auto& element : param) ss << element << (&element != &param.back() ? ", " : "");
96 ss << "]";
97 } else {
98 ss << param;
99 }
100 RCLCPP_WARN_STREAM(this->get_logger(), ss.str());
101 this->set_parameters({rclcpp::Parameter(name, rclcpp::ParameterValue(param))});
102 }
103 }
104
105 if (add_to_auto_reconfigurable_params) {
106 std::function<void(const rclcpp::Parameter&)> setter = [&param](const rclcpp::Parameter& p) { param = p.get_value<T>(); };
107 auto_reconfigurable_params_.push_back(std::make_tuple(name, setter));
108 }
109
110 return initial_set;
111}
std::vector< std::tuple< std::string, std::function< void(const rclcpp::Parameter &)> > > auto_reconfigurable_params_
Auto-reconfigurable parameters for dynamic reconfiguration.
constexpr bool is_vector_v

◆ derive_map_meta()

void Lanelet2MapServer::derive_map_meta ( Lanelet2MapMeta & map_meta) const
private

Fills the derived metadata fields for a discovered map.

Parameters
map_metametadata entry whose geographic bounds and size are updated

Definition at line 328 of file lanelet2_map_server.cpp.

328 {
329 map_meta.diagonal_length = -1.0;
330 pugi::xml_document document;
331 const pugi::xml_parse_result result = document.load_file(map_meta.map_path.c_str());
332 if (!result) {
333 RCLCPP_ERROR_STREAM(get_logger(), "Unable to parse map '" << map_meta.map_path << "': " << result.description());
334 return;
335 }
336
337 pugi::xml_node root = document.child("osm");
338 if (!root) {
339 root = document.document_element();
340 }
341 if (!root) {
342 RCLCPP_WARN_STREAM(get_logger(), "No root element found when deriving meta for '" << map_meta.map_path << "'");
343 return;
344 }
345
346 const double kDoubleMax = std::numeric_limits<double>::max();
347 const double kDoubleLowest = std::numeric_limits<double>::lowest();
348 double min_lat = kDoubleMax;
349 double min_lon = kDoubleMax;
350 double max_lat = kDoubleLowest;
351 double max_lon = kDoubleLowest;
352 bool found_node = false;
353
354 for (pugi::xml_node node : root.children("node")) {
355 const double lat = node.attribute("lat").as_double(std::numeric_limits<double>::quiet_NaN());
356 const double lon = node.attribute("lon").as_double(std::numeric_limits<double>::quiet_NaN());
357 if (std::isnan(lat) || std::isnan(lon)) {
358 continue;
359 }
360
361 min_lat = std::min(min_lat, lat);
362 max_lat = std::max(max_lat, lat);
363 min_lon = std::min(min_lon, lon);
364 max_lon = std::max(max_lon, lon);
365 found_node = true;
366 }
367
368 if (!found_node) {
369 RCLCPP_WARN_STREAM(get_logger(), "No node elements found while deriving bounds for '" << map_meta.map_path << "'");
370 return;
371 }
372
373 map_meta.min_lat = min_lat;
374 map_meta.max_lat = max_lat;
375 map_meta.min_lon = min_lon;
376 map_meta.max_lon = max_lon;
377
378 double distance = 0.0;
379 GeographicLib::Geodesic::WGS84().Inverse(min_lat, min_lon, max_lat, max_lon, distance);
380 map_meta.diagonal_length = distance;
381}

◆ derive_utm_zone()

void Lanelet2MapServer::derive_utm_zone ( const double latitude,
const double longitude,
int & zone,
bool & northp )
staticprivate

Derives the UTM zone and hemisphere from a geographic position.

Parameters
latitudelatitude in degrees
longitudelongitude in degrees
zoneoutput UTM zone number
northpoutput hemisphere flag, true for northern hemisphere

Definition at line 479 of file lanelet2_map_server.cpp.

479 {
480 northp = latitude >= 0.0;
481 zone = static_cast<int>(std::floor((longitude + 180.0) / 6.0)) + 1;
482}

◆ deriveOriginFromMap()

bool Lanelet2MapServer::deriveOriginFromMap ( const std::string & map_filepath,
double & origin_lat,
double & origin_lon ) const
private

Derives a south-west origin latitude and longitude from a Lanelet2 map file.

Parameters
map_filepathpath to the map file
origin_latoutput latitude of the derived south-west origin
origin_lonoutput longitude of the derived south-west origin
Returns
true if the origin could be derived from the map bounds

Definition at line 283 of file lanelet2_map_server.cpp.

283 {
284 if (map_filepath.empty()) {
285 RCLCPP_ERROR(this->get_logger(), "No map filepath provided, cannot derive origin from map.");
286 return false;
287 }
288
289 Lanelet2MapMeta map_meta;
290 map_meta.map_path = map_filepath;
291 derive_map_meta(map_meta);
292 if (map_meta.diagonal_length <= 0.0) {
293 return false;
294 }
295
296 origin_lat = map_meta.min_lat;
297 origin_lon = map_meta.min_lon;
298 return true;
299}
void derive_map_meta(Lanelet2MapMeta &map_meta) const
Fills the derived metadata fields for a discovered map.

◆ find_available_maps()

void Lanelet2MapServer::find_available_maps ( const std::string & directory,
std::vector< Lanelet2MapMeta > & maps ) const
private

Recursively scans a directory for available Lanelet2 map files.

Parameters
directoryroot directory to search
mapsoutput vector that receives discovered map metadata

Definition at line 301 of file lanelet2_map_server.cpp.

301 {
302 maps.clear();
303 try {
304 for (const auto& entry : std::filesystem::recursive_directory_iterator(directory)) {
305 if (!entry.is_regular_file()) {
306 continue;
307 }
308 if (entry.path().extension() == ".osm") {
309 Lanelet2MapMeta map_meta;
310 map_meta.map_path = entry.path().string();
311 maps.emplace_back(map_meta);
312 }
313 }
314 } catch (const std::filesystem::filesystem_error& e) {
315 RCLCPP_ERROR_STREAM(get_logger(), "Failed to scan '" << directory << "': " << e.what());
316 }
317 for (auto& map_meta : maps) {
318 derive_map_meta(map_meta);
319 }
320 RCLCPP_INFO(this->get_logger(), "Discovered %zu Lanelet2 maps in '%s'", maps.size(), directory.c_str());
321 for (const auto& map_meta : available_maps_) {
322 RCLCPP_INFO(this->get_logger(), "Map '%s': min_lat=%.9f, min_lon=%.9f, max_lat=%.9f, max_lon=%.9f, diagonal_length=%.3f",
323 map_meta.map_path.c_str(), map_meta.min_lat, map_meta.min_lon, map_meta.max_lat, map_meta.max_lon,
324 map_meta.diagonal_length);
325 }
326}

◆ loadMapContents()

void Lanelet2MapServer::loadMapContents ( )
private

Loads the configured map file and caches its serialized contents.

Definition at line 440 of file lanelet2_map_server.cpp.

440 {
441 if (map_filepath_.empty()) {
442 map_contents_ = "";
443 return;
444 }
445 std::ifstream file(map_filepath_);
446 map_contents_ = std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
447 RCLCPP_INFO(this->get_logger(), "Loaded map contents from '%s' to parameter 'map_contents'", map_filepath_.c_str());
448}

◆ map_sanity_check()

bool Lanelet2MapServer::map_sanity_check ( std::string map_filepath,
double origin_lat,
double origin_lon ) const
private

Tries to load a map with the provided origin to verify that it is usable.

Parameters
map_filepathpath to the map file
origin_latlatitude used for projection
origin_lonlongitude used for projection
Returns
true if the map passes the sanity check

Definition at line 467 of file lanelet2_map_server.cpp.

467 {
468 lanelet::projection::UtmProjector proj(lanelet::Origin({origin_lat, origin_lon}));
469 try {
470 lanelet::LaneletMapPtr map = lanelet::load(map_filepath, proj);
471 } catch (const lanelet::IOError& e) {
472 RCLCPP_ERROR_STREAM(this->get_logger(), "Could not load map '" << map_filepath << "': " << e.what());
473 return false;
474 }
475
476 return true;
477}

◆ navSatFixCallback()

void Lanelet2MapServer::navSatFixCallback ( const sensor_msgs::msg::NavSatFix::SharedPtr msg)
private

Stores the latest GNSS fix for automatic map selection.

Parameters
msgincoming GPS fix message

Definition at line 383 of file lanelet2_map_server.cpp.

383 {
384 current_latitude_ = msg->latitude;
385 current_longitude_ = msg->longitude;
386 gps_fix_received_ = true;
387}

◆ parametersCallback()

rcl_interfaces::msg::SetParametersResult Lanelet2MapServer::parametersCallback ( const std::vector< rclcpp::Parameter > & parameters)
private

Handles reconfiguration when a parameter value is changed.

Parameters
parametersparameters
Returns
parameter change result

Definition at line 113 of file lanelet2_map_server.cpp.

113 {
114 std::string previous_map_filepath = map_filepath_;
115 rcl_interfaces::msg::SetParametersResult result;
116 result.successful = false;
117 double previous_origin_lat = origin_lat_;
118 double previous_origin_lon = origin_lon_;
119 bool relevant_change = false;
120
121 bool map_filepath_changed = false;
122 bool origin_lat_changed = false;
123 bool origin_lon_changed = false;
124
125 RCLCPP_INFO(this->get_logger(), "Received request to change %zu parameter(s)", parameters.size());
126 for (const auto& p : parameters) {
127 if (p.get_name() == "map_contents") {
128 RCLCPP_INFO(this->get_logger(), "Incoming param: map_contents = <omitted, size=%zu>", p.get_value<std::string>().size());
129 } else {
130 RCLCPP_INFO(this->get_logger(), "Incoming param: %s = %s", p.get_name().c_str(), p.value_to_string().c_str());
131 }
132 }
133
134 for (const auto& param : parameters) {
135 for (auto& auto_reconfigurable_param : auto_reconfigurable_params_) {
136 if (param.get_name() == std::get<0>(auto_reconfigurable_param)) {
137 std::get<1>(auto_reconfigurable_param)(param);
138 RCLCPP_INFO(this->get_logger(), "Reconfigured parameter '%s' to: %s", param.get_name().c_str(),
139 param.value_to_string().c_str());
140 break;
141 }
142 }
143 // handle special cases
144 if (param.get_name() == "map_filepath") {
145 if (param.get_value<std::string>() != map_filepath_) {
146 result.reason = "Parameter 'map_filepath' is not reconfigurable when automatic map selection is enabled.";
147 return result;
148 }
149 map_filepath_changed = previous_map_filepath != map_filepath_;
150 relevant_change = relevant_change || map_filepath_changed;
151 }
152 if (param.get_name() == "origin_lat") {
153 if (param.get_value<double>() != origin_lat_) {
154 result.reason = "Parameter 'origin_lat' is not reconfigurable when automatic map selection is enabled.";
155 return result;
156 }
157 origin_lat_changed = previous_origin_lat != origin_lat_;
158 relevant_change = relevant_change || origin_lat_changed;
159
160 if (origin_lat_changed) origin_lat_set_ = true;
161 }
162 if (param.get_name() == "origin_lon") {
163 if (param.get_value<double>() != origin_lon_) {
164 result.reason = "Parameter 'origin_lon' is not reconfigurable when automatic map selection is enabled.";
165 return result;
166 }
167 origin_lon_changed = previous_origin_lon != origin_lon_;
168 relevant_change = relevant_change || origin_lon_changed;
169
170 if (origin_lon_changed) origin_lon_set_ = true;
171 }
172 if (param.get_name() == "map_contents" && param.get_value<std::string>() != map_contents_) {
173 result.reason = "Parameter 'map_contents' is not reconfigurable.";
174 return result;
175 }
176 if (param.get_name() == "map_directory" && use_automatic_map_selection_) {
178 if (available_maps_.empty()) {
179 RCLCPP_ERROR(this->get_logger(), "No Lanelet2 maps found in '%s'", map_directory_.c_str());
180 // reload parameters in timer callback since parameters cannot be updated in this callback
181 one_shot_timer_ = this->create_wall_timer(std::chrono::milliseconds(1), [this]() {
182 this->one_shot_timer_->cancel();
184 });
185 }
186 }
187 }
188
189 if (!use_automatic_map_selection_ && relevant_change) {
190 // set default origin (bottom left) if not set before
193 result.reason = "Could not derive lower-left origin from map in manual mode.";
194 result.successful = false;
195 return result;
196 }
197
198 RCLCPP_INFO(this->get_logger(), "Derived manual origin from lower-left map corner for '%s' (lat=%.9f, lon=%.9f)",
200 }
201
202 // load map if not unbalanced origin parameters are provided (both or none)
205 // reload parameters in timer callback since parameters cannot be updated in this callback
206 one_shot_timer_ = this->create_wall_timer(std::chrono::milliseconds(1), [this]() {
207 this->one_shot_timer_->cancel();
208
209 this->loadMapContents();
210 this->updateMapParameters();
211 this->pub_tf();
212 });
213 } else {
214 this->updateMapParameters();
215 RCLCPP_ERROR(this->get_logger(), "Map sanity check failed for map '%s' with origin (lat=%.9f, lon=%.9f)",
217 result.reason = "Map sanity check failed in manual mode.";
218 result.successful = false;
219 return result;
220 }
221 } else {
222 this->updateMapParameters();
223 RCLCPP_WARN(this->get_logger(),
224 "Waiting for origin readiness: if origin is explictly set, both parameters must be provided.");
225 result.reason = "Waiting for origin readiness: if origin is explictly set, both parameters must be provided.";
226 result.successful = true;
227 return result;
228 }
229 }
230 result.successful = true;
231 return result;
232}
rclcpp::TimerBase::SharedPtr one_shot_timer_
bool deriveOriginFromMap(const std::string &map_filepath, double &origin_lat, double &origin_lon) const
Derives a south-west origin latitude and longitude from a Lanelet2 map file.
void find_available_maps(const std::string &directory, std::vector< Lanelet2MapMeta > &maps) const
Recursively scans a directory for available Lanelet2 map files.

◆ pub_tf()

void Lanelet2MapServer::pub_tf ( ) const
private

Publishes the static transform from the derived UTM frame to the map frame.

Definition at line 484 of file lanelet2_map_server.cpp.

484 {
485 if (map_filepath_.empty()) {
486 return;
487 }
488 geometry_msgs::msg::TransformStamped t;
489
490 // Create Projector without offset
491 lanelet::projection::UtmProjector proj_utm(lanelet::Origin({origin_lat_, origin_lon_}), false);
492 lanelet::BasicPoint3d origin_utm = proj_utm.forward(lanelet::GPSPoint({origin_lat_, origin_lon_, 0.0}));
493
494 t.transform.translation.x = origin_utm.x();
495 t.transform.translation.y = origin_utm.y();
496 t.transform.translation.z = origin_utm.z();
497
498 t.transform.rotation.x = 0;
499 t.transform.rotation.y = 0;
500 t.transform.rotation.z = 0;
501 t.transform.rotation.w = 1;
502
503 bool northp = false;
504 int zone = 0;
506
507 std::string hemisphere;
508 if (northp) {
509 hemisphere = "N";
510 } else {
511 hemisphere = "S";
512 }
513
514 t.header.frame_id = "utm_" + std::to_string(zone) + hemisphere;
515 t.child_frame_id = map_frame_id_;
516 t.header.stamp = now();
517
518 // Send the transformation
519 tf_static_broadcaster_->sendTransform(t);
520 RCLCPP_INFO(get_logger(), "Broadcast static transform from '%s' to '%s'", t.header.frame_id.c_str(), t.child_frame_id.c_str());
521}
std::shared_ptr< tf2_ros::StaticTransformBroadcaster > tf_static_broadcaster_
static void derive_utm_zone(const double latitude, const double longitude, int &zone, bool &northp)
Derives the UTM zone and hemisphere from a geographic position.

◆ setup()

void Lanelet2MapServer::setup ( )
private

Sets up timers, callbacks, publishers, and initial map loading.

Definition at line 234 of file lanelet2_map_server.cpp.

234 {
235 // callback for dynamic parameter configuration
237 this->add_on_set_parameters_callback(std::bind(&Lanelet2MapServer::parametersCallback, this, std::placeholders::_1));
238
239 tf_static_broadcaster_ = std::make_shared<tf2_ros::StaticTransformBroadcaster>(this);
240
243 if (available_maps_.empty()) {
244 RCLCPP_ERROR(this->get_logger(), "No Lanelet2 maps found in '%s'", map_directory_.c_str());
246 }
247 // Create NavSatFix subscription and automatic map update timer
248 navsat_subscription_ = this->create_subscription<sensor_msgs::msg::NavSatFix>(
249 "~/gps/fix", 10, std::bind(&Lanelet2MapServer::navSatFixCallback, this, std::placeholders::_1));
251 this->create_wall_timer(std::chrono::seconds(1), std::bind(&Lanelet2MapServer::automaticMapUpdateTimerCallback, this));
252 } else {
255 RCLCPP_ERROR(this->get_logger(), "Could not derive lower-left origin from map '%s' in manual mode.",
256 map_filepath_.c_str());
258 return;
259 }
260 RCLCPP_INFO(this->get_logger(), "Derived manual origin from lower-left map corner for '%s' (lat=%.9f, lon=%.9f)",
262 } else if (origin_lat_set_ != origin_lon_set_) {
263 RCLCPP_ERROR(this->get_logger(),
264 "Manual mode requires both 'origin_lat' and 'origin_lon' when either is provided. Received origin_lat set=%s, "
265 "origin_lon set=%s.",
266 origin_lat_set_ ? "true" : "false", origin_lon_set_ ? "true" : "false");
268 return;
269 }
270
272 this->loadMapContents();
273 this->updateMapParameters();
274 this->pub_tf();
275 } else {
276 RCLCPP_ERROR(this->get_logger(), "Map sanity check failed for map '%s' with origin (lat=%.9f, lon=%.9f)",
279 }
280 }
281}
rclcpp::TimerBase::SharedPtr automatic_map_timer_
OnSetParametersCallbackHandle::SharedPtr parameters_callback_
Callback handle for dynamic parameter reconfiguration.
void automaticMapUpdateTimerCallback()
Periodically reevaluates the best map when automatic selection is enabled.
rcl_interfaces::msg::SetParametersResult parametersCallback(const std::vector< rclcpp::Parameter > &parameters)
Handles reconfiguration when a parameter value is changed.
void navSatFixCallback(const sensor_msgs::msg::NavSatFix::SharedPtr msg)
Stores the latest GNSS fix for automatic map selection.
rclcpp::Subscription< sensor_msgs::msg::NavSatFix >::SharedPtr navsat_subscription_

◆ unsetMapParameters()

void Lanelet2MapServer::unsetMapParameters ( )
private

Clears map-specific parameters after an invalid or unloaded map state.

Definition at line 457 of file lanelet2_map_server.cpp.

457 {
458 map_filepath_ = "";
459 map_contents_ = "";
460 origin_lat_ = 0.0;
461 origin_lon_ = 0.0;
462 origin_lat_set_ = false;
463 origin_lon_set_ = false;
465}

◆ updateMapParameters()

void Lanelet2MapServer::updateMapParameters ( )
private

Writes the current map state into this node's exported ROS parameters.

Definition at line 450 of file lanelet2_map_server.cpp.

450 {
451 this->set_parameter(rclcpp::Parameter("map_filepath", map_filepath_));
452 this->set_parameter(rclcpp::Parameter("map_contents", map_contents_));
453 this->set_parameter(rclcpp::Parameter("origin_lat", origin_lat_));
454 this->set_parameter(rclcpp::Parameter("origin_lon", origin_lon_));
455}

Member Data Documentation

◆ auto_reconfigurable_params_

std::vector<std::tuple<std::string, std::function<void(const rclcpp::Parameter&)> > > Lanelet2MapServer::auto_reconfigurable_params_
private

Auto-reconfigurable parameters for dynamic reconfiguration.

Definition at line 168 of file lanelet2_map_server.hpp.

◆ automatic_map_timer_

rclcpp::TimerBase::SharedPtr Lanelet2MapServer::automatic_map_timer_
private

Definition at line 176 of file lanelet2_map_server.hpp.

◆ available_maps_

std::vector<Lanelet2MapMeta> Lanelet2MapServer::available_maps_
private

Definition at line 181 of file lanelet2_map_server.hpp.

◆ current_latitude_

double Lanelet2MapServer::current_latitude_ = std::numeric_limits<double>::quiet_NaN()
private

Definition at line 192 of file lanelet2_map_server.hpp.

◆ current_longitude_

double Lanelet2MapServer::current_longitude_ = std::numeric_limits<double>::quiet_NaN()
private

Definition at line 193 of file lanelet2_map_server.hpp.

◆ gps_fix_received_

bool Lanelet2MapServer::gps_fix_received_ = false
private

Definition at line 194 of file lanelet2_map_server.hpp.

◆ map_contents_

std::string Lanelet2MapServer::map_contents_
private

Definition at line 184 of file lanelet2_map_server.hpp.

◆ map_directory_

std::string Lanelet2MapServer::map_directory_ = "/data/maps/default-maps"
private

Definition at line 180 of file lanelet2_map_server.hpp.

◆ map_filepath_

std::string Lanelet2MapServer::map_filepath_
private

Definition at line 182 of file lanelet2_map_server.hpp.

◆ map_frame_id_

std::string Lanelet2MapServer::map_frame_id_ = "map"
private

Definition at line 183 of file lanelet2_map_server.hpp.

◆ navsat_subscription_

rclcpp::Subscription<sensor_msgs::msg::NavSatFix>::SharedPtr Lanelet2MapServer::navsat_subscription_
private

Definition at line 191 of file lanelet2_map_server.hpp.

◆ one_shot_timer_

rclcpp::TimerBase::SharedPtr Lanelet2MapServer::one_shot_timer_
private

Definition at line 175 of file lanelet2_map_server.hpp.

◆ origin_lat_

double Lanelet2MapServer::origin_lat_
private

Definition at line 185 of file lanelet2_map_server.hpp.

◆ origin_lat_set_

bool Lanelet2MapServer::origin_lat_set_ = false
private

Definition at line 187 of file lanelet2_map_server.hpp.

◆ origin_lon_

double Lanelet2MapServer::origin_lon_
private

Definition at line 186 of file lanelet2_map_server.hpp.

◆ origin_lon_set_

bool Lanelet2MapServer::origin_lon_set_ = false
private

Definition at line 188 of file lanelet2_map_server.hpp.

◆ parameters_callback_

OnSetParametersCallbackHandle::SharedPtr Lanelet2MapServer::parameters_callback_
private

Callback handle for dynamic parameter reconfiguration.

Definition at line 173 of file lanelet2_map_server.hpp.

◆ tf_static_broadcaster_

std::shared_ptr<tf2_ros::StaticTransformBroadcaster> Lanelet2MapServer::tf_static_broadcaster_
private

Definition at line 190 of file lanelet2_map_server.hpp.

◆ use_automatic_map_selection_

bool Lanelet2MapServer::use_automatic_map_selection_ = false
private

Definition at line 178 of file lanelet2_map_server.hpp.


The documentation for this class was generated from the following files: