15 #include "nav2_rviz_plugins/nav2_panel.hpp"
17 #include <QtConcurrent/QtConcurrent>
18 #include <QVBoxLayout>
19 #include <QHBoxLayout>
30 #include "nav2_rviz_plugins/goal_common.hpp"
31 #include "nav2_rviz_plugins/utils.hpp"
32 #include "rviz_common/display_context.hpp"
33 #include "rviz_common/load_resource.hpp"
34 #include "ament_index_cpp/get_package_share_directory.hpp"
35 #include "yaml-cpp/yaml.h"
36 #include "geometry_msgs/msg/pose2_d.hpp"
38 using namespace std::chrono_literals;
40 namespace nav2_rviz_plugins
42 using nav2_util::geometry_utils::orientationAroundZAxis;
45 GoalPoseUpdater GoalUpdater;
47 Nav2Panel::Nav2Panel(QWidget * parent)
53 start_reset_button_ =
new QPushButton;
54 pause_resume_button_ =
new QPushButton;
55 navigation_mode_button_ =
new QPushButton;
56 save_waypoints_button_ =
new QPushButton;
57 load_waypoints_button_ =
new QPushButton;
58 pause_waypoint_button_ =
new QPushButton;
59 navigation_status_indicator_ =
new QLabel;
60 localization_status_indicator_ =
new QLabel;
61 navigation_goal_status_indicator_ =
new QLabel;
62 navigation_feedback_indicator_ =
new QLabel;
63 waypoint_status_indicator_ =
new QLabel;
64 number_of_loops_ =
new QLabel;
65 nr_of_loops_ =
new QLineEdit;
66 store_initial_pose_checkbox_ =
new QCheckBox(
"Store initial_pose");
70 const char * startup_msg =
"Configure and activate all nav2 lifecycle nodes";
71 const char * shutdown_msg =
"Deactivate and cleanup all nav2 lifecycle nodes";
72 const char * cancel_msg =
"Cancel navigation";
73 const char * pause_msg =
"Deactivate all nav2 lifecycle nodes";
74 const char * resume_msg =
"Activate all nav2 lifecycle nodes";
75 const char * single_goal_msg =
"Change to waypoint / nav through poses style navigation";
76 const char * waypoint_goal_msg =
"Start following waypoints";
77 const char * nft_goal_msg =
"Start navigating through poses";
78 const char * cancel_waypoint_msg =
"Cancel waypoint / viapoint accumulation mode";
80 const QString navigation_active(
"<table><tr><td width=150><b>Navigation:</b></td>"
81 "<td><font color=green>active</color></td></tr></table>");
82 const QString navigation_inactive(
"<table><tr><td width=150><b>Navigation:</b></td>"
83 "<td>inactive</td></tr></table>");
84 const QString navigation_unknown(
"<table><tr><td width=150><b>Navigation:</b></td>"
85 "<td>unknown</td></tr></table>");
86 const QString localization_active(
"<table><tr><td width=150><b>Localization:</b></td>"
87 "<td><font color=green>active</color></td></tr></table>");
88 const QString localization_inactive(
"<table><tr><td width=150><b>Localization:</b></td>"
89 "<td>inactive</td></tr></table>");
90 const QString localization_unknown(
"<table><tr><td width=150><b>Localization:</b></td>"
91 "<td>unknown</td></tr></table>");
93 navigation_status_indicator_->setText(navigation_unknown);
94 localization_status_indicator_->setText(localization_unknown);
95 navigation_goal_status_indicator_->setText(nav2_rviz_plugins::getGoalStatusLabel());
96 number_of_loops_->setText(
"Num of loops");
97 navigation_feedback_indicator_->setText(getNavThroughPosesFeedbackLabel());
98 navigation_status_indicator_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
99 localization_status_indicator_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
100 navigation_goal_status_indicator_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
101 navigation_feedback_indicator_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
102 waypoint_status_indicator_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
104 pre_initial_ =
new QState();
105 pre_initial_->setObjectName(
"pre_initial");
106 pre_initial_->assignProperty(start_reset_button_,
"text",
"Startup");
107 pre_initial_->assignProperty(start_reset_button_,
"enabled",
false);
109 pre_initial_->assignProperty(pause_resume_button_,
"text",
"Pause");
110 pre_initial_->assignProperty(pause_resume_button_,
"enabled",
false);
112 pre_initial_->assignProperty(save_waypoints_button_,
"text",
"Save WPs");
113 pre_initial_->assignProperty(save_waypoints_button_,
"enabled",
false);
115 pre_initial_->assignProperty(load_waypoints_button_,
"text",
"Load WPs");
116 pre_initial_->assignProperty(load_waypoints_button_,
"enabled",
false);
118 pre_initial_->assignProperty(pause_waypoint_button_,
"text",
"Pause WP");
119 pre_initial_->assignProperty(pause_waypoint_button_,
"enabled",
false);
121 pre_initial_->assignProperty(nr_of_loops_,
"text",
"0");
122 pre_initial_->assignProperty(nr_of_loops_,
"enabled",
false);
124 pre_initial_->assignProperty(store_initial_pose_checkbox_,
"enabled",
false);
126 pre_initial_->assignProperty(
127 navigation_mode_button_,
"text",
128 "Waypoint / Nav Through Poses Mode");
129 pre_initial_->assignProperty(navigation_mode_button_,
"enabled",
false);
131 initial_ =
new QState();
132 initial_->setObjectName(
"initial");
133 initial_->assignProperty(start_reset_button_,
"text",
"Startup");
134 initial_->assignProperty(start_reset_button_,
"toolTip", startup_msg);
135 initial_->assignProperty(start_reset_button_,
"enabled",
true);
137 initial_->assignProperty(pause_resume_button_,
"text",
"Pause");
138 initial_->assignProperty(pause_resume_button_,
"enabled",
false);
140 initial_->assignProperty(navigation_mode_button_,
"text",
"Waypoint / Nav Through Poses Mode");
141 initial_->assignProperty(navigation_mode_button_,
"enabled",
false);
143 initial_->assignProperty(save_waypoints_button_,
"text",
"Save WPs");
144 initial_->assignProperty(save_waypoints_button_,
"enabled",
false);
146 initial_->assignProperty(load_waypoints_button_,
"text",
"Load WPs");
147 initial_->assignProperty(load_waypoints_button_,
"enabled",
false);
149 initial_->assignProperty(pause_waypoint_button_,
"text",
"Pause WP");
150 initial_->assignProperty(pause_waypoint_button_,
"enabled",
false);
152 initial_->assignProperty(nr_of_loops_,
"text",
"0");
153 initial_->assignProperty(nr_of_loops_,
"enabled",
false);
155 initial_->assignProperty(store_initial_pose_checkbox_,
"enabled",
false);
158 idle_ =
new QState();
159 idle_->setObjectName(
"idle");
160 idle_->assignProperty(start_reset_button_,
"text",
"Reset");
161 idle_->assignProperty(start_reset_button_,
"toolTip", shutdown_msg);
162 idle_->assignProperty(start_reset_button_,
"enabled",
true);
164 idle_->assignProperty(pause_resume_button_,
"text",
"Pause");
165 idle_->assignProperty(pause_resume_button_,
"enabled",
true);
166 idle_->assignProperty(pause_resume_button_,
"toolTip", pause_msg);
168 idle_->assignProperty(navigation_mode_button_,
"text",
"Waypoint / Nav Through Poses Mode");
169 idle_->assignProperty(navigation_mode_button_,
"enabled",
true);
170 idle_->assignProperty(navigation_mode_button_,
"toolTip", single_goal_msg);
172 idle_->assignProperty(save_waypoints_button_,
"text",
"Save WPs");
173 idle_->assignProperty(save_waypoints_button_,
"enabled",
false);
175 idle_->assignProperty(load_waypoints_button_,
"text",
"Load WPs");
176 idle_->assignProperty(load_waypoints_button_,
"enabled",
false);
178 idle_->assignProperty(pause_waypoint_button_,
"text",
"Pause WP");
179 idle_->assignProperty(pause_waypoint_button_,
"enabled",
false);
181 idle_->assignProperty(nr_of_loops_,
"text",
"0");
182 idle_->assignProperty(nr_of_loops_,
"enabled",
false);
184 idle_->assignProperty(store_initial_pose_checkbox_,
"enabled",
false);
187 accumulating_ =
new QState();
188 accumulating_->setObjectName(
"accumulating");
189 accumulating_->assignProperty(start_reset_button_,
"text",
"Cancel Accumulation");
190 accumulating_->assignProperty(start_reset_button_,
"toolTip", cancel_waypoint_msg);
191 accumulating_->assignProperty(start_reset_button_,
"enabled",
true);
193 accumulating_->assignProperty(pause_resume_button_,
"text",
"Start Nav Through Poses");
194 accumulating_->assignProperty(pause_resume_button_,
"enabled",
true);
195 accumulating_->assignProperty(pause_resume_button_,
"toolTip", nft_goal_msg);
197 accumulating_->assignProperty(navigation_mode_button_,
"text",
"Start Waypoint Following");
198 accumulating_->assignProperty(navigation_mode_button_,
"enabled",
true);
199 accumulating_->assignProperty(navigation_mode_button_,
"toolTip", waypoint_goal_msg);
201 accumulating_->assignProperty(save_waypoints_button_,
"text",
"Save WPs");
202 accumulating_->assignProperty(save_waypoints_button_,
"enabled",
true);
204 accumulating_->assignProperty(load_waypoints_button_,
"text",
"Load WPs");
205 accumulating_->assignProperty(load_waypoints_button_,
"enabled",
true);
207 accumulating_->assignProperty(pause_waypoint_button_,
"text",
"Pause WP");
208 accumulating_->assignProperty(pause_waypoint_button_,
"enabled",
false);
210 accumulating_->assignProperty(nr_of_loops_,
"text", QString::fromStdString(loop_no_));
211 accumulating_->assignProperty(nr_of_loops_,
"enabled",
true);
212 accumulating_->assignProperty(store_initial_pose_checkbox_,
"enabled",
true);
214 accumulated_wp_ =
new QState();
215 accumulated_wp_->setObjectName(
"accumulated_wp");
216 accumulated_wp_->assignProperty(start_reset_button_,
"text",
"Cancel");
217 accumulated_wp_->assignProperty(start_reset_button_,
"toolTip", cancel_msg);
218 accumulated_wp_->assignProperty(start_reset_button_,
"enabled",
true);
220 accumulated_wp_->assignProperty(pause_resume_button_,
"text",
"Start Nav Through Poses");
221 accumulated_wp_->assignProperty(pause_resume_button_,
"enabled",
false);
222 accumulated_wp_->assignProperty(pause_resume_button_,
"toolTip", nft_goal_msg);
224 accumulated_wp_->assignProperty(navigation_mode_button_,
"text",
"Start Waypoint Following");
225 accumulated_wp_->assignProperty(navigation_mode_button_,
"enabled",
false);
226 accumulated_wp_->assignProperty(navigation_mode_button_,
"toolTip", waypoint_goal_msg);
228 accumulated_wp_->assignProperty(save_waypoints_button_,
"text",
"Save WPs");
229 accumulated_wp_->assignProperty(save_waypoints_button_,
"enabled",
false);
231 accumulated_wp_->assignProperty(load_waypoints_button_,
"text",
"Load WPs");
232 accumulated_wp_->assignProperty(load_waypoints_button_,
"enabled",
false);
234 accumulated_wp_->assignProperty(pause_waypoint_button_,
"text",
"Pause WP");
235 accumulated_wp_->assignProperty(pause_waypoint_button_,
"enabled",
true);
237 accumulated_wp_->assignProperty(nr_of_loops_,
"enabled",
false);
238 accumulated_wp_->assignProperty(store_initial_pose_checkbox_,
"enabled",
false);
240 accumulated_nav_through_poses_ =
new QState();
241 accumulated_nav_through_poses_->setObjectName(
"accumulated_nav_through_poses");
242 accumulated_nav_through_poses_->assignProperty(start_reset_button_,
"text",
"Cancel");
243 accumulated_nav_through_poses_->assignProperty(start_reset_button_,
"toolTip", cancel_msg);
245 accumulated_nav_through_poses_->assignProperty(save_waypoints_button_,
"text",
"Save WPs");
246 accumulated_nav_through_poses_->assignProperty(save_waypoints_button_,
"enabled",
false);
248 accumulated_nav_through_poses_->assignProperty(load_waypoints_button_,
"text",
"Load WPs");
249 accumulated_nav_through_poses_->assignProperty(load_waypoints_button_,
"enabled",
false);
251 accumulated_nav_through_poses_->assignProperty(pause_waypoint_button_,
"text",
"Pause WP");
252 accumulated_nav_through_poses_->assignProperty(pause_waypoint_button_,
"enabled",
false);
254 accumulated_nav_through_poses_->assignProperty(nr_of_loops_,
"enabled",
false);
256 accumulated_nav_through_poses_->assignProperty(start_reset_button_,
"enabled",
true);
257 accumulated_nav_through_poses_->assignProperty(store_initial_pose_checkbox_,
"enabled",
false);
259 accumulated_nav_through_poses_->assignProperty(
260 pause_resume_button_,
"text",
261 "Start Nav Through Poses");
262 accumulated_nav_through_poses_->assignProperty(pause_resume_button_,
"enabled",
false);
263 accumulated_nav_through_poses_->assignProperty(pause_resume_button_,
"toolTip", nft_goal_msg);
265 accumulated_nav_through_poses_->assignProperty(
266 navigation_mode_button_,
"text",
267 "Start Waypoint Following");
268 accumulated_nav_through_poses_->assignProperty(navigation_mode_button_,
"enabled",
false);
269 accumulated_nav_through_poses_->assignProperty(
270 navigation_mode_button_,
"toolTip",
273 accumulated_nav_through_poses_->assignProperty(
274 nr_of_loops_,
"text",
275 QString::fromStdString(loop_no_));
276 accumulated_nav_through_poses_->assignProperty(nr_of_loops_,
"enabled",
false);
277 accumulated_nav_through_poses_->assignProperty(store_initial_pose_checkbox_,
"enabled",
false);
280 canceled_ =
new QState();
281 canceled_->setObjectName(
"canceled");
284 reset_ =
new QState();
285 reset_->setObjectName(
"reset");
287 running_ =
new QState();
288 running_->setObjectName(
"running");
289 running_->assignProperty(start_reset_button_,
"text",
"Cancel");
290 running_->assignProperty(start_reset_button_,
"toolTip", cancel_msg);
292 running_->assignProperty(pause_resume_button_,
"text",
"Pause");
293 running_->assignProperty(pause_resume_button_,
"enabled",
false);
295 running_->assignProperty(navigation_mode_button_,
"text",
"Waypoint mode");
296 running_->assignProperty(navigation_mode_button_,
"enabled",
false);
298 running_->assignProperty(save_waypoints_button_,
"text",
"Save WPs");
299 running_->assignProperty(save_waypoints_button_,
"enabled",
false);
301 running_->assignProperty(load_waypoints_button_,
"text",
"Load WPs");
302 running_->assignProperty(load_waypoints_button_,
"enabled",
false);
304 running_->assignProperty(pause_waypoint_button_,
"text",
"Pause WP");
305 running_->assignProperty(pause_waypoint_button_,
"enabled",
false);
307 running_->assignProperty(nr_of_loops_,
"text",
"0");
308 running_->assignProperty(nr_of_loops_,
"enabled",
false);
310 running_->assignProperty(store_initial_pose_checkbox_,
"enabled",
false);
313 paused_ =
new QState();
314 paused_->setObjectName(
"pausing");
315 paused_->assignProperty(start_reset_button_,
"text",
"Reset");
316 paused_->assignProperty(start_reset_button_,
"toolTip", shutdown_msg);
318 paused_->assignProperty(pause_resume_button_,
"text",
"Resume");
319 paused_->assignProperty(pause_resume_button_,
"toolTip", resume_msg);
320 paused_->assignProperty(pause_resume_button_,
"enabled",
true);
322 paused_->assignProperty(navigation_mode_button_,
"text",
"");
323 paused_->assignProperty(navigation_mode_button_,
"enabled",
false);
325 paused_->assignProperty(save_waypoints_button_,
"text",
"Save WPs");
326 paused_->assignProperty(save_waypoints_button_,
"enabled",
false);
328 paused_->assignProperty(load_waypoints_button_,
"text",
"Load WPs");
329 paused_->assignProperty(load_waypoints_button_,
"enabled",
false);
331 paused_->assignProperty(pause_waypoint_button_,
"text",
"Pause WP");
332 paused_->assignProperty(pause_waypoint_button_,
"enabled",
false);
334 paused_->assignProperty(nr_of_loops_,
"enabled",
false);
336 paused_->assignProperty(store_initial_pose_checkbox_,
"enabled",
false);
339 resumed_ =
new QState();
340 resumed_->setObjectName(
"resuming");
343 resumed_wp_ =
new QState();
344 resumed_wp_->setObjectName(
"running");
345 resumed_wp_->assignProperty(start_reset_button_,
"text",
"Cancel");
346 resumed_wp_->assignProperty(start_reset_button_,
"toolTip", cancel_msg);
348 resumed_wp_->assignProperty(pause_resume_button_,
"text",
"Start Nav Through Poses");
349 resumed_wp_->assignProperty(pause_resume_button_,
"enabled",
false);
351 resumed_wp_->assignProperty(navigation_mode_button_,
"text",
"Start Waypoint Following");
352 resumed_wp_->assignProperty(navigation_mode_button_,
"enabled",
false);
354 resumed_wp_->assignProperty(save_waypoints_button_,
"text",
"Save WPs");
355 resumed_wp_->assignProperty(save_waypoints_button_,
"enabled",
true);
357 resumed_wp_->assignProperty(load_waypoints_button_,
"text",
"Load WPs");
358 resumed_wp_->assignProperty(load_waypoints_button_,
"enabled",
false);
360 resumed_wp_->assignProperty(pause_waypoint_button_,
"text",
"Resume WP");
361 resumed_wp_->assignProperty(pause_waypoint_button_,
"enabled",
true);
363 resumed_wp_->assignProperty(nr_of_loops_,
"enabled",
false);
364 resumed_wp_->assignProperty(store_initial_pose_checkbox_,
"enabled",
false);
366 QObject::connect(initial_, SIGNAL(exited()),
this, SLOT(onStartup()));
367 QObject::connect(canceled_, SIGNAL(exited()),
this, SLOT(onCancel()));
368 QObject::connect(reset_, SIGNAL(exited()),
this, SLOT(onShutdown()));
369 QObject::connect(paused_, SIGNAL(entered()),
this, SLOT(onPause()));
370 QObject::connect(resumed_, SIGNAL(exited()),
this, SLOT(onResume()));
371 QObject::connect(accumulating_, SIGNAL(entered()),
this, SLOT(onAccumulating()));
372 QObject::connect(accumulated_wp_, SIGNAL(entered()),
this, SLOT(onAccumulatedWp()));
373 QObject::connect(resumed_wp_, SIGNAL(entered()),
this, SLOT(onResumedWp()));
375 accumulated_nav_through_poses_, SIGNAL(entered()),
this,
376 SLOT(onAccumulatedNTP()));
378 save_waypoints_button_,
379 &QPushButton::released,
380 this, &Nav2Panel::handleGoalSaver);
382 load_waypoints_button_,
383 &QPushButton::released,
385 &Nav2Panel::handleGoalLoader);
388 &QLineEdit::editingFinished,
390 &Nav2Panel::loophandler);
392 store_initial_pose_checkbox_,
393 &QCheckBox::stateChanged,
395 &Nav2Panel::initialStateHandler);
398 initial_->addTransition(start_reset_button_, SIGNAL(clicked()), idle_);
399 idle_->addTransition(start_reset_button_, SIGNAL(clicked()), reset_);
400 running_->addTransition(start_reset_button_, SIGNAL(clicked()), canceled_);
401 paused_->addTransition(start_reset_button_, SIGNAL(clicked()), reset_);
402 idle_->addTransition(navigation_mode_button_, SIGNAL(clicked()), accumulating_);
403 accumulating_->addTransition(navigation_mode_button_, SIGNAL(clicked()), accumulated_wp_);
404 accumulating_->addTransition(
405 pause_resume_button_, SIGNAL(
406 clicked()), accumulated_nav_through_poses_);
407 accumulating_->addTransition(start_reset_button_, SIGNAL(clicked()), idle_);
408 accumulated_wp_->addTransition(start_reset_button_, SIGNAL(clicked()), canceled_);
409 accumulated_nav_through_poses_->addTransition(start_reset_button_, SIGNAL(clicked()), canceled_);
412 canceled_->addTransition(canceled_, SIGNAL(entered()), idle_);
413 reset_->addTransition(reset_, SIGNAL(entered()), initial_);
414 resumed_->addTransition(resumed_, SIGNAL(entered()), idle_);
417 idle_->addTransition(pause_resume_button_, SIGNAL(clicked()), paused_);
418 paused_->addTransition(pause_resume_button_, SIGNAL(clicked()), resumed_);
421 accumulated_wp_->addTransition(pause_waypoint_button_, SIGNAL(clicked()), resumed_wp_);
422 resumed_wp_->addTransition(pause_waypoint_button_, SIGNAL(clicked()), accumulated_wp_);
423 resumed_wp_->addTransition(start_reset_button_, SIGNAL(clicked()), canceled_);
428 ROSActionQTransition * idleTransition =
new ROSActionQTransition(QActionState::INACTIVE);
429 idleTransition->setTargetState(running_);
430 idle_->addTransition(idleTransition);
432 ROSActionQTransition * runningTransition =
new ROSActionQTransition(QActionState::ACTIVE);
433 runningTransition->setTargetState(idle_);
434 running_->addTransition(runningTransition);
436 ROSActionQTransition * idleAccumulatedWpTransition =
437 new ROSActionQTransition(QActionState::INACTIVE);
438 idleAccumulatedWpTransition->setTargetState(accumulated_wp_);
439 idle_->addTransition(idleAccumulatedWpTransition);
441 ROSActionQTransition * accumulatedWpTransition =
new ROSActionQTransition(QActionState::ACTIVE);
442 accumulatedWpTransition->setTargetState(accumulating_);
443 accumulated_wp_->addTransition(accumulatedWpTransition);
445 ROSActionQTransition * idleAccumulatedNTPTransition =
446 new ROSActionQTransition(QActionState::INACTIVE);
447 idleAccumulatedNTPTransition->setTargetState(accumulated_nav_through_poses_);
448 idle_->addTransition(idleAccumulatedNTPTransition);
450 ROSActionQTransition * accumulatedNTPTransition =
new ROSActionQTransition(QActionState::ACTIVE);
451 accumulatedNTPTransition->setTargetState(idle_);
452 accumulated_nav_through_poses_->addTransition(accumulatedNTPTransition);
454 auto options = rclcpp::NodeOptions().arguments(
455 {
"--ros-args",
"--remap",
"__node:=rviz_navigation_dialog_action_client",
"--"});
456 client_node_ = std::make_shared<rclcpp::Node>(
"_", options);
458 client_nav_ = std::make_shared<nav2_lifecycle_manager::LifecycleManagerClient>(
459 "lifecycle_manager_navigation", client_node_);
460 client_loc_ = std::make_shared<nav2_lifecycle_manager::LifecycleManagerClient>(
461 "lifecycle_manager_localization", client_node_);
462 initial_thread_ =
new InitialThread(client_nav_, client_loc_);
463 connect(initial_thread_, &InitialThread::finished, initial_thread_, &QObject::deleteLater);
465 QSignalTransition * activeSignal =
new QSignalTransition(
467 &InitialThread::navigationActive);
468 activeSignal->setTargetState(idle_);
469 pre_initial_->addTransition(activeSignal);
470 QSignalTransition * inactiveSignal =
new QSignalTransition(
472 &InitialThread::navigationInactive);
473 inactiveSignal->setTargetState(initial_);
474 pre_initial_->addTransition(inactiveSignal);
477 initial_thread_, &InitialThread::navigationActive,
478 [
this, navigation_active] {
479 navigation_status_indicator_->setText(navigation_active);
482 initial_thread_, &InitialThread::navigationInactive,
483 [
this, navigation_inactive] {
484 navigation_status_indicator_->setText(navigation_inactive);
485 navigation_goal_status_indicator_->setText(nav2_rviz_plugins::getGoalStatusLabel());
486 navigation_feedback_indicator_->setText(getNavThroughPosesFeedbackLabel());
489 initial_thread_, &InitialThread::localizationActive,
490 [
this, localization_active] {
491 localization_status_indicator_->setText(localization_active);
494 initial_thread_, &InitialThread::localizationInactive,
495 [
this, localization_inactive] {
496 localization_status_indicator_->setText(localization_inactive);
499 state_machine_.addState(pre_initial_);
500 state_machine_.addState(initial_);
501 state_machine_.addState(idle_);
502 state_machine_.addState(running_);
503 state_machine_.addState(canceled_);
504 state_machine_.addState(reset_);
505 state_machine_.addState(paused_);
506 state_machine_.addState(resumed_);
507 state_machine_.addState(accumulating_);
508 state_machine_.addState(accumulated_wp_);
509 state_machine_.addState(accumulated_nav_through_poses_);
510 state_machine_.addState(resumed_wp_);
512 state_machine_.setInitialState(pre_initial_);
515 QObject::connect(&state_machine_, SIGNAL(started()),
this, SLOT(startThread()));
516 state_machine_.start();
519 QVBoxLayout * main_layout =
new QVBoxLayout;
520 QHBoxLayout * side_layout =
new QHBoxLayout;
521 QVBoxLayout * status_layout =
new QVBoxLayout;
522 QHBoxLayout * logo_layout =
new QHBoxLayout;
523 QVBoxLayout * group_box_layout =
new QVBoxLayout;
525 QGroupBox * groupBox =
new QGroupBox(tr(
"Tools for WP-Following"));
526 imgDisplayLabel_ =
new QLabel(
"");
527 imgDisplayLabel_->setPixmap(
528 rviz_common::loadPixmap(
"package://nav2_rviz_plugins/icons/classes/nav2_logo_small.png"));
530 status_layout->addWidget(navigation_status_indicator_);
531 status_layout->addWidget(localization_status_indicator_);
532 status_layout->addWidget(navigation_goal_status_indicator_);
534 logo_layout->addWidget(imgDisplayLabel_, 5, Qt::AlignRight);
536 side_layout->addLayout(status_layout);
537 side_layout->addLayout(logo_layout);
539 main_layout->addLayout(side_layout);
540 main_layout->addWidget(navigation_feedback_indicator_);
541 main_layout->addWidget(waypoint_status_indicator_);
542 main_layout->addWidget(pause_resume_button_);
543 main_layout->addWidget(start_reset_button_);
544 main_layout->addWidget(navigation_mode_button_);
546 QHBoxLayout * group_box_l1_layout =
new QHBoxLayout;
547 QHBoxLayout * group_box_l2_layout =
new QHBoxLayout;
549 group_box_l1_layout->addWidget(save_waypoints_button_);
550 group_box_l1_layout->addWidget(load_waypoints_button_);
551 group_box_l1_layout->addWidget(pause_waypoint_button_);
553 group_box_l2_layout->addWidget(number_of_loops_);
554 group_box_l2_layout->addWidget(nr_of_loops_);
555 group_box_l2_layout->addWidget(store_initial_pose_checkbox_);
557 group_box_layout->addLayout(group_box_l1_layout);
558 group_box_layout->addLayout(group_box_l2_layout);
560 groupBox->setLayout(group_box_layout);
562 main_layout->addWidget(groupBox);
563 main_layout->setContentsMargins(10, 10, 10, 10);
564 setLayout(main_layout);
566 navigation_action_client_ =
567 rclcpp_action::create_client<nav2_msgs::action::NavigateToPose>(
570 waypoint_follower_action_client_ =
571 rclcpp_action::create_client<nav2_msgs::action::FollowWaypoints>(
574 nav_through_poses_action_client_ =
575 rclcpp_action::create_client<nav2_msgs::action::NavigateThroughPoses>(
577 "navigate_through_poses");
580 tf2_buffer_ = std::make_shared<tf2_ros::Buffer>(client_node_->get_clock());
581 auto timer_interface = std::make_shared<tf2_ros::CreateTimerROS>(
582 client_node_->get_node_base_interface(),
583 client_node_->get_node_timers_interface());
584 tf2_buffer_->setCreateTimerInterface(timer_interface);
585 transform_listener_ = std::make_shared<tf2_ros::TransformListener>(*tf2_buffer_);
587 navigation_goal_ = nav2_msgs::action::NavigateToPose::Goal();
588 waypoint_follower_goal_ = nav2_msgs::action::FollowWaypoints::Goal();
589 nav_through_poses_goal_ = nav2_msgs::action::NavigateThroughPoses::Goal();
591 wp_navigation_markers_pub_ =
592 client_node_->create_publisher<visualization_msgs::msg::MarkerArray>(
594 rclcpp::QoS(1).transient_local());
597 &GoalUpdater, SIGNAL(updateGoal(
double,
double,
double,QString)),
598 this, SLOT(onNewGoal(
double,
double,
double,QString)));
601 Nav2Panel::~Nav2Panel()
605 void Nav2Panel::initialStateHandler()
607 if (store_initial_pose_checkbox_->isChecked()) {
608 store_initial_pose_ =
true;
611 store_initial_pose_ =
false;
615 bool Nav2Panel::isLoopValueValid(std::string & loop_value)
618 if (loop_value.empty()) {
619 std::cout <<
"Loop value cannot be set to empty, setting to 0" << std::endl;
621 nr_of_loops_->setText(
"0");
626 for (
char & c : loop_value) {
627 if (isalpha(c) || isspace(c) || ispunct(c)) {
628 waypoint_status_indicator_->setText(
629 "<b> Note: </b> Set a valid value for the loop");
630 std::cout <<
"Set a valid value for the loop, check for alphabets and spaces" << std::endl;
631 navigation_mode_button_->setEnabled(
false);
638 }
catch (std::invalid_argument
const & ex) {
640 waypoint_status_indicator_->setText(
"<b> Note: </b> Set a valid value for the loop");
641 navigation_mode_button_->setEnabled(
false);
643 }
catch (std::out_of_range
const & ex) {
645 waypoint_status_indicator_->setText(
646 "<b> Note: </b> Loop value out of range, setting max possible value"
648 loop_value = std::to_string(std::numeric_limits<int>::max());
649 nr_of_loops_->setText(QString::fromStdString(loop_value));
654 void Nav2Panel::loophandler()
656 loop_no_ = nr_of_loops_->displayText().toStdString();
659 if (!isLoopValueValid(loop_no_)) {
664 navigation_mode_button_->setEnabled(
true);
667 if (!loop_no_.empty() && stoi(loop_no_) > 0) {
668 pause_resume_button_->setEnabled(
false);
670 pause_resume_button_->setEnabled(
true);
674 void Nav2Panel::handleGoalLoader()
676 acummulated_poses_.clear();
678 std::cout <<
"Loading Waypoints!" << std::endl;
680 QString file = QFileDialog::getOpenFileName(
683 tr(
"yaml(*.yaml);;All Files (*)"));
685 YAML::Node available_waypoints;
688 available_waypoints = YAML::LoadFile(file.toStdString());
689 }
catch (
const std::exception & ex) {
690 std::cout << ex.what() <<
", please select a valid file" << std::endl;
691 updateWpNavigationMarkers();
695 const YAML::Node & waypoint_iter = available_waypoints[
"waypoints"];
696 for (YAML::const_iterator it = waypoint_iter.begin(); it != waypoint_iter.end(); ++it) {
697 auto waypoint = waypoint_iter[it->first.as<std::string>()];
698 auto pose = waypoint[
"pose"].as<std::vector<double>>();
699 auto orientation = waypoint[
"orientation"].as<std::vector<double>>();
700 acummulated_poses_.push_back(convert_to_msg(pose, orientation));
704 updateWpNavigationMarkers();
707 geometry_msgs::msg::PoseStamped Nav2Panel::convert_to_msg(
708 std::vector<double> pose,
709 std::vector<double> orientation)
711 auto msg = geometry_msgs::msg::PoseStamped();
713 msg.header.frame_id =
"map";
716 msg.pose.position.x = pose[0];
717 msg.pose.position.y = pose[1];
718 msg.pose.position.z = pose[2];
720 msg.pose.orientation.w = orientation[0];
721 msg.pose.orientation.x = orientation[1];
722 msg.pose.orientation.y = orientation[2];
723 msg.pose.orientation.z = orientation[3];
728 void Nav2Panel::handleGoalSaver()
732 if (acummulated_poses_.empty()) {
733 std::cout <<
"No accumulated Points to Save!" << std::endl;
736 std::cout <<
"Saving Waypoints!" << std::endl;
740 out << YAML::BeginMap;
741 out << YAML::Key <<
"waypoints";
742 out << YAML::BeginMap;
745 for (
unsigned int i = 0; i < acummulated_poses_.size(); ++i) {
746 out << YAML::Key <<
"waypoint" + std::to_string(i);
747 out << YAML::BeginMap;
748 out << YAML::Key <<
"pose";
749 std::vector<double> pose =
750 {acummulated_poses_[i].pose.position.x, acummulated_poses_[i].pose.position.y,
751 acummulated_poses_[i].pose.position.z};
752 out << YAML::Value << pose;
753 out << YAML::Key <<
"orientation";
754 std::vector<double> orientation =
755 {acummulated_poses_[i].pose.orientation.w, acummulated_poses_[i].pose.orientation.x,
756 acummulated_poses_[i].pose.orientation.y, acummulated_poses_[i].pose.orientation.z};
757 out << YAML::Value << orientation;
762 QString file = QFileDialog::getSaveFileName(
765 tr(
"yaml(*.yaml);;All Files (*)"));
767 if (!file.toStdString().empty()) {
768 std::ofstream fout(file.toStdString() +
".yaml");
770 std::cout <<
"Saving waypoints succeeded" << std::endl;
772 std::cout <<
"Saving waypoints aborted" << std::endl;
777 Nav2Panel::onInitialize()
779 auto node = getDisplayContext()->getRosNodeAbstraction().lock()->get_raw_node();
782 node->declare_parameter(
"base_frame", rclcpp::ParameterValue(std::string(
"base_footprint")));
783 node->get_parameter(
"base_frame", base_frame_);
786 navigation_feedback_sub_ =
787 node->create_subscription<nav2_msgs::action::NavigateToPose::Impl::FeedbackMessage>(
788 "navigate_to_pose/_action/feedback",
789 rclcpp::SystemDefaultsQoS(),
790 [
this](
const nav2_msgs::action::NavigateToPose::Impl::FeedbackMessage::SharedPtr msg) {
791 if (stoi(nr_of_loops_->displayText().toStdString()) > 0) {
792 if (goal_index_ == 0 && !loop_counter_stop_) {
794 loop_counter_stop_ =
true;
796 if (goal_index_ != 0) {
797 loop_counter_stop_ =
false;
799 navigation_feedback_indicator_->setText(
800 getNavToPoseFeedbackLabel(msg->feedback) + QString(
802 "</td></tr><tr><td width=150>Waypoint:</td><td>" +
803 toString(goal_index_ + 1)).c_str()) + QString(
805 "</td></tr><tr><td width=150>Loop:</td><td>" +
806 toString(loop_count_)).c_str()));
808 navigation_feedback_indicator_->setText(getNavToPoseFeedbackLabel(msg->feedback));
811 nav_through_poses_feedback_sub_ =
812 node->create_subscription<nav2_msgs::action::NavigateThroughPoses::Impl::FeedbackMessage>(
813 "navigate_through_poses/_action/feedback",
814 rclcpp::SystemDefaultsQoS(),
815 [
this](
const nav2_msgs::action::NavigateThroughPoses::Impl::FeedbackMessage::SharedPtr msg) {
816 navigation_feedback_indicator_->setText(getNavThroughPosesFeedbackLabel(msg->feedback));
820 navigation_goal_status_sub_ = node->create_subscription<action_msgs::msg::GoalStatusArray>(
821 "navigate_to_pose/_action/status",
822 rclcpp::SystemDefaultsQoS(),
823 [
this](
const action_msgs::msg::GoalStatusArray::SharedPtr msg) {
824 navigation_goal_status_indicator_->setText(
825 nav2_rviz_plugins::getGoalStatusLabel(
"Feedback", msg->status_list.back().status));
828 loop_count_ == stoi(nr_of_loops_->displayText().toStdString()) &&
829 goal_index_ ==
static_cast<int>(store_poses_.size()) - 1 &&
830 msg->status_list.back().status == action_msgs::msg::GoalStatus::STATUS_SUCCEEDED)
832 store_poses_.clear();
833 waypoint_status_indicator_->clear();
836 navigation_feedback_indicator_->setText(getNavToPoseFeedbackLabel());
839 nav_through_poses_goal_status_sub_ = node->create_subscription<action_msgs::msg::GoalStatusArray>(
840 "navigate_through_poses/_action/status",
841 rclcpp::SystemDefaultsQoS(),
842 [
this](
const action_msgs::msg::GoalStatusArray::SharedPtr msg) {
843 navigation_goal_status_indicator_->setText(
844 nav2_rviz_plugins::getGoalStatusLabel(
"Feedback", msg->status_list.back().status));
845 if (msg->status_list.back().status != action_msgs::msg::GoalStatus::STATUS_EXECUTING) {
846 navigation_feedback_indicator_->setText(getNavThroughPosesFeedbackLabel());
852 Nav2Panel::startThread()
855 initial_thread_->start();
861 QFuture<void> futureNav =
865 client_nav_.get(), std::placeholders::_1), server_timeout_);
866 QFuture<void> futureLoc =
870 client_loc_.get(), std::placeholders::_1), server_timeout_);
874 Nav2Panel::onResume()
876 QFuture<void> futureNav =
880 client_nav_.get(), std::placeholders::_1), server_timeout_);
881 QFuture<void> futureLoc =
885 client_loc_.get(), std::placeholders::_1), server_timeout_);
889 Nav2Panel::onStartup()
891 QFuture<void> futureNav =
895 client_nav_.get(), std::placeholders::_1), server_timeout_);
896 QFuture<void> futureLoc =
900 client_loc_.get(), std::placeholders::_1), server_timeout_);
904 Nav2Panel::onShutdown()
906 QFuture<void> futureNav =
910 client_nav_.get(), std::placeholders::_1), server_timeout_);
911 QFuture<void> futureLoc =
915 client_loc_.get(), std::placeholders::_1), server_timeout_);
920 Nav2Panel::onCancel()
922 QFuture<void> future =
925 &Nav2Panel::onCancelButtonPressed,
927 waypoint_status_indicator_->clear();
928 store_poses_.clear();
929 acummulated_poses_.clear();
932 void Nav2Panel::onResumedWp()
934 QFuture<void> future =
937 &Nav2Panel::onCancelButtonPressed,
939 acummulated_poses_ = store_poses_;
940 loop_no_ = std::to_string(
941 stoi(nr_of_loops_->displayText().toStdString()) -
943 waypoint_status_indicator_->setText(
944 QString(std::string(
"<b> Note: </b> Navigation is paused.").c_str()));
948 Nav2Panel::onNewGoal(
double x,
double y,
double theta, QString frame)
950 auto pose = geometry_msgs::msg::PoseStamped();
953 pose.header.frame_id = frame.toStdString();
954 pose.pose.position.x = x;
955 pose.pose.position.y = y;
956 pose.pose.position.z = 0.0;
957 pose.pose.orientation = orientationAroundZAxis(theta);
959 if (store_poses_.empty()) {
960 if (state_machine_.configuration().contains(accumulating_)) {
961 waypoint_status_indicator_->clear();
962 acummulated_poses_.push_back(pose);
964 acummulated_poses_.clear();
965 updateWpNavigationMarkers();
966 std::cout <<
"Start navigation" << std::endl;
967 startNavigation(pose);
970 waypoint_status_indicator_->setText(
971 QString(std::string(
"<b> Note: </b> Cannot set goal in pause state").c_str()));
973 updateWpNavigationMarkers();
977 Nav2Panel::onCancelButtonPressed()
979 if (navigation_goal_handle_) {
980 auto future_cancel = navigation_action_client_->async_cancel_goal(navigation_goal_handle_);
982 if (rclcpp::spin_until_future_complete(client_node_, future_cancel, server_timeout_) !=
983 rclcpp::FutureReturnCode::SUCCESS)
985 RCLCPP_ERROR(client_node_->get_logger(),
"Failed to cancel goal");
987 navigation_goal_handle_.reset();
991 if (waypoint_follower_goal_handle_) {
993 waypoint_follower_action_client_->async_cancel_goal(waypoint_follower_goal_handle_);
995 if (rclcpp::spin_until_future_complete(client_node_, future_cancel, server_timeout_) !=
996 rclcpp::FutureReturnCode::SUCCESS)
998 RCLCPP_ERROR(client_node_->get_logger(),
"Failed to cancel waypoint follower");
1000 waypoint_follower_goal_handle_.reset();
1004 if (nav_through_poses_goal_handle_) {
1005 auto future_cancel =
1006 nav_through_poses_action_client_->async_cancel_goal(nav_through_poses_goal_handle_);
1008 if (rclcpp::spin_until_future_complete(client_node_, future_cancel, server_timeout_) !=
1009 rclcpp::FutureReturnCode::SUCCESS)
1011 RCLCPP_ERROR(client_node_->get_logger(),
"Failed to cancel nav through pose action");
1013 nav_through_poses_goal_handle_.reset();
1021 Nav2Panel::onAccumulatedWp()
1023 if (acummulated_poses_.empty()) {
1024 state_machine_.postEvent(
new ROSActionQEvent(QActionState::INACTIVE));
1025 waypoint_status_indicator_->setText(
1026 "<b> Note: </b> Uh oh! Someone forgot to select the waypoints");
1031 if (!isLoopValueValid(loop_no_)) {
1032 state_machine_.postEvent(
new ROSActionQEvent(QActionState::INACTIVE));
1037 waypoint_status_indicator_->clear();
1040 navigation_mode_button_->setEnabled(
false);
1041 pause_resume_button_->setEnabled(
false);
1045 if (store_poses_.empty()) {
1046 std::cout <<
"Start waypoint" << std::endl;
1049 nr_of_loops_->setText(QString::fromStdString(loop_no_));
1052 geometry_msgs::msg::TransformStamped init_transform;
1055 if (store_initial_pose_) {
1057 init_transform = tf2_buffer_->lookupTransform(
1058 acummulated_poses_[0].header.frame_id, base_frame_,
1059 tf2::TimePointZero);
1060 }
catch (
const tf2::TransformException & ex) {
1062 client_node_->get_logger(),
"Could not transform %s to %s: %s",
1063 acummulated_poses_[0].header.frame_id.c_str(), base_frame_.c_str(), ex.what());
1068 geometry_msgs::msg::PoseStamped initial_pose;
1069 initial_pose.header = init_transform.header;
1070 initial_pose.pose.position.x = init_transform.transform.translation.x;
1071 initial_pose.pose.position.y = init_transform.transform.translation.y;
1072 initial_pose.pose.position.z = init_transform.transform.translation.z;
1073 initial_pose.pose.orientation.x = init_transform.transform.rotation.x;
1074 initial_pose.pose.orientation.y = init_transform.transform.rotation.y;
1075 initial_pose.pose.orientation.z = init_transform.transform.rotation.z;
1076 initial_pose.pose.orientation.w = init_transform.transform.rotation.w;
1079 acummulated_poses_.insert(acummulated_poses_.begin(), initial_pose);
1080 updateWpNavigationMarkers();
1081 initial_pose_stored_ =
true;
1082 if (loop_count_ == 0) {
1085 }
else if (!store_initial_pose_ && initial_pose_stored_) {
1086 acummulated_poses_.erase(
1087 acummulated_poses_.begin(),
1088 acummulated_poses_.begin());
1091 std::cout <<
"Resuming waypoint" << std::endl;
1094 startWaypointFollowing(acummulated_poses_);
1095 store_poses_ = acummulated_poses_;
1096 acummulated_poses_.clear();
1100 Nav2Panel::onAccumulatedNTP()
1102 std::cout <<
"Start navigate through poses" << std::endl;
1103 startNavThroughPoses(acummulated_poses_);
1107 Nav2Panel::onAccumulating()
1109 acummulated_poses_.clear();
1110 store_poses_.clear();
1113 initial_pose_stored_ =
false;
1114 loop_counter_stop_ =
true;
1116 updateWpNavigationMarkers();
1120 Nav2Panel::timerEvent(QTimerEvent * event)
1122 if (state_machine_.configuration().contains(accumulated_wp_)) {
1123 if (event->timerId() == timer_.timerId()) {
1124 if (!waypoint_follower_goal_handle_) {
1125 RCLCPP_DEBUG(client_node_->get_logger(),
"Waiting for Goal");
1126 state_machine_.postEvent(
new ROSActionQEvent(QActionState::INACTIVE));
1130 rclcpp::spin_some(client_node_);
1131 auto status = waypoint_follower_goal_handle_->get_status();
1134 if (status == action_msgs::msg::GoalStatus::STATUS_ACCEPTED ||
1135 status == action_msgs::msg::GoalStatus::STATUS_EXECUTING)
1137 state_machine_.postEvent(
new ROSActionQEvent(QActionState::ACTIVE));
1139 state_machine_.postEvent(
new ROSActionQEvent(QActionState::INACTIVE));
1143 }
else if (state_machine_.configuration().contains(accumulated_nav_through_poses_)) {
1144 if (event->timerId() == timer_.timerId()) {
1145 if (!nav_through_poses_goal_handle_) {
1146 RCLCPP_DEBUG(client_node_->get_logger(),
"Waiting for Goal");
1147 state_machine_.postEvent(
new ROSActionQEvent(QActionState::INACTIVE));
1151 rclcpp::spin_some(client_node_);
1152 auto status = nav_through_poses_goal_handle_->get_status();
1155 if (status == action_msgs::msg::GoalStatus::STATUS_ACCEPTED ||
1156 status == action_msgs::msg::GoalStatus::STATUS_EXECUTING)
1158 state_machine_.postEvent(
new ROSActionQEvent(QActionState::ACTIVE));
1160 state_machine_.postEvent(
new ROSActionQEvent(QActionState::INACTIVE));
1165 if (event->timerId() == timer_.timerId()) {
1166 if (!navigation_goal_handle_) {
1167 RCLCPP_DEBUG(client_node_->get_logger(),
"Waiting for Goal");
1168 state_machine_.postEvent(
new ROSActionQEvent(QActionState::INACTIVE));
1172 rclcpp::spin_some(client_node_);
1173 auto status = navigation_goal_handle_->get_status();
1176 if (status == action_msgs::msg::GoalStatus::STATUS_ACCEPTED ||
1177 status == action_msgs::msg::GoalStatus::STATUS_EXECUTING)
1179 state_machine_.postEvent(
new ROSActionQEvent(QActionState::ACTIVE));
1181 state_machine_.postEvent(
new ROSActionQEvent(QActionState::INACTIVE));
1189 Nav2Panel::startWaypointFollowing(std::vector<geometry_msgs::msg::PoseStamped> poses)
1191 auto is_action_server_ready =
1192 waypoint_follower_action_client_->wait_for_action_server(std::chrono::seconds(5));
1193 if (!is_action_server_ready) {
1195 client_node_->get_logger(),
"follow_waypoints action server is not available."
1196 " Is the initial pose set?");
1201 waypoint_follower_goal_.poses = poses;
1202 waypoint_follower_goal_.goal_index = goal_index_;
1203 waypoint_follower_goal_.number_of_loops = stoi(loop_no_);
1206 client_node_->get_logger(),
"Sending a path of %zu waypoints:",
1207 waypoint_follower_goal_.poses.size());
1208 for (
auto waypoint : waypoint_follower_goal_.poses) {
1210 client_node_->get_logger(),
1211 "\t(%lf, %lf)", waypoint.pose.position.x, waypoint.pose.position.y);
1215 auto send_goal_options =
1216 rclcpp_action::Client<nav2_msgs::action::FollowWaypoints>::SendGoalOptions();
1217 send_goal_options.result_callback = [
this](
auto) {
1218 waypoint_follower_goal_handle_.reset();
1221 send_goal_options.feedback_callback = [
this](
1222 WaypointFollowerGoalHandle::SharedPtr ,
1223 const std::shared_ptr<const nav2_msgs::action::FollowWaypoints::Feedback> feedback) {
1224 goal_index_ = feedback->current_waypoint;
1227 auto future_goal_handle =
1228 waypoint_follower_action_client_->async_send_goal(waypoint_follower_goal_, send_goal_options);
1229 if (rclcpp::spin_until_future_complete(client_node_, future_goal_handle, server_timeout_) !=
1230 rclcpp::FutureReturnCode::SUCCESS)
1232 RCLCPP_ERROR(client_node_->get_logger(),
"Send goal call failed");
1237 waypoint_follower_goal_handle_ = future_goal_handle.get();
1238 if (!waypoint_follower_goal_handle_) {
1239 RCLCPP_ERROR(client_node_->get_logger(),
"Goal was rejected by server");
1243 timer_.start(200,
this);
1247 Nav2Panel::startNavThroughPoses(std::vector<geometry_msgs::msg::PoseStamped> poses)
1249 auto is_action_server_ready =
1250 nav_through_poses_action_client_->wait_for_action_server(std::chrono::seconds(5));
1251 if (!is_action_server_ready) {
1253 client_node_->get_logger(),
"navigate_through_poses action server is not available."
1254 " Is the initial pose set?");
1258 nav_through_poses_goal_.poses = poses;
1260 client_node_->get_logger(),
1261 "NavigateThroughPoses will be called using the BT Navigator's default behavior tree.");
1264 client_node_->get_logger(),
"Sending a path of %zu waypoints:",
1265 nav_through_poses_goal_.poses.size());
1266 for (
auto waypoint : nav_through_poses_goal_.poses) {
1268 client_node_->get_logger(),
1269 "\t(%lf, %lf)", waypoint.pose.position.x, waypoint.pose.position.y);
1273 auto send_goal_options =
1274 rclcpp_action::Client<nav2_msgs::action::NavigateThroughPoses>::SendGoalOptions();
1275 send_goal_options.result_callback = [
this](
auto) {
1276 nav_through_poses_goal_handle_.reset();
1279 auto future_goal_handle =
1280 nav_through_poses_action_client_->async_send_goal(nav_through_poses_goal_, send_goal_options);
1281 if (rclcpp::spin_until_future_complete(client_node_, future_goal_handle, server_timeout_) !=
1282 rclcpp::FutureReturnCode::SUCCESS)
1284 RCLCPP_ERROR(client_node_->get_logger(),
"Send goal call failed");
1289 nav_through_poses_goal_handle_ = future_goal_handle.get();
1290 if (!nav_through_poses_goal_handle_) {
1291 RCLCPP_ERROR(client_node_->get_logger(),
"Goal was rejected by server");
1295 timer_.start(200,
this);
1299 Nav2Panel::startNavigation(geometry_msgs::msg::PoseStamped pose)
1301 auto is_action_server_ready =
1302 navigation_action_client_->wait_for_action_server(std::chrono::seconds(5));
1303 if (!is_action_server_ready) {
1305 client_node_->get_logger(),
1306 "navigate_to_pose action server is not available."
1307 " Is the initial pose set?");
1312 navigation_goal_.pose = pose;
1315 client_node_->get_logger(),
1316 "NavigateToPose will be called using the BT Navigator's default behavior tree.");
1319 auto send_goal_options =
1320 rclcpp_action::Client<nav2_msgs::action::NavigateToPose>::SendGoalOptions();
1321 send_goal_options.result_callback = [
this](
auto) {
1322 navigation_goal_handle_.reset();
1325 auto future_goal_handle =
1326 navigation_action_client_->async_send_goal(navigation_goal_, send_goal_options);
1327 if (rclcpp::spin_until_future_complete(client_node_, future_goal_handle, server_timeout_) !=
1328 rclcpp::FutureReturnCode::SUCCESS)
1330 RCLCPP_ERROR(client_node_->get_logger(),
"Send goal call failed");
1335 navigation_goal_handle_ = future_goal_handle.get();
1336 if (!navigation_goal_handle_) {
1337 RCLCPP_ERROR(client_node_->get_logger(),
"Goal was rejected by server");
1341 timer_.start(200,
this);
1345 Nav2Panel::save(rviz_common::Config config)
const
1347 Panel::save(config);
1351 Nav2Panel::load(
const rviz_common::Config & config)
1353 Panel::load(config);
1357 Nav2Panel::resetUniqueId()
1363 Nav2Panel::getUniqueId()
1365 int temp_id = unique_id;
1371 Nav2Panel::updateWpNavigationMarkers()
1375 auto marker_array = std::make_unique<visualization_msgs::msg::MarkerArray>();
1377 for (
size_t i = 0; i < acummulated_poses_.size(); i++) {
1379 visualization_msgs::msg::Marker arrow_marker;
1380 arrow_marker.header = acummulated_poses_[i].header;
1381 arrow_marker.id = getUniqueId();
1382 arrow_marker.type = visualization_msgs::msg::Marker::ARROW;
1383 arrow_marker.action = visualization_msgs::msg::Marker::ADD;
1384 arrow_marker.pose = acummulated_poses_[i].pose;
1385 arrow_marker.scale.x = 0.3;
1386 arrow_marker.scale.y = 0.05;
1387 arrow_marker.scale.z = 0.02;
1388 arrow_marker.color.r = 0;
1389 arrow_marker.color.g = 255;
1390 arrow_marker.color.b = 0;
1391 arrow_marker.color.a = 1.0f;
1392 arrow_marker.lifetime = rclcpp::Duration(0s);
1393 arrow_marker.frame_locked =
false;
1394 marker_array->markers.push_back(arrow_marker);
1397 visualization_msgs::msg::Marker circle_marker;
1398 circle_marker.header = acummulated_poses_[i].header;
1399 circle_marker.id = getUniqueId();
1400 circle_marker.type = visualization_msgs::msg::Marker::SPHERE;
1401 circle_marker.action = visualization_msgs::msg::Marker::ADD;
1402 circle_marker.pose = acummulated_poses_[i].pose;
1403 circle_marker.scale.x = 0.05;
1404 circle_marker.scale.y = 0.05;
1405 circle_marker.scale.z = 0.05;
1406 circle_marker.color.r = 255;
1407 circle_marker.color.g = 0;
1408 circle_marker.color.b = 0;
1409 circle_marker.color.a = 1.0f;
1410 circle_marker.lifetime = rclcpp::Duration(0s);
1411 circle_marker.frame_locked =
false;
1412 marker_array->markers.push_back(circle_marker);
1415 visualization_msgs::msg::Marker marker_text;
1416 marker_text.header = acummulated_poses_[i].header;
1417 marker_text.id = getUniqueId();
1418 marker_text.type = visualization_msgs::msg::Marker::TEXT_VIEW_FACING;
1419 marker_text.action = visualization_msgs::msg::Marker::ADD;
1420 marker_text.pose = acummulated_poses_[i].pose;
1421 marker_text.pose.position.z += 0.2;
1422 marker_text.scale.x = 0.07;
1423 marker_text.scale.y = 0.07;
1424 marker_text.scale.z = 0.07;
1425 marker_text.color.r = 0;
1426 marker_text.color.g = 255;
1427 marker_text.color.b = 0;
1428 marker_text.color.a = 1.0f;
1429 marker_text.lifetime = rclcpp::Duration(0s);
1430 marker_text.frame_locked =
false;
1431 marker_text.text =
"wp_" + std::to_string(i + 1);
1432 marker_array->markers.push_back(marker_text);
1435 if (marker_array->markers.empty()) {
1436 visualization_msgs::msg::Marker clear_all_marker;
1437 clear_all_marker.action = visualization_msgs::msg::Marker::DELETEALL;
1438 marker_array->markers.push_back(clear_all_marker);
1441 wp_navigation_markers_pub_->publish(std::move(marker_array));
1445 Nav2Panel::getNavToPoseFeedbackLabel(nav2_msgs::action::NavigateToPose::Feedback msg)
1447 return QString(std::string(
"<table>" + toLabel(msg) +
"</table>").c_str());
1451 Nav2Panel::getNavThroughPosesFeedbackLabel(nav2_msgs::action::NavigateThroughPoses::Feedback msg)
1455 "<table><tr><td width=150>Poses remaining:</td><td>" +
1456 std::to_string(msg.number_of_poses_remaining) +
1457 "</td></tr>" + toLabel(msg) +
"</table>").c_str());
1460 template<
typename T>
1461 inline std::string Nav2Panel::toLabel(T & msg)
1464 "<tr><td width=150>ETA:</td><td>" +
1465 toString(rclcpp::Duration(msg.estimated_time_remaining).seconds(), 0) +
" s"
1466 "</td></tr><tr><td width=150>Distance remaining:</td><td>" +
1467 toString(msg.distance_remaining, 2) +
" m"
1468 "</td></tr><tr><td width=150>Time taken:</td><td>" +
1469 toString(rclcpp::Duration(msg.navigation_time).seconds(), 0) +
" s"
1470 "</td></tr><tr><td width=150>Recoveries:</td><td>" +
1471 std::to_string(msg.number_of_recoveries) +
1476 Nav2Panel::toString(
double val,
int precision)
1478 std::ostringstream out;
1479 out.precision(precision);
1480 out << std::fixed << val;
1486 #include <pluginlib/class_list_macros.hpp>
bool pause(const std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
Make pause service call.
bool reset(const std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
Make reset service call.
bool startup(const std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
Make start up service call.
bool resume(const std::chrono::nanoseconds timeout=std::chrono::nanoseconds(-1))
Make resume service call.
Panel to interface to the nav2 stack.