Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
nav2_panel.hpp
1 // Copyright (c) 2019 Intel Corporation
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef NAV2_RVIZ_PLUGINS__NAV2_PANEL_HPP_
16 #define NAV2_RVIZ_PLUGINS__NAV2_PANEL_HPP_
17 
18 #include <QtWidgets>
19 #include <QBasicTimer>
20 #include <QStateMachine>
21 #include <QSignalTransition>
22 #undef NO_ERROR
23 
24 #include <memory>
25 #include <string>
26 #include <vector>
27 
28 #include "nav2_lifecycle_manager/lifecycle_manager_client.hpp"
29 #include "nav2_msgs/action/navigate_to_pose.hpp"
30 #include "nav2_msgs/action/navigate_through_poses.hpp"
31 #include "nav2_msgs/action/follow_waypoints.hpp"
32 #include "nav2_rviz_plugins/ros_action_qevent.hpp"
33 #include "rclcpp/rclcpp.hpp"
34 #include "rclcpp_action/rclcpp_action.hpp"
35 #include "rviz_common/panel.hpp"
36 #include "rviz_common/ros_integration/ros_node_abstraction_iface.hpp"
37 #include "tf2_geometry_msgs/tf2_geometry_msgs.hpp"
38 #include "visualization_msgs/msg/marker_array.hpp"
39 #include "nav2_util/geometry_utils.hpp"
40 #include "nav2_ros_common/tf2_factories.hpp"
41 
42 class QPushButton;
43 
44 namespace nav2_rviz_plugins
45 {
46 
48 {
49  QWidget * widget;
50  QLineEdit * frame_id_edit;
51  QDoubleSpinBox * pos_x_spin;
52  QDoubleSpinBox * pos_y_spin;
53  QDoubleSpinBox * yaw_spin;
54 };
55 
56 class InitialThread;
57 
59 class Nav2Panel : public rviz_common::Panel
60 {
61  Q_OBJECT
62 
63 public:
64  explicit Nav2Panel(QWidget * parent = 0);
65  virtual ~Nav2Panel();
66 
67  void onInitialize() override;
68 
70  void load(const rviz_common::Config & config) override;
71  void save(rviz_common::Config config) const override;
72 
73 private Q_SLOTS:
74  void startThread();
75  void onStartup();
76  void onShutdown();
77  void onCancel();
78  void onPause();
79  void onResume();
80  void onIdle();
81  void onResumedWp();
82  void onAccumulatedWp();
83  void onAccumulatedNTP();
84  void onAccumulating();
85  void onNewGoal(double x, double y, double theta, QString frame);
86  void handleGoalSaver();
87  void handleGoalLoader();
88  void loophandler();
89  void initialStateHandler();
90  void onSendNavToPose();
91  void onAddNavThroughPose();
92  void onRemoveNavThroughPose();
93 
94 private:
95  void loadLogFiles();
96  void onCancelButtonPressed();
97  void timerEvent(QTimerEvent * event) override;
98  bool isLoopValueValid(std::string & loop);
99  void createNavThroughPoseTab(int index);
100  void syncTabsWithAccumulatedPoses();
101  void updateAccumulatedPosesFromTabs();
102  geometry_msgs::msg::PoseStamped getPoseFromNavThroughTab(const NavThroughPoseTab & tab);
103 
104  int unique_id {0};
105  int goal_index_ = 0;
106  int loop_count_ = 0;
107  bool store_initial_pose_ = false;
108  bool initial_pose_stored_ = false;
109  bool loop_counter_stop_ = true;
110  std::string loop_no_ = "0";
111  std::string base_frame_;
112 
113  // The Node pointer that we need to keep alive for the duration of this plugin.
114  std::shared_ptr<rviz_common::ros_integration::RosNodeAbstractionIface> node_ptr_;
115 
116  // Call to send NavigateToPose action request for goal poses
117  geometry_msgs::msg::PoseStamped convert_to_msg(
118  std::vector<double> pose,
119  std::vector<double> orientation);
120  void startWaypointFollowing(std::vector<geometry_msgs::msg::PoseStamped> poses);
121  void startNavigation(geometry_msgs::msg::PoseStamped);
122  void startNavThroughPoses(nav_msgs::msg::Goals poses);
123  using NavigationGoalHandle =
124  rclcpp_action::ClientGoalHandle<nav2_msgs::action::NavigateToPose>;
125  using WaypointFollowerGoalHandle =
126  rclcpp_action::ClientGoalHandle<nav2_msgs::action::FollowWaypoints>;
127  using NavThroughPosesGoalHandle =
128  rclcpp_action::ClientGoalHandle<nav2_msgs::action::NavigateThroughPoses>;
129 
130  // The (non-spinning) client node used to invoke the action client
131  rclcpp::Node::SharedPtr client_node_; // nosemgrep
132  rclcpp::executors::SingleThreadedExecutor::SharedPtr executor_;
133  // Timeout value when waiting for action servers to respond
134  std::chrono::milliseconds server_timeout_;
135 
136  // A timer used to check on the completion status of the action
137  QBasicTimer timer_;
138 
139  // The NavigateToPose action client
140  nav2::ActionClient<nav2_msgs::action::NavigateToPose>::SharedPtr navigation_action_client_;
141  nav2::ActionClient<nav2_msgs::action::FollowWaypoints>::SharedPtr
142  waypoint_follower_action_client_;
143  nav2::ActionClient<nav2_msgs::action::NavigateThroughPoses>::SharedPtr
144  nav_through_poses_action_client_;
145 
146  // Navigation action feedback subscribers
147  nav2::Subscription<nav2_msgs::action::NavigateToPose::Impl::FeedbackMessage>::SharedPtr
148  navigation_feedback_sub_;
149  nav2::Subscription<nav2_msgs::action::NavigateThroughPoses::Impl::FeedbackMessage>::SharedPtr
150  nav_through_poses_feedback_sub_;
151  nav2::Subscription<nav2_msgs::action::NavigateToPose::Impl::GoalStatusMessage>::SharedPtr
152  navigation_goal_status_sub_;
153  nav2::Subscription<nav2_msgs::action::NavigateThroughPoses::Impl::GoalStatusMessage>::SharedPtr
154  nav_through_poses_goal_status_sub_;
155 
156  // Tf's for initial pose
157  nav2::TransformBuffer::SharedPtr tf2_buffer_;
158  nav2::TransformListener::SharedPtr transform_listener_;
159 
160  // Goal-related state
161  nav2_msgs::action::NavigateToPose::Goal navigation_goal_;
162  nav2_msgs::action::FollowWaypoints::Goal waypoint_follower_goal_;
163  nav2_msgs::action::NavigateThroughPoses::Goal nav_through_poses_goal_;
164  NavigationGoalHandle::SharedPtr navigation_goal_handle_;
165  WaypointFollowerGoalHandle::SharedPtr waypoint_follower_goal_handle_;
166  NavThroughPosesGoalHandle::SharedPtr nav_through_poses_goal_handle_;
167 
168  // The client used to control the nav2 stack
169  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> client_nav_;
170  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> client_loc_;
171 
172  QCheckBox * store_initial_pose_checkbox_{nullptr};
173 
174  QPushButton * start_reset_button_{nullptr};
175  QPushButton * pause_resume_button_{nullptr};
176  QPushButton * navigation_mode_button_{nullptr};
177  QPushButton * add_pose_button_{nullptr};
178  QPushButton * remove_pose_button_{nullptr};
179  QPushButton * save_waypoints_button_{nullptr};
180  QPushButton * load_waypoints_button_{nullptr};
181  QPushButton * pause_waypoint_button_{nullptr};
182  QPushButton * start_nav_to_pose_button_{nullptr};
183 
184  QLabel * navigation_status_indicator_{nullptr};
185  QLabel * localization_status_indicator_{nullptr};
186  QLabel * navigation_goal_status_indicator_{nullptr};
187  QLabel * navigation_feedback_indicator_{nullptr};
188  QLabel * waypoint_status_indicator_{nullptr};
189  QLabel * number_of_loops_{nullptr};
190 
191  QLineEdit * nr_of_loops_{nullptr};
192 
193  // Behavior tree XML file selection
194  QLineEdit * behavior_tree_file_{nullptr};
195 
196  // Tab widget for tools
197  QTabWidget * tools_tab_widget_{nullptr};
198 
199  // NavigateToPose manual input widgets
200  QLineEdit * nav_to_pose_frame_id_{nullptr};
201  QDoubleSpinBox * nav_to_pose_x_{nullptr};
202  QDoubleSpinBox * nav_to_pose_y_{nullptr};
203  QDoubleSpinBox * nav_to_pose_yaw_{nullptr};
204 
205  // NavigateThroughPoses manual input widgets
206  QTabWidget * nav_through_poses_tabs_{nullptr};
207 
208  QStateMachine state_machine_;
209  InitialThread * initial_thread_;
210 
211  QState * pre_initial_{nullptr};
212  QState * initial_{nullptr};
213  QState * idle_{nullptr};
214  QState * reset_{nullptr};
215  QState * paused_{nullptr};
216  QState * resumed_{nullptr};
217  QState * paused_wp_{nullptr};
218  QState * resumed_wp_{nullptr};
219 
220  QLabel * imgDisplayLabel_{nullptr};
221 
222  // The following states are added to allow for the state of the button to only expose reset
223  // while the NavigateToPoses action is not active. While running, the user will be allowed to
224  // cancel the action. The ROSActionTransition allows for the state of the action to be detected
225  // and the button state to change automatically.
226  QState * running_{nullptr};
227  QState * canceled_{nullptr};
228  // The following states are added to allow to collect several poses to perform a waypoint-mode
229  // navigation or navigate through poses mode.
230  QState * accumulating_{nullptr};
231  QState * accumulated_wp_{nullptr};
232  QState * accumulated_nav_through_poses_{nullptr};
233 
234  nav_msgs::msg::Goals acummulated_poses_;
235  nav_msgs::msg::Goals store_poses_;
236 
237  // Storage for NavigateThroughPoses manual tabs
238  std::vector<NavThroughPoseTab> nav_through_pose_tabs_;
239 
240  // Publish the visual markers with the waypoints
241  void updateWpNavigationMarkers();
242 
243  // Create unique id numbers for markers
244  int getUniqueId();
245 
246  void resetUniqueId();
247 
248  // create label string from feedback msg
249  static inline QString getNavToPoseFeedbackLabel(
250  nav2_msgs::action::NavigateToPose::Feedback msg =
251  nav2_msgs::action::NavigateToPose::Feedback());
252  static inline QString getNavThroughPosesFeedbackLabel(
253  nav2_msgs::action::NavigateThroughPoses::Feedback =
254  nav2_msgs::action::NavigateThroughPoses::Feedback());
255  template<typename T>
256  static inline std::string toLabel(T & msg);
257 
258  // round off double to the specified precision and convert to string
259  static inline std::string toString(double val, int precision = 0);
260 
261  // Waypoint navigation visual markers publisher
262  // nosemgrep
263  rclcpp::Publisher<visualization_msgs::msg::MarkerArray>::SharedPtr wp_navigation_markers_pub_;
264 };
265 
266 class InitialThread : public QThread
267 {
268  Q_OBJECT
269 
270 public:
271  using SystemStatus = nav2_lifecycle_manager::SystemStatus;
272 
273  explicit InitialThread(
274  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> & client_nav,
275  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> & client_loc)
276  : client_nav_(client_nav), client_loc_(client_loc)
277  {}
278 
279  void run() override
280  {
281  SystemStatus status_nav = SystemStatus::TIMEOUT;
282  SystemStatus status_loc = SystemStatus::TIMEOUT;
283 
284  while (status_nav == SystemStatus::TIMEOUT) {
285  if (status_nav == SystemStatus::TIMEOUT) {
286  status_nav = client_nav_->is_active(std::chrono::seconds(1));
287  }
288  }
289 
290  // try to communicate twice, might not actually be up if in SLAM mode
291  bool tried_loc_bringup_once = false;
292  while (status_loc == SystemStatus::TIMEOUT) {
293  status_loc = client_loc_->is_active(std::chrono::seconds(1));
294  if (tried_loc_bringup_once) {
295  break;
296  }
297  tried_loc_bringup_once = true;
298  }
299 
300  if (status_nav == SystemStatus::ACTIVE) {
301  emit navigationActive();
302  } else {
303  emit navigationInactive();
304  }
305 
306  if (status_loc == SystemStatus::ACTIVE) {
307  emit localizationActive();
308  } else {
309  emit localizationInactive();
310  }
311  }
312 
313 signals:
314  void navigationActive();
315  void navigationInactive();
316  void localizationActive();
317  void localizationInactive();
318 
319 private:
320  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> client_nav_;
321  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> client_loc_;
322 };
323 
324 } // namespace nav2_rviz_plugins
325 
326 #endif // NAV2_RVIZ_PLUGINS__NAV2_PANEL_HPP_
Panel to interface to the nav2 stack.
Definition: nav2_panel.hpp:60
void load(const rviz_common::Config &config) override
Load and save configuration data.