obstacle_points.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020, Ubiquity Robotics
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  *
30  */
31 
33 #include <sensor_msgs/Range.h>
34 
35 ObstaclePoints::ObstaclePoints(ros::NodeHandle& nh, tf2_ros::Buffer& tf_buffer) : tf_buffer(tf_buffer) {
36  sonar_sub = nh.subscribe("/sonars", 1,
38  scan_sub = nh.subscribe("/scan", 1,
40 
41  nh.param<std::string>("base_frame", baseFrame, "base_link");
42 }
43 
44 void ObstaclePoints::range_callback(const sensor_msgs::Range::ConstPtr &msg) {
45  std::string frame = msg->header.frame_id;
46  ROS_DEBUG("Callback %s %f", frame.c_str(), msg->range);
47 
48  const std::lock_guard<std::mutex> lock(points_mutex);
49 
50  // create sensor object if this is a new sensor
51  std::map<std::string,RangeSensor>::iterator it = sensors.find(frame);
52  if (it == sensors.end()) {
53  try {
54  ROS_INFO("lookup %s %s", baseFrame.c_str(), frame.c_str());
55  geometry_msgs::TransformStamped sensor_to_base_tf =
57 
59  tf2::Vector3 origin, left_vector, right_vector;
60 
61  // sensor origin
62  geometry_msgs::PointStamped sensor_origin;
63  sensor_origin.point.x = 0;
64  sensor_origin.point.y = 0;
65  sensor_origin.point.z = 0;
66  geometry_msgs::PointStamped base_origin;
67  tf2::doTransform(sensor_origin, base_origin, sensor_to_base_tf);
68  fromMsg(base_origin.point, origin);
69  ROS_INFO("Obstacle: origin %f %f %f", origin.x(), origin.y(), origin.z());
70 
71  // vectors at the edges of cone when cone height is 1m
72  double theta = msg->field_of_view / 2.0;
73  float x = std::cos(theta);
74  float y = std::sin(theta);
75 
76  geometry_msgs::Vector3Stamped sensor_left;
77  sensor_left.vector.x = x;
78  sensor_left.vector.y = -y;
79  sensor_left.vector.z = 0.0;
80  geometry_msgs::Vector3Stamped base_left;
81  tf2::doTransform(sensor_left, base_left, sensor_to_base_tf);
82  fromMsg(base_left.vector, left_vector);
83 
84  geometry_msgs::Vector3Stamped sensor_right;
85  sensor_right.vector.x = x;
86  sensor_right.vector.y = y;
87  sensor_right.vector.z = 0.0;
88  geometry_msgs::Vector3Stamped base_right;
89  tf2::doTransform(sensor_right, base_right, sensor_to_base_tf);
90  fromMsg(base_right.vector, right_vector);
91 
92  RangeSensor sensor(sensors.size(), frame, origin,
93  left_vector, right_vector);
94  sensor.update(msg->range, msg->header.stamp);
95  sensors[frame] = sensor;
96  }
97  catch (tf2::TransformException &ex) {
98  ROS_WARN("%s", ex.what());
99  }
100  }
101  else {
102  RangeSensor& sensor = it->second;
103  sensor.update(msg->range, msg->header.stamp);
104  }
105 }
106 
107 void ObstaclePoints::scan_callback(const sensor_msgs::LaserScan::ConstPtr &msg)
108 {
109  float theta = msg->angle_min;
110  float increment = msg->angle_increment;
111  size_t array_size = (msg->ranges).size();
112 
113  const std::lock_guard<std::mutex> lock(points_mutex);
114  lidar_stamp = msg->header.stamp;
115 
116  if (!have_lidar) {
117  try {
118  std::string laserFrame = msg->header.frame_id;
119  geometry_msgs::TransformStamped laser_to_base_tf =
120  tf_buffer.lookupTransform(baseFrame, laserFrame, ros::Time(0));
121 
123 
124  // lidar origin
125  geometry_msgs::PointStamped origin;
126  origin.point.x = 0;
127  origin.point.y = 0;
128  origin.point.z = 0;
129  geometry_msgs::PointStamped base_origin;
130  tf2::doTransform(origin, base_origin, laser_to_base_tf);
131  fromMsg(base_origin.point, lidar_origin);
132 
133  // normal vector
134  geometry_msgs::Vector3Stamped normal;
135  normal.vector.x = 1.0;
136  normal.vector.y = 0.0;
137  normal.vector.z = 0.0;
138  geometry_msgs::Vector3Stamped base_normal;
139  tf2::doTransform(normal, base_normal, laser_to_base_tf);
140  fromMsg(base_normal.vector, lidar_normal);
141 
142  double min_range = msg->range_min;
143  double max_range = msg->range_max;
144  double min_angle = msg->angle_min;
145  double max_angle = msg->angle_max;
146  double angle_increment = msg->angle_increment;
147  lidar.reset(laserFrame, angle_increment, min_range, max_range, min_angle, max_angle);
148  have_lidar = true;
149 
150  // Sine / Cosine Look Up Tables
151  cosLUT.reserve(array_size);
152  sinLUT.reserve(array_size);
153  double angle = msg->angle_min;
154  for (unsigned int i = 0 ; i < array_size ; i++) {
155  double cosine = std::cos(angle);
156  double sine = std::sin(angle);
157  cosLUT.push_back(std::move(cosine));
158  sinLUT.push_back(std::move(sine));
159  angle += increment;
160  }
161  }
162  catch (tf2::TransformException &ex) {
163  ROS_WARN("%s", ex.what());
164  return;
165  }
166  }
167 
168  lidar_points.clear();
169  lidar_points.reserve(array_size);
170  for (const auto& r : msg->ranges) {
171  lidar_points.push_back(PolarLine(r, theta));
172  theta += increment;
173  }
174 }
175 
176 std::vector<tf2::Vector3> ObstaclePoints::get_points(ros::Duration max_age) {
177  ros::Time now = ros::Time::now();
178  std::vector<tf2::Vector3> points;
179 
180  const std::lock_guard<std::mutex> lock(points_mutex);
181  points.reserve(lidar_points.size());
182  ros::Duration lidar_age = now - lidar_stamp;
183  if (lidar_age < max_age) {
184  for (unsigned int i = 0 ; i < lidar_points.size() ; i++) {
185  float radius = lidar_points[i].radius;
186 
187  // ignore bogus samples
188  if (std::isnan(radius) || std::isinf(radius) || radius < lidar.min_range) continue;
189 
190  float x = lidar_origin.x() + radius * (lidar_normal.x() * cosLUT[i] -
191  lidar_normal.y() * sinLUT[i]);
192 
193  float y = lidar_origin.y() + radius * (lidar_normal.y() * cosLUT[i] +
194  lidar_normal.x() * sinLUT[i]);
195 
196  points.push_back(tf2::Vector3(x, y, 0));
197  }
198  }
199 
200  for (const auto& kv : sensors) {
201  const RangeSensor& sensor = kv.second;
202 
203  ros::Duration age = now - sensor.stamp;
204  if (age < max_age) {
205  points.push_back(sensor.left_vertex);
206  points.push_back(sensor.right_vertex);
207  }
208  }
209 
210  // Add all the test points
211  points.insert(points.end(), test_points.begin(), test_points.end());
212 
213  return points;
214 }
215 
216 std::vector<ObstaclePoints::Line> ObstaclePoints::get_lines(ros::Duration max_age) {
217  ros::Time now = ros::Time::now();
218 
219  const std::lock_guard<std::mutex> lock(points_mutex);
220  std::vector<ObstaclePoints::Line> lines;
221  for (const auto& kv : sensors) {
222  const RangeSensor& sensor = kv.second;
223  ros::Duration age = now - sensor.stamp;
224  if (age < max_age) lines.emplace_back(sensor.left_vertex, sensor.right_vertex);
225  }
226 
227  return lines;
228 }
229 
230 void ObstaclePoints::add_test_point(tf2::Vector3 p) {
231  const std::lock_guard<std::mutex> lock(points_mutex);
232  test_points.push_back(p);
233 }
234 
236  const std::lock_guard<std::mutex> lock(points_mutex);
237  test_points.clear();
238 }
239 
240 void LidarSensor::reset(const std::string & _frame,
241  const int _increment,
242  const double & _min_range,
243  const double & _max_range,
244  const double & _min_angle,
245  const double & _max_angle)
246 {
247  this->frame_id = _frame;
248  this->angle_increment = _increment;
249  this->min_range = _min_range;
250  this->max_range = _max_range;
251  this->min_angle = _min_angle;
252  this->max_angle = _max_angle;
253 }
254 
255 RangeSensor::RangeSensor(int id, std::string frame_id,
256  const tf2::Vector3& origin,
257  const tf2::Vector3& left_vec,
258  const tf2::Vector3& right_vec)
259 {
260  this->id = id;
261  this->frame_id = frame_id;
262  this->origin = origin;
263  this->left_vec = left_vec;
264  this->right_vec = right_vec;
265  ROS_INFO("Adding sensor %s", frame_id.c_str());
266 }
267 
268 void RangeSensor::update(float range, ros::Time stamp)
269 {
270  this->stamp = stamp;
271  left_vertex = origin + left_vec * range;
272  right_vertex = origin + right_vec * range;
273 }
274 
275 ObstaclePoints::PolarLine::PolarLine(float radius, float theta)
276 {
277  this->radius = radius;
278  this->theta = theta;
279 }
ros::Subscriber sonar_sub
PolarLine(float radius, float theta)
tf2::Vector3 left_vertex
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
virtual geometry_msgs::TransformStamped lookupTransform(const std::string &target_frame, const std::string &source_frame, const ros::Time &time, const ros::Duration timeout) const
ros::Subscriber scan_sub
ObstaclePoints(ros::NodeHandle &nh, tf2_ros::Buffer &tf_buffer)
void reset(const std::string &_frame, const int _increment, const double &_min_range, const double &_max_range, const double &_min_angle, const double &_max_angle)
void doTransform(const T &data_in, T &data_out, const geometry_msgs::TransformStamped &transform)
TFSIMD_FORCE_INLINE const tfScalar & y() const
#define ROS_WARN(...)
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
ros::Time lidar_stamp
void range_callback(const sensor_msgs::Range::ConstPtr &msg)
std::string baseFrame
std::vector< PolarLine > lidar_points
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void update(float range, ros::Time stamp)
void fromMsg(const A &, B &b)
TFSIMD_FORCE_INLINE const tfScalar & x() const
void add_test_point(tf2::Vector3 p)
std::map< std::string, RangeSensor > sensors
ros::Time stamp
tf2::Vector3 lidar_normal
LidarSensor lidar
void scan_callback(const sensor_msgs::LaserScan::ConstPtr &msg)
tf2_ros::Buffer & tf_buffer
std::vector< Line > get_lines(ros::Duration max_age)
std::vector< float > cosLUT
double min_range
std::vector< tf2::Vector3 > get_points(ros::Duration max_age)
std::vector< float > sinLUT
static Time now()
tf2::Vector3 right_vertex
tf2::Vector3 lidar_origin
std::vector< tf2::Vector3 > test_points
std::mutex points_mutex
#define ROS_DEBUG(...)


move_basic
Author(s): Jim Vaughan
autogenerated on Fri Mar 26 2021 02:46:58