Skip to content

Add footprintAreaCost #5250

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

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

tonynajjar
Copy link
Contributor


Basic Info

Info Please fill out this column
Ticket(s) this addresses (add tickets here #1)
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

Description of documentation updates required from your changes

Description of how this change was tested


Future work that may be required in bullet points

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

Signed-off-by: Tony Najjar <tony.najjar.1997@gmail.com>
double max_cost = 0.0;

// Check if footprint is rectangular for optimization
bool is_rectangular = isRectangularFootprint(footprint, min_x, max_x, min_y, max_y);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

optimization: doesn't need to be checked every time

@@ -143,6 +243,41 @@ double FootprintCollisionChecker<CostmapT>::footprintCostAtPose(
return footprintCost(oriented_footprint);
}

template<typename CostmapT>
bool FootprintCollisionChecker<CostmapT>::isPointInFootprint(
Copy link
Contributor Author

@tonynajjar tonynajjar Jun 10, 2025

Choose a reason for hiding this comment

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

taken from collision_monitor. Libraries also exist for this e.g boost

@@ -150,7 +148,8 @@ bool GridCollisionChecker::inCollision(
current_footprint.push_back(new_pt);
}

float footprint_cost = static_cast<float>(footprintCost(current_footprint));
// Check full area covered by footprint
float footprint_cost = static_cast<float>(footprintAreaCost(current_footprint));
Copy link
Contributor Author

Choose a reason for hiding this comment

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

can be parametrized to allow user to tune for speed vs accuracy

Signed-off-by: Tony Najjar <tony.najjar.1997@gmail.com>
Copy link
Contributor

mergify bot commented Jun 10, 2025

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

@tonynajjar
Copy link
Contributor Author

I asked my LLM to benchmark the 2 functions and this is the result. Take it with a grain of salt, I didn't sanity-check it but the results look reasonable.

=== Collision Method Benchmark ===
Comparing footprintCost (edge-only) vs footprintAreaCost (full area)

Running 10000 iterations per test...

Testing small_square... Done
  Vertices: 4
  Area (cells): 16.00
  Edge method: 0.038 μs/call
  Area method: 0.048 μs/call
  Speedup ratio: 1.28x (Area method SLOWER)
  Costs match: Yes

Testing medium_rect... Done
  Vertices: 4
  Area (cells): 72.00
  Edge method: 0.060 μs/call
  Area method: 0.152 μs/call
  Speedup ratio: 2.52x (Area method SLOWER)
  Costs match: Yes

Testing large_rect... Done
  Vertices: 4
  Area (cells): 200.00
  Edge method: 0.110 μs/call
  Area method: 0.303 μs/call
  Speedup ratio: 2.75x (Area method SLOWER)
  Costs match: Yes

Testing xlarge_rect... Done
  Vertices: 4
  Area (cells): 800.00
  Edge method: 0.351 μs/call
  Area method: 1.086 μs/call
  Speedup ratio: 3.10x (Area method SLOWER)
  Costs match: No
    Edge cost: 253.00, Area cost: 254.00

Testing hexagon... Done
  Vertices: 6
  Area (cells): 41.57
  Edge method: 0.013 μs/call
  Area method: 0.391 μs/call
  Speedup ratio: 30.62x (Area method SLOWER)
  Costs match: Yes

Testing octagon... Done
  Vertices: 8
  Area (cells): 101.82
  Edge method: 0.013 μs/call
  Area method: 0.793 μs/call
  Speedup ratio: 61.10x (Area method SLOWER)
  Costs match: Yes

Testing complex_12_sided... Done
  Vertices: 12
  Area (cells): 75.00
  Edge method: 0.013 μs/call
  Area method: 0.733 μs/call
  Speedup ratio: 54.49x (Area method SLOWER)
  Costs match: Yes

Testing complex_16_sided... Done
  Vertices: 16
  Area (cells): 76.54
  Edge method: 0.013 μs/call
  Area method: 0.895 μs/call
  Speedup ratio: 69.63x (Area method SLOWER)
  Costs match: Yes

Testing narrow_robot... Done
  Vertices: 4
  Area (cells): 64.00
  Edge method: 0.131 μs/call
  Area method: 0.109 μs/call
  Speedup ratio: 0.83x (Area method FASTER)
  Costs match: Yes

=== SUMMARY ===
Average edge method time: 0.082 μs
Average area method time: 0.501 μs
Overall speedup ratio: 6.08x
Area method faster in: 1/9 cases
Edge method faster in: 8/9 cases
Costs match in: 8/9 cases

WARNING: Some costs don't match! This indicates different behavior between methods.

@tonynajjar
Copy link
Contributor Author

@SteveMacenski do you have time for this soon? I have about an hour still where I could finish this

@SteveMacenski
Copy link
Member

@tonynajjar I just commented in the issue - looking at this 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.

Other than your comments and 1-2 nitpicks I would make, this seems sane for this method. I'm curious what LLM / notebook / tools did you do for this?


// Check all cells within bounding box
for (unsigned int mx = min_mx; mx <= max_mx; ++mx) {
for (unsigned int my = min_my; my <= max_my; ++my) {
Copy link
Member

Choose a reason for hiding this comment

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

I think for y; for x is actually faster, no?

@tonynajjar
Copy link
Contributor Author

tonynajjar commented Jun 11, 2025

I use Github Copilot in VScode with agent mode with the latest Claude Sonnet or GPT models. I still iterated quite a bit to get to this state but it's a huge help for sure...

Anyway, you advocated for the other strategy (swept area), so what would be your plan for this PR? Complete it and merge it until someone can implement the other strategy? Or discard it?
You're right that this method has the risk of jumping over a lethal space but practically from my tests that didn't happen yet so I'll use this solution until we implement better.

@tonynajjar
Copy link
Contributor Author

image

I just got a case where this approach fails (and it doesn't even involve single cells) because the angle change between 2 planned footprints is too big. The red footprint is TEB's feasibility checker kicking in showing where the collision would be if we try to follow SMAC's plan.

@tonynajjar
Copy link
Contributor Author

I increased the turning radius to 0.4 to see if that was a problem only with small turning radii but even in this case I'm not confident that the interpolation between the planned footprint is collision-free but I guess it depends on the interpolation model

image

@tonynajjar
Copy link
Contributor Author

tonynajjar commented Jun 12, 2025

With those changes I'm noticing a weird behavior but I don't see how it relates: For goals moderatly close to lethal space (i don't know what the distance limit is), SMAC doesn't reach the desired orientation.

Example: in the following image, pose 432 is sent as the goal from SMAC but the final pose does not match the orientation. (blue rectangle is the last planned footprint)

I'm sure that it is because of this PR as I tested without and it reaches any orientation

image

Do you have a guess why this PR could cause that?

Update1: I noticed that when that happens, there are many more arrows in the expansions visualizations. What could that mean?

image

Update2: Okay I think I'm slowly understanding better how SMAC works - I think the fact that there are expansion arrows up until the the goal means that SMAC never successfully used analytical expansion, which I assume would be responsible of reaching the right orientation accurately? If yes then next question: what causes the the analytical expansion to fail?

@SteveMacenski
Copy link
Member

Alot here to process, so I'll go in order

Anyway, you advocated for the other strategy (swept area), so what would be your plan for this PR? Complete it and merge it until someone can implement the other strategy? Or discard it?

I think from your later findings you might be on Team Swept Area now? For right now, I think we can leave this open for discussion until we find the final solution and/or use this in the interim or permanently.

I just got a case where this approach fails (and it doesn't even involve single cells) because the angle change between 2 planned footprints is too big

⬆️ So swept area might be better?

I increased the turning radius to 0.4

Its not that 0.4m is a magic number (though it did come from somewhere; I selected it based on the turning radius of common RC car toys that are able to get through tight spaces in houses, I figured if it can do it, then that's a good baseline for us. It also makes good turns in and out of aisles as a baseline that isn't just a point-turn but also isn't so arced out that its highly dependent on the width of aisles to successfully compute). It just interpolates more than the jumps for basically zero-radius turns. It doesn't surprise me that you could reproduce it, but I would expect it to be harder.


You're right on the analytic expansion. Are you using a tolerance > 0? If so, then it could return a solution nearby if it was unable to compute an exact match.

I'm sure that it is because of this PR as I tested without and it reaches any orientation ... what causes the the analytical expansion to fail?

I ... have no idea. Perhaps there's a bug in your Area check that is checking some wrong cells, so when you're near an obstacle, its checking part of the window it shouldn't. When analytic expansion tries to compute the exact path, then it is unable to do so because they're being reported in collision. The only relationship with the collision checking and analytic expansion is that the expansions are checked for collision using the collision checker.

So, I think that would indicate to me that something about this is buggy. I don't see an immediate problem though, so I'd need to add in some prints to log in the analytic expansion to see what it thinks is going on.

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.

2 participants