41 #include "dwb_core/dwb_local_planner.hpp"
42 #include "dwb_core/exceptions.hpp"
43 #include "dwb_core/illegal_trajectory_tracker.hpp"
44 #include "dwb_msgs/msg/critic_score.hpp"
45 #include "nav_2d_msgs/msg/twist2_d.hpp"
46 #include "nav_2d_utils/conversions.hpp"
47 #include "nav2_util/geometry_utils.hpp"
48 #include "nav2_ros_common/lifecycle_node.hpp"
49 #include "nav2_core/controller_exceptions.hpp"
50 #include "pluginlib/class_list_macros.hpp"
51 #include "nav_msgs/msg/path.hpp"
52 #include "geometry_msgs/msg/twist_stamped.hpp"
53 #include "nav2_ros_common/tf2_factories.hpp"
55 using nav2_util::geometry_utils::euclidean_distance;
61 : traj_gen_loader_(
"dwb_core",
"dwb_core::TrajectoryGenerator"),
62 critic_loader_(
"dwb_core",
"dwb_core::TrajectoryCritic")
67 const nav2::LifecycleNode::WeakPtr & parent,
68 std::string name, nav2::TransformBuffer::SharedPtr tf,
69 std::shared_ptr<nav2_costmap_2d::Costmap2DROS> costmap_ros)
72 auto node = node_.lock();
74 logger_ = node->get_logger();
75 clock_ = node->get_clock();
76 costmap_ros_ = costmap_ros;
78 dwb_plugin_name_ = name;
80 debug_trajectory_details_ = node->declare_or_get_parameter(
81 dwb_plugin_name_ +
".debug_trajectory_details",
false);
82 std::string traj_generator_name = node->declare_or_get_parameter(
83 dwb_plugin_name_ +
".trajectory_generator_name",
84 std::string(
"dwb_plugins::StandardTrajectoryGenerator"));
85 short_circuit_trajectory_evaluation_ = node->declare_or_get_parameter(
86 dwb_plugin_name_ +
".short_circuit_trajectory_evaluation",
true);
88 pub_ = std::make_unique<DWBPublisher>(node, dwb_plugin_name_);
91 traj_generator_ = traj_gen_loader_.createUniqueInstance(traj_generator_name);
93 traj_generator_->initialize(node, dwb_plugin_name_);
97 }
catch (
const std::exception & e) {
98 RCLCPP_ERROR(logger_,
"Couldn't load critics! Caught exception: %s", e.what());
100 "Couldn't load critics! Caught exception: " +
101 std::string(e.what()));
109 traj_generator_->activate();
115 pub_->on_deactivate();
116 traj_generator_->deactivate();
124 traj_generator_.reset();
130 if (base_name.find(
"Critic") == std::string::npos) {
131 base_name = base_name +
"Critic";
134 if (base_name.find(
"::") == std::string::npos) {
135 for (
unsigned int j = 0; j < default_critic_namespaces_.size(); j++) {
136 std::string full_name = default_critic_namespaces_[j] +
"::" + base_name;
137 if (critic_loader_.isClassAvailable(full_name)) {
148 auto node = node_.lock();
150 throw std::runtime_error{
"Failed to lock node"};
153 default_critic_namespaces_ = node->declare_or_get_parameter(
154 dwb_plugin_name_ +
".default_critic_namespaces",
155 std::vector<std::string>());
156 if (default_critic_namespaces_.empty()) {
157 default_critic_namespaces_.emplace_back(
"dwb_critics");
160 std::vector<std::string> critic_names =
161 node->declare_or_get_parameter<std::vector<std::string>>(
162 dwb_plugin_name_ +
".critics");
163 if (critic_names.empty()) {
164 throw std::runtime_error(
"No critics defined for " + dwb_plugin_name_);
167 for (
unsigned int i = 0; i < critic_names.size(); i++) {
168 std::string critic_plugin_name = critic_names[i];
170 std::string plugin_class = node->declare_or_get_parameter(
171 dwb_plugin_name_ +
"." + critic_plugin_name +
".class",
176 TrajectoryCritic::Ptr plugin = critic_loader_.createUniqueInstance(plugin_class);
179 "Using critic \"%s\" (%s)", critic_plugin_name.c_str(), plugin_class.c_str());
180 critics_.push_back(plugin);
182 plugin->initialize(node, critic_plugin_name, dwb_plugin_name_, costmap_ros_);
183 }
catch (
const std::exception & e) {
184 RCLCPP_ERROR(logger_,
"Couldn't initialize critic plugin!");
186 "Couldn't initialize critic plugin: " +
187 std::string(e.what()));
189 RCLCPP_INFO(logger_,
"Critic plugin initialized");
196 for (TrajectoryCritic::Ptr & critic : critics_) {
199 traj_generator_->reset();
202 geometry_msgs::msg::TwistStamped
204 const geometry_msgs::msg::PoseStamped & pose,
205 const geometry_msgs::msg::Twist & velocity,
207 const nav_msgs::msg::Path & transformed_global_plan,
208 const geometry_msgs::msg::PoseStamped & global_goal)
210 std::shared_ptr<dwb_msgs::msg::LocalPlanEvaluation> results =
nullptr;
211 if (pub_->shouldRecordEvaluation()) {
212 results = std::make_shared<dwb_msgs::msg::LocalPlanEvaluation>();
218 nav_2d_utils::twist3Dto2D(velocity), results, transformed_global_plan, global_goal);
219 pub_->publishEvaluation(results);
220 geometry_msgs::msg::TwistStamped cmd_vel;
221 cmd_vel.twist = nav_2d_utils::twist2Dto3D(cmd_vel2d.velocity);
224 pub_->publishEvaluation(results);
227 pub_->publishEvaluation(results);
230 pub_->publishEvaluation(results);
233 pub_->publishEvaluation(results);
238 nav_2d_msgs::msg::Twist2DStamped
240 const geometry_msgs::msg::PoseStamped & pose,
241 const nav_2d_msgs::msg::Twist2D & velocity,
242 std::shared_ptr<dwb_msgs::msg::LocalPlanEvaluation> & results,
243 const nav_msgs::msg::Path & transformed_global_plan,
244 const geometry_msgs::msg::PoseStamped & global_goal)
247 results->header.frame_id = pose.header.frame_id;
248 results->header.stamp = clock_->now();
252 std::unique_lock<nav2_costmap_2d::Costmap2D::mutex_t> lock(*(costmap->getMutex()));
254 for (TrajectoryCritic::Ptr & critic : critics_) {
255 if (!critic->prepare(pose.pose, velocity, global_goal.pose, transformed_global_plan)) {
256 RCLCPP_WARN(rclcpp::get_logger(
"DWBLocalPlanner"),
"A scoring function failed to prepare");
264 nav_2d_msgs::msg::Twist2DStamped cmd_vel;
265 cmd_vel.header.stamp = clock_->now();
266 cmd_vel.velocity = best.traj.velocity;
269 for (TrajectoryCritic::Ptr & critic : critics_) {
270 critic->debrief(cmd_vel.velocity);
275 pub_->publishLocalPlan(pose.header, best.traj);
276 pub_->publishCostGrid(costmap_ros_, critics_);
280 nav_2d_msgs::msg::Twist2D empty_cmd;
281 dwb_msgs::msg::Trajectory2D empty_traj;
283 for (TrajectoryCritic::Ptr & critic : critics_) {
284 critic->debrief(empty_cmd);
289 pub_->publishLocalPlan(pose.header, empty_traj);
290 pub_->publishCostGrid(costmap_ros_, critics_);
293 "Could not find a legal trajectory: " +
294 std::string(e.what()));
298 dwb_msgs::msg::TrajectoryScore
300 const geometry_msgs::msg::Pose & pose,
301 const nav_2d_msgs::msg::Twist2D velocity,
302 std::shared_ptr<dwb_msgs::msg::LocalPlanEvaluation> & results)
304 nav_2d_msgs::msg::Twist2D twist;
305 dwb_msgs::msg::Trajectory2D traj;
306 dwb_msgs::msg::TrajectoryScore best, worst;
311 traj_generator_->startNewIteration(velocity);
312 while (traj_generator_->hasMoreTwists()) {
313 twist = traj_generator_->nextTwist();
314 traj = traj_generator_->generateTrajectory(pose, velocity, twist);
317 dwb_msgs::msg::TrajectoryScore score =
scoreTrajectory(traj, best.total);
318 tracker.addLegalTrajectory();
320 results->twists.push_back(score);
322 if (best.total < 0 || score.total < best.total) {
325 results->best_index = results->twists.size() - 1;
328 if (worst.total < 0 || score.total > worst.total) {
331 results->worst_index = results->twists.size() - 1;
336 dwb_msgs::msg::TrajectoryScore failed_score;
337 failed_score.traj = traj;
339 dwb_msgs::msg::CriticScore cs;
340 cs.name = e.getCriticName();
342 failed_score.scores.push_back(cs);
343 failed_score.total = -1.0;
344 results->twists.push_back(failed_score);
346 tracker.addIllegalTrajectory(e);
350 if (best.total < 0) {
351 if (debug_trajectory_details_) {
352 RCLCPP_ERROR(rclcpp::get_logger(
"DWBLocalPlanner"),
"%s", tracker.getMessage().c_str());
353 for (
auto const & x : tracker.getPercentages()) {
356 "DWBLocalPlanner"),
"%.2f: %10s/%s", x.second,
357 x.first.first.c_str(), x.first.second.c_str());
366 dwb_msgs::msg::TrajectoryScore
368 const dwb_msgs::msg::Trajectory2D & traj,
371 dwb_msgs::msg::TrajectoryScore score;
374 for (TrajectoryCritic::Ptr & critic : critics_) {
375 dwb_msgs::msg::CriticScore cs;
376 cs.name = critic->getName();
377 cs.scale = critic->getScale();
379 if (cs.scale == 0.0) {
380 score.scores.push_back(cs);
384 double critic_score = critic->scoreTrajectory(traj);
385 cs.raw_score = critic_score;
386 score.scores.push_back(cs);
387 score.total += critic_score * cs.scale;
388 if (short_circuit_trajectory_evaluation_ && best_score > 0 && score.total > best_score) {
400 PLUGINLIB_EXPORT_CLASS(
Plugin-based flexible controller.
void newPathReceived(const nav_msgs::msg::Path &raw_global_path) override
nav2_core newPathReceived - Receives a new plan from the Planner Server
geometry_msgs::msg::TwistStamped computeVelocityCommands(const geometry_msgs::msg::PoseStamped &pose, const geometry_msgs::msg::Twist &velocity, nav2_core::GoalChecker *, const nav_msgs::msg::Path &transformed_global_plan, const geometry_msgs::msg::PoseStamped &global_goal) override
nav2_core computeVelocityCommands - calculates the best command given the current pose and velocity
virtual dwb_msgs::msg::TrajectoryScore coreScoringAlgorithm(const geometry_msgs::msg::Pose &pose, const nav_2d_msgs::msg::Twist2D velocity, std::shared_ptr< dwb_msgs::msg::LocalPlanEvaluation > &results)
Iterate through all the twists and find the best one.
void cleanup() override
Cleanup lifecycle node.
std::string resolveCriticClassName(std::string base_name)
try to resolve a possibly shortened critic name with the default namespaces and the suffix "Critic"
void deactivate() override
Deactivate lifecycle node.
void configure(const nav2::LifecycleNode::WeakPtr &parent, std::string name, nav2::TransformBuffer::SharedPtr tf, std::shared_ptr< nav2_costmap_2d::Costmap2DROS > costmap_ros) override
DWBLocalPlanner()
Constructor that brings up pluginlib loaders.
virtual dwb_msgs::msg::TrajectoryScore scoreTrajectory(const dwb_msgs::msg::Trajectory2D &traj, double best_score=-1)
Score a given command. Can be used for testing.
virtual void loadCritics()
Load the critic parameters from the namespace.
void activate() override
Activate lifecycle node.
Thrown when one of the critics encountered a fatal error.
Thrown when all the trajectories explored are illegal.
controller interface that acts as a virtual base class for all controller plugins
Function-object for checking whether a goal has been reached.
A 2D costmap provides a mapping between points in the world and their associated "costs".