Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
polygon_source.cpp
1 // Copyright (c) 2023 Pixel Robotics GmbH
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_source.hpp"
16 
17 #include <cmath>
18 #include <functional>
19 
20 #include "geometry_msgs/msg/polygon_stamped.hpp"
21 #include "tf2/transform_datatypes.hpp"
22 #include "nav2_ros_common/tf2_factories.hpp"
23 
24 #include "nav2_ros_common/node_utils.hpp"
25 #include "nav2_util/robot_utils.hpp"
26 
27 
28 namespace nav2_collision_monitor
29 {
30 
32  const nav2::LifecycleNode::WeakPtr & node,
33  const std::string & source_name,
34  const nav2::TransformBuffer::SharedPtr tf_buffer,
35  const std::string & base_frame_id,
36  const std::string & global_frame_id,
37  const tf2::Duration & transform_tolerance,
38  const rclcpp::Duration & source_timeout,
39  const bool base_shift_correction)
40 : Source(
41  node, source_name, tf_buffer, base_frame_id, global_frame_id,
42  transform_tolerance, source_timeout, base_shift_correction)
43 {
44 }
45 
47 {
48  data_sub_.reset();
49 }
50 
52 {
53  if (!Source::configure()) {
54  return false;
55  }
56  auto node = node_.lock();
57  if (!node) {
58  throw std::runtime_error{"Failed to lock node"};
59  }
60 
61  std::string source_topic;
62 
63  getParameters(source_topic);
64 
65  data_sub_ = node->create_subscription<geometry_msgs::msg::PolygonInstanceStamped>(
66  source_topic,
67  std::bind(&PolygonSource::dataCallback, this, std::placeholders::_1),
69 
70  return true;
71 }
72 
74  const rclcpp::Time & curr_time,
75  std::vector<Point> & data)
76 {
77  // Ignore data from the source if it is not being published yet or
78  // not published for a long time
79  if (data_.empty()) {
80  return false;
81  }
82 
83  // Remove stale data
84  data_.erase(
85  std::remove_if(
86  data_.begin(), data_.end(),
87  [this, curr_time](const geometry_msgs::msg::PolygonInstanceStamped & polygon_stamped) {
88  return curr_time - rclcpp::Time(polygon_stamped.header.stamp) > source_timeout_;
89  }), data_.end());
90 
91  tf2::Stamped<tf2::Transform> tf_transform;
92  for (const auto & polygon_instance : data_) {
94  // Obtaining the transform to get data from source frame and time where it was received
95  // to the base frame and current time
96  if (
97  !nav2_util::getTransform(
98  polygon_instance.header.frame_id, polygon_instance.header.stamp,
99  base_frame_id_, curr_time, global_frame_id_,
100  transform_tolerance_, tf_buffer_, tf_transform))
101  {
102  return false;
103  }
104  } else {
105  // Obtaining the transform to get data from source frame to base frame without time shift
106  // considered. Less accurate but much more faster option not dependent on state estimation
107  // frames.
108  if (
109  !nav2_util::getTransform(
110  polygon_instance.header.frame_id, base_frame_id_,
111  transform_tolerance_, tf_buffer_, tf_transform))
112  {
113  return false;
114  }
115  }
116  geometry_msgs::msg::PolygonStamped poly_out, polygon_stamped;
117  geometry_msgs::msg::TransformStamped tf = tf2::toMsg(tf_transform);
118  polygon_stamped.header = polygon_instance.header;
119  polygon_stamped.polygon = polygon_instance.polygon.polygon;
120  tf2::doTransform(polygon_stamped, poly_out, tf);
121  convertPolygonStampedToPoints(poly_out, data);
122  }
123  return true;
124 }
125 
127  const geometry_msgs::msg::PolygonStamped & polygon, std::vector<Point> & data) const
128 {
129  /* Full function generated by GPT */
130 
131  // Iterate over the vertices of the polygon
132  for (size_t i = 0; i < polygon.polygon.points.size(); ++i) {
133  const auto & current_point = polygon.polygon.points[i];
134  const auto & next_point =
135  polygon.polygon.points[(i + 1) % polygon.polygon.points.size()];
136 
137  // Calculate the distance between the current and next points
138  double segment_length =
139  std::hypot(next_point.x - current_point.x, next_point.y - current_point.y);
140 
141  // Calculate the number of points to sample in the current segment
142  int num_points_in_segment =
143  std::max(static_cast<int>(std::ceil(segment_length / sampling_distance_)), 1);
144 
145  // Calculate the step size for each pair of vertices
146  const double dx = (next_point.x - current_point.x) / num_points_in_segment;
147  const double dy = (next_point.y - current_point.y) / num_points_in_segment;
148 
149  // Sample the points with equal spacing
150  for (int j = 0; j <= num_points_in_segment; ++j) {
151  Point p;
152  p.x = current_point.x + j * dx;
153  p.y = current_point.y + j * dy;
154  p.source = source_name_;
155  data.push_back(p);
156  }
157  }
158 }
159 
160 void PolygonSource::getParameters(std::string & source_topic)
161 {
162  auto node = node_.lock();
163  if (!node) {
164  throw std::runtime_error{"Failed to lock node"};
165  }
166 
167  getCommonParameters(source_topic);
168 
169  sampling_distance_ = node->declare_or_get_parameter(
170  source_name_ + ".sampling_distance", 0.1);
171 }
172 
173 void PolygonSource::dataCallback(geometry_msgs::msg::PolygonInstanceStamped::ConstSharedPtr msg)
174 {
175  auto node = node_.lock();
176  if (!node) {
177  throw std::runtime_error{"Failed to lock node"};
178  }
179  auto curr_time = node->now();
180 
181  // check if older similar polygon exists already and replace it with the new one
182  for (auto & polygon_stamped : data_) {
183  if (msg->polygon.id == polygon_stamped.polygon.id) {
184  polygon_stamped = *msg;
185  return;
186  }
187  }
188  data_.push_back(*msg);
189 }
190 
191 } // namespace nav2_collision_monitor
A QoS profile for best-effort sensor data with a history of 10 messages.
void getParameters(std::string &source_topic)
Getting sensor-specific ROS-parameters.
void dataCallback(geometry_msgs::msg::PolygonInstanceStamped::ConstSharedPtr msg)
PolygonSource data callback.
PolygonSource(const nav2::LifecycleNode::WeakPtr &node, const std::string &source_name, const nav2::TransformBuffer::SharedPtr tf_buffer, const std::string &base_frame_id, const std::string &global_frame_id, const tf2::Duration &transform_tolerance, const rclcpp::Duration &source_timeout, const bool base_shift_correction)
PolygonSource constructor.
nav2::Subscription< geometry_msgs::msg::PolygonInstanceStamped >::SharedPtr data_sub_
PolygonSource data subscriber.
void convertPolygonStampedToPoints(const geometry_msgs::msg::PolygonStamped &polygon, std::vector< Point > &data) const
Converts a PolygonInstanceStamped to a std::vector<Point>
~PolygonSource()
PolygonSource destructor.
bool configure()
Data source configuration routine. Obtains ROS-parameters and creates subscriber.
bool getSourceData(const rclcpp::Time &curr_time, std::vector< Point > &data) override
Adds latest data from polygon source to the data array.
double sampling_distance_
distance between sampled points on polygon edges
std::vector< geometry_msgs::msg::PolygonInstanceStamped > data_
Latest data obtained.
Basic data source class.
Definition: source.hpp:44
nav2::LifecycleNode::WeakPtr node_
Collision Monitor node.
Definition: source.hpp:205
std::string base_frame_id_
Robot base frame ID.
Definition: source.hpp:221
tf2::Duration transform_tolerance_
Transform tolerance.
Definition: source.hpp:225
void getCommonParameters(std::string &source_topic)
Supporting routine obtaining ROS-parameters common for all data sources.
Definition: source.cpp:160
bool configure()
Source configuration routine.
Definition: source.cpp:62
std::string global_frame_id_
Global frame ID for correct transform calculation.
Definition: source.hpp:223
std::string source_name_
Name of data source.
Definition: source.hpp:215
bool base_shift_correction_
Whether to correct source data towards to base frame movement, considering the difference between cur...
Definition: source.hpp:230
nav2::TransformBuffer::SharedPtr tf_buffer_
TF buffer.
Definition: source.hpp:219
Point with 2D collision-check coordinates and optional z from the source.
Definition: types.hpp:52