Skip to content

Conversation

@SakshayMahna
Copy link
Contributor


Basic Info

Info Please fill out this column
Ticket(s) this addresses #4865
Primary OS tested on Ubuntu
Robotic platform tested on Gazebo Simulation of Turtlebot3
Does this PR contain AI generated software? No

Description of contribution in a few bullet points

  • Added default parameter files for Regulated Pure Pursuit Controller and Graceful Controller
  • Added 2 new parameters for Graceful Controller (lookahead_resolution and interpolate_after_goal)
  • Added lookahead logic to calculate next path point for Graceful Controller

Additional Information

  • Graceful Controller now calculates the next point on path using lookahead logic, it starts from a maximum lookahead value and searches for a path using lookahead distance in intervals of lookahead_resolution.
  • The controller also calculates interpolated point after goal. This can be switched on and off using the parameter interpolate_after_goal.

Description of documentation updates required from your changes

  • Added new parameter, so need to add that to default configs and documentation page.

Description of how this change was tested

  • Same unit tests and tested in simulation.

Future work that may be required in bullet points

  • The interpolation after goal logic seems a bit problematic and may need refinement.

For Maintainers:

  • Check that any new parameters added are updated in docs.nav2.org
  • Check that any significant change is added to the migration guide
  • Check that any new features OR changes to existing behaviors are reflected in the tuning guide
  • Check that any new functions have Doxygen added
  • Check that any new features have test coverage
  • Check that any new plugins is added to the plugins page
  • If BT Node, Additionally: add to BT's XML index of nodes for groot, BT package's readme table, and BT library lists

@mergify
Copy link
Contributor

mergify bot commented Mar 22, 2025

@SakshayMahna, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@mergify
Copy link
Contributor

mergify bot commented Mar 23, 2025

@SakshayMahna, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

1 similar comment
@mergify
Copy link
Contributor

mergify bot commented Mar 23, 2025

@SakshayMahna, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@codecov
Copy link

codecov bot commented Mar 29, 2025

Codecov Report

Attention: Patch coverage is 94.59459% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
...v2_graceful_controller/src/graceful_controller.cpp 73.33% 4 Missing ⚠️
Files with missing lines Coverage Δ
...e/nav2_graceful_controller/graceful_controller.hpp 100.00% <ø> (ø)
...ude/nav2_graceful_controller/parameter_handler.hpp 100.00% <ø> (ø)
nav2_graceful_controller/src/parameter_handler.cpp 100.00% <100.00%> (ø)
...t_controller/regulated_pure_pursuit_controller.hpp 100.00% <ø> (ø)
...ntroller/src/regulated_pure_pursuit_controller.cpp 85.63% <100.00%> (-2.71%) ⬇️
nav2_util/src/controller_utils.cpp 100.00% <100.00%> (ø)
...v2_graceful_controller/src/graceful_controller.cpp 89.34% <73.33%> (-0.35%) ⬇️

... and 5 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member

@SteveMacenski SteveMacenski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking aloud a bit:

This bit of code looks like we iterate through the path, try to find the max_lookahead distance away and back up closer and closer to the robot until we find a solution that is collision free.

Is that case, we should attempt to find the interpolated lookahead point for the max_lookahead away to start off with, that gives us the best and smoothest value.

After that point, its a bit arbitrary the distance selected, isn't it? Selecting a lookahead_resolution versus marching through the path points I don't think improves the smoothness, does it? Either way there's a discontinuity now on the distance away to use based on the collision state (unless we set the search resolution to be very fine, which is probably not computationally worthwhile).

For example, the resolution you set was 0.1, but a normal path from a planning plugin probably does it closer to 0.05 for the costmap resolution when that resolution is 5cm. So wouldn't this case actually be more coarse?

Did you test this without the lookahead_resolution feature and generate those charts using the normal path point iteration? I suspect the improvement in smoothness you see is when the max_lookahead is used due to lack of collision requiring backing up the path to finding the first valid trajectory. My intuition says that when we do the backing-up process, we own that discontinuity either way, given we're backing up by 5cm or 10cm, respectively.

@SakshayMahna
Copy link
Contributor Author

This bit of code looks like we iterate through the path, try to find the max_lookahead distance away and back up closer and closer to the robot until we find a solution that is collision free.

Yes, this is exactly what is being done. The reasoning behind this was, in case max_lookahead distance has a collision, there is atleast some solution (found by backing up closer to robot) that can be followed.

Is that case, we should attempt to find the interpolated lookahead point for the max_lookahead away to start off with, that gives us the best and smoothest value.

After that point, its a bit arbitrary the distance selected, isn't it? Selecting a lookahead_resolution versus marching through the path points I don't think improves the smoothness, does it? Either way there's a discontinuity now on the distance away to use based on the collision state (unless we set the search resolution to be very fine, which is probably not computationally worthwhile).

For example, the resolution you set was 0.1, but a normal path from a planning plugin probably does it closer to 0.05 for the costmap resolution when that resolution is 5cm. So wouldn't this case actually be more coarse?

Makes sense, the discontinuity is introduced once we move to another lookahead point. That's why thought of putting lookahead_resolution to adjust what may work best for the user.

Did you test this without the lookahead_resolution feature and generate those charts using the normal path point iteration? I suspect the improvement in smoothness you see is when the max_lookahead is used due to lack of collision requiring backing up the path to finding the first valid trajectory. My intuition says that when we do the backing-up process, we own that discontinuity either way, given we're backing up by 5cm or 10cm, respectively.

Velocity plot for using points on path (not using lookahead_resolution) seems almost similar:
choose_point_v

As long as the lookahead distance remains the same, the path is as smooth as it can be. It's only in case of collision we may need a strategy to generate a different solution for the robot. In this case the strategy is to reduce the lookahead distance, which introduces discontinuity. Possibly a different strategy may minimize this discontinuity.

@SteveMacenski
Copy link
Member

That's why thought of putting lookahead_resolution to adjust what may work best for the user.

Do you see an improvement using the lookahead_resolution instead of marching through the path as originally done in the back up procedure?

By default you have it set to 0.1, but the path resolution is ~0.05. If you lower that to 0.05 or even lower like 0.02, is it smoother than before?

If so, I think that's a neat feature and we can keep it, users can tune to their liking and we can set it default to the costmap resolution.

If not, I think maybe we should revert that bit and only use the interpolation when using the full lookahead distance. Else, just use the path points since there's a jump anyway.

@SakshayMahna
Copy link
Contributor Author

No, I don't see any improvement while using a smaller lookahead resolution.

The plots for the 3 cases (smaller resolution, larger resolution, using points) all look similar.
I'll just use the path points then.

Copy link
Member

@SteveMacenski SteveMacenski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's one superficial refactor that would in my opinion make this easier to read / understand:

  // Calculate target pose through lookahead interpolation
  double dist_to_target = params_->max_lookahead;
  geometry_msgs::msg::PoseStamped target_pose = nav2_util::getLookAheadPoint(
    dist_to_target, transformed_plan, params_->interpolate_after_goal);
  bool valid_target_pose_found = validateTargetPose(target_pose, dist_to_target, dist_to_goal, local_plan, costmap_transform, cmd_vel);

  if (!valid_target_pose_found) {
    ...
    ...

    valid_target_pose_found = validateTargetPose(target_pose, dist_to_target, dist_to_goal, local_plan, costmap_transform, cmd_vel);
    if (valid_target_pose_found) {
      break;
    }
  }

This would remove the else statement and explicitly setting the valid_target_pose_found instead of just capturing the validate method's return.

@SteveMacenski
Copy link
Member

@SakshayMahna can you work on these last couple of updates?

@SakshayMahna
Copy link
Contributor Author

Hello Steve,
Yes, missed the last few notifications and emails. Working on it.

@mergify
Copy link
Contributor

mergify bot commented May 28, 2025

This pull request is in conflict. Could you fix it @SakshayMahna?

@SakshayMahna
Copy link
Contributor Author

Hi @SteveMacenski
I did make the requested changes. However, I am not able to think of a way to get the code coverage to target (90.72%), I am stuck at 87.64%.

What I understand it is because of the fallback code that was added, that in case Lookahead Point is not found, fallback to default behaviour of checking the poses one by one.

The only way I think this can be tested is by adding an obstacle in the cost map. That way, the Lookahead Point will become invalid because of collision check by simulate_trajectory, and the execution would go to fallback code. But still I have doubts on how to make this work, because there is a set number of max iterations simulate_trajectory works for.

What do you think about this? Any ideas to improve the code coverage?

Copy link
Member

@SteveMacenski SteveMacenski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think some of these changes in refactoring will resolve the testing gap! :-)

@mergify
Copy link
Contributor

mergify bot commented Jun 8, 2025

This pull request is in conflict. Could you fix it @SakshayMahna?

@mergify
Copy link
Contributor

mergify bot commented Jun 8, 2025

@SakshayMahna, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@mergify
Copy link
Contributor

mergify bot commented Jun 8, 2025

This pull request is in conflict. Could you fix it @SakshayMahna?

@SakshayMahna
Copy link
Contributor Author

SakshayMahna commented Jun 8, 2025

Hi @SteveMacenski
I made a mistake while syncing the main branch. And managed to get all my commits deleted.
However, I had a backup, and was able to recover the relevant changes.
And I tested the changes running on simulation as well.

Sorry for the mess.

Copy link
Member

@SteveMacenski SteveMacenski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have a few open comments above, but overall doesn't this look simpler and cleaner! Great work 😄

@mergify
Copy link
Contributor

mergify bot commented Jun 16, 2025

@SakshayMahna, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@mergify
Copy link
Contributor

mergify bot commented Aug 8, 2025

This pull request is in conflict. Could you fix it @SakshayMahna?

@mergify
Copy link
Contributor

mergify bot commented Aug 8, 2025

@SakshayMahna, your PR has failed to build. Please check CI outputs and resolve issues.
You may need to rebase or pull in main due to API changes (or your contribution genuinely fails).

@SakshayMahna
Copy link
Contributor Author

Reverted the extra commits and pulled from main.

@SteveMacenski
Copy link
Member

Some of the tests are failing from these changes:

/opt/overlay_ws/src/navigation2/nav2_graceful_controller/test/test_graceful_controller.cpp:295
Expected equality of these values:
  node->get_parameter("test.transform_tolerance").as_double()
    Which is: 0.1
  1.0
    Which is: 1

/opt/overlay_ws/src/navigation2/nav2_graceful_controller/test/test_graceful_controller.cpp:295
Expected equality of these values:
  node->get_parameter("test.transform_tolerance").as_double()
    Which is: 0.1
  1.0
    Which is: 1/opt/overlay_ws/src/navigation2/nav2_graceful_controller/test/test_graceful_controller.cpp:296
Expected equality of these values:
  node->get_parameter("test.min_lookahead").as_double()
    Which is: 0.25
  1.0
    Which is: 1

/opt/overlay_ws/src/navigation2/nav2_graceful_controller/test/test_graceful_controller.cpp:296
Expected equality of these values:
  node->get_parameter("test.min_lookahead").as_double()
    Which is: 0.25
  1.0
    Which is: 1/opt/overlay_ws/src/navigation2/nav2_graceful_controller/test/test_graceful_controller.cpp:297
Expected equality of these values:
  node->get_parameter("test.max_lookahead").as_double()
    Which is: 1
  2.0
    Which is: 2

/opt/overlay_ws/src/navigation2/nav2_graceful_controller/test/test_graceful_controller.cpp:297
Expected equality of these values:
  node->get_parameter("test.max_lookahead").as_double()
    Which is: 1
  2.0
    Which is: 2unknown file
C++ exception with description "test.interpolate_after_goal" thrown in the test body.

unknown file
C++ exception with description "test.interpolate_after_goal" thrown in the test body.

@SteveMacenski
Copy link
Member

C++ exception with description "test.interpolate_after_goal" thrown in the test body.

This seems to be the issue, it doesn't update since that doesn't exist as a valid dynamic parameter so the other tests fail due to those not being updated from the failure

Signed-off-by: Sakshay Mahna <sakshum19@gmail.com>
@SteveMacenski SteveMacenski merged commit bab2a86 into ros-navigation:main Aug 11, 2025
12 of 15 checks passed
@SteveMacenski
Copy link
Member

@SakshayMahna thank you for the diligence! I know that took awhile! This is a really great update though to the controller and in architecture so we don't have that duplication - thanks so much!

@SakshayMahna
Copy link
Contributor Author

Thank you for pushing through as well Steve!
Happy to see it finally merged.

@mini-1235
Copy link
Collaborator

After this PR, I often observe that the motion target heading is opposite to the robot's movement direction, is this expected?
image

@SteveMacenski
Copy link
Member

Can you expand on that? I'm not sure @SakshayMahna and I fully grokk the picture's meaning.

Comment on lines +126 to +130
// Calculate orientation towards interpolated position
// Convert yaw to quaternion
double yaw = atan2(
point.y - prev_pose_it->pose.position.y,
point.x - prev_pose_it->pose.position.x);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SakshayMahna this block is new compared to the version in RPP. Maybe this shuld be scrutinized?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is the problem. There is a discontinuity taking place because of which the angle comes out to be reversed (added / subtracted by pi).

@mini-1235
Copy link
Collaborator

Can you expand on that? I'm not sure @SakshayMahna and I fully grokk the picture's meaning.

The red arrow is the motion target published by the graceful controller, while the blue path is the transformed plan. I thought the head of the red arrow should be the same direction with the transformed plan

If that's unclear, I will record a video tomorrow

@SteveMacenski
Copy link
Member

I agree it probably should be. Did you do an A-B test that this is definitely the PR that changes that behavior?

@mini-1235
Copy link
Collaborator

I agree it probably should be. Did you do an A-B test that this is definitely the PR that changes that behavior?

I did, after reverting this commit, I saw the heading is always the same as the transformed plan

@SteveMacenski
Copy link
Member

SteveMacenski commented Sep 11, 2025

@SakshayMahna does that make sense? Can you take a look :-)

@mini-1235 do you have a reproduction example on the Tb3/4 sims that he can use as a reference to test?

@mini-1235
Copy link
Collaborator

@mini-1235 do you have a reproduction example on the Tb3/4 sims that he can use as a reference to test?

It is very late in my time zone, I will write it down here tomorrow:)

@mini-1235
Copy link
Collaborator

@mini-1235 do you have a reproduction example on the Tb3/4 sims that he can use as a reference to test?

I replace the controller plugin in nav2_params and left everything else as default:

FollowPath:
      plugin: "nav2_graceful_controller::GracefulController"

Then launch the tb3 demo

ros2 launch nav2_bringup tb3_simulation_launch.py headless:=0

I will show my result before and after this PR:

Before

2025-09-12.21-21-12.mp4

After

2025-09-12.21-14-55.mp4

@SakshayMahna
Copy link
Contributor Author

Hi @mini-1235 ,
Thank you for raising this. I understand the problem. I'll have a look.

@SakshayMahna
Copy link
Contributor Author

As pointed out by Steve above, the problem is in the yaw interpolation. There is a discontinuity taking place because of which the angle comes out to be reversed (added / subtracted by pi).

I think I have a fix for it. Keeping the yaw value in a way to keep it in the direction of motion of robot.

@mini-1235
Copy link
Collaborator

As pointed out by Steve above, the problem is in the yaw interpolation. There is a discontinuity taking place because of which the angle comes out to be reversed (added / subtracted by pi).

I think I have a fix for it. Keeping the yaw value in a way to keep it in the direction of motion of robot.

@SakshayMahna Feel free to ping me when you open the PR, I can test it :)

@SakshayMahna
Copy link
Contributor Author

Thank you!
@mini-1235 Could you please have a look? I have created this PR: #5530

@SteveMacenski
Copy link
Member

Love it guys - please take a look and I will too!

BCKSELFDRIVEWORLD pushed a commit to BCKSELFDRIVEWORLD/navigation2 that referenced this pull request Sep 23, 2025
…s-navigation#5003)

* Add controller utils

Signed-off-by: Sakshay Mahna <sakshum19@gmail.com>

* Fix linting issues

Signed-off-by: Sakshay Mahna <sakshum19@gmail.com>

* Update regulated pure pursuit

Signed-off-by: Sakshay Mahna <sakshum19@gmail.com>

* Update graceful controller

Signed-off-by: Sakshay Mahna <sakshum19@gmail.com>

* Remove interpolate after goal & Use orientationAroundZAxis

Signed-off-by: Sakshay Mahna <sakshum19@gmail.com>

* Update nav2_util/src/controller_utils.cpp

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

* Update nav2_util/src/controller_utils.cpp

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

* Update nav2_util/src/controller_utils.cpp

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

* Remove interpolate_after_goal parameter from test

Signed-off-by: Sakshay Mahna <sakshum19@gmail.com>

---------

Signed-off-by: Sakshay Mahna <sakshum19@gmail.com>
Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
Co-authored-by: Steve Macenski <stevenmacenski@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants