Nav2 Navigation Stack - jazzy  jazzy
ROS 2 Navigation Stack
collision_monitor_node.cpp
1 // Copyright (c) 2022 Samsung R&D Institute Russia
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 "nav2_collision_monitor/collision_monitor_node.hpp"
16 
17 #include <exception>
18 #include <utility>
19 #include <functional>
20 
21 #include "tf2_ros/create_timer_ros.h"
22 
23 #include "nav2_util/node_utils.hpp"
24 #include "nav2_util/robot_utils.hpp"
25 
26 #include "nav2_collision_monitor/kinematics.hpp"
27 
28 namespace nav2_collision_monitor
29 {
30 
31 CollisionMonitor::CollisionMonitor(const rclcpp::NodeOptions & options)
32 : nav2_util::LifecycleNode("collision_monitor", "", options),
33  process_active_(false), robot_action_prev_{DO_NOTHING, {-1.0, -1.0, -1.0}, ""},
34  stop_stamp_{0, 0, get_clock()->get_clock_type()}, stop_pub_timeout_(1.0, 0.0)
35 {
36 }
37 
38 CollisionMonitor::~CollisionMonitor()
39 {
40  polygons_.clear();
41  sources_.clear();
42 }
43 
44 nav2_util::CallbackReturn
45 CollisionMonitor::on_configure(const rclcpp_lifecycle::State & state)
46 {
47  RCLCPP_INFO(get_logger(), "Configuring");
48 
49  // Transform buffer and listener initialization
50  tf_buffer_ = std::make_shared<tf2_ros::Buffer>(this->get_clock());
51  auto timer_interface = std::make_shared<tf2_ros::CreateTimerROS>(
52  this->get_node_base_interface(),
53  this->get_node_timers_interface());
54  tf_buffer_->setCreateTimerInterface(timer_interface);
55  tf_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf_buffer_);
56 
57  std::string cmd_vel_in_topic;
58  std::string cmd_vel_out_topic;
59  std::string state_topic;
60 
61  // Obtaining ROS parameters
62  if (!getParameters(cmd_vel_in_topic, cmd_vel_out_topic, state_topic)) {
63  on_cleanup(state);
64  return nav2_util::CallbackReturn::FAILURE;
65  }
66 
67  cmd_vel_in_sub_ = std::make_unique<nav2_util::TwistSubscriber>(
68  shared_from_this(),
69  cmd_vel_in_topic,
70  1,
71  std::bind(&CollisionMonitor::cmdVelInCallbackUnstamped, this, std::placeholders::_1),
72  std::bind(&CollisionMonitor::cmdVelInCallbackStamped, this, std::placeholders::_1));
73 
74  auto node = shared_from_this();
75  cmd_vel_out_pub_ = std::make_unique<nav2_util::TwistPublisher>(node, cmd_vel_out_topic, 1);
76 
77  if (!state_topic.empty()) {
78  state_pub_ = this->create_publisher<nav2_msgs::msg::CollisionMonitorState>(
79  state_topic, 1);
80  }
81 
82  collision_points_marker_pub_ = this->create_publisher<visualization_msgs::msg::MarkerArray>(
83  "~/collision_points_marker", 1);
84 
85  nav2_util::declare_parameter_if_not_declared(
86  node, "use_realtime_priority", rclcpp::ParameterValue(false));
87  bool use_realtime_priority = false;
88  node->get_parameter("use_realtime_priority", use_realtime_priority);
89  if (use_realtime_priority) {
90  try {
91  nav2_util::setSoftRealTimePriority();
92  } catch (const std::runtime_error & e) {
93  RCLCPP_ERROR(get_logger(), "%s", e.what());
94  on_cleanup(state);
95  return nav2_util::CallbackReturn::FAILURE;
96  }
97  }
98 
99  return nav2_util::CallbackReturn::SUCCESS;
100 }
101 
102 nav2_util::CallbackReturn
103 CollisionMonitor::on_activate(const rclcpp_lifecycle::State & /*state*/)
104 {
105  RCLCPP_INFO(get_logger(), "Activating");
106 
107  // Activating lifecycle publisher
108  cmd_vel_out_pub_->on_activate();
109  if (state_pub_) {
110  state_pub_->on_activate();
111  }
112  collision_points_marker_pub_->on_activate();
113 
114  // Activating polygons
115  for (std::shared_ptr<Polygon> polygon : polygons_) {
116  polygon->activate();
117  }
118 
119  // Since polygons are being published when cmd_vel_in appears,
120  // we need to publish polygons first time to display them at startup
121  publishPolygons();
122 
123  // Activating main worker
124  process_active_ = true;
125 
126  // Creating bond connection
127  createBond();
128 
129  return nav2_util::CallbackReturn::SUCCESS;
130 }
131 
132 nav2_util::CallbackReturn
133 CollisionMonitor::on_deactivate(const rclcpp_lifecycle::State & /*state*/)
134 {
135  RCLCPP_INFO(get_logger(), "Deactivating");
136 
137  // Deactivating main worker
138  process_active_ = false;
139 
140  // Reset action type to default after worker deactivating
141  robot_action_prev_ = {DO_NOTHING, {-1.0, -1.0, -1.0}, ""};
142 
143  // Deactivating polygons
144  for (std::shared_ptr<Polygon> polygon : polygons_) {
145  polygon->deactivate();
146  }
147 
148  // Deactivating lifecycle publishers
149  cmd_vel_out_pub_->on_deactivate();
150  if (state_pub_) {
151  state_pub_->on_deactivate();
152  }
153  collision_points_marker_pub_->on_deactivate();
154 
155  // Destroying bond connection
156  destroyBond();
157 
158  return nav2_util::CallbackReturn::SUCCESS;
159 }
160 
161 nav2_util::CallbackReturn
162 CollisionMonitor::on_cleanup(const rclcpp_lifecycle::State & /*state*/)
163 {
164  RCLCPP_INFO(get_logger(), "Cleaning up");
165 
166  cmd_vel_in_sub_.reset();
167  cmd_vel_out_pub_.reset();
168  state_pub_.reset();
169  collision_points_marker_pub_.reset();
170 
171  polygons_.clear();
172  sources_.clear();
173 
174  tf_listener_.reset();
175  tf_buffer_.reset();
176 
177  return nav2_util::CallbackReturn::SUCCESS;
178 }
179 
180 nav2_util::CallbackReturn
181 CollisionMonitor::on_shutdown(const rclcpp_lifecycle::State & /*state*/)
182 {
183  RCLCPP_INFO(get_logger(), "Shutting down");
184 
185  return nav2_util::CallbackReturn::SUCCESS;
186 }
187 
188 void CollisionMonitor::cmdVelInCallbackStamped(geometry_msgs::msg::TwistStamped::SharedPtr msg)
189 {
190  // If message contains NaN or Inf, ignore
191  if (!nav2_util::validateTwist(*msg)) {
192  RCLCPP_ERROR(get_logger(), "Velocity message contains NaNs or Infs! Ignoring as invalid!");
193  return;
194  }
195 
196  process({msg->twist.linear.x, msg->twist.linear.y, msg->twist.angular.z}, msg->header);
197 }
198 
199 void CollisionMonitor::cmdVelInCallbackUnstamped(geometry_msgs::msg::Twist::SharedPtr msg)
200 {
201  auto twist_stamped = std::make_shared<geometry_msgs::msg::TwistStamped>();
202  twist_stamped->twist = *msg;
203  cmdVelInCallbackStamped(twist_stamped);
204 }
205 
206 void CollisionMonitor::publishVelocity(
207  const Action & robot_action, const std_msgs::msg::Header & header)
208 {
209  if (robot_action.req_vel.isZero()) {
210  if (!robot_action_prev_.req_vel.isZero()) {
211  // Robot just stopped: saving stop timestamp and continue
212  stop_stamp_ = this->now();
213  } else if (this->now() - stop_stamp_ > stop_pub_timeout_) {
214  // More than stop_pub_timeout_ passed after robot has been stopped.
215  // Cease publishing output cmd_vel.
216  return;
217  }
218  }
219 
220  auto cmd_vel_out_msg = std::make_unique<geometry_msgs::msg::TwistStamped>();
221  cmd_vel_out_msg->header = header;
222  cmd_vel_out_msg->twist.linear.x = robot_action.req_vel.x;
223  cmd_vel_out_msg->twist.linear.y = robot_action.req_vel.y;
224  cmd_vel_out_msg->twist.angular.z = robot_action.req_vel.tw;
225  // linear.z, angular.x and angular.y will remain 0.0
226 
227  cmd_vel_out_pub_->publish(std::move(cmd_vel_out_msg));
228 }
229 
230 bool CollisionMonitor::getParameters(
231  std::string & cmd_vel_in_topic,
232  std::string & cmd_vel_out_topic,
233  std::string & state_topic)
234 {
235  std::string base_frame_id, odom_frame_id;
236  tf2::Duration transform_tolerance;
237  rclcpp::Duration source_timeout(2.0, 0.0);
238 
239  auto node = shared_from_this();
240 
241  nav2_util::declare_parameter_if_not_declared(
242  node, "cmd_vel_in_topic", rclcpp::ParameterValue("cmd_vel_smoothed"));
243  cmd_vel_in_topic = get_parameter("cmd_vel_in_topic").as_string();
244  nav2_util::declare_parameter_if_not_declared(
245  node, "cmd_vel_out_topic", rclcpp::ParameterValue("cmd_vel"));
246  cmd_vel_out_topic = get_parameter("cmd_vel_out_topic").as_string();
247  nav2_util::declare_parameter_if_not_declared(
248  node, "state_topic", rclcpp::ParameterValue(""));
249  state_topic = get_parameter("state_topic").as_string();
250 
251  nav2_util::declare_parameter_if_not_declared(
252  node, "base_frame_id", rclcpp::ParameterValue("base_footprint"));
253  base_frame_id = get_parameter("base_frame_id").as_string();
254  nav2_util::declare_parameter_if_not_declared(
255  node, "odom_frame_id", rclcpp::ParameterValue("odom"));
256  odom_frame_id = get_parameter("odom_frame_id").as_string();
257  nav2_util::declare_parameter_if_not_declared(
258  node, "transform_tolerance", rclcpp::ParameterValue(0.1));
259  transform_tolerance =
260  tf2::durationFromSec(get_parameter("transform_tolerance").as_double());
261  nav2_util::declare_parameter_if_not_declared(
262  node, "source_timeout", rclcpp::ParameterValue(2.0));
263  source_timeout =
264  rclcpp::Duration::from_seconds(get_parameter("source_timeout").as_double());
265  nav2_util::declare_parameter_if_not_declared(
266  node, "base_shift_correction", rclcpp::ParameterValue(true));
267  const bool base_shift_correction =
268  get_parameter("base_shift_correction").as_bool();
269 
270  nav2_util::declare_parameter_if_not_declared(
271  node, "stop_pub_timeout", rclcpp::ParameterValue(1.0));
272  stop_pub_timeout_ =
273  rclcpp::Duration::from_seconds(get_parameter("stop_pub_timeout").as_double());
274 
275  if (
276  !configureSources(
277  base_frame_id, odom_frame_id, transform_tolerance, source_timeout, base_shift_correction))
278  {
279  return false;
280  }
281 
282  if (!configurePolygons(base_frame_id, transform_tolerance)) {
283  return false;
284  }
285 
286  return true;
287 }
288 
289 bool CollisionMonitor::configurePolygons(
290  const std::string & base_frame_id,
291  const tf2::Duration & transform_tolerance)
292 {
293  try {
294  auto node = shared_from_this();
295 
296  // Leave it to be not initialized: to intentionally cause an error if it will not set
297  nav2_util::declare_parameter_if_not_declared(
298  node, "polygons", rclcpp::PARAMETER_STRING_ARRAY);
299  std::vector<std::string> polygon_names = get_parameter("polygons").as_string_array();
300  for (std::string polygon_name : polygon_names) {
301  // Leave it not initialized: the will cause an error if it will not set
302  nav2_util::declare_parameter_if_not_declared(
303  node, polygon_name + ".type", rclcpp::PARAMETER_STRING);
304  const std::string polygon_type = get_parameter(polygon_name + ".type").as_string();
305 
306  if (polygon_type == "polygon") {
307  polygons_.push_back(
308  std::make_shared<Polygon>(
309  node, polygon_name, tf_buffer_, base_frame_id, transform_tolerance));
310  } else if (polygon_type == "circle") {
311  polygons_.push_back(
312  std::make_shared<Circle>(
313  node, polygon_name, tf_buffer_, base_frame_id, transform_tolerance));
314  } else if (polygon_type == "velocity_polygon") {
315  polygons_.push_back(
316  std::make_shared<VelocityPolygon>(
317  node, polygon_name, tf_buffer_, base_frame_id, transform_tolerance));
318  } else { // Error if something else
319  RCLCPP_ERROR(
320  get_logger(),
321  "[%s]: Unknown polygon type: %s",
322  polygon_name.c_str(), polygon_type.c_str());
323  return false;
324  }
325 
326  // Configure last added polygon
327  if (!polygons_.back()->configure()) {
328  return false;
329  }
330  }
331  } catch (const std::exception & ex) {
332  RCLCPP_ERROR(get_logger(), "Error while getting parameters: %s", ex.what());
333  return false;
334  }
335 
336  return true;
337 }
338 
339 bool CollisionMonitor::configureSources(
340  const std::string & base_frame_id,
341  const std::string & odom_frame_id,
342  const tf2::Duration & transform_tolerance,
343  const rclcpp::Duration & source_timeout,
344  const bool base_shift_correction)
345 {
346  try {
347  auto node = shared_from_this();
348 
349  // Leave it to be not initialized: to intentionally cause an error if it will not set
350  nav2_util::declare_parameter_if_not_declared(
351  node, "observation_sources", rclcpp::PARAMETER_STRING_ARRAY);
352  std::vector<std::string> source_names = get_parameter("observation_sources").as_string_array();
353  for (std::string source_name : source_names) {
354  nav2_util::declare_parameter_if_not_declared(
355  node, source_name + ".type",
356  rclcpp::ParameterValue("scan")); // Laser scanner by default
357  const std::string source_type = get_parameter(source_name + ".type").as_string();
358 
359  if (source_type == "scan") {
360  std::shared_ptr<Scan> s = std::make_shared<Scan>(
361  node, source_name, tf_buffer_, base_frame_id, odom_frame_id,
362  transform_tolerance, source_timeout, base_shift_correction);
363 
364  s->configure();
365 
366  sources_.push_back(s);
367  } else if (source_type == "pointcloud") {
368  std::shared_ptr<PointCloud> p = std::make_shared<PointCloud>(
369  node, source_name, tf_buffer_, base_frame_id, odom_frame_id,
370  transform_tolerance, source_timeout, base_shift_correction);
371 
372  p->configure();
373 
374  sources_.push_back(p);
375  } else if (source_type == "range") {
376  std::shared_ptr<Range> r = std::make_shared<Range>(
377  node, source_name, tf_buffer_, base_frame_id, odom_frame_id,
378  transform_tolerance, source_timeout, base_shift_correction);
379 
380  r->configure();
381 
382  sources_.push_back(r);
383  } else if (source_type == "polygon") {
384  std::shared_ptr<PolygonSource> ps = std::make_shared<PolygonSource>(
385  node, source_name, tf_buffer_, base_frame_id, odom_frame_id,
386  transform_tolerance, source_timeout, base_shift_correction);
387  ps->configure();
388 
389  sources_.push_back(ps);
390  } else { // Error if something else
391  RCLCPP_ERROR(
392  get_logger(),
393  "[%s]: Unknown source type: %s",
394  source_name.c_str(), source_type.c_str());
395  return false;
396  }
397  }
398  } catch (const std::exception & ex) {
399  RCLCPP_ERROR(get_logger(), "Error while getting parameters: %s", ex.what());
400  return false;
401  }
402 
403  return true;
404 }
405 
406 void CollisionMonitor::process(const Velocity & cmd_vel_in, const std_msgs::msg::Header & header)
407 {
408  // Current timestamp for all inner routines prolongation
409  rclcpp::Time curr_time = this->now();
410 
411  // Do nothing if main worker in non-active state
412  if (!process_active_) {
413  return;
414  }
415 
416  // Points array collected from different data sources in a robot base frame
417  std::unordered_map<std::string, std::vector<Point>> sources_collision_points_map;
418 
419  // By default - there is no action
420  Action robot_action{DO_NOTHING, cmd_vel_in, ""};
421  // Polygon causing robot action (if any)
422  std::shared_ptr<Polygon> action_polygon;
423 
424  // Fill collision points array from different data sources
425  auto marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
426  for (std::shared_ptr<Source> source : sources_) {
427  auto iter = sources_collision_points_map.insert(
428  {source->getSourceName(), std::vector<Point>()});
429 
430  if (source->getEnabled()) {
431  if (!source->getData(curr_time, iter.first->second) &&
432  source->getSourceTimeout().seconds() != 0.0)
433  {
434  action_polygon = nullptr;
435  robot_action.polygon_name = "invalid source";
436  robot_action.action_type = STOP;
437  robot_action.req_vel.x = 0.0;
438  robot_action.req_vel.y = 0.0;
439  robot_action.req_vel.tw = 0.0;
440  break;
441  }
442  }
443 
444  if (collision_points_marker_pub_->get_subscription_count() > 0) {
445  // visualize collision points with markers
446  visualization_msgs::msg::Marker marker;
447  marker.header.frame_id = get_parameter("base_frame_id").as_string();
448  marker.header.stamp = rclcpp::Time(0, 0);
449  marker.ns = "collision_points_" + source->getSourceName();
450  marker.id = 0;
451  marker.type = visualization_msgs::msg::Marker::POINTS;
452  marker.action = visualization_msgs::msg::Marker::ADD;
453  marker.scale.x = 0.02;
454  marker.scale.y = 0.02;
455  marker.color.r = 1.0;
456  marker.color.a = 1.0;
457  marker.lifetime = rclcpp::Duration(0, 0);
458  marker.frame_locked = true;
459 
460  for (const auto & point : iter.first->second) {
461  geometry_msgs::msg::Point p;
462  p.x = point.x;
463  p.y = point.y;
464  p.z = 0.0;
465  marker.points.push_back(p);
466  }
467  marker_array->markers.push_back(marker);
468  }
469  }
470 
471  if (collision_points_marker_pub_->get_subscription_count() > 0) {
472  collision_points_marker_pub_->publish(std::move(marker_array));
473  }
474 
475  for (std::shared_ptr<Polygon> polygon : polygons_) {
476  if (!polygon->getEnabled()) {
477  continue;
478  }
479  if (robot_action.action_type == STOP) {
480  // If robot already should stop, do nothing
481  break;
482  }
483 
484  // Update polygon coordinates
485  polygon->updatePolygon(cmd_vel_in);
486 
487  const ActionType at = polygon->getActionType();
488  if (at == STOP || at == SLOWDOWN || at == LIMIT) {
489  // Process STOP/SLOWDOWN for the selected polygon
490  if (processStopSlowdownLimit(
491  polygon, sources_collision_points_map, cmd_vel_in, robot_action))
492  {
493  action_polygon = polygon;
494  }
495  } else if (at == APPROACH) {
496  // Process APPROACH for the selected polygon
497  if (processApproach(polygon, sources_collision_points_map, cmd_vel_in, robot_action)) {
498  action_polygon = polygon;
499  }
500  }
501  }
502 
503  if (robot_action.polygon_name != robot_action_prev_.polygon_name) {
504  // Report changed robot behavior
505  notifyActionState(robot_action, action_polygon);
506  }
507 
508  // Publish required robot velocity
509  publishVelocity(robot_action, header);
510 
511  // Publish polygons for better visualization
512  publishPolygons();
513 
514  robot_action_prev_ = robot_action;
515 }
516 
517 bool CollisionMonitor::processStopSlowdownLimit(
518  const std::shared_ptr<Polygon> polygon,
519  const std::unordered_map<std::string, std::vector<Point>> & sources_collision_points_map,
520  const Velocity & velocity,
521  Action & robot_action) const
522 {
523  if (!polygon->isShapeSet()) {
524  return false;
525  }
526 
527  if (polygon->getPointsInside(sources_collision_points_map) >= polygon->getMinPoints()) {
528  if (polygon->getActionType() == STOP) {
529  // Setting up zero velocity for STOP model
530  robot_action.polygon_name = polygon->getName();
531  robot_action.action_type = STOP;
532  robot_action.req_vel.x = 0.0;
533  robot_action.req_vel.y = 0.0;
534  robot_action.req_vel.tw = 0.0;
535  return true;
536  } else if (polygon->getActionType() == SLOWDOWN) {
537  const Velocity safe_vel = velocity * polygon->getSlowdownRatio();
538  // Check that currently calculated velocity is safer than
539  // chosen for previous shapes one
540  if (safe_vel < robot_action.req_vel) {
541  robot_action.polygon_name = polygon->getName();
542  robot_action.action_type = SLOWDOWN;
543  robot_action.req_vel = safe_vel;
544  return true;
545  }
546  } else { // Limit
547  // Compute linear velocity
548  const double linear_vel = std::hypot(velocity.x, velocity.y); // absolute
549  Velocity safe_vel;
550  double ratio = 1.0;
551  if (linear_vel != 0.0) {
552  ratio = std::clamp(polygon->getLinearLimit() / linear_vel, 0.0, 1.0);
553  }
554  safe_vel.x = velocity.x * ratio;
555  safe_vel.y = velocity.y * ratio;
556  safe_vel.tw = std::clamp(
557  velocity.tw, -polygon->getAngularLimit(), polygon->getAngularLimit());
558  // Check that currently calculated velocity is safer than
559  // chosen for previous shapes one
560  if (safe_vel < robot_action.req_vel) {
561  robot_action.polygon_name = polygon->getName();
562  robot_action.action_type = LIMIT;
563  robot_action.req_vel = safe_vel;
564  return true;
565  }
566  }
567  }
568 
569  return false;
570 }
571 
572 bool CollisionMonitor::processApproach(
573  const std::shared_ptr<Polygon> polygon,
574  const std::unordered_map<std::string, std::vector<Point>> & sources_collision_points_map,
575  const Velocity & velocity,
576  Action & robot_action) const
577 {
578  if (!polygon->isShapeSet()) {
579  return false;
580  }
581 
582  // Obtain time before a collision
583  const double collision_time = polygon->getCollisionTime(sources_collision_points_map, velocity);
584  if (collision_time >= 0.0) {
585  // If collision will occurr, reduce robot speed
586  const double change_ratio = collision_time / polygon->getTimeBeforeCollision();
587  const Velocity safe_vel = velocity * change_ratio;
588  // Check that currently calculated velocity is safer than
589  // chosen for previous shapes one
590  if (safe_vel < robot_action.req_vel) {
591  robot_action.polygon_name = polygon->getName();
592  robot_action.action_type = APPROACH;
593  robot_action.req_vel = safe_vel;
594  return true;
595  }
596  }
597 
598  return false;
599 }
600 
601 void CollisionMonitor::notifyActionState(
602  const Action & robot_action, const std::shared_ptr<Polygon> action_polygon) const
603 {
604  if (robot_action.action_type == STOP) {
605  if (robot_action.polygon_name == "invalid source") {
606  RCLCPP_WARN(
607  get_logger(),
608  "Robot to stop due to invalid source."
609  " Either due to data not published yet, or to lack of new data received within the"
610  " sensor timeout, or if impossible to transform data to base frame");
611  } else {
612  RCLCPP_INFO(
613  get_logger(),
614  "Robot to stop due to %s polygon",
615  action_polygon->getName().c_str());
616  }
617  } else if (robot_action.action_type == SLOWDOWN) {
618  RCLCPP_INFO(
619  get_logger(),
620  "Robot to slowdown for %f percents due to %s polygon",
621  action_polygon->getSlowdownRatio() * 100,
622  action_polygon->getName().c_str());
623  } else if (robot_action.action_type == LIMIT) {
624  RCLCPP_INFO(
625  get_logger(),
626  "Robot to limit speed due to %s polygon",
627  action_polygon->getName().c_str());
628  } else if (robot_action.action_type == APPROACH) {
629  RCLCPP_INFO(
630  get_logger(),
631  "Robot to approach for %f seconds away from collision",
632  action_polygon->getTimeBeforeCollision());
633  } else { // robot_action.action_type == DO_NOTHING
634  RCLCPP_INFO(
635  get_logger(),
636  "Robot to continue normal operation");
637  }
638 
639  if (state_pub_) {
640  std::unique_ptr<nav2_msgs::msg::CollisionMonitorState> state_msg =
641  std::make_unique<nav2_msgs::msg::CollisionMonitorState>();
642  state_msg->polygon_name = robot_action.polygon_name;
643  state_msg->action_type = robot_action.action_type;
644 
645  state_pub_->publish(std::move(state_msg));
646  }
647 }
648 
649 void CollisionMonitor::publishPolygons() const
650 {
651  for (std::shared_ptr<Polygon> polygon : polygons_) {
652  if (polygon->getEnabled()) {
653  polygon->publish();
654  }
655  }
656 }
657 
658 } // namespace nav2_collision_monitor
659 
660 #include "rclcpp_components/register_node_macro.hpp"
661 
662 // Register the component with class_loader.
663 // This acts as a sort of entry point, allowing the component to be discoverable when its library
664 // is being loaded into a running process.
665 RCLCPP_COMPONENTS_REGISTER_NODE(nav2_collision_monitor::CollisionMonitor)
CollisionMonitor(const rclcpp::NodeOptions &options=rclcpp::NodeOptions())
Constructor for the nav2_collision_monitor::CollisionMonitor.
Action for robot.
Definition: types.hpp:76
Velocity for 2D model of motion.
Definition: types.hpp:25