19 #include "nav2_mppi_controller/tools/trajectory_visualizer.hpp"
25 nav2::LifecycleNode::WeakPtr parent,
const std::string & name,
28 auto node = parent.lock();
29 logger_ = node->get_logger();
31 trajectories_publisher_ =
32 node->create_publisher<visualization_msgs::msg::MarkerArray>(
"~/candidate_trajectories");
33 optimal_path_pub_ = node->create_publisher<nav_msgs::msg::Path>(
"~/optimal_path");
34 parameters_handler_ = parameters_handler;
36 auto getParam = parameters_handler->
getParamGetter(name +
".TrajectoryVisualizer");
38 getParam(trajectory_step_,
"trajectory_step", 5);
39 getParam(time_step_,
"time_step", 3);
46 trajectories_publisher_.reset();
47 optimal_path_pub_.reset();
52 trajectories_publisher_->on_activate();
53 optimal_path_pub_->on_activate();
58 trajectories_publisher_->on_deactivate();
59 optimal_path_pub_->on_deactivate();
63 const Eigen::ArrayXXf & trajectory,
64 const std::string & marker_namespace,
65 const builtin_interfaces::msg::Time & cmd_stamp)
67 if (optimal_path_pub_->get_subscription_count() == 0 &&
68 trajectories_publisher_->get_subscription_count() == 0)
73 size_t size = trajectory.rows();
78 auto add_marker = [&](
auto i) {
79 float component =
static_cast<float>(i) /
static_cast<float>(size);
81 auto pose = utils::createPose(trajectory(i, 0), trajectory(i, 1), 0.06);
84 utils::createScale(0.03, 0.03, 0.07) :
85 utils::createScale(0.07, 0.07, 0.09);
86 auto color = utils::createColor(0, component, component, 1);
87 auto marker = utils::createMarker(
88 marker_id_++, pose, scale, color, frame_id_, marker_namespace);
89 points_->markers.push_back(marker);
92 geometry_msgs::msg::PoseStamped pose_stamped;
93 pose_stamped.header.frame_id = frame_id_;
94 pose_stamped.pose = pose;
96 tf2::Quaternion quaternion_tf2;
97 quaternion_tf2.setRPY(0., 0., trajectory(i, 2));
98 pose_stamped.pose.orientation = tf2::toMsg(quaternion_tf2);
100 optimal_path_->poses.push_back(pose_stamped);
103 optimal_path_->header.stamp = cmd_stamp;
104 optimal_path_->header.frame_id = frame_id_;
105 for (
size_t i = 0; i < size; i++) {
112 const Eigen::ArrayXf & costs,
113 const std::vector<bool> & collisions,
114 const builtin_interfaces::msg::Time & stamp)
116 if (trajectories_publisher_->get_subscription_count() == 0) {
120 const size_t n_rows = trajectories.x.rows();
121 if (n_rows == 0 || costs.size() == 0 ||
122 static_cast<size_t>(costs.size()) < n_rows)
128 float min_val = std::numeric_limits<float>::max();
129 float max_val = std::numeric_limits<float>::lowest();
130 for (Eigen::Index k = 0; k < costs.size(); ++k) {
131 if (!collisions.empty() &&
static_cast<size_t>(k) < collisions.size() && collisions[k]) {
134 auto curr_cost = costs(k);
135 if (curr_cost < min_val) {min_val = curr_cost;}
136 if (curr_cost > max_val) {max_val = curr_cost;}
138 if (max_val < min_val) {
139 min_val = costs.minCoeff();
140 max_val = costs.maxCoeff();
142 float range = max_val - min_val;
144 for (
size_t i = 0; i < n_rows; i += trajectory_step_) {
145 float norm = (range > 0.0f) ?
146 (costs(i) - min_val) / range : 0.0f;
148 !collisions.empty() && i < collisions.size() && collisions[i];
154 size_t trajectory_idx,
156 float normalized_cost,
158 const builtin_interfaces::msg::Time & stamp)
160 using visualization_msgs::msg::Marker;
161 const size_t n_cols = trajectories.x.cols();
164 marker.header.frame_id = frame_id_;
165 marker.header.stamp = stamp;
166 marker.ns =
"Candidate Trajectories";
167 marker.id = marker_id_++;
168 marker.type = Marker::LINE_STRIP;
169 marker.action = Marker::ADD;
170 marker.pose.orientation.w = 1.0;
171 marker.scale.x = 0.01;
172 marker.color = in_collision ?
173 utils::createColor(1.0f, 0.0f, 1.0f, 0.6f) :
176 marker.points.reserve(n_cols / time_step_ + 1);
177 for (
size_t j = 0; j < n_cols; j += time_step_) {
178 geometry_msgs::msg::Point pt;
179 pt.x = trajectories.x(trajectory_idx, j);
180 pt.y = trajectories.y(trajectory_idx, j);
182 marker.points.push_back(pt);
185 points_->markers.push_back(std::move(marker));
191 normalized = std::clamp(normalized, 0.0f, 1.0f);
193 if (normalized < 0.5f) {
194 r = 2.0f * normalized;
198 g = 2.0f * (1.0f - normalized);
200 return utils::createColor(r, g, 0.0f, 0.8f);
206 points_ = std::make_unique<visualization_msgs::msg::MarkerArray>();
207 optimal_path_ = std::make_unique<nav_msgs::msg::Path>();
212 if (trajectories_publisher_->get_subscription_count() > 0) {
213 trajectories_publisher_->publish(std::move(points_));
216 if (optimal_path_pub_->get_subscription_count() > 0) {
217 optimal_path_pub_->publish(std::move(optimal_path_));
Handles getting parameters and dynamic parameter changes.
auto getParamGetter(const std::string &ns)
Get an object to retrieve parameters.
void add(const Eigen::ArrayXXf &trajectory, const std::string &marker_namespace, const builtin_interfaces::msg::Time &cmd_stamp)
Add an optimal trajectory to visualize.
void on_deactivate()
Deactivate object.
void reset()
Reset object.
void on_configure(nav2::LifecycleNode::WeakPtr parent, const std::string &name, const std::string &frame_id, ParametersHandler *parameters_handler)
Configure trajectory visualizer.
void addCostColoredTrajectory(size_t trajectory_idx, const models::Trajectories &trajectories, float normalized_cost, bool in_collision, const builtin_interfaces::msg::Time &stamp)
Create a LINE_STRIP marker for a single trajectory colored by normalized cost.
void visualize()
Visualize the plan.
static std_msgs::msg::ColorRGBA costToColor(float normalized)
Convert a normalized cost [0,1] to a green->yellow->red color.
void on_activate()
Activate object.
void on_cleanup()
Cleanup object on shutdown.