path2d.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018, the neonavigation authors
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  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the copyright holder nor the names of its
14  * contributors may be used to endorse or promote products derived from
15  * this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 #ifndef TRAJECTORY_TRACKER_PATH2D_H
31 #define TRAJECTORY_TRACKER_PATH2D_H
32 
33 #include <limits>
34 #include <utility>
35 #include <vector>
36 
37 #include <Eigen/Core>
38 #include <Eigen/Geometry>
39 
40 #include <geometry_msgs/Pose.h>
41 #include <nav_msgs/Path.h>
42 #include <tf2/utils.h>
43 #include <trajectory_tracker_msgs/PathWithVelocity.h>
44 
47 
48 #include <ros/ros.h>
49 
50 namespace trajectory_tracker
51 {
52 class Pose2D
53 {
54 public:
55  Eigen::Vector2d pos_;
56  float yaw_;
57  float velocity_;
58 
59  inline Pose2D()
60  : pos_(0, 0)
61  , yaw_(0)
62  , velocity_(0)
63  {
64  }
65  inline Pose2D(const Eigen::Vector2d& p, float y, float velocity)
66  : pos_(p)
67  , yaw_(y)
68  , velocity_(velocity)
69  {
70  }
71  inline Pose2D(const geometry_msgs::Pose& pose, float velocity)
72  : pos_(Eigen::Vector2d(pose.position.x, pose.position.y))
73  , yaw_(tf2::getYaw(pose.orientation))
74  , velocity_(velocity)
75  {
76  }
77  inline explicit Pose2D(const geometry_msgs::PoseStamped& pose)
78  : pos_(Eigen::Vector2d(pose.pose.position.x, pose.pose.position.y))
79  , yaw_(tf2::getYaw(pose.pose.orientation))
80  , velocity_(std::numeric_limits<float>::quiet_NaN())
81  {
82  }
83  inline explicit Pose2D(const trajectory_tracker_msgs::PoseStampedWithVelocity& pose)
84  : pos_(Eigen::Vector2d(pose.pose.position.x, pose.pose.position.y))
85  , yaw_(tf2::getYaw(pose.pose.orientation))
86  , velocity_(pose.linear_velocity.x)
87  {
88  }
89  inline void rotate(const float ang)
90  {
91  const float org_x = pos_.x();
92  const float org_y = pos_.y();
93  const float cos_v = std::cos(ang);
94  const float sin_v = std::sin(ang);
95 
96  pos_.x() = cos_v * org_x - sin_v * org_y;
97  pos_.y() = sin_v * org_x + cos_v * org_y;
98  yaw_ += ang;
99  while (yaw_ < 0)
100  yaw_ += 2 * M_PI;
101  while (yaw_ > 2 * M_PI)
102  yaw_ -= 2 * M_PI;
103  }
104  void toMsg(geometry_msgs::PoseStamped& pose) const
105  {
106  pose.pose.position.x = pos_.x();
107  pose.pose.position.y = pos_.y();
108  pose.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0, 0, 1), yaw_));
109  }
110  void toMsg(trajectory_tracker_msgs::PoseStampedWithVelocity& pose) const
111  {
112  pose.pose.position.x = pos_.x();
113  pose.pose.position.y = pos_.y();
114  pose.pose.orientation = tf2::toMsg(tf2::Quaternion(tf2::Vector3(0, 0, 1), yaw_));
115  pose.linear_velocity.x = velocity_;
116  }
117 };
118 class Path2D : public std::vector<Pose2D>
119 {
120 private:
121  using Super = std::vector<Pose2D>;
122 
123 public:
124  using Iterator = std::vector<Pose2D>::iterator;
125  using ConstIterator = std::vector<Pose2D>::const_iterator;
126 
127  inline float length() const
128  {
129  double l = 0;
130  for (size_t i = 1; i < size(); i++)
131  l += ((*this)[i - 1].pos_ - (*this)[i].pos_).norm();
132  return l;
133  }
135  const ConstIterator& begin,
136  const ConstIterator& end,
137  const bool allow_switch_back,
138  const bool allow_in_place_turn = true,
139  const double epsilon = 1e-6) const
140  {
141  float sign_vel_prev = 0;
142  ConstIterator it_prev = begin;
143  for (ConstIterator it = begin + 1; it < end; ++it)
144  {
145  if ((it->pos_ - it_prev->pos_).squaredNorm() < epsilon)
146  {
147  if (allow_in_place_turn)
148  {
149  // stop reading forward if the path is in-place turning
150  return it;
151  }
152  sign_vel_prev = 0;
153  }
154  else if (allow_switch_back)
155  {
156  const Eigen::Vector2d inc = it->pos_ - it_prev->pos_;
157  const float angle = atan2(inc[1], inc[0]);
158  const float angle_pose = it->yaw_;
159  const float sign_vel_req = std::cos(angle) * std::cos(angle_pose) + std::sin(angle) * std::sin(angle_pose);
160  if (sign_vel_prev * sign_vel_req < 0)
161  {
162  // stop reading forward if the path is switching back
163  return it;
164  }
165  sign_vel_prev = sign_vel_req;
166  }
167  it_prev = it;
168  }
169  return end;
170  }
172  const ConstIterator& begin,
173  const ConstIterator& end,
174  const Eigen::Vector2d& target,
175  const float max_search_range = 0,
176  const float epsilon = 1e-6) const
177  {
178  return findNearestWithDistance(begin, end, target, max_search_range, epsilon).first;
179  }
180  inline std::pair<ConstIterator, double> findNearestWithDistance(
181  const ConstIterator& begin,
182  const ConstIterator& end,
183  const Eigen::Vector2d& target,
184  const float max_search_range = 0,
185  const float epsilon = 1e-6) const
186  {
187  if (begin == end)
188  {
189  if (end == this->end())
190  {
191  return std::make_pair(end, std::numeric_limits<double>::max());
192  }
193  return std::make_pair(end, (end->pos_ - target).norm());
194  }
195  float distance_path_search = 0;
196  ConstIterator it_nearest = begin;
197  float min_dist = (begin->pos_ - target).norm() + epsilon;
198 
199  ConstIterator it_prev = begin;
200  for (ConstIterator it = begin + 1; it < end; ++it)
201  {
202  const Eigen::Vector2d inc = it->pos_ - it_prev->pos_;
203  distance_path_search += inc.norm();
204  if (max_search_range > 0 && distance_path_search > max_search_range)
205  break;
206 
207  const float d =
208  trajectory_tracker::lineStripDistanceSigned(it_prev->pos_, it->pos_, target);
209 
210  // Use earlier point if the robot is same distance from two line strip
211  // to avoid chattering.
212  const float d_compare = (d > 0) ? d : (-d - epsilon);
213  const float d_abs = std::abs(d);
214 
215  // If it is the last point, select it as priority
216  // to calculate correct remained distance.
217  if (d_compare <= min_dist || (it + 1 == end && d_abs <= min_dist + epsilon))
218  {
219  min_dist = d_abs;
220  it_nearest = it;
221  }
222  it_prev = it;
223  }
224  return std::make_pair(it_nearest, min_dist);
225  }
226  inline double remainedDistance(
227  const ConstIterator& begin,
228  const ConstIterator& nearest,
229  const ConstIterator& end,
230  const Eigen::Vector2d& target_on_line) const
231  {
232  double remain = (nearest->pos_ - target_on_line).norm();
233  if (nearest + 1 >= end)
234  {
235  const ConstIterator last = end - 1;
236  const ConstIterator last_pre = end - 2;
237  if (last_pre < begin || last < begin)
238  {
239  // no enough points: orientation control mode
240  return 0;
241  }
242  const Eigen::Vector2d vec_path = last->pos_ - last_pre->pos_;
243  const Eigen::Vector2d vec_remain = last->pos_ - target_on_line;
244  if (vec_path.dot(vec_remain) >= 0)
245  {
246  // ongoing
247  return remain;
248  }
249  // overshoot
250  return -remain;
251  }
252  ConstIterator it_prev = nearest;
253  for (ConstIterator it = nearest + 1; it < end; ++it)
254  {
255  remain += (it_prev->pos_ - it->pos_).norm();
256  it_prev = it;
257  }
258  return remain;
259  }
260  inline float getCurvature(
261  const ConstIterator& begin,
262  const ConstIterator& end,
263  const Eigen::Vector2d& target_on_line,
264  const float max_search_range) const
265  {
266  if (end - begin <= 1)
267  {
268  return 0;
269  }
270  else if (end - begin == 2)
271  {
272  // When only two poses are remained, the logic same as planner_cspace::planner_3d::RotationCache is used.
273  ConstIterator it_prev = begin;
274  ConstIterator it = begin + 1;
275  Pose2D rel(it->pos_ - it_prev->pos_, it->yaw_, 0.0f);
276  rel.rotate(-it_prev->yaw_);
277  const float sin_v = std::sin(rel.yaw_);
278  static const float EPS = 1.0e-6f;
279  if (std::abs(sin_v) < EPS)
280  {
281  return 0;
282  }
283  const float cos_v = std::cos(rel.yaw_);
284  const float r1 = rel.pos_.y() + rel.pos_.x() * cos_v / sin_v;
285  const float r2 = std::copysign(
286  std::sqrt(std::pow(rel.pos_.x(), 2) + std::pow(rel.pos_.x() * cos_v / sin_v, 2)),
287  rel.pos_.x() * sin_v);
288  return 1.0f / ((r1 + r2) / 2);
289  }
290  const float max_search_range_sq = max_search_range * max_search_range;
292  ConstIterator it_prev2 = begin;
293  ConstIterator it_prev1 = begin + 1;
294  for (ConstIterator it = begin + 2; it < end; ++it)
295  {
296  curv += trajectory_tracker::curv3p(it_prev2->pos_, it_prev1->pos_, it->pos_);
297  if ((it->pos_ - target_on_line).squaredNorm() > max_search_range_sq)
298  break;
299  it_prev2 = it_prev1;
300  it_prev1 = it;
301  }
302  return curv;
303  }
304  // PATH_TYPE should be trajectory_tracker_msgs::PathWithVelocity or nav_msgs::Path
305  template <typename PATH_TYPE>
306  inline void fromMsg(const PATH_TYPE& path, const double in_place_turn_eps = 1.0e-6)
307  {
308  clear();
309  bool in_place_turning = false;
310  trajectory_tracker::Pose2D in_place_turn_end;
311  for (const auto& pose : path.poses)
312  {
313  const trajectory_tracker::Pose2D next(pose);
314  if (empty())
315  {
316  push_back(next);
317  continue;
318  }
319  if ((back().pos_ - next.pos_).squaredNorm() >= std::pow(in_place_turn_eps, 2))
320  {
321  if (in_place_turning)
322  {
323  push_back(in_place_turn_end);
324  in_place_turning = false;
325  }
326  push_back(next);
327  }
328  else
329  {
330  in_place_turn_end = trajectory_tracker::Pose2D(
331  back().pos_, next.yaw_, next.velocity_);
332  in_place_turning = true;
333  }
334  }
335  if (in_place_turning)
336  {
337  push_back(in_place_turn_end);
338  }
339  }
340  // PATH_TYPE should be trajectory_tracker_msgs::PathWithVelocity or nav_msgs::Path
341  template <typename PATH_TYPE>
342  inline void toMsg(PATH_TYPE& path) const
343  {
344  path.poses.clear();
345  path.poses.resize(size());
346  for (size_t i = 0; i < size(); ++i)
347  {
348  path.poses[i].header = path.header;
349  at(i).toMsg(path.poses[i]);
350  }
351  }
352 
353  inline std::vector<ConstIterator> enumerateLocalGoals(
354  const ConstIterator& begin,
355  const ConstIterator& end,
356  const bool allow_switch_back,
357  const bool allow_in_place_turn = true,
358  const double epsilon = 1e-6) const
359  {
360  ConstIterator it_search_begin = begin;
361  std::vector<ConstIterator> results;
362  while (true)
363  {
364  const ConstIterator it_local_goal =
365  findLocalGoal(it_search_begin, end, allow_switch_back, allow_in_place_turn, epsilon);
366  if (it_local_goal == end)
367  break;
368  results.push_back(it_local_goal);
369  it_search_begin = it_local_goal;
370  }
371  return results;
372  }
373 
374  inline std::vector<double> getEstimatedTimeOfArrivals(
375  const ConstIterator& begin,
376  const ConstIterator& end,
377  const double linear_speed,
378  const double angular_speed,
379  const double initial_eta_sec = 0.0) const
380  {
381  if (begin == end)
382  {
383  return std::vector<double>();
384  }
385  std::vector<double> results(1, initial_eta_sec);
386  double elapsed_sec = initial_eta_sec;
387  ConstIterator it_prev = begin;
388  for (ConstIterator it = begin + 1; it < end; ++it)
389  {
390  const double dist = (it_prev->pos_ - it->pos_).norm();
391  if (dist > 1.0e-6)
392  {
393  elapsed_sec += dist / linear_speed;
394  }
395  else
396  {
397  double ang_diff = std::abs(it_prev->yaw_ - it->yaw_);
398  if (ang_diff > M_PI)
399  {
400  ang_diff = 2 * M_PI - ang_diff;
401  }
402  elapsed_sec += ang_diff / angular_speed;
403  }
404  results.push_back(elapsed_sec);
405  it_prev = it;
406  }
407  return results;
408  }
409 };
410 } // namespace trajectory_tracker
411 
412 #endif // TRAJECTORY_TRACKER_PATH2D_H
trajectory_tracker::Pose2D::Pose2D
Pose2D(const geometry_msgs::Pose &pose, float velocity)
Definition: path2d.h:71
trajectory_tracker::Pose2D::Pose2D
Pose2D(const Eigen::Vector2d &p, float y, float velocity)
Definition: path2d.h:65
epsilon
double epsilon
trajectory_tracker::Path2D::remainedDistance
double remainedDistance(const ConstIterator &begin, const ConstIterator &nearest, const ConstIterator &end, const Eigen::Vector2d &target_on_line) const
Definition: path2d.h:226
utils.h
ros.h
trajectory_tracker::Pose2D
Definition: path2d.h:52
trajectory_tracker::Pose2D::Pose2D
Pose2D(const trajectory_tracker_msgs::PoseStampedWithVelocity &pose)
Definition: path2d.h:83
trajectory_tracker::Path2D
Definition: path2d.h:118
trajectory_tracker::Pose2D::Pose2D
Pose2D(const geometry_msgs::PoseStamped &pose)
Definition: path2d.h:77
trajectory_tracker::Path2D::findNearestWithDistance
std::pair< ConstIterator, double > findNearestWithDistance(const ConstIterator &begin, const ConstIterator &end, const Eigen::Vector2d &target, const float max_search_range=0, const float epsilon=1e-6) const
Definition: path2d.h:180
average.h
trajectory_tracker::Path2D::ConstIterator
std::vector< Pose2D >::const_iterator ConstIterator
Definition: path2d.h:125
trajectory_tracker::Path2D::findLocalGoal
ConstIterator findLocalGoal(const ConstIterator &begin, const ConstIterator &end, const bool allow_switch_back, const bool allow_in_place_turn=true, const double epsilon=1e-6) const
Definition: path2d.h:134
f
f
trajectory_tracker::Path2D::toMsg
void toMsg(PATH_TYPE &path) const
Definition: path2d.h:342
trajectory_tracker
Definition: average.h:34
trajectory_tracker::Average
Definition: average.h:37
trajectory_tracker::curv3p
float curv3p(const Eigen::Vector2d &a, const Eigen::Vector2d &b, const Eigen::Vector2d &c)
Definition: eigen_line.h:40
trajectory_tracker::Path2D::Super
std::vector< Pose2D > Super
Definition: path2d.h:121
trajectory_tracker::Pose2D::Pose2D
Pose2D()
Definition: path2d.h:59
trajectory_tracker::Path2D::fromMsg
void fromMsg(const PATH_TYPE &path, const double in_place_turn_eps=1.0e-6)
Definition: path2d.h:306
d
d
trajectory_tracker::Path2D::Iterator
std::vector< Pose2D >::iterator Iterator
Definition: path2d.h:124
trajectory_tracker::lineStripDistanceSigned
float lineStripDistanceSigned(const Eigen::Vector2d &a, const Eigen::Vector2d &b, const Eigen::Vector2d &c)
Definition: eigen_line.h:69
trajectory_tracker::Pose2D::toMsg
void toMsg(trajectory_tracker_msgs::PoseStampedWithVelocity &pose) const
Definition: path2d.h:110
eigen_line.h
getYaw
double getYaw(const tf2::Quaternion &q)
trajectory_tracker::Path2D::enumerateLocalGoals
std::vector< ConstIterator > enumerateLocalGoals(const ConstIterator &begin, const ConstIterator &end, const bool allow_switch_back, const bool allow_in_place_turn=true, const double epsilon=1e-6) const
Definition: path2d.h:353
trajectory_tracker::Path2D::length
float length() const
Definition: path2d.h:127
std
tf2
trajectory_tracker::Pose2D::velocity_
float velocity_
Definition: path2d.h:57
trajectory_tracker::Pose2D::toMsg
void toMsg(geometry_msgs::PoseStamped &pose) const
Definition: path2d.h:104
angle
TF2SIMD_FORCE_INLINE tf2Scalar angle(const Quaternion &q1, const Quaternion &q2)
tf2::Quaternion
tf2::toMsg
B toMsg(const A &a)
trajectory_tracker::Path2D::getCurvature
float getCurvature(const ConstIterator &begin, const ConstIterator &end, const Eigen::Vector2d &target_on_line, const float max_search_range) const
Definition: path2d.h:260
trajectory_tracker::Pose2D::pos_
Eigen::Vector2d pos_
Definition: path2d.h:55
trajectory_tracker::Path2D::findNearest
ConstIterator findNearest(const ConstIterator &begin, const ConstIterator &end, const Eigen::Vector2d &target, const float max_search_range=0, const float epsilon=1e-6) const
Definition: path2d.h:171
trajectory_tracker::Pose2D::yaw_
float yaw_
Definition: path2d.h:56
trajectory_tracker::Path2D::getEstimatedTimeOfArrivals
std::vector< double > getEstimatedTimeOfArrivals(const ConstIterator &begin, const ConstIterator &end, const double linear_speed, const double angular_speed, const double initial_eta_sec=0.0) const
Definition: path2d.h:374
trajectory_tracker::Pose2D::rotate
void rotate(const float ang)
Definition: path2d.h:89


trajectory_tracker
Author(s): Atsushi Watanabe
autogenerated on Wed Mar 19 2025 02:14:15