35 #include "dwb_core/publisher.hpp"
43 #include "sensor_msgs/point_cloud2_iterator.hpp"
44 #include "nav_2d_utils/conversions.hpp"
45 #include "nav2_util/node_utils.hpp"
46 #include "sensor_msgs/msg/point_cloud2.hpp"
47 #include "visualization_msgs/msg/marker_array.hpp"
48 #include "visualization_msgs/msg/marker.hpp"
52 using nav2_util::declare_parameter_if_not_declared;
57 DWBPublisher::DWBPublisher(
58 const rclcpp_lifecycle::LifecycleNode::WeakPtr & parent,
59 const std::string & plugin_name)
61 plugin_name_(plugin_name)
63 auto node = node_.lock();
64 clock_ = node->get_clock();
67 nav2_util::CallbackReturn
68 DWBPublisher::on_configure()
70 auto node = node_.lock();
72 throw std::runtime_error{
"Failed to lock node"};
75 declare_parameter_if_not_declared(
76 node, plugin_name_ +
".publish_evaluation",
77 rclcpp::ParameterValue(
true));
78 declare_parameter_if_not_declared(
79 node, plugin_name_ +
".publish_global_plan",
80 rclcpp::ParameterValue(
true));
81 declare_parameter_if_not_declared(
82 node, plugin_name_ +
".publish_transformed_plan",
83 rclcpp::ParameterValue(
true));
84 declare_parameter_if_not_declared(
85 node, plugin_name_ +
".publish_local_plan",
86 rclcpp::ParameterValue(
true));
87 declare_parameter_if_not_declared(
88 node, plugin_name_ +
".publish_trajectories",
89 rclcpp::ParameterValue(
true));
90 declare_parameter_if_not_declared(
91 node, plugin_name_ +
".publish_cost_grid_pc",
92 rclcpp::ParameterValue(
false));
93 declare_parameter_if_not_declared(
94 node, plugin_name_ +
".marker_lifetime",
95 rclcpp::ParameterValue(0.1));
97 node->get_parameter(plugin_name_ +
".publish_evaluation", publish_evaluation_);
98 node->get_parameter(plugin_name_ +
".publish_global_plan", publish_global_plan_);
99 node->get_parameter(plugin_name_ +
".publish_transformed_plan", publish_transformed_);
100 node->get_parameter(plugin_name_ +
".publish_local_plan", publish_local_plan_);
101 node->get_parameter(plugin_name_ +
".publish_trajectories", publish_trajectories_);
102 node->get_parameter(plugin_name_ +
".publish_cost_grid_pc", publish_cost_grid_pc_);
104 eval_pub_ = node->create_publisher<dwb_msgs::msg::LocalPlanEvaluation>(
"evaluation", 1);
105 global_pub_ = node->create_publisher<nav_msgs::msg::Path>(
"received_global_plan", 1);
106 transformed_pub_ = node->create_publisher<nav_msgs::msg::Path>(
"transformed_global_plan", 1);
107 local_pub_ = node->create_publisher<nav_msgs::msg::Path>(
"local_plan", 1);
108 marker_pub_ = node->create_publisher<visualization_msgs::msg::MarkerArray>(
"marker", 1);
109 cost_grid_pc_pub_ = node->create_publisher<sensor_msgs::msg::PointCloud2>(
"cost_cloud", 1);
111 double marker_lifetime = 0.0;
112 node->get_parameter(plugin_name_ +
".marker_lifetime", marker_lifetime);
113 marker_lifetime_ = rclcpp::Duration::from_seconds(marker_lifetime);
115 return nav2_util::CallbackReturn::SUCCESS;
118 nav2_util::CallbackReturn
119 DWBPublisher::on_activate()
121 eval_pub_->on_activate();
122 global_pub_->on_activate();
123 transformed_pub_->on_activate();
124 local_pub_->on_activate();
125 marker_pub_->on_activate();
126 cost_grid_pc_pub_->on_activate();
128 return nav2_util::CallbackReturn::SUCCESS;
131 nav2_util::CallbackReturn
132 DWBPublisher::on_deactivate()
134 eval_pub_->on_deactivate();
135 global_pub_->on_deactivate();
136 transformed_pub_->on_deactivate();
137 local_pub_->on_deactivate();
138 marker_pub_->on_deactivate();
139 cost_grid_pc_pub_->on_deactivate();
141 return nav2_util::CallbackReturn::SUCCESS;
144 nav2_util::CallbackReturn
145 DWBPublisher::on_cleanup()
149 transformed_pub_.reset();
152 cost_grid_pc_pub_.reset();
154 return nav2_util::CallbackReturn::SUCCESS;
158 DWBPublisher::publishEvaluation(std::shared_ptr<dwb_msgs::msg::LocalPlanEvaluation> results)
161 if (publish_evaluation_ && eval_pub_->get_subscription_count() > 0) {
162 auto msg = std::make_unique<dwb_msgs::msg::LocalPlanEvaluation>(*results);
163 eval_pub_->publish(std::move(msg));
165 publishTrajectories(*results);
170 DWBPublisher::publishTrajectories(
const dwb_msgs::msg::LocalPlanEvaluation & results)
172 if (marker_pub_->get_subscription_count() < 1) {
return;}
174 if (!publish_trajectories_) {
return;}
175 auto ma = std::make_unique<visualization_msgs::msg::MarkerArray>();
176 visualization_msgs::msg::Marker m;
178 if (results.twists.size() == 0) {
return;}
180 geometry_msgs::msg::Point pt;
182 m.header = results.header;
183 m.type = m.LINE_STRIP;
184 m.pose.orientation.w = 1;
187 m.lifetime = marker_lifetime_;
189 double best_cost = results.twists[results.best_index].total;
190 double worst_cost = results.twists[results.worst_index].total;
191 double denominator = worst_cost - best_cost;
193 if (std::fabs(denominator) < 1e-9) {
197 unsigned currentValidId = 0;
198 unsigned currentInvalidId = 0;
199 string validNamespace(
"ValidTrajectories");
200 string invalidNamespace(
"InvalidTrajectories");
201 for (
unsigned int i = 0; i < results.twists.size(); i++) {
202 const dwb_msgs::msg::TrajectoryScore & twist = results.twists[i];
203 double displayLevel = (twist.total - best_cost) / denominator;
204 if (twist.total >= 0) {
205 m.color.r = displayLevel;
206 m.color.g = 1.0 - displayLevel;
209 m.ns = validNamespace;
210 m.id = currentValidId;
217 m.ns = invalidNamespace;
218 m.id = currentInvalidId;
222 for (
unsigned int j = 0; j < twist.traj.poses.size(); ++j) {
223 pt.x = twist.traj.poses[j].x;
224 pt.y = twist.traj.poses[j].y;
226 m.points.push_back(pt);
228 ma->markers.push_back(m);
230 marker_pub_->publish(std::move(ma));
234 DWBPublisher::publishLocalPlan(
235 const std_msgs::msg::Header & header,
236 const dwb_msgs::msg::Trajectory2D & traj)
238 if (!publish_local_plan_) {
return;}
241 std::make_unique<nav_msgs::msg::Path>(
242 nav_2d_utils::poses2DToPath(
243 traj.poses, header.frame_id,
246 if (local_pub_->get_subscription_count() > 0) {
247 local_pub_->publish(std::move(path));
252 DWBPublisher::publishCostGrid(
253 const std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros,
254 const std::vector<TrajectoryCritic::Ptr> critics)
256 if (cost_grid_pc_pub_->get_subscription_count() < 1) {
return;}
258 if (!publish_cost_grid_pc_) {
return;}
260 auto cost_grid_pc = std::make_unique<sensor_msgs::msg::PointCloud2>();
261 cost_grid_pc->header.frame_id = costmap_ros->getGlobalFrameID();
262 cost_grid_pc->header.stamp = clock_->now();
265 double x_coord, y_coord;
269 std::vector<std::pair<std::string, std::vector<float>>> cost_channels;
270 std::vector<float> total_cost(size_x * size_y, 0.0);
272 for (TrajectoryCritic::Ptr critic : critics) {
273 unsigned int channel_index = cost_channels.size();
274 critic->addCriticVisualization(cost_channels);
275 if (channel_index == cost_channels.size()) {
279 double scale = critic->getScale();
280 for (
unsigned int i = 0; i < size_x * size_y; i++) {
281 total_cost[i] += cost_channels[channel_index].second[i] * scale;
285 cost_channels.push_back(std::make_pair(
"total_cost", total_cost));
287 cost_grid_pc->width = size_x * size_y;
288 cost_grid_pc->height = 1;
289 cost_grid_pc->fields.resize(3 + cost_channels.size());
290 cost_grid_pc->is_dense =
true;
291 cost_grid_pc->is_bigendian =
false;
294 for (
size_t i = 0; i < cost_grid_pc->fields.size(); ++i, offset += 4) {
295 cost_grid_pc->fields[i].offset = offset;
296 cost_grid_pc->fields[i].count = 1;
297 cost_grid_pc->fields[i].datatype = sensor_msgs::msg::PointField::FLOAT32;
299 cost_grid_pc->fields[i].name = cost_channels[i - 3].first;
303 cost_grid_pc->fields[0].name =
"x";
304 cost_grid_pc->fields[1].name =
"y";
305 cost_grid_pc->fields[2].name =
"z";
307 cost_grid_pc->point_step = offset;
308 cost_grid_pc->row_step = cost_grid_pc->point_step * cost_grid_pc->width;
309 cost_grid_pc->data.resize(cost_grid_pc->row_step * cost_grid_pc->height);
311 std::vector<sensor_msgs::PointCloud2Iterator<float>> cost_grid_pc_iter;
313 for (
size_t i = 0; i < cost_grid_pc->fields.size(); ++i) {
314 sensor_msgs::PointCloud2Iterator<float> iter(*cost_grid_pc, cost_grid_pc->fields[i].name);
315 cost_grid_pc_iter.push_back(iter);
319 for (
unsigned int cy = 0; cy < size_y; cy++) {
320 for (
unsigned int cx = 0; cx < size_x; cx++) {
321 costmap->
mapToWorld(cx, cy, x_coord, y_coord);
322 *cost_grid_pc_iter[0] = x_coord;
323 *cost_grid_pc_iter[1] = y_coord;
324 *cost_grid_pc_iter[2] = 0.0;
326 for (
size_t i = 3; i < cost_grid_pc_iter.size(); ++i) {
327 *cost_grid_pc_iter[i] = cost_channels[i - 3].second[j];
328 ++cost_grid_pc_iter[i];
330 ++cost_grid_pc_iter[0];
331 ++cost_grid_pc_iter[1];
332 ++cost_grid_pc_iter[2];
337 cost_grid_pc_pub_->publish(std::move(cost_grid_pc));
341 DWBPublisher::publishGlobalPlan(
const nav_2d_msgs::msg::Path2D plan)
343 publishGenericPlan(plan, *global_pub_, publish_global_plan_);
347 DWBPublisher::publishTransformedPlan(
const nav_2d_msgs::msg::Path2D plan)
349 publishGenericPlan(plan, *transformed_pub_, publish_transformed_);
353 DWBPublisher::publishLocalPlan(
const nav_2d_msgs::msg::Path2D plan)
355 publishGenericPlan(plan, *local_pub_, publish_local_plan_);
359 DWBPublisher::publishGenericPlan(
360 const nav_2d_msgs::msg::Path2D plan,
361 rclcpp::Publisher<nav_msgs::msg::Path> & pub,
bool flag)
363 if (pub.get_subscription_count() < 1) {
return;}
365 auto path = std::make_unique<nav_msgs::msg::Path>(nav_2d_utils::pathToPath(plan));
366 pub.publish(std::move(path));
A 2D costmap provides a mapping between points in the world and their associated "costs".
void mapToWorld(unsigned int mx, unsigned int my, double &wx, double &wy) const
Convert from map coordinates to world coordinates.
unsigned int getSizeInCellsX() const
Accessor for the x size of the costmap in cells.
unsigned int getSizeInCellsY() const
Accessor for the y size of the costmap in cells.