Nav2 Navigation Stack - rolling  main
ROS 2 Navigation Stack
smoother_utils.hpp
1 // Copyright (c) 2022, Samsung Research America
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. Reserved.
14 
15 #ifndef NAV2_UTIL__SMOOTHER_UTILS_HPP_
16 #define NAV2_UTIL__SMOOTHER_UTILS_HPP_
17 
18 #include <cmath>
19 #include <vector>
20 #include <string>
21 #include <memory>
22 #include <utility>
23 
24 #include "nav2_util/geometry_utils.hpp"
25 #include "nav_msgs/msg/path.hpp"
26 #include "angles/angles.h"
27 #include "tf2/utils.hpp"
28 
29 namespace nav2_util
30 {
31 
37 {
38  unsigned int start;
39  unsigned int end;
40 };
41 
50 inline std::vector<PathSegment> findDirectionalPathSegments(
51  const nav_msgs::msg::Path & path, bool is_holonomic = false)
52 {
53  std::vector<PathSegment> segments;
54  PathSegment curr_segment;
55  curr_segment.start = 0;
56 
57  // If holonomic, no directional changes and
58  // may have abrupt angular changes from naive grid search
59  if (is_holonomic) {
60  curr_segment.end = path.poses.size() - 1;
61  segments.push_back(curr_segment);
62  return segments;
63  }
64 
65  // Iterating through the path to determine the position of the cusp
66  for (unsigned int idx = 1; idx < path.poses.size() - 1; ++idx) {
67  // We have two vectors for the dot product OA and AB. Determining the vectors.
68  double oa_x = path.poses[idx].pose.position.x -
69  path.poses[idx - 1].pose.position.x;
70  double oa_y = path.poses[idx].pose.position.y -
71  path.poses[idx - 1].pose.position.y;
72  double ab_x = path.poses[idx + 1].pose.position.x -
73  path.poses[idx].pose.position.x;
74  double ab_y = path.poses[idx + 1].pose.position.y -
75  path.poses[idx].pose.position.y;
76 
77  // Checking for the existence of cusp, in the path, using the dot product.
78  double dot_product = (oa_x * ab_x) + (oa_y * ab_y);
79  if (dot_product < 0.0) {
80  curr_segment.end = idx;
81  segments.push_back(curr_segment);
82  curr_segment.start = idx;
83  }
84 
85  // Checking for the existence of a differential rotation in place.
86  double cur_theta = tf2::getYaw(path.poses[idx].pose.orientation);
87  double next_theta = tf2::getYaw(path.poses[idx + 1].pose.orientation);
88  double dtheta = angles::shortest_angular_distance(cur_theta, next_theta);
89  if (fabs(ab_x) < 1e-4 && fabs(ab_y) < 1e-4 && fabs(dtheta) > 1e-4) {
90  curr_segment.end = idx;
91  segments.push_back(curr_segment);
92  curr_segment.start = idx;
93  }
94  }
95 
96  curr_segment.end = path.poses.size() - 1;
97  segments.push_back(curr_segment);
98  return segments;
99 }
100 
108 inline void updateApproximatePathOrientations(
109  nav_msgs::msg::Path & path,
110  bool & reversing_segment,
111  bool is_holonomic = false)
112 {
113  double dx, dy, theta, pt_yaw;
114  reversing_segment = false;
115 
116  // Find if this path segment is in reverse
117  dx = path.poses[2].pose.position.x - path.poses[1].pose.position.x;
118  dy = path.poses[2].pose.position.y - path.poses[1].pose.position.y;
119  theta = atan2(dy, dx);
120  pt_yaw = tf2::getYaw(path.poses[1].pose.orientation);
121  if (!is_holonomic && fabs(angles::shortest_angular_distance(pt_yaw, theta)) > M_PI_2) {
122  reversing_segment = true;
123  }
124 
125  // Find the angle relative the path position vectors
126  for (unsigned int i = 0; i != path.poses.size() - 1; i++) {
127  dx = path.poses[i + 1].pose.position.x - path.poses[i].pose.position.x;
128  dy = path.poses[i + 1].pose.position.y - path.poses[i].pose.position.y;
129  theta = atan2(dy, dx);
130 
131  // If points are overlapping, pass
132  if (fabs(dx) < 1e-4 && fabs(dy) < 1e-4) {
133  continue;
134  }
135 
136  // Flip the angle if this path segment is in reverse
137  if (reversing_segment) {
138  theta += M_PI; // orientationAroundZAxis will normalize
139  }
140 
141  path.poses[i].pose.orientation = nav2_util::geometry_utils::orientationAroundZAxis(theta);
142  }
143 }
144 
145 } // namespace nav2_util
146 
147 #endif // NAV2_UTIL__SMOOTHER_UTILS_HPP_
A segment of a path in start/end indices.