Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
velocity_polygon.cpp
1 // Copyright (c) 2023 Dexory
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/velocity_polygon.hpp"
16 
17 #include "nav2_ros_common/node_utils.hpp"
18 #include "nav2_ros_common/tf2_factories.hpp"
19 
20 namespace nav2_collision_monitor
21 {
22 
24  const nav2::LifecycleNode::WeakPtr & node, const std::string & polygon_name,
25  const nav2::TransformBuffer::SharedPtr tf_buffer, const std::string & base_frame_id,
26  const tf2::Duration & transform_tolerance)
27 : Polygon::Polygon(node, polygon_name, tf_buffer, base_frame_id, transform_tolerance)
28 {
29  RCLCPP_INFO(logger_, "[%s]: Creating VelocityPolygon", polygon_name_.c_str());
30 }
31 
33 {
34  RCLCPP_INFO(logger_, "[%s]: Destroying VelocityPolygon", polygon_name_.c_str());
35 }
36 
38  std::string & polygon_sub_topic,
39  std::string & polygon_pub_topic,
40  std::string & footprint_topic)
41 {
42  auto node = node_.lock();
43  if (!node) {
44  throw std::runtime_error{"Failed to lock node"};
45  }
46  clock_ = node->get_clock();
47 
48  if (!getCommonParameters(polygon_sub_topic, polygon_pub_topic, footprint_topic, false)) {
49  return false;
50  }
51 
52  try {
53  // Get velocity_polygons parameter
54  std::vector<std::string> velocity_polygons =
55  node->declare_or_get_parameter<std::vector<std::string>>(
56  polygon_name_ + ".velocity_polygons");
57 
58  // holonomic param
59  holonomic_ = node->declare_or_get_parameter(
60  polygon_name_ + ".holonomic", false);
61 
62  for (std::string velocity_polygon_name : velocity_polygons) {
63  // polygon points parameter
64  std::vector<Point> poly;
65  std::string poly_string =
66  node->declare_or_get_parameter<std::string>(
67  polygon_name_ + "." + velocity_polygon_name + ".points");
68 
69  if (!getPolygonFromString(poly_string, poly)) {
70  return false;
71  }
72 
73  // linear_min param
74  double linear_min = node->declare_or_get_parameter<double>(
75  polygon_name_ + "." + velocity_polygon_name + ".linear_min");
76 
77  // linear_max param
78  double linear_max = node->declare_or_get_parameter<double>(
79  polygon_name_ + "." + velocity_polygon_name + ".linear_max");
80 
81  // theta_min param
82  double theta_min = node->declare_or_get_parameter<double>(
83  polygon_name_ + "." + velocity_polygon_name + ".theta_min");
84 
85  // theta_max param
86  double theta_max = node->declare_or_get_parameter<double>(
87  polygon_name_ + "." + velocity_polygon_name + ".theta_max");
88 
89  // direction_end_angle param and direction_start_angle param
90  double direction_end_angle = 0.0;
91  double direction_start_angle = 0.0;
92  if (holonomic_) {
93  direction_end_angle = node->declare_or_get_parameter(
94  polygon_name_ + "." + velocity_polygon_name + ".direction_end_angle", M_PI);
95 
96  direction_start_angle = node->declare_or_get_parameter(
97  polygon_name_ + "." + velocity_polygon_name + ".direction_start_angle", -M_PI);
98  }
99 
100  SubPolygonParameter sub_polygon = {
101  poly, velocity_polygon_name, linear_min, linear_max, theta_min,
102  theta_max, direction_end_angle, direction_start_angle};
103  sub_polygons_.push_back(sub_polygon);
104  }
105  } catch (const std::exception & ex) {
106  RCLCPP_ERROR(
107  logger_, "[%s]: Error while getting polygon parameters: %s", polygon_name_.c_str(),
108  ex.what());
109  return false;
110  }
111  return true;
112 }
113 
114 void VelocityPolygon::updatePolygon(const Velocity & cmd_vel_in)
115 {
116  for (auto & sub_polygon : sub_polygons_) {
117  if (isInRange(cmd_vel_in, sub_polygon)) {
118  // Set the polygon that is within the speed range
119  poly_ = sub_polygon.poly_;
120 
121  // Update visualization polygon
122  polygon_.polygon.points.clear();
123  for (const Point & p : poly_) {
124  geometry_msgs::msg::Point32 p_s;
125  p_s.x = p.x;
126  p_s.y = p.y;
127  // p_s.z will remain 0.0
128  polygon_.polygon.points.push_back(p_s);
129  }
130  return;
131  }
132  }
133 
134  // Log for uncovered velocity
135  RCLCPP_WARN_THROTTLE(
136  logger_, *clock_, 2.0,
137  "Velocity is not covered by any of the velocity polygons. x: %.3f y: %.3f tw: %.3f ",
138  cmd_vel_in.x, cmd_vel_in.y, cmd_vel_in.tw);
139  return;
140 }
141 
143  const Velocity & cmd_vel_in, const SubPolygonParameter & sub_polygon)
144 {
145  // 1. Always check angular range first
146  bool in_range =
147  (cmd_vel_in.tw <= sub_polygon.theta_max_ &&
148  cmd_vel_in.tw >= sub_polygon.theta_min_);
149 
150  if (holonomic_) {
151  // 2. For holonomic robots: use speed magnitude + direction
152  const double magnitude = std::hypot(cmd_vel_in.x, cmd_vel_in.y);
153  // Direction is undefined at rest; choose 0 and rely on configured direction ranges.
154  const double direction = (magnitude > 0.0) ? std::atan2(cmd_vel_in.y, cmd_vel_in.x) : 0.0;
155 
156  // Linear range on speed magnitude
157  in_range &= (magnitude <= sub_polygon.linear_max_ &&
158  magnitude >= sub_polygon.linear_min_);
159 
160  // Direction range
161  if (sub_polygon.direction_start_angle_ <= sub_polygon.direction_end_angle_) {
162  in_range &=
163  (direction >= sub_polygon.direction_start_angle_ &&
164  direction <= sub_polygon.direction_end_angle_);
165  } else {
166  in_range &=
167  (direction >= sub_polygon.direction_start_angle_ ||
168  direction <= sub_polygon.direction_end_angle_);
169  }
170  } else {
171  // 3. Non-holonomic: keep x-based behavior
172  in_range &=
173  (cmd_vel_in.x <= sub_polygon.linear_max_ &&
174  cmd_vel_in.x >= sub_polygon.linear_min_);
175  }
176 
177  return in_range;
178 }
179 
180 } // namespace nav2_collision_monitor
Basic polygon shape class. For STOP/SLOWDOWN/LIMIT model it represents zone around the robot while fo...
Definition: polygon.hpp:45
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:407
rclcpp::Logger logger_
Collision monitor node logger stored for further usage.
Definition: polygon.hpp:307
geometry_msgs::msg::PolygonStamped polygon_
Polygon, used for: 1. visualization; 2. storing latest dynamic polygon message.
Definition: polygon.hpp:365
std::vector< Point > poly_
Polygon points (vertices) in a base_frame_id_.
Definition: polygon.hpp:370
std::string polygon_name_
Name of polygon.
Definition: polygon.hpp:315
nav2::LifecycleNode::WeakPtr node_
Collision Monitor node.
Definition: polygon.hpp:305
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:704
std::vector< SubPolygonParameter > sub_polygons_
Vector to store the parameters of the sub-polygon.
bool getParameters(std::string &, std::string &polygon_pub_topic, std::string &) override
Overridden getParameters function for VelocityPolygon parameters.
bool isInRange(const Velocity &cmd_vel_in, const SubPolygonParameter &sub_polygon_param)
Check if the velocities and direction is in expected range.
virtual ~VelocityPolygon()
VelocityPolygon destructor.
void updatePolygon(const Velocity &cmd_vel_in) override
Overridden updatePolygon function for VelocityPolygon.
bool holonomic_
Flag to indicate if the robot is holonomic.
VelocityPolygon(const nav2::LifecycleNode::WeakPtr &node, const std::string &polygon_name, const nav2::TransformBuffer::SharedPtr tf_buffer, const std::string &base_frame_id, const tf2::Duration &transform_tolerance)
VelocityPolygon constructor.
Point with 2D collision-check coordinates and optional z from the source.
Definition: types.hpp:52
Custom struct to store the parameters of the sub-polygon.
Velocity for 2D model of motion.
Definition: types.hpp:26