Nav2 Navigation Stack - rolling  main
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 "tf2_ros/transform_listener.hpp"
41 #include "tf2_ros/create_timer_ros.hpp"
42 #include "tf2_ros/buffer.hpp"
43 
44 class QPushButton;
45 
46 namespace nav2_rviz_plugins
47 {
48 
49 class InitialThread;
50 
52 class Nav2Panel : public rviz_common::Panel
53 {
54  Q_OBJECT
55 
56 public:
57  explicit Nav2Panel(QWidget * parent = 0);
58  virtual ~Nav2Panel();
59 
60  void onInitialize() override;
61 
63  void load(const rviz_common::Config & config) override;
64  void save(rviz_common::Config config) const override;
65 
66 private Q_SLOTS:
67  void startThread();
68  void onStartup();
69  void onShutdown();
70  void onCancel();
71  void onPause();
72  void onResume();
73  void onResumedWp();
74  void onAccumulatedWp();
75  void onAccumulatedNTP();
76  void onAccumulating();
77  void onNewGoal(double x, double y, double theta, QString frame);
78  void handleGoalSaver();
79  void handleGoalLoader();
80  void loophandler();
81  void initialStateHandler();
82 
83 private:
84  void loadLogFiles();
85  void onCancelButtonPressed();
86  void timerEvent(QTimerEvent * event) override;
87  bool isLoopValueValid(std::string & loop);
88 
89  int unique_id {0};
90  int goal_index_ = 0;
91  int loop_count_ = 0;
92  bool store_initial_pose_ = false;
93  bool initial_pose_stored_ = false;
94  bool loop_counter_stop_ = true;
95  std::string loop_no_ = "0";
96  std::string base_frame_;
97 
98  // The Node pointer that we need to keep alive for the duration of this plugin.
99  std::shared_ptr<rviz_common::ros_integration::RosNodeAbstractionIface> node_ptr_;
100 
101  // Call to send NavigateToPose action request for goal poses
102  geometry_msgs::msg::PoseStamped convert_to_msg(
103  std::vector<double> pose,
104  std::vector<double> orientation);
105  void startWaypointFollowing(std::vector<geometry_msgs::msg::PoseStamped> poses);
106  void startNavigation(geometry_msgs::msg::PoseStamped);
107  void startNavThroughPoses(nav_msgs::msg::Goals poses);
108  using NavigationGoalHandle =
109  rclcpp_action::ClientGoalHandle<nav2_msgs::action::NavigateToPose>;
110  using WaypointFollowerGoalHandle =
111  rclcpp_action::ClientGoalHandle<nav2_msgs::action::FollowWaypoints>;
112  using NavThroughPosesGoalHandle =
113  rclcpp_action::ClientGoalHandle<nav2_msgs::action::NavigateThroughPoses>;
114 
115  // The (non-spinning) client node used to invoke the action client
116  rclcpp::Node::SharedPtr client_node_;
117  rclcpp::executors::SingleThreadedExecutor::SharedPtr executor_;
118  // Timeout value when waiting for action servers to respond
119  std::chrono::milliseconds server_timeout_;
120 
121  // A timer used to check on the completion status of the action
122  QBasicTimer timer_;
123 
124  // The NavigateToPose action client
125  nav2::ActionClient<nav2_msgs::action::NavigateToPose>::SharedPtr navigation_action_client_;
126  nav2::ActionClient<nav2_msgs::action::FollowWaypoints>::SharedPtr
127  waypoint_follower_action_client_;
128  nav2::ActionClient<nav2_msgs::action::NavigateThroughPoses>::SharedPtr
129  nav_through_poses_action_client_;
130 
131  // Navigation action feedback subscribers
132  nav2::Subscription<nav2_msgs::action::NavigateToPose::Impl::FeedbackMessage>::SharedPtr
133  navigation_feedback_sub_;
134  nav2::Subscription<nav2_msgs::action::NavigateThroughPoses::Impl::FeedbackMessage>::SharedPtr
135  nav_through_poses_feedback_sub_;
136  nav2::Subscription<nav2_msgs::action::NavigateToPose::Impl::GoalStatusMessage>::SharedPtr
137  navigation_goal_status_sub_;
138  nav2::Subscription<nav2_msgs::action::NavigateThroughPoses::Impl::GoalStatusMessage>::SharedPtr
139  nav_through_poses_goal_status_sub_;
140 
141  // Tf's for initial pose
142  std::shared_ptr<tf2_ros::Buffer> tf2_buffer_;
143  std::shared_ptr<tf2_ros::TransformListener> transform_listener_;
144 
145  // Goal-related state
146  nav2_msgs::action::NavigateToPose::Goal navigation_goal_;
147  nav2_msgs::action::FollowWaypoints::Goal waypoint_follower_goal_;
148  nav2_msgs::action::NavigateThroughPoses::Goal nav_through_poses_goal_;
149  NavigationGoalHandle::SharedPtr navigation_goal_handle_;
150  WaypointFollowerGoalHandle::SharedPtr waypoint_follower_goal_handle_;
151  NavThroughPosesGoalHandle::SharedPtr nav_through_poses_goal_handle_;
152 
153  // The client used to control the nav2 stack
154  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> client_nav_;
155  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> client_loc_;
156 
157  QCheckBox * store_initial_pose_checkbox_{nullptr};
158 
159  QPushButton * start_reset_button_{nullptr};
160  QPushButton * pause_resume_button_{nullptr};
161  QPushButton * navigation_mode_button_{nullptr};
162  QPushButton * save_waypoints_button_{nullptr};
163  QPushButton * load_waypoints_button_{nullptr};
164  QPushButton * pause_waypoint_button_{nullptr};
165 
166  QLabel * navigation_status_indicator_{nullptr};
167  QLabel * localization_status_indicator_{nullptr};
168  QLabel * navigation_goal_status_indicator_{nullptr};
169  QLabel * navigation_feedback_indicator_{nullptr};
170  QLabel * waypoint_status_indicator_{nullptr};
171  QLabel * number_of_loops_{nullptr};
172 
173  QLineEdit * nr_of_loops_{nullptr};
174 
175  QStateMachine state_machine_;
176  InitialThread * initial_thread_;
177 
178  QState * pre_initial_{nullptr};
179  QState * initial_{nullptr};
180  QState * idle_{nullptr};
181  QState * reset_{nullptr};
182  QState * paused_{nullptr};
183  QState * resumed_{nullptr};
184  QState * paused_wp_{nullptr};
185  QState * resumed_wp_{nullptr};
186 
187  QLabel * imgDisplayLabel_{nullptr};
188 
189  // The following states are added to allow for the state of the button to only expose reset
190  // while the NavigateToPoses action is not active. While running, the user will be allowed to
191  // cancel the action. The ROSActionTransition allows for the state of the action to be detected
192  // and the button state to change automatically.
193  QState * running_{nullptr};
194  QState * canceled_{nullptr};
195  // The following states are added to allow to collect several poses to perform a waypoint-mode
196  // navigation or navigate through poses mode.
197  QState * accumulating_{nullptr};
198  QState * accumulated_wp_{nullptr};
199  QState * accumulated_nav_through_poses_{nullptr};
200 
201  nav_msgs::msg::Goals acummulated_poses_;
202  nav_msgs::msg::Goals store_poses_;
203 
204  // Publish the visual markers with the waypoints
205  void updateWpNavigationMarkers();
206 
207  // Create unique id numbers for markers
208  int getUniqueId();
209 
210  void resetUniqueId();
211 
212  // create label string from feedback msg
213  static inline QString getNavToPoseFeedbackLabel(
214  nav2_msgs::action::NavigateToPose::Feedback msg =
215  nav2_msgs::action::NavigateToPose::Feedback());
216  static inline QString getNavThroughPosesFeedbackLabel(
217  nav2_msgs::action::NavigateThroughPoses::Feedback =
218  nav2_msgs::action::NavigateThroughPoses::Feedback());
219  template<typename T>
220  static inline std::string toLabel(T & msg);
221 
222  // round off double to the specified precision and convert to string
223  static inline std::string toString(double val, int precision = 0);
224 
225  // Waypoint navigation visual markers publisher
226  rclcpp::Publisher<visualization_msgs::msg::MarkerArray>::SharedPtr wp_navigation_markers_pub_;
227 };
228 
229 class InitialThread : public QThread
230 {
231  Q_OBJECT
232 
233 public:
234  using SystemStatus = nav2_lifecycle_manager::SystemStatus;
235 
236  explicit InitialThread(
237  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> & client_nav,
238  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> & client_loc)
239  : client_nav_(client_nav), client_loc_(client_loc)
240  {}
241 
242  void run() override
243  {
244  SystemStatus status_nav = SystemStatus::TIMEOUT;
245  SystemStatus status_loc = SystemStatus::TIMEOUT;
246 
247  while (status_nav == SystemStatus::TIMEOUT) {
248  if (status_nav == SystemStatus::TIMEOUT) {
249  status_nav = client_nav_->is_active(std::chrono::seconds(1));
250  }
251  }
252 
253  // try to communicate twice, might not actually be up if in SLAM mode
254  bool tried_loc_bringup_once = false;
255  while (status_loc == SystemStatus::TIMEOUT) {
256  status_loc = client_loc_->is_active(std::chrono::seconds(1));
257  if (tried_loc_bringup_once) {
258  break;
259  }
260  tried_loc_bringup_once = true;
261  }
262 
263  if (status_nav == SystemStatus::ACTIVE) {
264  emit navigationActive();
265  } else {
266  emit navigationInactive();
267  }
268 
269  if (status_loc == SystemStatus::ACTIVE) {
270  emit localizationActive();
271  } else {
272  emit localizationInactive();
273  }
274  }
275 
276 signals:
277  void navigationActive();
278  void navigationInactive();
279  void localizationActive();
280  void localizationInactive();
281 
282 private:
283  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> client_nav_;
284  std::shared_ptr<nav2_lifecycle_manager::LifecycleManagerClient> client_loc_;
285 };
286 
287 } // namespace nav2_rviz_plugins
288 
289 #endif // NAV2_RVIZ_PLUGINS__NAV2_PANEL_HPP_
Panel to interface to the nav2 stack.
Definition: nav2_panel.hpp:53
void load(const rviz_common::Config &config) override
Load and save configuration data.