Nav2 Navigation Stack - kilted  kilted
ROS 2 Navigation Stack
polygon.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/polygon.hpp"
16 
17 #include <exception>
18 #include <utility>
19 
20 #include "geometry_msgs/msg/point.hpp"
21 #include "geometry_msgs/msg/point32.hpp"
22 #include "tf2/transform_datatypes.hpp"
23 
24 #include "nav2_util/node_utils.hpp"
25 #include "nav2_util/robot_utils.hpp"
26 #include "nav2_util/array_parser.hpp"
27 
28 #include "nav2_collision_monitor/kinematics.hpp"
29 
30 namespace nav2_collision_monitor
31 {
32 
34  const nav2_util::LifecycleNode::WeakPtr & node,
35  const std::string & polygon_name,
36  const std::shared_ptr<tf2_ros::Buffer> tf_buffer,
37  const std::string & base_frame_id,
38  const tf2::Duration & transform_tolerance)
39 : node_(node), polygon_name_(polygon_name), action_type_(DO_NOTHING),
40  slowdown_ratio_(0.0), linear_limit_(0.0), angular_limit_(0.0),
41  footprint_sub_(nullptr), tf_buffer_(tf_buffer),
42  base_frame_id_(base_frame_id), transform_tolerance_(transform_tolerance),
43  node_clock_(nullptr)
44 {
45  RCLCPP_INFO(logger_, "[%s]: Creating Polygon", polygon_name_.c_str());
46 }
47 
49 {
50  RCLCPP_INFO(logger_, "[%s]: Destroying Polygon", polygon_name_.c_str());
51  polygon_sub_.reset();
52  polygon_pub_.reset();
53  poly_.clear();
54  dyn_params_handler_.reset();
55  node_clock_.reset();
56 }
57 
59 {
60  auto node = node_.lock();
61  if (!node) {
62  throw std::runtime_error{"Failed to lock node"};
63  }
64 
65  node_clock_ = node->get_clock();
66  std::string polygon_sub_topic, polygon_pub_topic, footprint_topic;
67 
68  if (!getParameters(polygon_sub_topic, polygon_pub_topic, footprint_topic)) {
69  return false;
70  }
71 
72  createSubscription(polygon_sub_topic);
73 
74  if (!footprint_topic.empty()) {
75  RCLCPP_INFO(
76  logger_,
77  "[%s]: Making footprint subscriber on %s topic",
78  polygon_name_.c_str(), footprint_topic.c_str());
79  footprint_sub_ = std::make_unique<nav2_costmap_2d::FootprintSubscriber>(
80  node, footprint_topic, *tf_buffer_,
81  base_frame_id_, tf2::durationToSec(transform_tolerance_));
82  }
83 
84  if (visualize_) {
85  // Fill polygon_ for future usage
86  polygon_.header.frame_id = base_frame_id_;
87  std::vector<Point> poly;
88  getPolygon(poly);
89  for (const Point & p : poly) {
90  geometry_msgs::msg::Point32 p_s;
91  p_s.x = p.x;
92  p_s.y = p.y;
93  // p_s.z will remain 0.0
94  polygon_.polygon.points.push_back(p_s);
95  }
96 
97  rclcpp::QoS polygon_qos = rclcpp::SystemDefaultsQoS(); // set to default
98  polygon_pub_ = node->create_publisher<geometry_msgs::msg::PolygonStamped>(
99  polygon_pub_topic, polygon_qos);
100  }
101 
102  // Add callback for dynamic parameters
103  dyn_params_handler_ = node->add_on_set_parameters_callback(
104  std::bind(&Polygon::dynamicParametersCallback, this, std::placeholders::_1));
105 
106  return true;
107 }
108 
110 {
111  if (visualize_) {
112  polygon_pub_->on_activate();
113  }
114 }
115 
117 {
118  if (visualize_) {
119  polygon_pub_->on_deactivate();
120  }
121 }
122 
123 std::string Polygon::getName() const
124 {
125  return polygon_name_;
126 }
127 
128 ActionType Polygon::getActionType() const
129 {
130  return action_type_;
131 }
132 
134 {
135  return enabled_;
136 }
137 
139 {
140  return min_points_;
141 }
142 
144 {
145  return slowdown_ratio_;
146 }
147 
149 {
150  return linear_limit_;
151 }
152 
154 {
155  return angular_limit_;
156 }
157 
159 {
160  return time_before_collision_;
161 }
162 
163 std::vector<std::string> Polygon::getSourcesNames() const
164 {
165  return sources_names_;
166 }
167 
168 void Polygon::getPolygon(std::vector<Point> & poly) const
169 {
170  poly = poly_;
171 }
172 
174 {
175  if (poly_.empty()) {
176  RCLCPP_WARN(logger_, "[%s]: Polygon shape is not set yet", polygon_name_.c_str());
177  return false;
178  }
179  return true;
180 }
181 
182 void Polygon::updatePolygon(const Velocity & /*cmd_vel_in*/)
183 {
184  if (footprint_sub_ != nullptr) {
185  // Get latest robot footprint from footprint subscriber
186  std::vector<geometry_msgs::msg::Point> footprint_vec;
187  std_msgs::msg::Header footprint_header;
188  footprint_sub_->getFootprintInRobotFrame(footprint_vec, footprint_header);
189 
190  std::size_t new_size = footprint_vec.size();
191  poly_.resize(new_size);
192  polygon_.header.frame_id = base_frame_id_;
193  polygon_.polygon.points.resize(new_size);
194 
195  geometry_msgs::msg::Point32 p_s;
196  for (std::size_t i = 0; i < new_size; i++) {
197  poly_[i] = {footprint_vec[i].x, footprint_vec[i].y};
198  p_s.x = footprint_vec[i].x;
199  p_s.y = footprint_vec[i].y;
200  polygon_.polygon.points[i] = p_s;
201  }
202  } else if (!polygon_.header.frame_id.empty() && polygon_.header.frame_id != base_frame_id_) {
203  // Polygon is published in another frame: correct poly_ vertices to the latest frame state
204  std::size_t new_size = polygon_.polygon.points.size();
205 
206  // Get the transform from PolygonStamped frame to base_frame_id_
207  tf2::Stamped<tf2::Transform> tf_transform;
208  if (
209  !nav2_util::getTransform(
210  polygon_.header.frame_id, base_frame_id_,
211  transform_tolerance_, tf_buffer_, tf_transform))
212  {
213  return;
214  }
215 
216  // Correct main poly_ vertices
217  poly_.resize(new_size);
218  for (std::size_t i = 0; i < new_size; i++) {
219  // Transform point coordinates from PolygonStamped frame -> to base frame
220  tf2::Vector3 p_v3_s(polygon_.polygon.points[i].x, polygon_.polygon.points[i].y, 0.0);
221  tf2::Vector3 p_v3_b = tf_transform * p_v3_s;
222 
223  // Fill poly_ array
224  poly_[i] = {p_v3_b.x(), p_v3_b.y()};
225  }
226  }
227 }
228 
229 int Polygon::getPointsInside(const std::vector<Point> & points) const
230 {
231  int num = 0;
232  for (const Point & point : points) {
233  if (isPointInside(point)) {
234  num++;
235  }
236  }
237  return num;
238 }
239 
241  const std::unordered_map<std::string,
242  std::vector<Point>> & sources_collision_points_map) const
243 {
244  int num = 0;
245  std::vector<std::string> polygon_sources_names = getSourcesNames();
246 
247  // Sum the number of points from all sources associated with current polygon
248  for (const auto & source_name : polygon_sources_names) {
249  const auto & iter = sources_collision_points_map.find(source_name);
250  if (iter != sources_collision_points_map.end()) {
251  num += getPointsInside(iter->second);
252  }
253  }
254 
255  return num;
256 }
257 
259  const std::unordered_map<std::string, std::vector<Point>> & sources_collision_points_map,
260  const Velocity & velocity) const
261 {
262  // Initial robot pose is {0,0} in base_footprint coordinates
263  Pose pose = {0.0, 0.0, 0.0};
264  Velocity vel = velocity;
265 
266  std::vector<std::string> polygon_sources_names = getSourcesNames();
267  std::vector<Point> collision_points;
268 
269  // Save all points coming from the sources associated with current polygon
270  for (const auto & source_name : polygon_sources_names) {
271  const auto & iter = sources_collision_points_map.find(source_name);
272  if (iter != sources_collision_points_map.end()) {
273  collision_points.insert(collision_points.end(), iter->second.begin(), iter->second.end());
274  }
275  }
276 
277  // Array of points transformed to the frame concerned with pose on each simulation step
278  std::vector<Point> points_transformed = collision_points;
279 
280  // Check static polygon
281  if (getPointsInside(collision_points) >= min_points_) {
282  return 0.0;
283  }
284 
285  // Robot movement simulation
286  for (double time = 0.0; time <= time_before_collision_; time += simulation_time_step_) {
287  // Shift the robot pose towards to the vel during simulation_time_step_ time interval
288  // NOTE: vel is changing during the simulation
289  projectState(simulation_time_step_, pose, vel);
290  // Transform collision_points to the frame concerned with current robot pose
291  points_transformed = collision_points;
292  transformPoints(pose, points_transformed);
293  // If the collision occurred on this stage, return the actual time before a collision
294  // as if robot was moved with given velocity
295  if (getPointsInside(points_transformed) >= min_points_) {
296  return time;
297  }
298  }
299 
300  // There is no collision
301  return -1.0;
302 }
303 
305 {
306  if (!visualize_) {
307  return;
308  }
309 
310  auto node = node_.lock();
311  if (!node) {
312  throw std::runtime_error{"Failed to lock node"};
313  }
314 
315  // Actualize the time to current and publish the polygon
316  polygon_.header.stamp = node->now();
317  auto msg = std::make_unique<geometry_msgs::msg::PolygonStamped>(polygon_);
318  polygon_pub_->publish(std::move(msg));
319 }
320 
322  std::string & polygon_sub_topic,
323  std::string & polygon_pub_topic,
324  std::string & footprint_topic,
325  bool use_dynamic_sub_topic)
326 {
327  auto node = node_.lock();
328  if (!node) {
329  throw std::runtime_error{"Failed to lock node"};
330  }
331 
332  try {
333  // Get action type.
334  // Leave it not initialized: the will cause an error if it will not set.
335  nav2_util::declare_parameter_if_not_declared(
336  node, polygon_name_ + ".action_type", rclcpp::PARAMETER_STRING);
337  const std::string at_str =
338  node->get_parameter(polygon_name_ + ".action_type").as_string();
339  if (at_str == "stop") {
340  action_type_ = STOP;
341  } else if (at_str == "slowdown") {
342  action_type_ = SLOWDOWN;
343  } else if (at_str == "limit") {
344  action_type_ = LIMIT;
345  } else if (at_str == "approach") {
346  action_type_ = APPROACH;
347  } else if (at_str == "none") {
348  action_type_ = DO_NOTHING;
349  } else { // Error if something else
350  RCLCPP_ERROR(logger_, "[%s]: Unknown action type: %s", polygon_name_.c_str(), at_str.c_str());
351  return false;
352  }
353 
354  nav2_util::declare_parameter_if_not_declared(
355  node, polygon_name_ + ".enabled", rclcpp::ParameterValue(true));
356  enabled_ = node->get_parameter(polygon_name_ + ".enabled").as_bool();
357 
358  nav2_util::declare_parameter_if_not_declared(
359  node, polygon_name_ + ".min_points", rclcpp::ParameterValue(4));
360  min_points_ = node->get_parameter(polygon_name_ + ".min_points").as_int();
361 
362  try {
363  nav2_util::declare_parameter_if_not_declared(
364  node, polygon_name_ + ".max_points", rclcpp::PARAMETER_INTEGER);
365  min_points_ = node->get_parameter(polygon_name_ + ".max_points").as_int() + 1;
366  RCLCPP_WARN(
367  logger_,
368  "[%s]: \"max_points\" parameter was deprecated. Use \"min_points\" instead to specify "
369  "the minimum number of data readings within a zone to trigger the action",
370  polygon_name_.c_str());
371  } catch (const std::exception &) {
372  // This is normal situation: max_points parameter should not being declared
373  }
374 
375  if (action_type_ == SLOWDOWN) {
376  nav2_util::declare_parameter_if_not_declared(
377  node, polygon_name_ + ".slowdown_ratio", rclcpp::ParameterValue(0.5));
378  slowdown_ratio_ = node->get_parameter(polygon_name_ + ".slowdown_ratio").as_double();
379  }
380 
381  if (action_type_ == LIMIT) {
382  nav2_util::declare_parameter_if_not_declared(
383  node, polygon_name_ + ".linear_limit", rclcpp::ParameterValue(0.5));
384  linear_limit_ = node->get_parameter(polygon_name_ + ".linear_limit").as_double();
385  nav2_util::declare_parameter_if_not_declared(
386  node, polygon_name_ + ".angular_limit", rclcpp::ParameterValue(0.5));
387  angular_limit_ = node->get_parameter(polygon_name_ + ".angular_limit").as_double();
388  }
389 
390  if (action_type_ == APPROACH) {
391  nav2_util::declare_parameter_if_not_declared(
392  node, polygon_name_ + ".time_before_collision", rclcpp::ParameterValue(2.0));
394  node->get_parameter(polygon_name_ + ".time_before_collision").as_double();
395  nav2_util::declare_parameter_if_not_declared(
396  node, polygon_name_ + ".simulation_time_step", rclcpp::ParameterValue(0.1));
398  node->get_parameter(polygon_name_ + ".simulation_time_step").as_double();
399  }
400 
401  nav2_util::declare_parameter_if_not_declared(
402  node, polygon_name_ + ".visualize", rclcpp::ParameterValue(false));
403  visualize_ = node->get_parameter(polygon_name_ + ".visualize").as_bool();
404  if (visualize_) {
405  // Get polygon topic parameter in case if it is going to be published
406  nav2_util::declare_parameter_if_not_declared(
407  node, polygon_name_ + ".polygon_pub_topic", rclcpp::ParameterValue(polygon_name_));
408  polygon_pub_topic = node->get_parameter(polygon_name_ + ".polygon_pub_topic").as_string();
409  }
410 
411  nav2_util::declare_parameter_if_not_declared(
412  node, polygon_name_ + ".polygon_subscribe_transient_local", rclcpp::ParameterValue(false));
414  node->get_parameter(polygon_name_ + ".polygon_subscribe_transient_local").as_bool();
415 
416  if (use_dynamic_sub_topic) {
417  if (action_type_ != APPROACH) {
418  // Get polygon sub topic
419  nav2_util::declare_parameter_if_not_declared(
420  node, polygon_name_ + ".polygon_sub_topic", rclcpp::PARAMETER_STRING);
421  polygon_sub_topic =
422  node->get_parameter(polygon_name_ + ".polygon_sub_topic").as_string();
423  } else {
424  // Obtain the footprint topic to make a footprint subscription for approach polygon
425  nav2_util::declare_parameter_if_not_declared(
426  node, polygon_name_ + ".footprint_topic",
427  rclcpp::ParameterValue("local_costmap/published_footprint"));
428  footprint_topic =
429  node->get_parameter(polygon_name_ + ".footprint_topic").as_string();
430  }
431  }
432 
433  // By default, use all observation sources for polygon
434  nav2_util::declare_parameter_if_not_declared(
435  node, "observation_sources", rclcpp::PARAMETER_STRING_ARRAY);
436  const std::vector<std::string> observation_sources =
437  node->get_parameter("observation_sources").as_string_array();
438  nav2_util::declare_parameter_if_not_declared(
439  node, polygon_name_ + ".sources_names", rclcpp::ParameterValue(observation_sources));
440  sources_names_ = node->get_parameter(polygon_name_ + ".sources_names").as_string_array();
441 
442  // Check the observation sources configured for polygon are defined
443  for (auto source_name : sources_names_) {
444  if (std::find(observation_sources.begin(), observation_sources.end(), source_name) ==
445  observation_sources.end())
446  {
447  RCLCPP_ERROR_STREAM(
448  logger_,
449  "Observation source [" << source_name <<
450  "] configured for polygon [" << getName() <<
451  "] is not defined as one of the node's observation_source!");
452  return false;
453  }
454  }
455  } catch (const std::exception & ex) {
456  RCLCPP_ERROR(
457  logger_,
458  "[%s]: Error while getting common polygon parameters: %s",
459  polygon_name_.c_str(), ex.what());
460  return false;
461  }
462 
463  return true;
464 }
465 
467  std::string & polygon_sub_topic,
468  std::string & polygon_pub_topic,
469  std::string & footprint_topic)
470 {
471  auto node = node_.lock();
472  if (!node) {
473  throw std::runtime_error{"Failed to lock node"};
474  }
475 
476  // Clear the subscription topics. They will be set later, if necessary.
477  polygon_sub_topic.clear();
478  footprint_topic.clear();
479 
480  bool use_dynamic_sub = true; // if getting parameter points fails, use dynamic subscription
481  try {
482  // Leave it uninitialized: it will throw an inner exception if the parameter is not set
483  nav2_util::declare_parameter_if_not_declared(
484  node, polygon_name_ + ".points", rclcpp::PARAMETER_STRING);
485  std::string poly_string =
486  node->get_parameter(polygon_name_ + ".points").as_string();
487 
488  use_dynamic_sub = !getPolygonFromString(poly_string, poly_);
489  } catch (const rclcpp::exceptions::ParameterUninitializedException &) {
490  RCLCPP_INFO(
491  logger_,
492  "[%s]: Polygon points are not defined. Using dynamic subscription instead.",
493  polygon_name_.c_str());
494  }
495 
496  if (!getCommonParameters(
497  polygon_sub_topic, polygon_pub_topic, footprint_topic, use_dynamic_sub))
498  {
499  if (use_dynamic_sub && polygon_sub_topic.empty() && footprint_topic.empty()) {
500  RCLCPP_ERROR(
501  logger_,
502  "[%s]: Error while getting polygon parameters:"
503  " static points and sub topic both not defined",
504  polygon_name_.c_str());
505  }
506  return false;
507  }
508 
509  return true;
510 }
511 
512 void Polygon::createSubscription(std::string & polygon_sub_topic)
513 {
514  auto node = node_.lock();
515  if (!node) {
516  throw std::runtime_error{"Failed to lock node"};
517  }
518 
519  if (!polygon_sub_topic.empty()) {
520  RCLCPP_INFO(
521  logger_,
522  "[%s]: Subscribing on %s topic for polygon",
523  polygon_name_.c_str(), polygon_sub_topic.c_str());
524  rclcpp::QoS polygon_qos = rclcpp::SystemDefaultsQoS(); // set to default
526  polygon_qos.transient_local();
527  }
528  polygon_sub_ = node->create_subscription<geometry_msgs::msg::PolygonStamped>(
529  polygon_sub_topic, polygon_qos,
530  std::bind(&Polygon::polygonCallback, this, std::placeholders::_1));
531  }
532 }
533 
534 void Polygon::updatePolygon(geometry_msgs::msg::PolygonStamped::ConstSharedPtr msg)
535 {
536  std::size_t new_size = msg->polygon.points.size();
537 
538  if (new_size < 3) {
539  RCLCPP_ERROR(
540  logger_,
541  "[%s]: Polygon should have at least 3 points",
542  polygon_name_.c_str());
543  return;
544  }
545 
546  // Get the transform from PolygonStamped frame to base_frame_id_
547  tf2::Stamped<tf2::Transform> tf_transform;
548  if (
549  !nav2_util::getTransform(
550  msg->header.frame_id, base_frame_id_,
551  transform_tolerance_, tf_buffer_, tf_transform))
552  {
553  return;
554  }
555 
556  // Set main poly_ vertices first time
557  poly_.resize(new_size);
558  for (std::size_t i = 0; i < new_size; i++) {
559  // Transform point coordinates from PolygonStamped frame -> to base frame
560  tf2::Vector3 p_v3_s(msg->polygon.points[i].x, msg->polygon.points[i].y, 0.0);
561  tf2::Vector3 p_v3_b = tf_transform * p_v3_s;
562 
563  // Fill poly_ array
564  poly_[i] = {p_v3_b.x(), p_v3_b.y()};
565  }
566 
567  // Store incoming polygon for further (possible) poly_ vertices corrections
568  // from PolygonStamped frame -> to base frame
569  polygon_ = *msg;
570 }
571 
572 rcl_interfaces::msg::SetParametersResult
574  std::vector<rclcpp::Parameter> parameters)
575 {
576  rcl_interfaces::msg::SetParametersResult result;
577 
578  for (auto parameter : parameters) {
579  const auto & param_type = parameter.get_type();
580  const auto & param_name = parameter.get_name();
581  if(param_name.find(polygon_name_ + ".") != 0) {
582  continue;
583  }
584  if (param_type == rcl_interfaces::msg::ParameterType::PARAMETER_BOOL) {
585  if (param_name == polygon_name_ + "." + "enabled") {
586  enabled_ = parameter.as_bool();
587  }
588  }
589  }
590  result.successful = true;
591  return result;
592 }
593 
594 void Polygon::polygonCallback(geometry_msgs::msg::PolygonStamped::ConstSharedPtr msg)
595 {
596  RCLCPP_INFO_THROTTLE(
597  logger_,
598  *node_clock_,
599  2000,
600  "[%s]: Polygon shape update has arrived",
601  polygon_name_.c_str());
602  updatePolygon(msg);
603 }
604 
605 inline bool Polygon::isPointInside(const Point & point) const
606 {
607  // Adaptation of Shimrat, Moshe. "Algorithm 112: position of point relative to polygon."
608  // Communications of the ACM 5.8 (1962): 434.
609  // Implementation of ray crossings algorithm for point in polygon task solving.
610  // Y coordinate is fixed. Moving the ray on X+ axis starting from given point.
611  // Odd number of intersections with polygon boundaries means the point is inside polygon.
612  const int poly_size = poly_.size();
613  int i, j; // Polygon vertex iterators
614  bool res = false; // Final result, initialized with already inverted value
615 
616  // Starting from the edge where the last point of polygon is connected to the first
617  i = poly_size - 1;
618  for (j = 0; j < poly_size; j++) {
619  // Checking the edge only if given point is between edge boundaries by Y coordinates.
620  // One of the condition should contain equality in order to exclude the edges
621  // parallel to X+ ray.
622  if ((point.y <= poly_[i].y) == (point.y > poly_[j].y)) {
623  // Calculating the intersection coordinate of X+ ray
624  const double x_inter = poly_[i].x +
625  (point.y - poly_[i].y) * (poly_[j].x - poly_[i].x) /
626  (poly_[j].y - poly_[i].y);
627  // If intersection with checked edge is greater than point.x coordinate, inverting the result
628  if (x_inter > point.x) {
629  res = !res;
630  }
631  }
632  i = j;
633  }
634  return res;
635 }
636 
638  std::string & poly_string,
639  std::vector<Point> & polygon)
640 {
641  std::string error;
642  std::vector<std::vector<float>> vvf = nav2_util::parseVVF(poly_string, error);
643 
644  if (error != "") {
645  RCLCPP_ERROR(
646  logger_, "Error parsing polygon parameter %s: '%s'",
647  poly_string.c_str(), error.c_str());
648  return false;
649  }
650 
651  // Check for minimum 4 points
652  if (vvf.size() <= 3) {
653  RCLCPP_ERROR(
654  logger_,
655  "Polygon must have at least three points.");
656  return false;
657  }
658  for (unsigned int i = 0; i < vvf.size(); i++) {
659  if (vvf[i].size() == 2) {
660  Point point;
661  point.x = vvf[i][0];
662  point.y = vvf[i][1];
663  polygon.push_back(point);
664  } else {
665  RCLCPP_ERROR(
666  logger_,
667  "Points in the polygon specification must be pairs of numbers"
668  "Found a point with %d numbers.",
669  static_cast<int>(vvf[i].size()));
670  polygon.clear();
671  return false;
672  }
673  }
674 
675  return true;
676 }
677 
678 } // namespace nav2_collision_monitor
nav2_util::LifecycleNode::WeakPtr node_
Collision Monitor node.
Definition: polygon.hpp:260
virtual bool getParameters(std::string &polygon_sub_topic, std::string &polygon_pub_topic, std::string &footprint_topic)
Supporting routine obtaining polygon-specific ROS-parameters.
Definition: polygon.cpp:466
int getMinPoints() const
Obtains polygon minimum points to enter inside polygon causing the action.
Definition: polygon.cpp:138
double getTimeBeforeCollision() const
Obtains required time before collision for current polygon. Applicable for APPROACH model.
Definition: polygon.cpp:158
rclcpp::Clock::SharedPtr node_clock_
Collision monitor node's clock.
Definition: polygon.hpp:302
virtual void updatePolygon(const Velocity &)
Updates polygon from footprint subscriber (if any)
Definition: polygon.cpp:182
virtual int getPointsInside(const std::vector< Point > &points) const
Gets number of points inside given polygon.
Definition: polygon.cpp:229
bool getCommonParameters(std::string &polygon_sub_topic, std::string &polygon_pub_topic, std::string &footprint_topic, bool use_dynamic_sub=false)
Supporting routine obtaining ROS-parameters common for all shapes.
Definition: polygon.cpp:321
double time_before_collision_
Time before collision in seconds.
Definition: polygon.hpp:280
bool enabled_
Whether polygon is enabled.
Definition: polygon.hpp:284
rclcpp::Logger logger_
Collision monitor node logger stored for further usage.
Definition: polygon.hpp:262
ActionType action_type_
Action type for the polygon.
Definition: polygon.hpp:270
geometry_msgs::msg::PolygonStamped polygon_
Polygon, used for: 1. visualization; 2. storing latest dynamic polygon message.
Definition: polygon.hpp:308
rclcpp::Subscription< geometry_msgs::msg::PolygonStamped >::SharedPtr polygon_sub_
Polygon subscription.
Definition: polygon.hpp:288
virtual void createSubscription(std::string &polygon_sub_topic)
Creates polygon or radius topic subscription.
Definition: polygon.cpp:512
rclcpp::node_interfaces::OnSetParametersCallbackHandle::SharedPtr dyn_params_handler_
Dynamic parameters handler.
Definition: polygon.hpp:264
bool polygon_subscribe_transient_local_
Whether the subscription to polygon topic has transient local QoS durability.
Definition: polygon.hpp:286
virtual bool isShapeSet()
Returns true if polygon points were set. Otherwise, prints a warning and returns false.
Definition: polygon.cpp:173
double simulation_time_step_
Time step for robot movement simulation.
Definition: polygon.hpp:282
void activate()
Activates polygon lifecycle publisher.
Definition: polygon.cpp:109
bool configure()
Shape configuration routine. Obtains ROS-parameters related to shape object and creates polygon lifec...
Definition: polygon.cpp:58
bool isPointInside(const Point &point) const
Checks if point is inside polygon.
Definition: polygon.cpp:605
double getLinearLimit() const
Obtains speed linear limit for current polygon. Applicable for LIMIT model.
Definition: polygon.cpp:148
std::string getName() const
Returns the name of polygon.
Definition: polygon.cpp:123
virtual void getPolygon(std::vector< Point > &poly) const
Gets polygon points.
Definition: polygon.cpp:168
tf2::Duration transform_tolerance_
Transform tolerance.
Definition: polygon.hpp:300
std::shared_ptr< tf2_ros::Buffer > tf_buffer_
TF buffer.
Definition: polygon.hpp:296
ActionType getActionType() const
Obtains polygon action type.
Definition: polygon.cpp:128
int min_points_
Minimum number of data readings within a zone to trigger the action.
Definition: polygon.hpp:272
std::vector< Point > poly_
Polygon points (vertices) in a base_frame_id_.
Definition: polygon.hpp:313
Polygon(const nav2_util::LifecycleNode::WeakPtr &node, const std::string &polygon_name, const std::shared_ptr< tf2_ros::Buffer > tf_buffer, const std::string &base_frame_id, const tf2::Duration &transform_tolerance)
Polygon constructor.
Definition: polygon.cpp:33
rcl_interfaces::msg::SetParametersResult dynamicParametersCallback(std::vector< rclcpp::Parameter > parameters)
Callback executed when a parameter change is detected.
Definition: polygon.cpp:573
std::vector< std::string > sources_names_
Name of the observation sources to check for polygon.
Definition: polygon.hpp:292
void deactivate()
Deactivates polygon lifecycle publisher.
Definition: polygon.cpp:116
std::unique_ptr< nav2_costmap_2d::FootprintSubscriber > footprint_sub_
Footprint subscriber.
Definition: polygon.hpp:290
void polygonCallback(geometry_msgs::msg::PolygonStamped::ConstSharedPtr msg)
Dynamic polygon callback.
Definition: polygon.cpp:594
double getSlowdownRatio() const
Obtains speed slowdown ratio for current polygon. Applicable for SLOWDOWN model.
Definition: polygon.cpp:143
double getAngularLimit() const
Obtains speed angular z limit for current polygon. Applicable for LIMIT model.
Definition: polygon.cpp:153
double getCollisionTime(const std::unordered_map< std::string, std::vector< Point >> &sources_collision_points_map, const Velocity &velocity) const
Obtains estimated (simulated) time before a collision. Applicable for APPROACH model.
Definition: polygon.cpp:258
std::string polygon_name_
Name of polygon.
Definition: polygon.hpp:268
double linear_limit_
Robot linear limit.
Definition: polygon.hpp:276
virtual ~Polygon()
Polygon destructor.
Definition: polygon.cpp:48
bool getEnabled() const
Obtains polygon enabled state.
Definition: polygon.cpp:133
double angular_limit_
Robot angular limit.
Definition: polygon.hpp:278
bool getPolygonFromString(std::string &poly_string, std::vector< Point > &polygon)
Extracts Polygon points from a string with of the form [[x1,y1],[x2,y2],[x3,y3]......
Definition: polygon.cpp:637
rclcpp_lifecycle::LifecyclePublisher< geometry_msgs::msg::PolygonStamped >::SharedPtr polygon_pub_
Polygon publisher for visualization purposes.
Definition: polygon.hpp:310
bool visualize_
Whether to publish the polygon.
Definition: polygon.hpp:306
std::vector< std::string > getSourcesNames() const
Obtains the name of the observation sources for current polygon.
Definition: polygon.cpp:163
std::string base_frame_id_
Base frame ID.
Definition: polygon.hpp:298
double slowdown_ratio_
Robot slowdown (share of its actual speed)
Definition: polygon.hpp:274
void publish()
Publishes polygon message into a its own topic.
Definition: polygon.cpp:304
Velocity for 2D model of motion.
Definition: types.hpp:25