-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Route server corner smoothing #5226
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
SteveMacenski
merged 48 commits into
ros-navigation:main
from
alexanderjyuen:route_server_corner_smoothing
Jun 12, 2025
Merged
Changes from 47 commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
b2f9d6d
added edge length method
alexanderjyuen d198fa8
Added corner arc class
alexanderjyuen 8cb47e0
replaced double vectors with Coordinates, added methods to return sta…
alexanderjyuen 88b1648
using Coordinates, fixed direction of tangents
alexanderjyuen c4dc85d
added corner arc in header, added logger in protected variable
alexanderjyuen 815d88c
first pass of corner smoothing algorithm
alexanderjyuen 537cf97
reassigning next edge to have a different start, if a corner occurs b…
alexanderjyuen e623d9d
using unique pointer instead of raw pointers for new edges and nodes
alexanderjyuen 66eee22
added smoothing parameter
alexanderjyuen d33bc2d
made angle of interpolation a parameter
alexanderjyuen 6c1b2b6
const for return methods, added flag for smoothing corners
alexanderjyuen 9cac954
moved getEdgeLength() into the Directional Edge struct
alexanderjyuen 2c96ceb
using float instead of double
alexanderjyuen d4bd9dc
smoothing radius is float, couple methods moved to protected
alexanderjyuen 752ff04
removed signed_angle_ as a member variable
alexanderjyuen 690ad2a
removed unnecessary member variables
alexanderjyuen 7dc35f8
removed angle of interpolation and inferring it from path density and…
alexanderjyuen 2626b6a
consolidated corner arc into one header function
alexanderjyuen 5d6d37d
readded newline
alexanderjyuen 4f7bba1
changed corner arc to corner smoothing
alexanderjyuen 4d6b8e0
replaced the use of edges with coordinates to generate smoothing arc,…
alexanderjyuen f0dff73
linting
alexanderjyuen 53f2209
fixing cpplint
alexanderjyuen 5b0b709
linting for headers
alexanderjyuen c827e52
cpplinting
alexanderjyuen d46468f
Update nav2_route/src/path_converter.cpp
SteveMacenski edbe42a
Update nav2_route/src/path_converter.cpp
SteveMacenski 46ca874
Update nav2_route/src/path_converter.cpp
SteveMacenski 68befab
Update nav2_route/src/path_converter.cpp
SteveMacenski e9a1882
Update nav2_route/include/nav2_route/corner_smoothing.hpp
SteveMacenski 9555c93
fixed divide by zeros and accessing empty route.edges
alexanderjyuen b3cf20a
Merge branch 'route_server_corner_smoothing' of github.com:alexanderj…
alexanderjyuen 5a39b87
uncrustify linting
alexanderjyuen 752d1f2
cpp linting
alexanderjyuen b41c896
path converter linting
alexanderjyuen 2024731
changed all doubles to floats
alexanderjyuen ee16acb
added check for edges that are colinear to avoid divide by 0, fixed f…
alexanderjyuen 4e5baaf
linting
alexanderjyuen cc2114a
Update nav2_route/include/nav2_route/corner_smoothing.hpp
SteveMacenski 1ce133e
added doxygen for corner arc class
alexanderjyuen 9dafb46
Merge branch 'route_server_corner_smoothing' of github.com:alexanderj…
alexanderjyuen 1728030
added warning message if corner can't be smoothed
alexanderjyuen 55d54ec
added smooth_corners to the nav2 params file
alexanderjyuen 989d092
added smoothing flag and radius parameter to README.md'
alexanderjyuen 7e3e547
typo in README
alexanderjyuen dfff167
added testing for corner smoothing
alexanderjyuen 0a7fa13
Merge branch 'main' into route_server_corner_smoothing
alexanderjyuen b2903a4
Update nav2_route/include/nav2_route/corner_smoothing.hpp
SteveMacenski File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| // Copyright (c) 2025, Polymath Robotics | ||
| // | ||
| // Licensed under the Apache License, Version 2.0 (the "License"); | ||
| // you may not use this file except in compliance with the License. | ||
| // You may obtain a copy of the License at | ||
| // | ||
| // http://www.apache.org/licenses/LICENSE-2.0 | ||
| // | ||
| // Unless required by applicable law or agreed to in writing, software | ||
| // distributed under the License is distributed on an "AS IS" BASIS, | ||
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| // See the License for the specific language governing permissions and | ||
| // limitations under the License. | ||
|
|
||
| #ifndef NAV2_ROUTE__CORNER_SMOOTHING_HPP_ | ||
| #define NAV2_ROUTE__CORNER_SMOOTHING_HPP_ | ||
|
|
||
| #include <vector> | ||
| #include <cmath> | ||
| #include <algorithm> | ||
|
|
||
| #include "nav2_route/types.hpp" | ||
| #include "nav2_route/utils.hpp" | ||
|
|
||
| namespace nav2_route | ||
| { | ||
| /** | ||
| * @class nav2_route::CornerArc | ||
| * @brief A class used to smooth corners defined by the edges and nodes | ||
| * of the route graph. Used with path converter to output a corner smoothed plan | ||
| */ | ||
| class CornerArc | ||
| { | ||
| public: | ||
| /** | ||
| * @brief A constructor for nav2_route::CornerArc | ||
| * @param start start coordinate of corner to be smoothed | ||
| * @param corner corner coordinate of corner to be smoothed | ||
| * @param end end coordinate of corner to be smoothed | ||
| * @param minimum_radius smoothing radius to fit to the corner | ||
| */ | ||
| CornerArc( | ||
| const Coordinates & start, const Coordinates & corner, const Coordinates & end, | ||
| float minimum_radius) | ||
| { | ||
| start_edge_length_ = hypotf(corner.x - start.x, corner.y - start.y); | ||
| end_edge_length_ = hypotf(end.x - corner.x, end.y - corner.y); | ||
|
|
||
| // invalid scenario would cause equations to blow up | ||
| if (start_edge_length_ == 0.0 || end_edge_length_ == 0.0) {return;} | ||
|
|
||
| float angle = getAngleBetweenEdges(start, corner, end); | ||
|
|
||
| // cannot smooth a 0 (back and forth) or 180 (straight line) angle | ||
| if (std::abs(angle) < 1E-6 || std::abs(angle - M_PI) < 1E-6) {return;} | ||
|
|
||
| float tangent_length = minimum_radius / (std::tan(std::fabs(angle) / 2)); | ||
|
|
||
| if (tangent_length < start_edge_length_ && tangent_length < end_edge_length_) { | ||
| std::vector<float> start_edge_unit_tangent = | ||
| {(start.x - corner.x) / start_edge_length_, (start.y - corner.y) / start_edge_length_}; | ||
| std::vector<float> end_edge_unit_tangent = | ||
| {(end.x - corner.x) / end_edge_length_, (end.y - corner.y) / end_edge_length_}; | ||
|
|
||
| float bisector_x = start_edge_unit_tangent[0] + end_edge_unit_tangent[0]; | ||
| float bisector_y = start_edge_unit_tangent[1] + end_edge_unit_tangent[1]; | ||
| float bisector_magnitude = std::sqrt(bisector_x * bisector_x + bisector_y * bisector_y); | ||
|
|
||
| std::vector<float> unit_bisector = | ||
| {bisector_x / bisector_magnitude, bisector_y / bisector_magnitude}; | ||
SteveMacenski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| start_coordinate_.x = corner.x + start_edge_unit_tangent[0] * tangent_length; | ||
| start_coordinate_.y = corner.y + start_edge_unit_tangent[1] * tangent_length; | ||
|
|
||
| end_coordinate_.x = corner.x + end_edge_unit_tangent[0] * tangent_length; | ||
| end_coordinate_.y = corner.y + end_edge_unit_tangent[1] * tangent_length; | ||
|
|
||
| float bisector_length = minimum_radius / std::sin(angle / 2); | ||
|
|
||
| circle_center_coordinate_.x = corner.x + unit_bisector[0] * bisector_length; | ||
| circle_center_coordinate_.y = corner.y + unit_bisector[1] * bisector_length; | ||
|
|
||
| valid_corner_ = true; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @brief A destructor for nav2_route::CornerArc | ||
| */ | ||
| ~CornerArc() = default; | ||
|
|
||
| void interpolateArc( | ||
SteveMacenski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| const float & max_angle_resolution, | ||
| std::vector<geometry_msgs::msg::PoseStamped> & poses) | ||
| { | ||
| std::vector<float> r_start{start_coordinate_.x - circle_center_coordinate_.x, | ||
| start_coordinate_.y - circle_center_coordinate_.y}; | ||
| std::vector<float> r_end{end_coordinate_.x - circle_center_coordinate_.x, | ||
| end_coordinate_.y - circle_center_coordinate_.y}; | ||
| float cross = r_start[0] * r_end[1] - r_start[1] * r_end[0]; | ||
| float dot = r_start[0] * r_end[0] + r_start[1] * r_end[1]; | ||
| float signed_angle = std::atan2(cross, dot); | ||
| // lower limit for N is 1 to protect against divide by 0 | ||
| int N = std::max(1, static_cast<int>(std::ceil(std::abs(signed_angle) / max_angle_resolution))); | ||
| float angle_resolution = signed_angle / N; | ||
|
|
||
| float x, y; | ||
| for (int i = 0; i <= N; i++) { | ||
| float angle = i * angle_resolution; | ||
| x = circle_center_coordinate_.x + | ||
| (r_start[0] * std::cos(angle) - r_start[1] * std::sin(angle)); | ||
| y = circle_center_coordinate_.y + | ||
| (r_start[0] * std::sin(angle) + r_start[1] * std::cos(angle)); | ||
| poses.push_back(utils::toMsg(x, y)); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * @brief return if a valid corner arc (one that doesn't overrun the edge lengths) is generated | ||
| * @return if the a corner was able to be generated | ||
| */ | ||
| bool isCornerValid() const {return valid_corner_;} | ||
|
|
||
| /** | ||
| * @brief return the start coordinate of the corner arc | ||
| * @return start coordinate of the arc | ||
| */ | ||
| Coordinates getCornerStart() const {return start_coordinate_;} | ||
|
|
||
| /** | ||
| * @brief return the end coordinate of the corner arc | ||
| * @return end coordinate of the arc | ||
| */ | ||
| Coordinates getCornerEnd() const {return end_coordinate_;} | ||
|
|
||
| protected: | ||
| /** | ||
| * @brief find the signed angle between a corner generated by 3 points | ||
| * @param start start coordinate of corner to be smoothed | ||
| * @param corner corner coordinate of corner to be smoothed | ||
| * @param end end coordinate of corner to be smoothed | ||
| * @return signed angle of the corner | ||
| */ | ||
| float getAngleBetweenEdges( | ||
| const Coordinates & start, const Coordinates & corner, | ||
| const Coordinates & end) | ||
| { | ||
| float start_dx = start.x - corner.x; | ||
| float start_dy = start.y - corner.y; | ||
|
|
||
| float end_dx = end.x - corner.x; | ||
| float end_dy = end.y - corner.y; | ||
|
|
||
| float angle = | ||
| acos((start_dx * end_dx + start_dy * end_dy) / (start_edge_length_ * end_edge_length_)); | ||
SteveMacenski marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| return angle; | ||
| } | ||
|
|
||
| private: | ||
| bool valid_corner_{false}; | ||
| float start_edge_length_; | ||
| float end_edge_length_; | ||
| Coordinates start_coordinate_; | ||
| Coordinates end_coordinate_; | ||
| Coordinates circle_center_coordinate_; | ||
| }; | ||
|
|
||
| } // namespace nav2_route | ||
|
|
||
| #endif // NAV2_ROUTE__CORNER_SMOOTHING_HPP_ | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.