Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
costmap_2d_cloud.cpp
1 /*
2  * Copyright (C) 2009, Willow Garage, Inc.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  * * Redistributions of source code must retain the above copyright notice,
7  * this list of conditions and the following disclaimer.
8  * * Redistributions in binary form must reproduce the above copyright
9  * notice, this list of conditions and the following disclaimer in the
10  * documentation and/or other materials provided with the distribution.
11  * * Neither the names of Stanford University or Willow Garage, Inc. nor the names of its
12  * contributors may be used to endorse or promote products derived from
13  * this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25  * POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 #include <string>
29 #include <vector>
30 #include <memory>
31 #include <utility>
32 
33 #include "rclcpp/executors.hpp"
34 #include "rclcpp/logging.hpp"
35 #include "rclcpp/node.hpp"
36 #include "rclcpp/publisher.hpp"
37 #include "rclcpp/time.hpp"
38 #include "rclcpp/utilities.hpp"
39 #include "sensor_msgs/msg/point_cloud2.hpp"
40 #include "sensor_msgs/point_cloud2_iterator.hpp"
41 #include "nav2_voxel_grid/voxel_grid.hpp"
42 #include "nav2_msgs/msg/voxel_grid.hpp"
43 #include "nav2_util/execution_timer.hpp"
44 #include "nav2_ros_common/lifecycle_node.hpp"
45 
46 static inline void mapToWorld3D(
47  const unsigned int mx,
48  const unsigned int my, const unsigned int mz,
49  const double origin_x, const double origin_y, const double origin_z,
50  const double x_resolution, const double y_resolution,
51  const double z_resolution,
52  double & wx, double & wy, double & wz)
53 {
54  // returns the center point of the cell
55  wx = origin_x + (mx + 0.5) * x_resolution;
56  wy = origin_y + (my + 0.5) * y_resolution;
57  wz = origin_z + (mz + 0.5) * z_resolution;
58 }
59 
60 struct Cell
61 {
62  double x;
63  double y;
64  double z;
65  nav2_voxel_grid::VoxelStatus status;
66 };
67 typedef std::vector<Cell> V_Cell;
68 
69 float g_colors_r[] = {0.0f, 0.0f, 1.0f};
70 float g_colors_g[] = {0.0f, 0.0f, 0.0f};
71 float g_colors_b[] = {0.0f, 1.0f, 0.0f};
72 float g_colors_a[] = {0.0f, 0.5f, 1.0f};
73 
74 V_Cell g_marked;
75 V_Cell g_unknown;
76 
77 rclcpp::Node::SharedPtr g_node; // nosemgrep
78 
79 rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr pub_marked; // nosemgrep
80 rclcpp::Publisher<sensor_msgs::msg::PointCloud2>::SharedPtr pub_unknown; // nosemgrep
81 
89 void pointCloud2Helper(
90  std::unique_ptr<sensor_msgs::msg::PointCloud2> & cloud,
91  uint32_t num_channels,
92  std_msgs::msg::Header header,
93  V_Cell & g_cells)
94 {
95  cloud->header = header;
96  cloud->width = num_channels;
97  cloud->height = 1;
98  cloud->is_dense = true;
99  cloud->is_bigendian = false;
100  sensor_msgs::PointCloud2Modifier modifier(*cloud);
101 
102  modifier.setPointCloud2Fields(
103  6, "x", 1, sensor_msgs::msg::PointField::FLOAT32,
104  "y", 1, sensor_msgs::msg::PointField::FLOAT32,
105  "z", 1, sensor_msgs::msg::PointField::FLOAT32,
106  "r", 1, sensor_msgs::msg::PointField::UINT8,
107  "g", 1, sensor_msgs::msg::PointField::UINT8,
108  "b", 1, sensor_msgs::msg::PointField::UINT8);
109 
110  sensor_msgs::PointCloud2Iterator<float> iter_x(*cloud, "x");
111  sensor_msgs::PointCloud2Iterator<float> iter_y(*cloud, "y");
112  sensor_msgs::PointCloud2Iterator<float> iter_z(*cloud, "z");
113 
114  sensor_msgs::PointCloud2Iterator<uint8_t> iter_r(*cloud, "r");
115  sensor_msgs::PointCloud2Iterator<uint8_t> iter_g(*cloud, "g");
116  sensor_msgs::PointCloud2Iterator<uint8_t> iter_b(*cloud, "b");
117 
118  for (uint32_t i = 0; i < num_channels; ++i) {
119  Cell & c = g_cells[i];
120  // assigning value to the point cloud2's iterator
121  *iter_x = c.x;
122  *iter_y = c.y;
123  *iter_z = c.z;
124  *iter_r = g_colors_r[c.status] * 255.0;
125  *iter_g = g_colors_g[c.status] * 255.0;
126  *iter_b = g_colors_b[c.status] * 255.0;
127 
128  ++iter_x;
129  ++iter_y;
130  ++iter_z;
131  ++iter_r;
132  ++iter_g;
133  ++iter_b;
134  }
135 }
136 
137 void voxelCallback(const nav2_msgs::msg::VoxelGrid::ConstSharedPtr grid)
138 {
139  if (grid->data.empty()) {
140  RCLCPP_ERROR(g_node->get_logger(), "Received empty voxel grid");
141  return;
142  }
143 
145  timer.start();
146 
147  RCLCPP_DEBUG(g_node->get_logger(), "Received voxel grid");
148  const std::string frame_id = grid->header.frame_id;
149  const rclcpp::Time stamp = grid->header.stamp;
150  const uint32_t * data = &grid->data.front();
151  const double x_origin = grid->origin.x;
152  const double y_origin = grid->origin.y;
153  const double z_origin = grid->origin.z;
154  const double x_res = grid->resolutions.x;
155  const double y_res = grid->resolutions.y;
156  const double z_res = grid->resolutions.z;
157  const uint32_t x_size = grid->size_x;
158  const uint32_t y_size = grid->size_y;
159  const uint32_t z_size = grid->size_z;
160 
161  g_marked.clear();
162  g_unknown.clear();
163  uint32_t num_marked = 0;
164  uint32_t num_unknown = 0;
165  for (uint32_t y_grid = 0; y_grid < y_size; ++y_grid) {
166  for (uint32_t x_grid = 0; x_grid < x_size; ++x_grid) {
167  for (uint32_t z_grid = 0; z_grid < z_size; ++z_grid) {
168  nav2_voxel_grid::VoxelStatus status =
169  nav2_voxel_grid::VoxelGrid::getVoxel(
170  x_grid, y_grid,
171  z_grid, x_size, y_size, z_size, data);
172  if (status == nav2_voxel_grid::UNKNOWN) {
173  Cell c;
174  c.status = status;
175  mapToWorld3D(
176  x_grid, y_grid, z_grid, x_origin, y_origin,
177  z_origin, x_res, y_res, z_res, c.x, c.y, c.z);
178 
179  g_unknown.push_back(c);
180 
181  ++num_unknown;
182  } else if (status == nav2_voxel_grid::MARKED) {
183  Cell c;
184  c.status = status;
185  mapToWorld3D(
186  x_grid, y_grid, z_grid, x_origin, y_origin,
187  z_origin, x_res, y_res, z_res, c.x, c.y, c.z);
188 
189  g_marked.push_back(c);
190 
191  ++num_marked;
192  }
193  }
194  }
195  }
196 
197  std_msgs::msg::Header pcl_header;
198  pcl_header.frame_id = frame_id;
199  pcl_header.stamp = stamp;
200 
201  {
202  auto cloud = std::make_unique<sensor_msgs::msg::PointCloud2>();
203  pointCloud2Helper(cloud, num_marked, pcl_header, g_marked);
204  pub_marked->publish(std::move(cloud));
205  }
206 
207  {
208  auto cloud = std::make_unique<sensor_msgs::msg::PointCloud2>();
209  pointCloud2Helper(cloud, num_unknown, pcl_header, g_unknown);
210  pub_unknown->publish(std::move(cloud));
211  }
212 
213  timer.end();
214  RCLCPP_DEBUG(
215  g_node->get_logger(), "Published %d points in %f seconds",
216  num_marked + num_unknown, timer.elapsed_time_in_seconds());
217 }
218 
219 int main(int argc, char ** argv)
220 {
221  rclcpp::init(argc, argv);
222  g_node = rclcpp::Node::make_shared("costmap_2d_cloud"); // nosemgrep
223 
224  RCLCPP_DEBUG(g_node->get_logger(), "Starting up costmap_2d_cloud");
225 
226  pub_marked = g_node->create_publisher<sensor_msgs::msg::PointCloud2>(
227  "voxel_marked_cloud", nav2::qos::StandardTopicQoS());
228  pub_unknown = g_node->create_publisher<sensor_msgs::msg::PointCloud2>(
229  "voxel_unknown_cloud", nav2::qos::StandardTopicQoS());
230  auto sub = g_node->create_subscription<nav2_msgs::msg::VoxelGrid>(
231  "voxel_grid", nav2::qos::StandardTopicQoS(), voxelCallback);
232 
233  rclcpp::spin(g_node->get_node_base_interface());
234 
235  g_node.reset();
236  pub_marked.reset();
237  pub_unknown.reset();
238 
239  rclcpp::shutdown();
240 
241  return 0;
242 }
A QoS profile for standard reliable topics with a history of 10 messages.
Measures execution time of code between calls to start and end.
void start()
Call just prior to code you want to measure.
double elapsed_time_in_seconds()
Extract the measured time as a floating point number of seconds.
void end()
Call just after the code you want to measure.