Skip to content
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

Feat/smac planner include orientation flexibility #4127

Open
wants to merge 19 commits into
base: main
Choose a base branch
from

Conversation

stevedanomodolor
Copy link
Contributor

@stevedanomodolor stevedanomodolor commented Feb 20, 2024


Basic Info

Info Please fill out this column
Ticket(s) this addresses (add tickets here #4019)
Primary OS tested on (Ubuntu, MacOS, Windows)
Robotic platform tested on (Steve's Robot, gazebo simulation of Tally, hardware turtlebot)
Does this PR contain AI generated software? (No; Yes and it is marked inline in the code)

Description of contribution in a few bullet points

  • tackles issue [Smac Planner] Enable goal orientation non-specificity #3789
  • Includes the possibility for the user to determine whether they want the goal heading should be default(the one defined in the goal), bidirectional (user defined + 180 degrees), or all_direction. This way, the user can save time calling the planner multiple times when the angle of the goal does not have to be fixed and has a bit of flexibility.
  • Results can be seen.
Success rate for  ALL_DIRECTION_SmacHybrid  is:  98.33333333333333 %
Success rate for  ALL_DIRECTION_SmacLattice  is:  97.66666666666667 %
Success rate for  ALL_DIRECTION_Smac2d  is:  100.0 %
Success rate for  BIDIRECTIONAL_SmacHybrid  is:  98.33333333333333 %
Success rate for  BIDIRECTIONAL_SmacLattice  is:  97.66666666666667 %
Success rate for  BIDIRECTIONAL_Smac2d  is:  100.0 %
Success rate for  DEFAULT_SmacHybrid  is:  96.66666666666667 %
Success rate for  DEFAULT_SmacLattice  is:  95.0 %
Success rate for  DEFAULT_Smac2d  is:  100.0 %
Success rate for  NORMAL_SmacHybrid  is:  96.66666666666667 %
Success rate for  NORMAL_SmacLattice  is:  95.0 %
Success rate for  NORMAL_Smac2d  is:  100.0 %
**********************Results Goal heading mode Default **********************
Read data
-------------------  -----------------------  -------------------  ------------------  ------------------
Planner              Average path length (m)  Average Time (s)     Average cost        Max cost
DEFAULT_SmacHybrid   48.59179172137297        0.08409778965140845  1.0656706399532687  54.59154929577465
DEFAULT_SmacLattice  49.30762557367365        0.4135887128204226   0.8137733557552133  53.813380281690144
DEFAULT_Smac2d       48.52958672840513        0.12046826587323943  0.7580233687132835  65.47183098591549
-------------------  -----------------------  -------------------  ------------------  ------------------
**********************Results Goal heading mode bidrectional **********************
Read data
-------------------------  -----------------------  -------------------  ------------------  -----------------
Planner                    Average path length (m)  Average Time (s)     Average cost        Max cost
BIDIRECTIONAL_SmacHybrid   48.72823963695479        0.03030190022535211  1.0223910481559262  54.13028169014085
BIDIRECTIONAL_SmacLattice  49.50773050762388        0.17851250328169013  0.7209227860091986  51.23943661971831
BIDIRECTIONAL_Smac2d       48.52960037283171        0.12235441819718311  0.7580233687132835  65.47183098591549
-------------------------  -----------------------  -------------------  ------------------  -----------------
**********************Results Goal heading mode all direction **********************
Read data
-------------------------  -----------------------  --------------------  ------------------  -----------------
Planner                    Average path length (m)  Average Time (s)      Average cost        Max cost
ALL_DIRECTION_SmacHybrid   48.72823963695479        0.031168896616197185  1.0223910481559262  54.13028169014085
ALL_DIRECTION_SmacLattice  49.50773050762388        0.18361958839788733   0.7209227860091986  51.23943661971831
ALL_DIRECTION_Smac2d       48.52960037283171        0.12754024430633804   0.7580233687132835  65.47183098591549


**********************Results Goal heading mode NO changes **********************
Read data
-----------  -----------------------  -------------------  ------------------  ------------------
Planner      Average path length (m)  Average Time (s)     Average cost        Max cost
SmacHybrid   48.59179172137297        0.0930492549330986   1.0656706399532687  54.59154929577465
SmacLattice  49.30762557367365        0.44674316980633805  0.8137733557552133  53.813380281690144
Smac2d       48.52958672840513        0.12973642600352114  0.7580233687132835  65.47183098591549
-----------  -----------------------  -------------------  ------------------  ------------------

Description of documentation updates required from your changes


How to run


Future work that may be required in bullet points

For Maintainers:

  • Check that any new parameters added are updated in navigation.ros.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

@stevedanomodolor stevedanomodolor marked this pull request as draft February 20, 2024 19:14
@SteveMacenski
Copy link
Member

SteveMacenski commented Feb 21, 2024

@stevedanomodolor what's the status here - do you want me to review in detail, have gaps that are TODO, or have some questions to discuss? I don't want to go through and nitpick some small issues if you're really looking for feedback elsewhere right now.

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 didn't review the analytic expansions yet, pending your answer to my above question. But overall from what I read so far, very few notes. This is very good and I couldn't have done it better myself!

nav2_smac_planner/include/nav2_smac_planner/constants.hpp Outdated Show resolved Hide resolved
nav2_smac_planner/CMakeLists.txt Outdated Show resolved Hide resolved
nav2_smac_planner/src/a_star.cpp Outdated Show resolved Hide resolved
nav2_smac_planner/src/a_star.cpp Show resolved Hide resolved
nav2_smac_planner/src/a_star.cpp Outdated Show resolved Hide resolved
nav2_smac_planner/src/smac_planner_hybrid.cpp Outdated Show resolved Hide resolved
nav2_smac_planner/src/smac_planner_hybrid.cpp Outdated Show resolved Hide resolved
nav2_smac_planner/src/smac_planner_hybrid.cpp Outdated Show resolved Hide resolved
nav2_smac_planner/src/smac_planner_hybrid.cpp Outdated Show resolved Hide resolved
@stevedanomodolor
Copy link
Contributor Author

stevedanomodolor commented Feb 21, 2024

@stevedanomodolor what's the status here - do you want me to review in detail, have gaps that are TODO, or have some questions to discuss? I don't want to go through and nitpick some small issues if you're really looking for feedback elsewhere right now.

If you consider the general approach to be ok, then you can review it in detail. If the approach is good, what is just left is to modify the test to take into consideration these changes hench the todo in the CMakelists.

@SteveMacenski
Copy link
Member

SteveMacenski commented Feb 21, 2024

I think the analytic expansions might need to be rethought a bit. I think we should be taking all N of the goals and computing the analytic path, if valid. If any are valid, take the shortest one. There shouldn't be a loop surrounding the preamble which tells us if we want to do analytic expansions in this iteration:

      closest_distance = goal_distance_pair.second;
      NodePtr goal_node = goal_distance_pair.first;
      // We want to expand at a rate of d/expansion_ratio,
      // but check to see if we are so close that we would be expanding every iteration
      // If so, limit it to the expansion ratio (rounded up)
      int desired_iterations = std::max(
        static_cast<int>(closest_distance / _search_info.analytic_expansion_ratio),
        static_cast<int>(std::ceil(_search_info.analytic_expansion_ratio)));
      // If we are closer now, we should update the target number of iterations to go
      analytic_iterations =
        std::min(analytic_iterations, desired_iterations);

      // Always run the expansion on the first run in case there is a
      // trivial path to be found
      if (analytic_iterations <= 0) {

I think your logic is that if we sort by heuristic, then the first that comes back as a valid expansion will be the shortest. I think that would generally be true if the heuristic was a very purist implementation of a distance heuristic. But instead, we have the maximum of a few heuristics including cost information so the "closest" and the one with the "lowest travel cost" aren't necessarily the same thing. So I think largely these changes should be taken back to square one unfortunately and loop to find each of the N goals orientation's analytic expansion length (if valid) and then select the lowest cost one. Interestingly, you can use the new scoringFn to measure that for the final one to store. Luckily, there wasn't a huge number of changes you made to the analytic expansions, so its not a big setback at all and largely its just moving code around and measuring different things

So after

          while (min_turn_rad < max_min_turn_rad) {
            min_turn_rad += 0.5;  // In Grid Coords, 1/2 cell steps
            ompl::base::StateSpacePtr state_space;
            if (node->motion_table.motion_model == MotionModel::DUBIN) {
              state_space = std::make_shared<ompl::base::DubinsStateSpace>(min_turn_rad);
            } else {
              state_space = std::make_shared<ompl::base::ReedsSheppStateSpace>(min_turn_rad);
            }
            refined_analytic_nodes = getAnalyticPath(node, goal_node, getter, state_space);
            score = scoringFn(refined_analytic_nodes);
            if (score <= best_score) {
              analytic_nodes = refined_analytic_nodes;
              best_score = score;
            }
          }

You can use that best_score, store it for that particular angle to decide which to use.

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 ran out of time this evening to review, but this is a few things -- also you have a number of linting issues I can see. Check CI for the full list of formatting problems

nav2_smac_planner/include/nav2_smac_planner/a_star.hpp Outdated Show resolved Hide resolved
nav2_smac_planner/CMakeLists.txt Outdated Show resolved Hide resolved
nav2_smac_planner/src/smac_planner_hybrid.cpp Outdated Show resolved Hide resolved
@SteveMacenski
Copy link
Member

Its also ready enough to update docs for the new variable for the mode to describe the mode, and the migration guide update to show this feature. An image/gif of this in action with the different modes would be great!

I looked through it and all looks good except the analytic expansions I didn't get to right now

Copy link
Contributor

@jwallace42 jwallace42 left a comment

Choose a reason for hiding this comment

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

Looks good!

I think you are missing some work for the distance heuristic.

The distance heuristic is pre computed based on free space. We current only calculate it for the the first goal. This means that we could artificially inflate the cost to go making the heuristic inadmissible.

My suggestion would be to remove the distance heuristic when we are in ALL_DIRECTION mode. For the BIDIRECTIONAL mode I would pre compute the distance for both angles and take the min of those two.

From what I have seen the distance heuristic is rarely greater than the obstacle heuristic so you probably haven't seen any issues.

nav2_smac_planner/src/a_star.cpp Outdated Show resolved Hide resolved
@SteveMacenski
Copy link
Member

Any questions or anything I can unblock on? 😄

Copy link
Contributor

mergify bot commented Mar 9, 2024

@stevedanomodolor, 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).

2 similar comments
Copy link
Contributor

mergify bot commented Mar 9, 2024

@stevedanomodolor, 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).

Copy link
Contributor

mergify bot commented Mar 10, 2024

@stevedanomodolor, 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).

@stevedanomodolor
Copy link
Contributor Author

stevedanomodolor commented Mar 10, 2024

Any questions or anything I can unblock on? 😄

No blocking points, just making changes based on @jwallace42 feedback and testing them but after merging to the main and pulling the latest dockers, pr is not building.

Copy link
Contributor

mergify bot commented Mar 10, 2024

@stevedanomodolor, 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
Copy link
Contributor

mergify bot commented Mar 10, 2024

@stevedanomodolor, 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).

@SteveMacenski
Copy link
Member

SteveMacenski commented Mar 11, 2024

Yeah there's a transient issue due to Rolling moving to 24.04 so a bunch of tooling and package indices are being messed with. Don't worry about it, its not your fault as long as it works locally. Just make sure to keep up on unit testing.

Want me to take a look again?

nav2_smac_planner/src/a_star.cpp Outdated Show resolved Hide resolved
nav2_smac_planner/src/a_star.cpp Show resolved Hide resolved
nav2_smac_planner/src/analytic_expansion.cpp Show resolved Hide resolved
@stevedanomodolor
Copy link
Contributor Author

Yeah there's a transient issue due to Rolling moving to 24.04 so a bunch of tooling and package indices are being messed with. Don't worry about it, its not your fault as long as it works locally. Just make sure to keep up on unit testing.

Want me to take a look again?

I will take advantage of the time to add more unit testing after making the modification you suggested. After the added unit tests, you can look into it.

Copy link
Contributor

mergify bot commented Mar 23, 2024

@stevedanomodolor, 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).

9 similar comments
Copy link
Contributor

mergify bot commented Mar 24, 2024

@stevedanomodolor, 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).

Copy link
Contributor

mergify bot commented Mar 24, 2024

@stevedanomodolor, 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).

Copy link
Contributor

mergify bot commented Mar 24, 2024

@stevedanomodolor, 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).

Copy link
Contributor

mergify bot commented Mar 24, 2024

@stevedanomodolor, 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).

Copy link
Contributor

mergify bot commented Mar 25, 2024

@stevedanomodolor, 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).

Copy link
Contributor

mergify bot commented Mar 25, 2024

@stevedanomodolor, 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).

Copy link
Contributor

mergify bot commented Mar 25, 2024

@stevedanomodolor, 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).

Copy link
Contributor

mergify bot commented Mar 25, 2024

@stevedanomodolor, 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).

Copy link
Contributor

mergify bot commented Mar 25, 2024

@stevedanomodolor, 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).

Copy link
Contributor

@jwallace42 jwallace42 left a comment

Choose a reason for hiding this comment

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

Just a few small things missing.

nav2_smac_planner/include/nav2_smac_planner/a_star.hpp Outdated Show resolved Hide resolved
nav2_smac_planner/include/nav2_smac_planner/a_star.hpp Outdated Show resolved Hide resolved

if (!_search_info.cache_obstacle_heuristic || goal_coords != _goal_coordinates) {
if (!_search_info.cache_obstacle_heuristic || goals_coordinates != _goals_coordinates) {
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to check if any goal coord matches any new goal coord. Both vectors don't have to match. The yaw doesn't have to match.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does really matter if the yaw matches if the goal is to reset the obstacle heurtistic which does not depend on the information on the yaw?

Copy link
Contributor

Choose a reason for hiding this comment

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

I am not quite sure I understand.

The obstacle critic should only be reset when the map coords(costmap coords) are changed. Since all the goals should have the same x,y you can just check the initial of both sets to determine if the obstacle heuristic needs to be recalculated.

It doesn't matter if the yaw matches, but it does matter if there is a mismatch because we will end up recomputing the obstacle heuristic for changes in yaw which has no affect on the obstacle heuristic.

!_goal->isNodeValid(_traverse_unknown, _collision_checker))
{
throw nav2_core::GoalOccupied("Goal was in lethal cost");
if (getToleranceHeuristic() < 0.001) {
Copy link
Contributor

Choose a reason for hiding this comment

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

What about the goal coordinates?

After this step there will be a mismatch better the goalSet and the goal_coordinates.

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, I did that on purpose because I use the goal_coordinates for comparision when i call the setgoals function and I dont want to lose the order because i need it here getInitialGoalCoordinate.

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah so the current flow is

  1. setGoal get called, initializes the goalSet and goals_coords
  2. CreatePath -> areInputsValid which adjusts goalSet, Note: this could invalidate the first goals_coord value i.e (goals_coords[0]). After this point goalSet.size() != goals_coords.size()
  3. Then initial coord get passing to try analytic expansion, the heading of this coord can be invalid.
    In the analytic expansion, getHeuristicCost is calucalted which is a function of the heading.

As a result, you might up attempting analytic expansions in the wrong iterations. You need to calculate the heuristic cost of the valid set of all goal and take the min.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're correct. The change I implemented, which includes pruning, has led to additional problems. In addition to what you said, during the initial stage, I calculate the distance heuristic in advance based on the goal heading with the lowest cost, but there's a chance this goal might be invalid and the heuristic can led the wrong goal. The optimal solution would be to adjust the distance heuristic lookup to depend on the heading. I plan to apply this only for standard and bidirectional headings, considering the impact of the distance heuristic is relatively minor compared to the obstacle heuristic, what do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you should also do it for the all direction headings.

The easiest thing would be to create a set of lookup tables rather than just taking the min. Then based on the goals used you construct the final min lookup table used for the search.

@SteveMacenski
Copy link
Member

Thanks Josh!

@stevedanomodolor stevedanomodolor marked this pull request as draft April 15, 2024 17:01
Copy link
Contributor

mergify bot commented Apr 15, 2024

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

Signed-off-by: stevedan <stevedan.o.omodolor@gmail.com>
Signed-off-by: stevedan <stevedan.o.omodolor@gmail.com>
Signed-off-by: stevedan <stevedan.o.omodolor@gmail.com>
Signed-off-by: stevedan <stevedan.o.omodolor@gmail.com>
@stevedanomodolor
Copy link
Contributor Author

Just a few small things missing.

I made some changes for simplicity when computing the distance heuristics.

… and node2d

Signed-off-by: stevedan <stevedan.o.omodolor@gmail.com>
@stevedanomodolor stevedanomodolor force-pushed the feat/smac_planner_include_orientation_flexibility branch from afa9489 to c0abe18 Compare April 18, 2024 22:02
@stevedanomodolor stevedanomodolor marked this pull request as ready for review April 19, 2024 04:48
@stevedanomodolor
Copy link
Contributor Author

@SteveMacenski locally, all my ctest are passing but for some reason the behavior tests are failing

Test project /opt/overlay_ws/build/nav2_system_tests
      Start  1: copyright
 1/33 Test  #1: copyright ................................   Passed    1.60 sec
      Start  2: cppcheck
 2/33 Test  #2: cppcheck .................................   Passed    0.13 sec
      Start  3: cpplint
 3/33 Test  #3: cpplint ..................................   Passed    1.28 sec
      Start  4: flake8
 4/33 Test  #4: flake8 ...................................   Passed    0.71 sec
      Start  5: lint_cmake
 5/33 Test  #5: lint_cmake ...............................   Passed    0.13 sec
      Start  6: pep257
 6/33 Test  #6: pep257 ...................................   Passed    0.37 sec
      Start  7: uncrustify
 7/33 Test  #7: uncrustify ...............................   Passed    0.25 sec
      Start  8: xmllint
 8/33 Test  #8: xmllint ..................................   Passed    0.97 sec
      Start  9: test_behavior_tree_node
 9/33 Test  #9: test_behavior_tree_node ..................   Passed    2.54 sec
      Start 10: test_planner_costmaps
10/33 Test #10: test_planner_costmaps ....................   Passed    1.67 sec
      Start 11: test_planner_random
11/33 Test #11: test_planner_random ......................   Passed    1.87 sec
      Start 12: test_planner_plugins
12/33 Test #12: test_planner_plugins .....................   Passed    1.81 sec
      Start 13: test_planner_is_path_valid
13/33 Test #13: test_planner_is_path_valid ...............   Passed    1.52 sec
      Start 14: test_localization
14/33 Test #14: test_localization ........................   Passed    2.85 sec
      Start 15: test_bt_navigator
15/33 Test #15: test_bt_navigator ........................   Passed   43.79 sec
      Start 16: test_bt_navigator_with_wrong_init_pose
16/33 Test #16: test_bt_navigator_with_wrong_init_pose ...   Passed   28.65 sec
      Start 17: test_bt_navigator_with_dijkstra
17/33 Test #17: test_bt_navigator_with_dijkstra ..........   Passed   44.83 sec
      Start 18: test_bt_navigator_2
18/33 Test #18: test_bt_navigator_2 ......................   Passed   44.59 sec
      Start 19: test_dynamic_obstacle
19/33 Test #19: test_dynamic_obstacle ....................   Passed   44.72 sec
      Start 20: test_nav_through_poses
20/33 Test #20: test_nav_through_poses ...................   Passed   64.68 sec
      Start 21: test_failure_navigator
21/33 Test #21: test_failure_navigator ...................   Passed   28.67 sec
      Start 22: test_waypoint_follower
22/33 Test #22: test_waypoint_follower ...................   Passed   49.94 sec
      Start 23: test_gps_waypoint_follower
23/33 Test #23: test_gps_waypoint_follower ...............   Passed  117.55 sec
      Start 24: test_spin_behavior
24/33 Test #24: test_spin_behavior .......................   Passed  114.69 sec
      Start 25: test_spin_behavior_fake
25/33 Test #25: test_spin_behavior_fake ..................   Passed  133.69 sec
      Start 26: test_wait_behavior
26/33 Test #26: test_wait_behavior .......................   Passed   41.77 sec
      Start 27: test_backup_recovery
27/33 Test #27: test_backup_recovery .....................   Passed   28.31 sec
      Start 28: test_drive_on_heading_recovery
28/33 Test #28: test_drive_on_heading_recovery ...........   Passed   39.67 sec
      Start 29: test_assisted_teleop_behavior
29/33 Test #29: test_assisted_teleop_behavior ............   Passed   27.86 sec
      Start 30: test_keepout_filter
30/33 Test #30: test_keepout_filter ......................   Passed   43.02 sec
      Start 31: test_speed_filter_global
31/33 Test #31: test_speed_filter_global .................   Passed   39.02 sec
      Start 32: test_speed_filter_local
32/33 Test #32: test_speed_filter_local ..................   Passed   38.72 sec
      Start 33: test_error_codes
33/33 Test #33: test_error_codes .........................   Passed   10.59 sec

100% tests passed, 0 tests failed out of 33

Label Time Summary:
copyright     =   1.60 sec*proc (1 test)
cppcheck      =   0.13 sec*proc (1 test)
cpplint       =   1.28 sec*proc (1 test)
flake8        =   0.71 sec*proc (1 test)
gtest         =   5.87 sec*proc (3 tests)
lint_cmake    =   0.13 sec*proc (1 test)
linter        =   5.44 sec*proc (8 tests)
pep257        =   0.37 sec*proc (1 test)
uncrustify    =   0.25 sec*proc (1 test)
xmllint       =   0.97 sec*proc (1 test)

Total Test time (real) = 1002.50 sec

@SteveMacenski
Copy link
Member

SteveMacenski commented Apr 23, 2024

The spin/backup are periodically flaky. I wack them down and they come up on occasion. Given this doesn't touch the behavior server at all, I'm not concerned by those failures. It just means I need to play wackamole again or finally delete and rewrite them myself. I retriggered CI for kicks and giggles, it may pass this time.

I'd just focus on the review comments and performance checking (and any test failures that could be plausibly caused by you, which I don't see)

@stevedanomodolor
Copy link
Contributor Author

The spin/backup are periodically flaky. I wack them down and they come up on occasion. Given this doesn't touch the behavior server at all, I'm not concerned by those failures. It just means I need to play wackamole again or finally delete and rewrite them myself. I retriggered CI for kicks and giggles, it may pass this time.

I'd just focus on the review comments and performance checking (and any test failures that could be plausibly caused by you, which I don't see)

I update the readme with the latest performance check comparing before and after the changes

Signed-off-by: stevedan <stevedan.o.omodolor@gmail.com>
…ility

Signed-off-by: Stevedan Ogochukwu Omodolor <61468301+stevedanomodolor@users.noreply.github.com>
Copy link

codecov bot commented May 8, 2024

Codecov Report

Attention: Patch coverage is 86.51685% with 24 lines in your changes are missing coverage. Please review.

Project coverage is 89.57%. Comparing base (f12544d) to head (4f10498).
Report is 2 commits behind head on main.

❗ Current head 4f10498 differs from pull request most recent head eff8859. Consider uploading reports for the commit eff8859 to get more accurate results

Files Patch % Lines
nav2_smac_planner/src/a_star.cpp 81.69% 13 Missing ⚠️
nav2_smac_planner/src/smac_planner_hybrid.cpp 76.47% 4 Missing ⚠️
nav2_smac_planner/src/smac_planner_lattice.cpp 78.94% 4 Missing ⚠️
nav2_smac_planner/src/analytic_expansion.cpp 93.47% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4127      +/-   ##
==========================================
+ Coverage   89.55%   89.57%   +0.02%     
==========================================
  Files         435      435              
  Lines       19848    19950     +102     
==========================================
+ Hits        17775    17871      +96     
- Misses       2073     2079       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@stevedanomodolor stevedanomodolor marked this pull request as draft May 8, 2024 20:30
Signed-off-by: stevedan <stevedan.o.omodolor@gmail.com>
@stevedanomodolor stevedanomodolor force-pushed the feat/smac_planner_include_orientation_flexibility branch from deaa173 to eff8859 Compare May 8, 2024 21:09
@stevedanomodolor stevedanomodolor marked this pull request as ready for review May 8, 2024 21:37
@SteveMacenski
Copy link
Member

SteveMacenski commented May 14, 2024

I update the readme with the latest performance check comparing before and after the changes

I don't see that?

Apologies in the delay in reviews, this is a big PR and I've been a bit underwater recently so this unfortunately didn't get the attention on the schedule I would have liked. Doing it today though.

getDistanceHeuristic(node_coords, goal_coords, obstacle_heuristic);
node_coords, goals_coords[0], motion_table.cost_penalty);
float distance_heuristic = std::numeric_limits<float>::max();
for (unsigned int i = 0; i < goals_coords.size(); i++) {
Copy link
Member

Choose a reason for hiding this comment

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

I'd be interested in the runtime impact of this over the all headings setting

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Included in the pr descrition

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@SteveMacenski What if during the initailzation fase, I construct 3 tables for each direction and then based on the goal, take the one the look up table value?. It similar to what @jwallace42 suggested but, I compute everything beforehand.

Copy link
Member

Choose a reason for hiding this comment

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

That would be alot of memory, leaving this as a single table is best I think -- but I think this is moot now from the discussion below?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@SteveMacenski I am just starting to see a lots of problem with the 3 table idea, because if i precompute the table, there is a possibility the minimum distance heuristic corresponding to a goal be prune because now i do goal path pruning. The other option is to create a default table in the beginning during the is path valid function, I can precompute a temporal table based on this default. This way in defautl goal heading mode, I dont influence the computation time, what do you think?. The only downside here is that during I will have two lookup tables in memory though.

Copy link
Member

Choose a reason for hiding this comment

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

I don't quite understand what you're asking.

I think we should leave the table structure as it is. The content should just be set according to the heading policy

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The problem with setting it beforehand is that there is a change that one of the goals set to be minimum will be pruned later in the isinputvalid function making the lookup table invalid hence why I decided to go with the current approach. I am working on the following, still needs testing and benchmarking but for the last few days, I have been having issues building and running dockers in rolling(the comment from the other issue :). This is still wip

void NodeHybrid::resetDistanceHeuristic(
  const CoordinateVector & goals_coords,
  const GoalHeadingMode & goal_heading_mode)
{
  dist_heuristic_lookup_table = initial_dist_heuristic_lookup_table;

  if (goal_heading_mode == GoalHeadingMode::DEFAULT) {
    return;
  }

  std::unordered_set<int> goal_heading_angles;
  if (goal_heading_mode == GoalHeadingMode::BIDIRECTIONAL ||
    goal_heading_mode == GoalHeadingMode::ALL_DIRECTION)
  {
    goal_heading_angles.reserve(goals_coords.size());
    for (const auto & coord : goals_coords) {
      goal_heading_angles.insert(motion_table.getClosestAngularBin(coord.theta));
    }
  }
  int ceiling_size = static_cast<int>(ceil(size_lookup / 2.0));
  int total_size = static_cast<int>(size_lookup);
  auto is_goal_heading = [&](int heading) {
      return goal_heading_angles.find(heading) != goal_heading_angles.end();
    };
  int index = 0;
  if (goal_heading_mode == GoalHeadingMode::BIDIRECTIONAL) {
    for (float x = ceil(-size_lookup / 2.0); x <= floor(size_lookup / 2.0); x += 1.0) {
      for (float y = 0.0; y <= floor(size_lookup / 2.0); y += 1.0) {
        for (int heading = 0; heading < dim_3_size_int; ++heading) {
          int heading_angle_180 = (heading + dim_3_size_int / 2) % dim_3_size_int;
          int index_180 = (index-heading) + heading_angle_180;
          // std::cout << "index: " << index << " index_180: " << index_180 << " size: " << dist_heuristic_lookup_table.size() << std::endl;

          float dist_heuristic = initial_dist_heuristic_lookup_table[index];
          float dist_heuristic_180 = initial_dist_heuristic_lookup_table[index_180];

          if (dist_heuristic_180 < dist_heuristic && is_goal_heading(heading_angle_180)) {
            dist_heuristic_lookup_table[index] = dist_heuristic_180;
          }
          index++;
        }
      }
    }
  } else if (goal_heading_mode == GoalHeadingMode::ALL_DIRECTION) {
    for (int x = 0; x < size_lookup; ++x) {
      for (int y = 0; y < ceiling_size; ++y) {
        std::vector<float> dist_heuristic_angles(dim_3_size_int);
        std::vector<int> indices(dim_3_size_int);

        for (int heading = 0; heading < dim_3_size_int; ++heading) {
          dist_heuristic_angles[heading] = dist_heuristic_lookup_table[index];
          indices[heading] = index;
          index ++;
        }
        // we want to get the minimum distance heuristic for all the goal heading angles
        // and that is also one of the goal heading angles
        auto min_it = std::min_element(
          dist_heuristic_angles.begin(), dist_heuristic_angles.end(), [&](float a, float b) {
            int a_index = &a - &dist_heuristic_angles[0];
            int b_index = &b - &dist_heuristic_angles[0];
            return (is_goal_heading(a_index) ? a : std::numeric_limits<float>::max()) <
            (is_goal_heading(b_index) ? b : std::numeric_limits<float>::max());
          });
        // if we find one we update the distance heuristic for all the goal heading angles
        if (min_it != dist_heuristic_angles.end()) {
          for (int heading = 0; heading < dim_3_size_int; ++heading) {
            dist_heuristic_lookup_table[indices[heading]] = *min_it;
          }
        }
      }
    }
  }
}

return std::max(obstacle_heuristic, dist_heuristic);
getObstacleHeuristic(node_coords, goals_coords[0], motion_table.cost_penalty);
float distance_heuristic = std::numeric_limits<float>::max();
for (unsigned int i = 0; i < goals_coords.size(); i++) {
Copy link
Member

Choose a reason for hiding this comment

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

Ditto. It might be best to just use the main goal. If so, then this could be reverted to taking in the Coordinates.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

With the suggestion above, I can make this changes

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@SteveMacenski With the below approach, this way I can just pass the coordinates instead of the coordinatevector, the only problem I see with this is https://github.com/stevedanomodolor/navigation2/blob/1a34ea3f3789aa66955a389b8db17acef95a836b/nav2_smac_planner/src/node_lattice.cpp#L422. I am sure how much of an influence it would be.

 dist_heuristic_lookup_table.resize(size_lookup_total);
  dist_heuristic_lookup_table_bidirectional;
  dist_heuristic_lookup_table_all_direction;

Copy link
Member

Choose a reason for hiding this comment

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

The obstacle_heuristic == 0.0 case is defensive programming in case everything goes very wrong - this should not happen that both the cost is 0 and its outside of the window around the goal. This is a "just in case" case

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Then I will go with the approach I mentioned above and update the benchmarks again, this could reduce more time.

Copy link
Member

Choose a reason for hiding this comment

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

Great!

nav2_smac_planner/src/a_star.cpp Show resolved Hide resolved
nav2_smac_planner/src/a_star.cpp Show resolved Hide resolved
nav2_smac_planner/src/a_star.cpp Outdated Show resolved Hide resolved
nav2_smac_planner/src/a_star.cpp Outdated Show resolved Hide resolved
nav2_smac_planner/src/a_star.cpp Outdated Show resolved Hide resolved
@stevedanomodolor
Copy link
Contributor Author

I update the readme with the latest performance check comparing before and after the changes

I don't see that?

Apologies in the delay in reviews, this is a big PR and I've been a bit underwater recently so this unfortunately didn't get the attention on the schedule I would have liked. Doing it today though.

the pr description*

Signed-off-by: stevedan <stevedan.o.omodolor@gmail.com>
@SteveMacenski
Copy link
Member

Ah got it, thanks! I was looking in the package's readme. I'm surprised its so much faster, that's a cool result!

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.

None yet

3 participants