Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
range.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/range.hpp"
16 
17 #include <math.h>
18 #include <cmath>
19 #include <functional>
20 
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_ros_common/validate_messages.hpp"
26 #include "nav2_util/robot_utils.hpp"
27 
28 namespace nav2_collision_monitor
29 {
30 
31 constexpr size_t MAX_RANGE_DATA_POINTS = 1e4;
32 
34  const nav2::LifecycleNode::WeakPtr & node,
35  const std::string & source_name,
36  const nav2::TransformBuffer::SharedPtr tf_buffer,
37  const std::string & base_frame_id,
38  const std::string & global_frame_id,
39  const tf2::Duration & transform_tolerance,
40  const rclcpp::Duration & source_timeout,
41  const bool base_shift_correction)
42 : Source(
43  node, source_name, tf_buffer, base_frame_id, global_frame_id,
44  transform_tolerance, source_timeout, base_shift_correction),
45  data_(nullptr)
46 {
47  RCLCPP_INFO(logger_, "[%s]: Creating Range", source_name_.c_str());
48 }
49 
51 {
52  RCLCPP_INFO(logger_, "[%s]: Destroying Range", source_name_.c_str());
53  data_sub_.reset();
54 }
55 
57 {
58  if (!Source::configure()) {
59  return false;
60  }
61  auto node = node_.lock();
62  if (!node) {
63  throw std::runtime_error{"Failed to lock node"};
64  }
65 
66  std::string source_topic;
67 
68  getParameters(source_topic);
69 
70  data_sub_ = node->create_subscription<sensor_msgs::msg::Range>(
71  source_topic,
72  std::bind(&Range::dataCallback, this, std::placeholders::_1),
74 
75  return true;
76 }
77 
79  const rclcpp::Time & curr_time,
80  std::vector<Point> & data)
81 {
82  // Ignore data from the source if it is not being published yet or
83  // not being published for a long time
84  if (data_ == nullptr) {
85  return false;
86  }
87  if (!sourceValid(data_->header.stamp, curr_time)) {
88  return false;
89  }
90 
91  // Ignore data, if its range is out of scope of range sensor abilities
92  if (data_->range < data_->min_range || data_->range > data_->max_range) {
93  RCLCPP_DEBUG(
94  logger_,
95  "[%s]: Data range %fm is out of {%f..%f} sensor span. Ignoring...",
96  source_name_.c_str(), data_->range, data_->min_range, data_->max_range);
97  return false;
98  }
99 
100  const size_t point_count = static_cast<size_t>(
101  std::ceil(static_cast<double>(data_->field_of_view) / obstacles_angle_)) + 1;
102  if (point_count > MAX_RANGE_DATA_POINTS) {
103  RCLCPP_ERROR(
104  logger_,
105  "[%s]: Range data would generate %zu points, exceeding the limit of %zu. Ignoring...",
106  source_name_.c_str(), point_count, MAX_RANGE_DATA_POINTS);
107  return false;
108  }
109 
110  tf2::Transform tf_transform;
111  if (!getTransform(curr_time, data_->header, tf_transform)) {
112  return false;
113  }
114 
115  // Calculate poses and refill data array
116  float angle;
117  for (
118  angle = -data_->field_of_view / 2;
119  angle < data_->field_of_view / 2;
120  angle += obstacles_angle_)
121  {
122  // Transform point coordinates from source frame -> to base frame
123  tf2::Vector3 p_v3_s(
124  data_->range * std::cos(angle),
125  data_->range * std::sin(angle),
126  0.0);
127  tf2::Vector3 p_v3_b = tf_transform * p_v3_s;
128 
129  // Refill data array
130  data.push_back({p_v3_b.x(), p_v3_b.y(), p_v3_b.z(), source_name_});
131  }
132 
133  // Make sure that last (field_of_view / 2) point will be in the data array
134  angle = data_->field_of_view / 2;
135 
136  // Transform point coordinates from source frame -> to base frame
137  tf2::Vector3 p_v3_s(
138  data_->range * std::cos(angle),
139  data_->range * std::sin(angle),
140  0.0);
141  tf2::Vector3 p_v3_b = tf_transform * p_v3_s;
142 
143  // Refill data array
144  data.push_back({p_v3_b.x(), p_v3_b.y(), p_v3_b.z(), source_name_});
145 
146  return true;
147 }
148 
149 void Range::getParameters(std::string & source_topic)
150 {
151  auto node = node_.lock();
152  if (!node) {
153  throw std::runtime_error{"Failed to lock node"};
154  }
155 
156  getCommonParameters(source_topic);
157 
158  obstacles_angle_ = node->declare_or_get_parameter(
159  source_name_ + ".obstacles_angle", M_PI / 180);
160 
161  if (!std::isfinite(obstacles_angle_) || obstacles_angle_ <= 0.0) {
162  throw std::runtime_error{
163  "Range source " + source_name_ + " has invalid obstacles_angle parameter"};
164  }
165 }
166 
167 void Range::dataCallback(sensor_msgs::msg::Range::ConstSharedPtr msg)
168 {
169  if (!nav2::validateMsg(*msg)) {
170  RCLCPP_ERROR(
171  logger_,
172  "[%s]: Malformed range message. Rejecting...",
173  source_name_.c_str());
174  return;
175  }
176 
177  data_ = msg;
178 }
179 
180 } // namespace nav2_collision_monitor
A QoS profile for best-effort sensor data with a history of 10 messages.
sensor_msgs::msg::Range::ConstSharedPtr data_
Latest data obtained from range sensor.
Definition: range.hpp:102
void dataCallback(sensor_msgs::msg::Range::ConstSharedPtr msg)
Range sensor data callback.
Definition: range.cpp:167
~Range()
Range destructor.
Definition: range.cpp:50
nav2::Subscription< sensor_msgs::msg::Range >::SharedPtr data_sub_
Range sensor data subscriber.
Definition: range.hpp:96
Range(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)
Range constructor.
Definition: range.cpp:33
void getParameters(std::string &source_topic)
Getting sensor-specific ROS-parameters.
Definition: range.cpp:149
double obstacles_angle_
Angle increment (in rad) between two obstacle points at the range arc.
Definition: range.hpp:99
bool configure()
Data source configuration routine. Obtains ROS-parameters and creates range sensor subscriber.
Definition: range.cpp:56
bool getSourceData(const rclcpp::Time &curr_time, std::vector< Point > &data) override
Adds latest data from range sensor to the data array.
Definition: range.cpp:78
Basic data source class.
Definition: source.hpp:44
nav2::LifecycleNode::WeakPtr node_
Collision Monitor node.
Definition: source.hpp:205
rclcpp::Logger logger_
Collision monitor node logger stored for further usage.
Definition: source.hpp:207
bool getTransform(const rclcpp::Time &curr_time, const std_msgs::msg::Header &data_header, tf2::Transform &tf_transform) const
Obtain the transform to get data from source frame and time where it was received to the base frame a...
Definition: source.cpp:325
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 source_name_
Name of data source.
Definition: source.hpp:215
bool sourceValid(const rclcpp::Time &source_time, const rclcpp::Time &curr_time) const
Checks whether the source data might be considered as valid.
Definition: source.cpp:179