Skip to content

Commit 1d94a1c

Browse files
committed
add grid_map_msgs/GridMap topic type
1 parent 1e47740 commit 1d94a1c

File tree

9 files changed

+234
-6
lines changed

9 files changed

+234
-6
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ find_package(rclcpp REQUIRED)
1515
find_package(std_msgs REQUIRED)
1616
find_package(sensor_msgs REQUIRED)
1717
find_package(nav_msgs REQUIRED)
18+
find_package(grid_map_msgs REQUIRED)
1819
find_package(visualization_msgs REQUIRED)
1920
find_package(tf2 REQUIRED)
2021
find_package(tf2_msgs REQUIRED)
@@ -36,6 +37,7 @@ set(INCLUDE_DIRS
3637
${std_msgs_INCLUDE_DIRS}
3738
${sensor_msgs_INCLUDE_DIRS}
3839
${nav_msgs_INCLUDE_DIRS}
40+
${grid_map_msgs_INCLUDE_DIRS}
3941
${rclcpp_components_INCLUDE_DIRS}
4042
)
4143
include_directories(${INCLUDE_DIRS})
@@ -46,6 +48,7 @@ set(ament_dependencies
4648
std_msgs
4749
sensor_msgs
4850
nav_msgs
51+
grid_map_msgs
4952
visualization_msgs
5053
tf2
5154
tf2_msgs

README.md

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# `pointcloud_to_grid` ROS 2 package
2-
This package converts `sensor_msgs/PointCloud2` LIDAR data to `nav_msgs/OccupancyGrid` 2D map data based on intensity and / or height.
2+
This package converts `sensor_msgs/PointCloud2` LIDAR data to both `nav_msgs/OccupancyGrid` and `grid_map_msgs/GridMap` 2D map data based on intensity and / or height.
33
![](doc/grid_map01.gif)
44

55
[![Static Badge](https://img.shields.io/badge/ROS_2-Humble-34aec5)](https://docs.ros.org/en/humble/)
@@ -17,7 +17,8 @@ Don't foget to `source ~/ros2_ws/install/setup.bash`.
1717

1818

1919
## Features
20-
- Few dependencies (ROS 2 and PCL mainly) [ROS installation](http://wiki.ros.org/ROS/Installation)
20+
- Few dependencies (ROS 2, PCL, and grid_map_msgs mainly) [ROS installation](http://wiki.ros.org/ROS/Installation)
21+
- **Dual output format support**: Publishes both `nav_msgs/OccupancyGrid` and `grid_map_msgs/GridMap` messages simultaneously
2122
- Simple as possible
2223
- Fast
2324

@@ -58,6 +59,42 @@ Start the visualization in a **new terminal** :
5859
ros2 launch pointcloud_to_grid rviz.launch.py
5960
```
6061

62+
## Dual Output Format Support
63+
64+
The package now supports publishing both `nav_msgs/OccupancyGrid` and `grid_map_msgs/GridMap` message types simultaneously. This allows for better integration with different ROS 2 packages that may prefer one format over the other.
65+
66+
### New Parameters
67+
68+
In addition to the existing parameters, the following new parameters control the GridMap output topics:
69+
70+
| Parameter | Type | Default | Description |
71+
|-----------|------|---------|-------------|
72+
| `mapi_gridmap_topic_name` | string | `intensity_gridmap` | Topic name for intensity GridMap |
73+
| `maph_gridmap_topic_name` | string | `height_gridmap` | Topic name for height GridMap |
74+
75+
### Output Topics
76+
77+
The node now publishes to four topics simultaneously:
78+
79+
**OccupancyGrid format:**
80+
- `intensity_grid` (`nav_msgs/OccupancyGrid`)
81+
- `height_grid` (`nav_msgs/OccupancyGrid`)
82+
83+
**GridMap format:**
84+
- `intensity_gridmap` (`grid_map_msgs/GridMap`)
85+
- `height_gridmap` (`grid_map_msgs/GridMap`)
86+
87+
### Usage Example
88+
89+
```bash
90+
# Launch with custom GridMap topic names
91+
ros2 launch pointcloud_to_grid demo.launch.py topic:=my_pointcloud mapi_gridmap_topic_name:=my_intensity_map maph_gridmap_topic_name:=my_height_map
92+
```
93+
94+
## QoS Configuration
95+
96+
The package is configured to use `BEST_EFFORT` reliability QoS policy for the input point cloud subscription. This ensures compatibility with typical LiDAR sensor publishers that often use this policy for performance reasons. This prevents QoS compatibility warnings that might appear with the default `RELIABLE` policy.
97+
6198

6299
## Related solutions
63100
- [github.com/ANYbotics/grid_map](https://github.com/ANYbotics/grid_map) - This is a C++ library with ROS interface to manage two-dimensional grid maps with multiple data layers.

include/pointcloud_to_grid/pointcloud_to_grid_core.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#pragma once
22
#include "rclcpp/rclcpp.hpp"
33
#include "nav_msgs/msg/occupancy_grid.hpp"
4+
#include "grid_map_msgs/msg/grid_map.hpp"
45
#include <memory>
56
class PointXY
67
{
@@ -30,6 +31,8 @@ class GridMap
3031
std::string frame_out;
3132
std::string mapi_topic_name;
3233
std::string maph_topic_name;
34+
std::string mapi_gridmap_topic_name;
35+
std::string maph_gridmap_topic_name;
3336
float topleft_x;
3437
float topleft_y;
3538
float bottomright_x;
@@ -56,6 +59,38 @@ class GridMap
5659
// resolution/grid size [m/cell]
5760
}
5861

62+
void initGridMap(std::shared_ptr<grid_map_msgs::msg::GridMap> grid_map_msg, const std::string& layer_name)
63+
{
64+
grid_map_msg->header.frame_id = GridMap::frame_out;
65+
grid_map_msg->info.resolution = cell_size;
66+
grid_map_msg->info.length_x = length_x;
67+
grid_map_msg->info.length_y = length_y;
68+
grid_map_msg->info.pose.position.x = position_x;
69+
grid_map_msg->info.pose.position.y = position_y;
70+
grid_map_msg->info.pose.position.z = 0.0;
71+
grid_map_msg->info.pose.orientation.w = 1.0;
72+
grid_map_msg->info.pose.orientation.x = 0.0;
73+
grid_map_msg->info.pose.orientation.y = 0.0;
74+
grid_map_msg->info.pose.orientation.z = 0.0;
75+
76+
// Clear existing layers and add the new one
77+
grid_map_msg->layers.clear();
78+
grid_map_msg->layers.push_back(layer_name);
79+
80+
// Initialize data array
81+
grid_map_msg->data.clear();
82+
grid_map_msg->data.resize(1); // One layer
83+
grid_map_msg->data[0].layout.dim.resize(2);
84+
grid_map_msg->data[0].layout.dim[0].label = "column_index";
85+
grid_map_msg->data[0].layout.dim[0].size = cell_num_y;
86+
grid_map_msg->data[0].layout.dim[0].stride = cell_num_x * cell_num_y;
87+
grid_map_msg->data[0].layout.dim[1].label = "row_index";
88+
grid_map_msg->data[0].layout.dim[1].size = cell_num_x;
89+
grid_map_msg->data[0].layout.dim[1].stride = cell_num_x;
90+
grid_map_msg->data[0].layout.data_offset = 0;
91+
grid_map_msg->data[0].data.resize(cell_num_x * cell_num_y);
92+
}
93+
5994
void paramRefresh()
6095
{
6196
topleft_x = position_x + length_x / 2;

launch/demo.launch.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ def generate_launch_description():
2424
{'length_x': 40.0},
2525
{'length_y': 60.0},
2626
#{'frame_out': 'os1_sensor'},
27+
# OccupancyGrid topics
2728
{'mapi_topic_name': 'intensity_grid'},
2829
{'maph_topic_name': 'height_grid'},
30+
# GridMap topics
31+
{'mapi_gridmap_topic_name': 'intensity_gridmap'},
32+
{'maph_gridmap_topic_name': 'height_gridmap'},
2933
]
3034
)
3135

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
#!/usr/bin/env python3
2+
3+
from launch import LaunchDescription
4+
from launch_ros.actions import Node
5+
from launch.actions import DeclareLaunchArgument
6+
from launch.substitutions import LaunchConfiguration
7+
8+
def generate_launch_description():
9+
return LaunchDescription([
10+
DeclareLaunchArgument(
11+
'cell_size',
12+
default_value='0.5',
13+
description='Cell size for the grid map [m/cell]'
14+
),
15+
DeclareLaunchArgument(
16+
'length_x',
17+
default_value='20.0',
18+
description='Length in x-direction [m]'
19+
),
20+
DeclareLaunchArgument(
21+
'length_y',
22+
default_value='30.0',
23+
description='Length in y-direction [m]'
24+
),
25+
DeclareLaunchArgument(
26+
'cloud_in_topic',
27+
default_value='nonground',
28+
description='Input point cloud topic'
29+
),
30+
31+
Node(
32+
package='pointcloud_to_grid',
33+
executable='pointcloud_to_grid_node',
34+
name='pointcloud_to_grid_dual',
35+
parameters=[{
36+
'cell_size': LaunchConfiguration('cell_size'),
37+
'length_x': LaunchConfiguration('length_x'),
38+
'length_y': LaunchConfiguration('length_y'),
39+
'cloud_in_topic': LaunchConfiguration('cloud_in_topic'),
40+
# OccupancyGrid topics
41+
'mapi_topic_name': 'intensity_grid',
42+
'maph_topic_name': 'height_grid',
43+
# GridMap topics
44+
'mapi_gridmap_topic_name': 'intensity_gridmap',
45+
'maph_gridmap_topic_name': 'height_gridmap',
46+
'verbose1': True,
47+
}],
48+
output='screen'
49+
)
50+
])

launch/grid_trajectory.launch.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ def generate_launch_description():
2424
{'length_x': 40.0}, # meters
2525
{'length_y': 60.0}, # meters
2626
#{'frame_out': 'os1_sensor'},
27+
# OccupancyGrid topics
2728
{'mapi_topic_name': 'intensity_grid'},
2829
{'maph_topic_name': 'height_grid'},
30+
# GridMap topics
31+
{'mapi_gridmap_topic_name': 'intensity_gridmap'},
32+
{'maph_gridmap_topic_name': 'height_gridmap'},
2933
{'search_length': 4.0}, # meters
3034
{'search_range_deg': 80.0}, # degrees
3135
{'search_resolution_deg': 0.5}, # degrees

package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
<depend>sensor_msgs</depend>
1818
<depend>nav_msgs</depend>
1919
<depend>visualization_msgs</depend>
20+
<depend>grid_map_msgs</depend>
2021
<depend>tf2_msgs</depend>
2122
<depend>tf2</depend>
2223
<depend>tf2_ros</depend>

src/grid_trajectory.cpp

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// ROS
22
#include "rclcpp/rclcpp.hpp"
33
#include "nav_msgs/msg/occupancy_grid.hpp"
4+
#include "grid_map_msgs/msg/grid_map.hpp"
45
#include "sensor_msgs/msg/point_cloud.hpp"
56
#include "sensor_msgs/msg/point_cloud2.hpp"
67
#include "visualization_msgs/msg/marker_array.hpp"
@@ -26,6 +27,8 @@
2627
// nav_msgs::msg::OccupancyGrid::Ptr height_grid(new nav_msgs::msg::OccupancyGrid);
2728
auto height_grid = std::make_shared<nav_msgs::msg::OccupancyGrid>();
2829
auto intensity_grid = std::make_shared<nav_msgs::msg::OccupancyGrid>();
30+
auto height_gridmap = std::make_shared<grid_map_msgs::msg::GridMap>();
31+
auto intensity_gridmap = std::make_shared<grid_map_msgs::msg::GridMap>();
2932
class PointCloudToGrid : public rclcpp::Node
3033
{
3134
rcl_interfaces::msg::SetParametersResult parametersCallback(const std::vector<rclcpp::Parameter> &parameters)
@@ -46,10 +49,24 @@ class PointCloudToGrid : public rclcpp::Node
4649
grid_map.maph_topic_name = param.as_string();
4750
pub_hgrid = this->create_publisher<nav_msgs::msg::OccupancyGrid>(grid_map.maph_topic_name, 10);
4851
}
52+
if (param.get_name() == "mapi_gridmap_topic_name")
53+
{
54+
grid_map.mapi_gridmap_topic_name = param.as_string();
55+
pub_igridmap = this->create_publisher<grid_map_msgs::msg::GridMap>(grid_map.mapi_gridmap_topic_name, 10);
56+
}
57+
if (param.get_name() == "maph_gridmap_topic_name")
58+
{
59+
grid_map.maph_gridmap_topic_name = param.as_string();
60+
pub_hgridmap = this->create_publisher<grid_map_msgs::msg::GridMap>(grid_map.maph_gridmap_topic_name, 10);
61+
}
4962
if (param.get_name() == "cloud_in_topic")
5063
{
5164
cloud_in_topic = param.as_string();
52-
sub_pc2_ = this->create_subscription<sensor_msgs::msg::PointCloud2>(cloud_in_topic, 10, std::bind(&PointCloudToGrid::lidar_callback, this, std::placeholders::_1));
65+
// Configure QoS for sensor data - use BEST_EFFORT reliability to match typical sensor publishers
66+
auto sensor_qos = rclcpp::QoS(10).reliability(RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT);
67+
sub_pc2_ = this->create_subscription<sensor_msgs::msg::PointCloud2>(
68+
cloud_in_topic, sensor_qos,
69+
std::bind(&PointCloudToGrid::lidar_callback, this, std::placeholders::_1));
5370
}
5471
if (param.get_name() == "cell_size")
5572
{
@@ -114,6 +131,8 @@ class PointCloudToGrid : public rclcpp::Node
114131
{
115132
this->declare_parameter<std::string>("mapi_topic_name", "intensity_grid");
116133
this->declare_parameter<std::string>("maph_topic_name", "height_grid");
134+
this->declare_parameter<std::string>("mapi_gridmap_topic_name", "intensity_gridmap");
135+
this->declare_parameter<std::string>("maph_gridmap_topic_name", "height_gridmap");
117136
this->declare_parameter<std::string>("cloud_in_topic", cloud_in_topic);
118137
this->declare_parameter<float>("cell_size", 0.5);
119138
this->declare_parameter<float>("position_x", 0.0);
@@ -131,6 +150,8 @@ class PointCloudToGrid : public rclcpp::Node
131150

132151
this->get_parameter("mapi_topic_name", grid_map.mapi_topic_name);
133152
this->get_parameter("maph_topic_name", grid_map.maph_topic_name);
153+
this->get_parameter("mapi_gridmap_topic_name", grid_map.mapi_gridmap_topic_name);
154+
this->get_parameter("maph_gridmap_topic_name", grid_map.maph_gridmap_topic_name);
134155
this->get_parameter("cloud_in_topic", cloud_in_topic);
135156
this->get_parameter("cell_size", grid_map.cell_size);
136157
this->get_parameter("position_x", grid_map.position_x);
@@ -150,12 +171,20 @@ class PointCloudToGrid : public rclcpp::Node
150171

151172
pub_igrid = this->create_publisher<nav_msgs::msg::OccupancyGrid>(grid_map.mapi_topic_name, 10);
152173
pub_hgrid = this->create_publisher<nav_msgs::msg::OccupancyGrid>(grid_map.maph_topic_name, 10);
174+
pub_igridmap = this->create_publisher<grid_map_msgs::msg::GridMap>(grid_map.mapi_gridmap_topic_name, 10);
175+
pub_hgridmap = this->create_publisher<grid_map_msgs::msg::GridMap>(grid_map.maph_gridmap_topic_name, 10);
153176
pub_marker = this->create_publisher<visualization_msgs::msg::MarkerArray>("debug_marker", 10);
154-
sub_pc2_ = this->create_subscription<sensor_msgs::msg::PointCloud2>(cloud_in_topic, 10, std::bind(&PointCloudToGrid::lidar_callback, this, std::placeholders::_1));
177+
178+
// Configure QoS for sensor data - use BEST_EFFORT reliability to match typical sensor publishers
179+
auto sensor_qos = rclcpp::QoS(10).reliability(RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT);
180+
sub_pc2_ = this->create_subscription<sensor_msgs::msg::PointCloud2>(
181+
cloud_in_topic, sensor_qos,
182+
std::bind(&PointCloudToGrid::lidar_callback, this, std::placeholders::_1));
155183
callback_handle_ = this->add_on_set_parameters_callback(std::bind(&PointCloudToGrid::parametersCallback, this, std::placeholders::_1));
156184
RCLCPP_INFO_STREAM(this->get_logger(), "pointcloud_to_grid_node has been started.");
157185
RCLCPP_INFO_STREAM(this->get_logger(), "Subscribing to: " << cloud_in_topic.c_str());
158186
RCLCPP_INFO_STREAM(this->get_logger(), "Publishing to: " << grid_map.mapi_topic_name.c_str() << " and " << grid_map.maph_topic_name.c_str());
187+
RCLCPP_INFO_STREAM(this->get_logger(), "Publishing GridMaps to: " << grid_map.mapi_gridmap_topic_name.c_str() << " and " << grid_map.maph_gridmap_topic_name.c_str());
159188
}
160189

161190
private:
@@ -180,6 +209,8 @@ class PointCloudToGrid : public rclcpp::Node
180209
// Initialize grid
181210
grid_map.initGrid(intensity_grid);
182211
grid_map.initGrid(height_grid);
212+
grid_map.initGridMap(intensity_gridmap, "intensity");
213+
grid_map.initGridMap(height_gridmap, "height");
183214
// width*height/cell_size^2 eg width = 20m, height = 30m, cell_size data size = 6000
184215
// or cell_num_x * cell_num_ys
185216
// -128 127 int8[] data
@@ -299,8 +330,23 @@ class PointCloudToGrid : public rclcpp::Node
299330
height_grid->info.map_load_time = this->now();
300331
height_grid->data = hpoints;
301332

333+
// Convert to GridMap format
334+
intensity_gridmap->header.stamp = this->now();
335+
intensity_gridmap->header.frame_id = input_msg->header.frame_id;
336+
for (size_t i = 0; i < ipoints.size(); ++i) {
337+
intensity_gridmap->data[0].data[i] = static_cast<float>(ipoints[i]) / 127.0f; // Normalize to float
338+
}
339+
340+
height_gridmap->header.stamp = this->now();
341+
height_gridmap->header.frame_id = input_msg->header.frame_id;
342+
for (size_t i = 0; i < hpoints.size(); ++i) {
343+
height_gridmap->data[0].data[i] = static_cast<float>(hpoints[i]) / 127.0f; // Normalize to float
344+
}
345+
302346
pub_hgrid->publish(*height_grid);
303347
pub_igrid->publish(*intensity_grid);
348+
pub_hgridmap->publish(*height_gridmap);
349+
pub_igridmap->publish(*intensity_gridmap);
304350
pub_marker->publish(mark_array);
305351
// pub_hgrid->publish(height_grid);
306352
if (verbose1)
@@ -310,6 +356,7 @@ class PointCloudToGrid : public rclcpp::Node
310356
}
311357

312358
rclcpp::Publisher<nav_msgs::msg::OccupancyGrid>::SharedPtr pub_igrid, pub_hgrid;
359+
rclcpp::Publisher<grid_map_msgs::msg::GridMap>::SharedPtr pub_igridmap, pub_hgridmap;
313360
rclcpp::Publisher<visualization_msgs::msg::MarkerArray>::SharedPtr pub_marker;
314361
rclcpp::Subscription<sensor_msgs::msg::PointCloud2>::SharedPtr sub_pc2_;
315362
OnSetParametersCallbackHandle::SharedPtr callback_handle_;

0 commit comments

Comments
 (0)