Skip to content

Commit 45c4b33

Browse files
committed
feat(autoware_map_loader): add support of GetSelectedLanelet2Map service
Signed-off-by: Ryohsuke Mitsudome <ryohsuke.mitsudome@tier4.jp>
1 parent a2a83b7 commit 45c4b33

13 files changed

Lines changed: 817 additions & 1 deletion

map/autoware_map_loader/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ rclcpp_components_register_node(pointcloud_map_loader_node
3030
ament_auto_add_library(lanelet2_map_loader_node SHARED
3131
src/lanelet2_map_loader/lanelet2_map_loader_node.cpp
3232
src/lanelet2_map_loader/lanelet2_map_loader_utils.cpp
33+
src/lanelet2_map_loader/lanelet2_map_cell_metadata.cpp
34+
src/lanelet2_map_loader/lanelet2_selected_map_loader_module.cpp
3335
)
3436

3537
rclcpp_components_register_node(lanelet2_map_loader_node
@@ -66,6 +68,8 @@ if(BUILD_TESTING)
6668
add_testcase(test/test_partial_map_loader_module.cpp)
6769
add_testcase(test/test_differential_map_loader_module.cpp)
6870
add_testcase(test/test_lanelet2_map_loader_utils.cpp)
71+
add_testcase(test/test_lanelet2_map_cell_metadata.cpp)
72+
add_testcase(test/test_lanelet2_selected_map_loader_module.cpp)
6973
endif()
7074

7175
install(PROGRAMS

map/autoware_map_loader/README.md

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,39 @@ Please see [autoware_map_msgs/msg/MapProjectorInfo.msg](https://github.com/autow
137137
`lanelet2_map_path` can point to either a single `.osm` file or a directory.
138138
When a directory is given, all `.osm` files inside are loaded and merged into a single map before publishing.
139139

140+
#### Selected map loading (`enable_selected_map_loading`)
141+
142+
When `enable_selected_map_loading` is `true`, the node additionally:
143+
144+
- Publishes per-cell bounding-box metadata on `output/lanelet2_map_metadata`.
145+
- Exposes the `service/get_selected_lanelet2_map` service
146+
(`autoware_map_msgs/srv/GetSelectedLanelet2Map`), which returns the binary
147+
map for the requested set of cell IDs.
148+
149+
Cell IDs equal the absolute file path of the corresponding `.osm` file.
150+
151+
##### Cell metadata source
152+
153+
The node determines bounding boxes for each cell in one of two ways:
154+
155+
1. **From a metadata YAML file** — when `metadata_file_path` points to an
156+
existing file. The expected format is:
157+
158+
```yaml
159+
x_resolution: 100.0
160+
y_resolution: 100.0
161+
1.osm: [58700.0, 42500.0] # [min_x, min_y] of this cell
162+
2.osm: [58800.0, 42500.0]
163+
```
164+
165+
Relative filenames are resolved against the directory that contains the
166+
YAML file. The bounding box of each cell is
167+
`[min_x, min_y, min_x + x_resolution, min_y + y_resolution]`.
168+
169+
2. **Computed from the loaded map** — when `metadata_file_path` is empty or
170+
the file does not exist, the axis-aligned bounding box is derived from all
171+
points in each loaded map.
172+
140173
### How to run
141174

142175
`ros2 run autoware_map_loader lanelet2_map_loader --ros-args -p lanelet2_map_path:=path/to/map.osm`
@@ -147,7 +180,12 @@ When a directory is given, all `.osm` files inside are loaded and merged into a
147180

148181
### Published Topics
149182

150-
- ~output/lanelet2_map (autoware_map_msgs/LaneletMapBin) : Binary data of loaded Lanelet2 Map
183+
- `/map/vector_map` (autoware_map_msgs/LaneletMapBin) : Merged binary Lanelet2 map
184+
- `output/lanelet2_map_metadata` (autoware_map_msgs/LaneletMapMetaData) : Per-cell bounding-box metadata *(only when `enable_selected_map_loading` is `true`)*
185+
186+
### Services
187+
188+
- `service/get_selected_lanelet2_map` (autoware_map_msgs/srv/GetSelectedLanelet2Map) : Returns the binary map for a requested set of cell IDs *(only when `enable_selected_map_loading` is `true`)*
151189

152190
### Parameters
153191

map/autoware_map_loader/config/lanelet2_map_loader.param.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
center_line_resolution: 5.0 # [m]
55
use_waypoints: true # "centerline" in the Lanelet2 map will be used as a "waypoints" tag.
66
lanelet2_map_path: $(var lanelet2_map_path) # Path to a lanelet2 .osm map file, or a directory containing .osm files
7+
enable_selected_map_loading: false # expose service/get_selected_lanelet2_map and publish cell metadata
8+
metadata_file_path: $(var metadata_file_path) # path to lanelet2_map_metadata.yaml; if empty or missing, bboxes are computed from map points

map/autoware_map_loader/include/autoware/map_loader/lanelet2_map_loader_node.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,18 @@
2929

3030
namespace autoware::map_loader
3131
{
32+
33+
// Forward declaration — full definition lives in the private source directory.
34+
class Lanelet2SelectedMapLoaderModule;
35+
3236
class Lanelet2MapLoaderNode : public rclcpp::Node
3337
{
3438
public:
3539
static constexpr lanelet::autoware::Version version = lanelet::autoware::version;
3640

3741
public:
3842
explicit Lanelet2MapLoaderNode(const rclcpp::NodeOptions & options);
43+
~Lanelet2MapLoaderNode(); // defined in .cpp so unique_ptr can see the full module type
3944

4045
static lanelet::LaneletMapPtr load_map(
4146
const std::string & lanelet2_filename,
@@ -51,6 +56,8 @@ class Lanelet2MapLoaderNode : public rclcpp::Node
5156

5257
rclcpp::Subscription<MapProjectorInfo::Message>::SharedPtr sub_map_projector_info_;
5358
rclcpp::Publisher<VectorMap::Message>::SharedPtr pub_map_bin_;
59+
60+
std::unique_ptr<Lanelet2SelectedMapLoaderModule> selected_map_loader_module_;
5461
};
5562
} // namespace autoware::map_loader
5663

map/autoware_map_loader/launch/lanelet2_map_loader.launch.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<launch>
22
<arg name="lanelet2_map_loader_param_path" default="$(find-pkg-share autoware_map_loader)/config/lanelet2_map_loader.param.yaml"/>
33
<arg name="lanelet2_map_path"/>
4+
<arg name="metadata_file_path" default=""/>
45
<arg name="lanelet2_map_topic" default="vector_map"/>
56
<arg name="lanelet2_map_marker_topic" default="vector_map_marker"/>
67

map/autoware_map_loader/schema/lanelet2_map_loader.schema.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,16 @@
2525
"type": "string",
2626
"description": "Path to a lanelet2 .osm map file, or a directory containing .osm files",
2727
"default": ""
28+
},
29+
"enable_selected_map_loading": {
30+
"type": "boolean",
31+
"description": "Expose service/get_selected_lanelet2_map and publish per-cell metadata.",
32+
"default": false
33+
},
34+
"metadata_file_path": {
35+
"type": "string",
36+
"description": "Path to lanelet2_map_metadata.yaml. If empty or missing, bounding boxes are computed from the loaded map points.",
37+
"default": ""
2838
}
2939
},
3040
"required": ["center_line_resolution", "use_waypoints", "lanelet2_map_path"],
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2024 The Autoware Contributors
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+
#include "lanelet2_map_cell_metadata.hpp"
16+
17+
#include <yaml-cpp/yaml.h>
18+
19+
#include <filesystem>
20+
#include <limits>
21+
#include <map>
22+
#include <optional>
23+
#include <string>
24+
25+
namespace autoware::map_loader::utils
26+
{
27+
28+
Lanelet2FileMetaData compute_cell_metadata(
29+
const std::string & cell_id, const lanelet::LaneletMap & map)
30+
{
31+
double min_x = std::numeric_limits<double>::max();
32+
double min_y = std::numeric_limits<double>::max();
33+
double max_x = std::numeric_limits<double>::lowest();
34+
double max_y = std::numeric_limits<double>::lowest();
35+
36+
for (const lanelet::ConstPoint3d & pt : map.pointLayer) {
37+
if (pt.x() < min_x) min_x = pt.x();
38+
if (pt.y() < min_y) min_y = pt.y();
39+
if (pt.x() > max_x) max_x = pt.x();
40+
if (pt.y() > max_y) max_y = pt.y();
41+
}
42+
43+
if (map.pointLayer.empty()) {
44+
min_x = max_x = min_y = max_y = 0.0;
45+
}
46+
47+
return {cell_id, min_x, min_y, max_x, max_y};
48+
}
49+
50+
std::optional<std::map<std::string, Lanelet2FileMetaData>> load_cell_metadata_from_yaml(
51+
const std::string & yaml_path)
52+
{
53+
if (!std::filesystem::exists(yaml_path)) {
54+
return std::nullopt;
55+
}
56+
57+
const std::filesystem::path map_dir = std::filesystem::path(yaml_path).parent_path();
58+
59+
const YAML::Node node = YAML::LoadFile(yaml_path);
60+
const double x_res = node["x_resolution"].as<double>();
61+
const double y_res = node["y_resolution"].as<double>();
62+
63+
std::map<std::string, Lanelet2FileMetaData> result;
64+
for (const auto & kv : node) {
65+
const std::string key = kv.first.as<std::string>();
66+
if (key == "x_resolution" || key == "y_resolution") {
67+
continue;
68+
}
69+
const double min_x = kv.second[0].as<double>();
70+
const double min_y = kv.second[1].as<double>();
71+
const std::string abs_path = (map_dir / key).string();
72+
result[abs_path] = {abs_path, min_x, min_y, min_x + x_res, min_y + y_res};
73+
}
74+
75+
return result;
76+
}
77+
78+
} // namespace autoware::map_loader::utils
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2024 The Autoware Contributors
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+
#ifndef LANELET2_MAP_LOADER__LANELET2_MAP_CELL_METADATA_HPP_
16+
#define LANELET2_MAP_LOADER__LANELET2_MAP_CELL_METADATA_HPP_
17+
18+
#include <lanelet2_core/LaneletMap.h>
19+
20+
#include <map>
21+
#include <optional>
22+
#include <string>
23+
24+
namespace autoware::map_loader
25+
{
26+
27+
/// @brief Bounding-box metadata for a single lanelet2 map cell (one OSM file).
28+
///
29+
/// The bounding box covers all points in the loaded map, making it accurate without
30+
/// an external metadata file or a fixed grid resolution.
31+
/// @p id equals the absolute file path and serves as the cell identifier in
32+
/// `GetSelectedLanelet2Map` requests.
33+
struct Lanelet2FileMetaData
34+
{
35+
std::string id; ///< Unique cell identifier (== absolute file path).
36+
double min_x;
37+
double min_y;
38+
double max_x;
39+
double max_y;
40+
};
41+
42+
} // namespace autoware::map_loader
43+
44+
namespace autoware::map_loader::utils
45+
{
46+
47+
/// @brief Compute the axis-aligned bounding box of all points in @p map.
48+
/// If the map has no points all coordinates are set to 0.
49+
Lanelet2FileMetaData compute_cell_metadata(
50+
const std::string & cell_id, const lanelet::LaneletMap & map);
51+
52+
/// @brief Load per-cell bounding-box metadata from @p yaml_path.
53+
///
54+
/// The expected YAML format is:
55+
/// @code
56+
/// x_resolution: 100.0
57+
/// y_resolution: 100.0
58+
/// 1.osm: [58700.0, 42500.0] # [min_x, min_y] of that cell
59+
/// 2.osm: [58800.0, 42500.0]
60+
/// ...
61+
/// @endcode
62+
///
63+
/// Cell bounding boxes are `[min_x, min_y, min_x + x_resolution, min_y + y_resolution]`.
64+
/// Relative filename keys are resolved against the parent directory of @p yaml_path.
65+
///
66+
/// @return Populated metadata dict on success, or `std::nullopt` if the file does not exist or
67+
/// cannot be parsed.
68+
std::optional<std::map<std::string, Lanelet2FileMetaData>> load_cell_metadata_from_yaml(
69+
const std::string & yaml_path);
70+
71+
} // namespace autoware::map_loader::utils
72+
73+
#endif // LANELET2_MAP_LOADER__LANELET2_MAP_CELL_METADATA_HPP_

map/autoware_map_loader/src/lanelet2_map_loader/lanelet2_map_loader_node.cpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,9 @@
3434
#include "autoware/map_loader/lanelet2_map_loader_node.hpp"
3535

3636
#include "lanelet2_local_projector.hpp"
37+
#include "lanelet2_map_cell_metadata.hpp"
3738
#include "lanelet2_map_loader_utils.hpp"
39+
#include "lanelet2_selected_map_loader_module.hpp"
3840

3941
#include <autoware/geography_utils/lanelet2_projector.hpp>
4042
#include <autoware/lanelet2_utils/conversion.hpp>
@@ -49,13 +51,17 @@
4951
#include <lanelet2_io/Io.h>
5052
#include <lanelet2_projection/UTM.h>
5153

54+
#include <filesystem>
55+
#include <map>
5256
#include <memory>
57+
#include <optional>
5358
#include <stdexcept>
5459
#include <string>
5560
#include <vector>
5661

5762
namespace autoware::map_loader
5863
{
64+
5965
using autoware_map_msgs::msg::LaneletMapBin;
6066
using autoware_map_msgs::msg::MapProjectorInfo;
6167

@@ -71,15 +77,24 @@ Lanelet2MapLoaderNode::Lanelet2MapLoaderNode(const rclcpp::NodeOptions & options
7177
declare_parameter<std::string>("lanelet2_map_path");
7278
declare_parameter<double>("center_line_resolution");
7379
declare_parameter<bool>("use_waypoints");
80+
declare_parameter<bool>("enable_selected_map_loading");
81+
declare_parameter<std::string>("metadata_file_path");
7482
}
7583

84+
// Defined here so the compiler sees the full type of Lanelet2SelectedMapLoaderModule
85+
// when generating the unique_ptr destructor.
86+
Lanelet2MapLoaderNode::~Lanelet2MapLoaderNode() = default;
87+
7688
void Lanelet2MapLoaderNode::on_map_projector_info(
7789
const MapProjectorInfo::Message::ConstSharedPtr msg)
7890
{
7991
const auto allow_unsupported_version = get_parameter("allow_unsupported_version").as_bool();
8092
const auto lanelet2_map_path = get_parameter("lanelet2_map_path").as_string();
8193
const auto center_line_resolution = get_parameter("center_line_resolution").as_double();
8294
const auto use_waypoints = get_parameter("use_waypoints").as_bool();
95+
const auto enable_selected_map_loading =
96+
get_parameter("enable_selected_map_loading").as_bool();
97+
const auto metadata_file_path = get_parameter("metadata_file_path").as_string();
8398

8499
// get lanelet2 file paths (handles both a single .osm file and a directory)
85100
const std::vector<std::string> lanelet2_paths = utils::get_lanelet2_paths(lanelet2_map_path);
@@ -101,6 +116,26 @@ void Lanelet2MapLoaderNode::on_map_projector_info(
101116
maps.push_back(map_tmp);
102117
}
103118

119+
if (enable_selected_map_loading) {
120+
std::map<std::string, Lanelet2FileMetaData> cell_metadata_dict;
121+
122+
const auto yaml_metadata = utils::load_cell_metadata_from_yaml(metadata_file_path);
123+
if (yaml_metadata) {
124+
cell_metadata_dict = *yaml_metadata;
125+
RCLCPP_INFO(get_logger(), "Loaded cell metadata from %s.", metadata_file_path.c_str());
126+
} else {
127+
for (size_t i = 0; i < lanelet2_paths.size(); ++i) {
128+
cell_metadata_dict[lanelet2_paths[i]] =
129+
utils::compute_cell_metadata(lanelet2_paths[i], *maps[i]);
130+
}
131+
}
132+
133+
selected_map_loader_module_ = std::make_unique<Lanelet2SelectedMapLoaderModule>(
134+
this, std::move(cell_metadata_dict), *msg, center_line_resolution, use_waypoints);
135+
136+
RCLCPP_INFO(get_logger(), "Selected lanelet2 map loading is enabled.");
137+
}
138+
104139
// merge all loaded maps into a new empty map
105140
auto map = std::make_shared<lanelet::LaneletMap>();
106141
for (auto & loaded_map : maps) {

0 commit comments

Comments
 (0)