-
Notifications
You must be signed in to change notification settings - Fork 1.6k
MPPI cost-based visualization #5643
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
base: main
Are you sure you want to change the base?
Conversation
Signed-off-by: Tony Najjar <[email protected]>
Signed-off-by: Tony Najjar <[email protected]>
| float weight_{0}; | ||
|
|
||
| bool visualize_{false}; | ||
| nav2::Publisher<geometry_msgs::msg::PoseStamped>::SharedPtr target_pose_pub_; |
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.
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 add the orientation, I think that would help. If we don't add that, then yes a sphere could make sense
| auto color = utils::createColor(0, green_component, blue_component, 1); | ||
| auto marker = utils::createMarker( | ||
| marker_id_++, pose, scale, color, frame_id_, marker_namespace); | ||
| // Use 10th and 90th percentile for robust color mapping |
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 found this percentile separation to be the best for my case
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 do the eigen normalization, we can promise normalization from 0-1 always. I think that would be the best?
| const float j_flt = static_cast<float>(j); | ||
| float blue_component = 1.0f - j_flt / shape_1; | ||
| float green_component = j_flt / shape_1; | ||
| // Use percentile-based normalization to handle outliers |
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 important because the CostCritic creates high-cost outliers which increases the range of the color gradient to a point where it's just green or red
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.
We could also skip trajectories marked as collision from the normalization process. Only have the scale normalization apply to non-collision trajectories. Have in-collision trajectories be straight up red-only (which makes sense to a casual viewer as well)
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.
We could also skip trajectories marked as collision from the normalization process
I thought about that but how would you determine that? Just based off the cost? or would you add a in_collision field to Trajectories
Signed-off-by: Tony Najjar <[email protected]>
Signed-off-by: Tony Najjar <[email protected]>
|
I only had a quick look as I am traveling. I think keeping the optimal trajectory visualized and distinguished is important, as it's the most useful part. |
| auto node = parent_.lock(); | ||
| if (node) { | ||
| target_pose_pub_ = node->create_publisher<geometry_msgs::msg::PoseStamped>( | ||
| "/PathAlignCritic/furthest_reached_path_point", 1); |
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.
Remove the first /, which will mess with multirobot / namespacing
| float path_segments_flt = static_cast<float>(path_segments_count); | ||
|
|
||
| // Visualize target pose if enabled | ||
| if (visualize_ && path_segments_count > 0) { |
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.
Check if there are any subscriptions
|
|
||
| // Visualize target pose if enabled | ||
| if (visualize_ && path_segments_count > 0) { | ||
| auto node = parent_.lock(); |
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.
You could store the clock here:
navigation2/nav2_mppi_controller/include/nav2_mppi_controller/critic_function.hpp
Line 73 in 5202339
| logger_ = parent_.lock()->get_logger(); |
| target_pose.pose.position.y = data.path.y(path_segments_count); | ||
| target_pose.pose.position.z = 0.0; | ||
| target_pose.pose.orientation.w = 1.0; | ||
| target_pose_pub_->publish(target_pose); |
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.
Unique pointer + std::move
| target_pose.pose.position.x = data.path.x(path_segments_count); | ||
| target_pose.pose.position.y = data.path.y(path_segments_count); | ||
| target_pose.pose.position.z = 0.0; | ||
| target_pose.pose.orientation.w = 1.0; |
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.
Why not set the orientation?
| // Use 10th and 90th percentile for robust color mapping | ||
| size_t idx_10th = static_cast<size_t>(sorted_costs.size() * 0.1); | ||
| size_t idx_90th = static_cast<size_t>(sorted_costs.size() * 0.9); |
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.
Can we use something eigen-y for this instead? sorting is expensive and eigen operations are vectorized. Finding the min/max cost and normalizing that should be easy in Eigen & there should be examples of that in the Optimizer when we normalize costs for scoring. Then you wouldn't need to manually normalize in the for loop.
| // Color scheme with smooth gradient: | ||
| // Green (0.0) -> Yellow-Green (0.25) -> Yellow (0.5) -> Orange (0.75) -> Red (1.0) | ||
| // Very high outlier costs (>95th percentile) will be clamped to red | ||
| blue_component = 0.0f; | ||
|
|
||
| if (normalized_cost < 0.5f) { | ||
| // Transition from Green to Yellow (0.0 - 0.5) | ||
| float t = normalized_cost * 2.0f; // Scale to [0, 1] | ||
| red_component = t; | ||
| green_component = 1.0f; | ||
| } else { | ||
| // Transition from Yellow to Red (0.5 - 1.0) | ||
| float t = (normalized_cost - 0.5f) * 2.0f; // Scale to [0, 1] | ||
| red_component = 1.0f; | ||
| green_component = 1.0f - t; |
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'm not really sensitive to the particular color policy, but I'd like this to be architecturally a lambda or method that is utils::createColor given the input of normalized_cost. That would move alot of this code out of this method and make it more streamline and clear where the color picking policy is like the other parts of this file.
| point.x = trajectories.x(i, j); | ||
| point.y = trajectories.y(i, j); | ||
| // Increment z by time_step_elevation_ for each time step | ||
| if (time_step_elevation_ > 0.0f) { |
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 replaced the color gradient indicative of time_steps to an elevation gradient (the higher the point, the bigger the timestep)
How much does this really help? I think this is pretty confusing as some may see this as the trajectory itself actually going into the air. Especially when doing first-time roobt setup where you have TF issues or you're doing SE2 navigation where the Z dimension is real, I think this can cause confusion.
Is this super important to include or just something you added as a 'nice to have'
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.
Is this super important to include or just something you added as a 'nice to have'
Not super important for me, I just didn't want to lose what we already have (the timestep gradient) and that was just one way to represent it. I'm fine with removing. btw default is no elevation
|
Thanks for the review, will polish it tomorrow |
|
I'll be on a plane to singapore, so it might be a minute before I can give it another looksee given ROSCon. |
Signed-off-by: Tony Najjar <[email protected]>



Basic Info
Description of contribution in a few bullet points
furthest_reached_path_pointto the Path critics (this revealed a bug which I will fix in another PR)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:
backport-*.