Skip to content

Commit 9431ee4

Browse files
committed
Move from controller_utils to path_utils
Signed-off-by: mini-1235 <[email protected]>
1 parent ae8b599 commit 9431ee4

File tree

5 files changed

+151
-131
lines changed

5 files changed

+151
-131
lines changed

nav2_controller/plugins/simple_path_handler.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
#include "angles/angles.h"
1919
#include "pluginlib/class_list_macros.hpp"
2020
#include "nav2_controller/plugins/simple_path_handler.hpp"
21-
#include "nav2_util/controller_utils.hpp"
21+
#include "nav2_util/path_utils.hpp"
2222
#include "nav2_util/geometry_utils.hpp"
2323
#include "nav2_core/controller_exceptions.hpp"
2424

nav2_util/include/nav2_util/controller_utils.hpp

Lines changed: 0 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -62,73 +62,6 @@ geometry_msgs::msg::PoseStamped getLookAheadPoint(
6262
double &, const nav_msgs::msg::Path &,
6363
const bool interpolate_after_goal = false);
6464

65-
/**
66-
* @brief Find the iterator of the first pose at which there is an inversion on the path,
67-
* @param path to check for inversion
68-
* @return the first point after the inversion found in the path
69-
*/
70-
inline unsigned int findFirstPathInversion(nav_msgs::msg::Path & path)
71-
{
72-
// At least 3 poses for a possible inversion
73-
if (path.poses.size() < 3) {
74-
return path.poses.size();
75-
}
76-
77-
// Iterating through the path to determine the position of the path inversion
78-
for (unsigned int idx = 1; idx < path.poses.size() - 1; ++idx) {
79-
// We have two vectors for the dot product OA and AB. Determining the vectors.
80-
float oa_x = path.poses[idx].pose.position.x -
81-
path.poses[idx - 1].pose.position.x;
82-
float oa_y = path.poses[idx].pose.position.y -
83-
path.poses[idx - 1].pose.position.y;
84-
float ab_x = path.poses[idx + 1].pose.position.x -
85-
path.poses[idx].pose.position.x;
86-
float ab_y = path.poses[idx + 1].pose.position.y -
87-
path.poses[idx].pose.position.y;
88-
89-
// Checking for the existence of cusp, in the path, using the dot product.
90-
float dot_product = (oa_x * ab_x) + (oa_y * ab_y);
91-
if (dot_product < 0.0f) {
92-
return idx + 1;
93-
}
94-
95-
if (
96-
(hypot(oa_x, oa_y) == 0.0 &&
97-
path.poses[idx - 1].pose.orientation !=
98-
path.poses[idx].pose.orientation)
99-
||
100-
(hypot(ab_x, ab_y) == 0.0 &&
101-
path.poses[idx].pose.orientation !=
102-
path.poses[idx + 1].pose.orientation))
103-
{
104-
// returning the distance since the points overlap
105-
// but are not simply duplicate points (e.g. in place rotation)
106-
return idx + 1;
107-
}
108-
}
109-
110-
return path.poses.size();
111-
}
112-
113-
/**
114-
* @brief Find and remove poses after the first inversion in the path
115-
* @param path to check for inversion
116-
* @return The location of the inversion, return 0 if none exist
117-
*/
118-
inline unsigned int removePosesAfterFirstInversion(nav_msgs::msg::Path & path)
119-
{
120-
nav_msgs::msg::Path cropped_path = path;
121-
const unsigned int first_after_inversion = findFirstPathInversion(cropped_path);
122-
if (first_after_inversion == path.poses.size()) {
123-
return 0u;
124-
}
125-
126-
cropped_path.poses.erase(
127-
cropped_path.poses.begin() + first_after_inversion, cropped_path.poses.end());
128-
path = cropped_path;
129-
return first_after_inversion;
130-
}
131-
13265
} // namespace nav2_util
13366

13467
#endif // NAV2_UTIL__CONTROLLER_UTILS_HPP_

nav2_util/include/nav2_util/path_utils.hpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,73 @@ bool transformPathInTargetFrame(
7474
tf2_ros::Buffer & tf_buffer, const std::string target_frame,
7575
const double transform_timeout = 0.1);
7676

77+
/**
78+
* @brief Find the iterator of the first pose at which there is an inversion on the path,
79+
* @param path to check for inversion
80+
* @return the first point after the inversion found in the path
81+
*/
82+
inline unsigned int findFirstPathInversion(nav_msgs::msg::Path & path)
83+
{
84+
// At least 3 poses for a possible inversion
85+
if (path.poses.size() < 3) {
86+
return path.poses.size();
87+
}
88+
89+
// Iterating through the path to determine the position of the path inversion
90+
for (unsigned int idx = 1; idx < path.poses.size() - 1; ++idx) {
91+
// We have two vectors for the dot product OA and AB. Determining the vectors.
92+
float oa_x = path.poses[idx].pose.position.x -
93+
path.poses[idx - 1].pose.position.x;
94+
float oa_y = path.poses[idx].pose.position.y -
95+
path.poses[idx - 1].pose.position.y;
96+
float ab_x = path.poses[idx + 1].pose.position.x -
97+
path.poses[idx].pose.position.x;
98+
float ab_y = path.poses[idx + 1].pose.position.y -
99+
path.poses[idx].pose.position.y;
100+
101+
// Checking for the existence of cusp, in the path, using the dot product.
102+
float dot_product = (oa_x * ab_x) + (oa_y * ab_y);
103+
if (dot_product < 0.0f) {
104+
return idx + 1;
105+
}
106+
107+
if (
108+
(hypot(oa_x, oa_y) == 0.0 &&
109+
path.poses[idx - 1].pose.orientation !=
110+
path.poses[idx].pose.orientation)
111+
||
112+
(hypot(ab_x, ab_y) == 0.0 &&
113+
path.poses[idx].pose.orientation !=
114+
path.poses[idx + 1].pose.orientation))
115+
{
116+
// returning the distance since the points overlap
117+
// but are not simply duplicate points (e.g. in place rotation)
118+
return idx + 1;
119+
}
120+
}
121+
122+
return path.poses.size();
123+
}
124+
125+
/**
126+
* @brief Find and remove poses after the first inversion in the path
127+
* @param path to check for inversion
128+
* @return The location of the inversion, return 0 if none exist
129+
*/
130+
inline unsigned int removePosesAfterFirstInversion(nav_msgs::msg::Path & path)
131+
{
132+
nav_msgs::msg::Path cropped_path = path;
133+
const unsigned int first_after_inversion = findFirstPathInversion(cropped_path);
134+
if (first_after_inversion == path.poses.size()) {
135+
return 0u;
136+
}
137+
138+
cropped_path.poses.erase(
139+
cropped_path.poses.begin() + first_after_inversion, cropped_path.poses.end());
140+
path = cropped_path;
141+
return first_after_inversion;
142+
}
143+
77144
} // namespace nav2_util
78145

79146
#endif // NAV2_UTIL__PATH_UTILS_HPP_

nav2_util/test/test_controller_utils.cpp

Lines changed: 0 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -387,66 +387,3 @@ TEST(InterpolationUtils, lookaheadExtrapolation)
387387
EXPECT_NEAR(pt.pose.position.x, 2.0 + cos(-45.0 * M_PI / 180) * 10.0, EPSILON);
388388
EXPECT_NEAR(pt.pose.position.y, -2.0 + sin(-45.0 * M_PI / 180) * 10.0, EPSILON);
389389
}
390-
391-
TEST(UtilsTests, FindPathInversionTest)
392-
{
393-
// Straight path, no inversions to be found
394-
nav_msgs::msg::Path path;
395-
for (unsigned int i = 0; i != 10; i++) {
396-
geometry_msgs::msg::PoseStamped pose;
397-
pose.pose.position.x = i;
398-
path.poses.push_back(pose);
399-
}
400-
EXPECT_EQ(nav2_util::findFirstPathInversion(path), 10u);
401-
402-
// To short to process
403-
path.poses.erase(path.poses.begin(), path.poses.begin() + 7);
404-
EXPECT_EQ(nav2_util::findFirstPathInversion(path), 3u);
405-
406-
// Has inversion at index 10, so should return 11 for the first point afterwards
407-
// 0 1 2 3 4 5 6 7 8 9 10 **9** 8 7 6 5 4 3 2 1
408-
path.poses.clear();
409-
for (unsigned int i = 0; i != 10; i++) {
410-
geometry_msgs::msg::PoseStamped pose;
411-
pose.pose.position.x = i;
412-
path.poses.push_back(pose);
413-
}
414-
for (unsigned int i = 0; i != 10; i++) {
415-
geometry_msgs::msg::PoseStamped pose;
416-
pose.pose.position.x = 10 - i;
417-
path.poses.push_back(pose);
418-
}
419-
EXPECT_EQ(nav2_util::findFirstPathInversion(path), 11u);
420-
}
421-
422-
TEST(UtilsTests, RemovePosesAfterPathInversionTest)
423-
{
424-
nav_msgs::msg::Path path;
425-
// straight path
426-
for (unsigned int i = 0; i != 10; i++) {
427-
geometry_msgs::msg::PoseStamped pose;
428-
pose.pose.position.x = i;
429-
path.poses.push_back(pose);
430-
}
431-
EXPECT_EQ(nav2_util::removePosesAfterFirstInversion(path), 0u);
432-
433-
// try empty path
434-
path.poses.clear();
435-
EXPECT_EQ(nav2_util::removePosesAfterFirstInversion(path), 0u);
436-
437-
// cusping path
438-
for (unsigned int i = 0; i != 10; i++) {
439-
geometry_msgs::msg::PoseStamped pose;
440-
pose.pose.position.x = i;
441-
path.poses.push_back(pose);
442-
}
443-
for (unsigned int i = 0; i != 10; i++) {
444-
geometry_msgs::msg::PoseStamped pose;
445-
pose.pose.position.x = 10 - i;
446-
path.poses.push_back(pose);
447-
}
448-
EXPECT_EQ(nav2_util::removePosesAfterFirstInversion(path), 11u);
449-
// Check to see if removed
450-
EXPECT_EQ(path.poses.size(), 11u);
451-
EXPECT_EQ(path.poses.back().pose.position.x, 10);
452-
}

nav2_util/test/test_path_utils.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,3 +456,86 @@ TEST(TransformPathTest, MissingTransform)
456456
input_path, transformed_path, *tf_buffer_, "base_link", 0.1));
457457
rclcpp::shutdown();
458458
}
459+
460+
TEST(UtilsTests, FindPathInversionTest)
461+
{
462+
// Straight path, no inversions to be found
463+
nav_msgs::msg::Path path;
464+
for (unsigned int i = 0; i != 10; i++) {
465+
geometry_msgs::msg::PoseStamped pose;
466+
pose.pose.position.x = i;
467+
path.poses.push_back(pose);
468+
}
469+
EXPECT_EQ(nav2_util::findFirstPathInversion(path), 10u);
470+
471+
// To short to process
472+
path.poses.erase(path.poses.begin(), path.poses.begin() + 7);
473+
EXPECT_EQ(nav2_util::findFirstPathInversion(path), 3u);
474+
475+
// Has inversion at index 10, so should return 11 for the first point afterwards
476+
// 0 1 2 3 4 5 6 7 8 9 10 **9** 8 7 6 5 4 3 2 1
477+
path.poses.clear();
478+
for (unsigned int i = 0; i != 10; i++) {
479+
geometry_msgs::msg::PoseStamped pose;
480+
pose.pose.position.x = i;
481+
path.poses.push_back(pose);
482+
}
483+
for (unsigned int i = 0; i != 10; i++) {
484+
geometry_msgs::msg::PoseStamped pose;
485+
pose.pose.position.x = 10 - i;
486+
path.poses.push_back(pose);
487+
}
488+
EXPECT_EQ(nav2_util::findFirstPathInversion(path), 11u);
489+
490+
// In place rotation
491+
path.poses.clear();
492+
for (unsigned int i = 0; i != 10; i++) {
493+
geometry_msgs::msg::PoseStamped pose;
494+
pose.pose.position.x = i;
495+
path.poses.push_back(pose);
496+
}
497+
geometry_msgs::msg::PoseStamped last_pose;
498+
last_pose = path.poses.back();
499+
tf2::Quaternion q;
500+
q.setRPY(0, 0, M_PI_2); // rotate 90 degrees
501+
last_pose.pose.orientation.x = q.x();
502+
last_pose.pose.orientation.y = q.y();
503+
last_pose.pose.orientation.z = q.z();
504+
last_pose.pose.orientation.w = q.w();
505+
path.poses.push_back(last_pose);
506+
last_pose.pose.position.x = 11.0;
507+
path.poses.push_back(last_pose);
508+
EXPECT_EQ(nav2_util::findFirstPathInversion(path), 10u);
509+
}
510+
511+
TEST(UtilsTests, RemovePosesAfterPathInversionTest)
512+
{
513+
nav_msgs::msg::Path path;
514+
// straight path
515+
for (unsigned int i = 0; i != 10; i++) {
516+
geometry_msgs::msg::PoseStamped pose;
517+
pose.pose.position.x = i;
518+
path.poses.push_back(pose);
519+
}
520+
EXPECT_EQ(nav2_util::removePosesAfterFirstInversion(path), 0u);
521+
522+
// try empty path
523+
path.poses.clear();
524+
EXPECT_EQ(nav2_util::removePosesAfterFirstInversion(path), 0u);
525+
526+
// cusping path
527+
for (unsigned int i = 0; i != 10; i++) {
528+
geometry_msgs::msg::PoseStamped pose;
529+
pose.pose.position.x = i;
530+
path.poses.push_back(pose);
531+
}
532+
for (unsigned int i = 0; i != 10; i++) {
533+
geometry_msgs::msg::PoseStamped pose;
534+
pose.pose.position.x = 10 - i;
535+
path.poses.push_back(pose);
536+
}
537+
EXPECT_EQ(nav2_util::removePosesAfterFirstInversion(path), 11u);
538+
// Check to see if removed
539+
EXPECT_EQ(path.poses.size(), 11u);
540+
EXPECT_EQ(path.poses.back().pose.position.x, 10);
541+
}

0 commit comments

Comments
 (0)