-
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?
Changes from 4 commits
2d429c6
f0f3333
cecc6ea
5202339
88a4adc
8ab4228
d1092e7
081e54d
b9f522e
9c23e57
1890dd9
b400b90
a3611d4
41b4c35
0f57a9c
70e7162
a88f5dc
badadf1
303e0cb
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -30,6 +30,16 @@ void PathAlignCritic::initialize() | |||
| threshold_to_consider_, | ||||
| "threshold_to_consider", 0.5f); | ||||
| getParam(use_path_orientations_, "use_path_orientations", false); | ||||
| getParam(visualize_, "visualize", false); | ||||
|
|
||||
| if (visualize_) { | ||||
| auto node = parent_.lock(); | ||||
| if (node) { | ||||
| target_pose_pub_ = node->create_publisher<geometry_msgs::msg::PoseStamped>( | ||||
| "/PathAlignCritic/furthest_reached_path_point", 1); | ||||
|
||||
| target_pose_pub_->on_activate(); | ||||
| } | ||||
| } | ||||
|
|
||||
| RCLCPP_INFO( | ||||
| logger_, | ||||
|
|
@@ -48,6 +58,20 @@ void PathAlignCritic::score(CriticData & data) | |||
| // Up to furthest only, closest path point is always 0 from path handler | ||||
| const size_t path_segments_count = *data.furthest_reached_path_point; | ||||
| float path_segments_flt = static_cast<float>(path_segments_count); | ||||
|
|
||||
| // Visualize target pose if enabled | ||||
| if (visualize_ && path_segments_count > 0) { | ||||
|
||||
| auto node = parent_.lock(); | ||||
|
||||
| logger_ = parent_.lock()->get_logger(); |
Outdated
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?
Outdated
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,6 +13,8 @@ | |
| // limitations under the License. | ||
|
|
||
| #include <memory> | ||
| #include <vector> | ||
| #include <algorithm> | ||
| #include "nav2_mppi_controller/tools/trajectory_visualizer.hpp" | ||
|
|
||
| namespace mppi | ||
|
|
@@ -36,6 +38,7 @@ void TrajectoryVisualizer::on_configure( | |
|
|
||
| getParam(trajectory_step_, "trajectory_step", 5); | ||
| getParam(time_step_, "time_step", 3); | ||
| getParam(time_step_elevation_, "time_step_elevation", 0.0f); | ||
|
|
||
| reset(); | ||
| } | ||
|
|
@@ -104,27 +107,95 @@ void TrajectoryVisualizer::add( | |
| } | ||
|
|
||
| void TrajectoryVisualizer::add( | ||
| const models::Trajectories & trajectories, const std::string & marker_namespace) | ||
| const models::Trajectories & trajectories, const Eigen::ArrayXf & costs, | ||
| const std::string & marker_namespace, | ||
| const builtin_interfaces::msg::Time & cmd_stamp) | ||
| { | ||
| size_t n_rows = trajectories.x.rows(); | ||
| size_t n_cols = trajectories.x.cols(); | ||
| const float shape_1 = static_cast<float>(n_cols); | ||
| points_->markers.reserve(floor(n_rows / trajectory_step_) * floor(n_cols * time_step_)); | ||
| points_->markers.reserve(n_rows / trajectory_step_); | ||
|
|
||
| for (size_t i = 0; i < n_rows; i += trajectory_step_) { | ||
| for (size_t j = 0; j < n_cols; j += time_step_) { | ||
| 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 | ||
|
||
| // Sort costs to find percentiles | ||
| std::vector<float> sorted_costs(costs.data(), costs.data() + costs.size()); | ||
| std::sort(sorted_costs.begin(), sorted_costs.end()); | ||
|
|
||
| auto pose = utils::createPose(trajectories.x(i, j), trajectories.y(i, j), 0.03); | ||
| auto scale = utils::createScale(0.03, 0.03, 0.03); | ||
| 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 | ||
|
||
| 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); | ||
|
||
|
|
||
| points_->markers.push_back(marker); | ||
| float min_cost = sorted_costs[idx_10th]; | ||
| float max_cost = sorted_costs[idx_90th]; | ||
| float cost_range = max_cost - min_cost; | ||
|
|
||
| // Avoid division by zero | ||
| if (cost_range < 1e-6f) { | ||
| cost_range = 1.0f; | ||
| } | ||
|
|
||
| for (size_t i = 0; i < n_rows; i += trajectory_step_) { | ||
| float red_component, green_component, blue_component; | ||
|
|
||
| // Normalize cost using percentile-based range, clamping outliers | ||
| float normalized_cost = (costs(i) - min_cost) / cost_range; | ||
|
|
||
| // Clamp to [0, 1] range (handles outliers beyond percentiles) | ||
| normalized_cost = std::max(0.0f, std::min(1.0f, normalized_cost)); | ||
|
|
||
| // Apply power function for better visual distribution | ||
| normalized_cost = std::pow(normalized_cost, 0.5f); | ||
|
|
||
| // 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; | ||
|
||
| } | ||
|
|
||
| // Create line strip marker for this trajectory | ||
| visualization_msgs::msg::Marker marker; | ||
| marker.header.frame_id = frame_id_; | ||
| marker.header.stamp = cmd_stamp; | ||
| marker.ns = marker_namespace; | ||
| marker.id = marker_id_++; | ||
| marker.type = visualization_msgs::msg::Marker::LINE_STRIP; | ||
| marker.action = visualization_msgs::msg::Marker::ADD; | ||
| marker.pose.orientation.w = 1.0; | ||
|
|
||
| // Set line width | ||
| marker.scale.x = 0.01; // Line width | ||
|
|
||
| // Set color for entire trajectory | ||
| marker.color.r = red_component; | ||
| marker.color.g = green_component; | ||
| marker.color.b = blue_component; | ||
| marker.color.a = 0.8f; // Slightly transparent | ||
|
|
||
| // Add all points in this trajectory to the line strip | ||
| for (size_t j = 0; j < n_cols; j += time_step_) { | ||
| geometry_msgs::msg::Point point; | ||
| 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) { | ||
|
||
| point.z = static_cast<float>(j) * time_step_elevation_; | ||
| } else { | ||
| point.z = 0.0f; | ||
| } | ||
| marker.points.push_back(point); | ||
| } | ||
|
|
||
| points_->markers.push_back(marker); | ||
| } | ||
| } | ||
|
|
||
|
|
||
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.
Maybe this is better as a Marker sphere.
Currently:
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