-
Notifications
You must be signed in to change notification settings - Fork 1.4k
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
Fixed the problem of static layer not restoring old map values for footprint #4824
base: main
Are you sure you want to change the base?
Fixed the problem of static layer not restoring old map values for footprint #4824
Conversation
@CihatAltiparmak, your PR has failed to build. Please check CI outputs and resolve issues. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't carefully review this yet (Saturday afternoon over coffee!), but wouldn't it be possible for us to simply remove the setConvexPolygonCost
from the internal static layer grid and apply it to the master grid update (master_grid.setConvexPolygonCost())
)?
That would apply it more globally however which might not be wanted in some cases (though I find that generally hard to believe some layers would be set for that and others are not, practically speaking).
Alternatively, you could have setConvexPolygonCost
split into 2 stages. Stage 1 is getting the cells that belong to the footprint
// we assume the polygon is given in the global_frame...
// we need to transform it to map coordinates
std::vector<MapLocation> map_polygon;
for (unsigned int i = 0; i < polygon.size(); ++i) {
MapLocation loc;
if (!worldToMap(polygon[i].x, polygon[i].y, loc.x, loc.y)) {
// ("Polygon lies outside map bounds, so we can't fill it");
return false;
}
map_polygon.push_back(loc);
}
std::vector<MapLocation> polygon_cells;
// get the cells that fill the polygon
convexFillCells(map_polygon, polygon_cells);
// NEW: Now return this!
And return those. The second step would be to obtain their values in the loop, store them, and set the new values for FREE. After we do the master grid update, use the originally obtained values to repopulate the static layer. You'd basically just break the setConvexPolygonCost
into 3 methods: (1) get the cells that belong to a convex shape, (2) sets its value for a fixed value (for free), and (3) sets its value to using a vector of input of values stored originally (to reset).
I think that's similar to what you did, but I think this would require alot less changes.
Thank you for give a feedback in a light speed.
Of course, I can. I just wondered your idea about whether adding new method would be useful for future. For instance, I wanna use setConvexCost in such a way that I can update with max value (
I agree with you. I could not get any chance to take a look at other layers, however I can see where this issue comes from. (#4282 ) |
Ah, that is pretty recent. Yeah I think doing the second thing I recommended on splitting up the functions would be the best move here. Then, parameterize if you want to repopulate (see comment in the issue ticket) |
Signed-off-by: CihatAltiparmak <[email protected]>
Signed-off-by: CihatAltiparmak <[email protected]>
Signed-off-by: CihatAltiparmak <[email protected]>
Signed-off-by: CihatAltiparmak <[email protected]>
ba90d2d
to
9896607
Compare
Signed-off-by: CihatAltiparmak <[email protected]>
Signed-off-by: CihatAltiparmak <[email protected]>
Hi @SteveMacenski , If you get a chance, would you take a look at my modifications, I've tried to minimize diffs to ease your work. Btw, I can consider to add the test cases to increase code coverage if you want. Additionaly, I will take a look at the other layers. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please revert changes to the workflows of the node, I think it creates a number of regressions. I think you should only need to adjust the updateCosts
portion of the implementation. I can see why you did this, wanting to restore
from the previous iteration's stored values, but I think you can do this much more easily by just restoring a given iteration's costs at the end of the updateCosts
method.
@@ -138,6 +138,7 @@ StaticLayer::getParameters() | |||
declareParameter("transform_tolerance", rclcpp::ParameterValue(0.0)); | |||
declareParameter("map_topic", rclcpp::ParameterValue("map")); | |||
declareParameter("footprint_clearing_enabled", rclcpp::ParameterValue(false)); | |||
declareParameter("restore_outdated_footprint", rclcpp::ParameterValue(false)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Make sure to open a docs PR on docs.nav2.org that adds this parameter to the static layer & in the migration guide that this change is made
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have removed this parameter, but if you are willing to add it, it can be updated the Costmap2D object itself of static layer
in order to to add such a option. Thus, it can be permanent in the master grid. What do you think?
} | ||
|
||
updateFootprint(robot_x, robot_y, robot_yaw, min_x, min_y, max_x, max_y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I couldn't find how to revert this. Because, if updateFootprint
doesn't run continuously, master_grid
cannot be restored. But I will think about that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How it is being restored now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we don't execute updateFootprint
before if checks, it will be updated only when new occupancy map msg is published. This is my concern. In my way, if footprint_clearing_enabled
is true, the area occupied by robot's footprint is updated per each updateCost
execution. In current nav2 stack, it is hard to see that. If I am wrong, fix me please.
Ignore my comment here. I explained its cause here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of updating only when new map has been published, what about to check how updateFootprint
updates the bounds of the costmap_
? Thus, we can prevent the potential incompabilities between costmap_
and master_grid
.
Pseudo is like that.
void
StaticLayer::updateFootprint(
double robot_x, double robot_y, double robot_yaw,
double * min_x, double * min_y,
double * max_x,
double * max_y)
{
if (!footprint_clearing_enabled_) {return;}
for (const auto & point : transformed_footprint_) {
unsigned int mx, my;
if (!worldToMap(point.x, point.y, mx, my)) {
return;
}
touch(point.x, point.y, min_x, min_y, max_x, max_y);
}
transformFootprint(robot_x, robot_y, robot_yaw, getFootprint(), transformed_footprint_);
}
@@ -412,7 +448,14 @@ StaticLayer::updateCosts( | |||
} | |||
|
|||
if (footprint_clearing_enabled_) { | |||
setConvexPolygonCost(transformed_footprint_, nav2_costmap_2d::FREE_SPACE); | |||
if (restore_outdated_footprint_) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this need to happen at the end of the function, after we update the master map?
That would let everything happen in 1 call of updateCosts
sequentially under lock without storing and dealing with map / partial map updates between iterations.
There was a problem hiding this 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 htese functions can live in the costmap_2d object like setConvexPolygonCost
-- then have setConvexPolygonCost
itself use some of these to minimize code duplication
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's really cool idea. I am sory I couldn't get it at the beginning of the conversation. It dramatically decreased the diffs.
Signed-off-by: CihatAltiparmak <[email protected]>
Signed-off-by: CihatAltiparmak <[email protected]>
Signed-off-by: CihatAltiparmak <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what this currently does is clear the footprint on the master grid after update, but that would bypass the set updateWithXYZ()
policies that users can set in order to set how they want updates to be performed (i.e. use max value or have it overwrite). This would lose information like having non-zero costs due to sensor measurements, even if removing the static map values, which wouldn't be a solution without introducing a regression.
This was a good thought / nice clean way to do this while minimizing code changes, but I think we need to do what we discussed previously unless there's another way around that issue. Break up setConvexPolygonCost
into a few methods inside of costmap2d
, use those methods here to obtain the cost values originally in the layer's internal costmap, clear the costmap, update the master grid, then revert the layer's internal costmap.
Maybe: Is there a way to apply the updateWithXYZ()
policies for the following block? That would reduce the number of localized grid operations back to the same we do now (just each one has an extra couple of checks, which should be minimal in terms of computational cost)
if (footprint_clearing_enabled_) {
master_grid.setConvexPolygonCost(transformed_footprint_, nav2_costmap_2d::FREE_SPACE);
}
I also don't understand why updateFootprint
as a method was updated. I think the footprint must be transformed into the current frame before touch
-ing the points to expand the bounds. I also don't think that updateFootprint should be completed if not updating its bounds. Can/should these be reverted?
Firstly, my apologies for long delay due to my exams so on.
I have a question here. why do we have to update the areas with max value or overwrite after clearing the footprint area? Doesn't
I commented on one of your reviews, but I saw this later. You are right. Ignore my comments in that review. I will figure out all of them. |
No need for apologies, life happens 😉
There's a setting The behavior that this PR currently implements is overriding of values. The master costmap is always cleared fully under footprint, rather than having the option to combine using the max value that could already exist in the costmap from another layer or a previous update. Imagine you had a laser scan layer below this one - the measurements from the laser scan would be deleted which represent real data being lost by overriding them. The obstacle layer that processes the laser scan has itself a clear under footprint parameter that would need to be also enabled to deal with that. There could be situations where you might not set clear under footprint for all layers -- so deleting the footprint's costs for the full master grid without consulting its combination policy is important. The clear under footprint is specific to each layer, not to the master costmap itself. The combination policy that the user selected the layer to run at should be respected :-) if the combination policy is 'override', then what you have is exactly the same as doing the footprint clearing on the local internal costmap to the layer. However, if the policy is 'use maximum', then its not the same. Before this PR, the cleared values under the footprint in the static layer would contribute |
Basic Info
Description of contribution in a few bullet points
map_buffer
just after The methodprocessMap
is run so we can utilizemap_buffer
to restore the region cleared before.map_received_in_update_bounds_
because seems we really don't need to.processMap
method because now we are using lock in parts we useprocessMap
Description of documentation updates required from your changes
We have added some methods to Costmap2d. So we may need to update Costmap2D API documentation.
Future work that may be required in bullet points
For Maintainers: