Nav2 Navigation Stack - lyrical  lyrical
ROS 2 Navigation Stack
selector.cpp
1 // Copyright (c) 2024 Neobotix GmbH
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 #include "nav2_rviz_plugins/selector.hpp"
16 #include "nav2_rviz_plugins/utils.hpp"
17 #include "rviz_common/display_context.hpp"
18 
19 using namespace std::chrono_literals;
20 
21 namespace nav2_rviz_plugins
22 {
23 Selector::Selector(QWidget * parent)
24 : Panel(parent)
25 {
26  client_node_ = std::make_shared<rclcpp::Node>("nav2_rviz_selector_node"); // nosemgrep
27  rclcpp::QoS qos(rclcpp::KeepLast(1));
28  qos.transient_local().reliable();
29 
30  pub_controller_ =
31  client_node_->create_publisher<std_msgs::msg::String>("controller_selector", qos);
32  pub_planner_ = client_node_->create_publisher<std_msgs::msg::String>("planner_selector", qos);
33  pub_goal_checker_ =
34  client_node_->create_publisher<std_msgs::msg::String>("goal_checker_selector", qos);
35  pub_smoother_ = client_node_->create_publisher<std_msgs::msg::String>("smoother_selector", qos);
36  pub_progress_checker_ =
37  client_node_->create_publisher<std_msgs::msg::String>("progress_checker_selector", qos);
38  pub_path_handler_ =
39  client_node_->create_publisher<std_msgs::msg::String>("path_handler_selector", qos);
40 
41  main_layout_ = new QVBoxLayout;
42  row_1_label_layout_ = new QHBoxLayout;
43  row_2_label_layout_ = new QHBoxLayout;
44  row_3_label_layout_ = new QHBoxLayout;
45  row_1_layout_ = new QHBoxLayout;
46  row_2_layout_ = new QHBoxLayout;
47  row_3_layout_ = new QHBoxLayout;
48  controller_ = new QComboBox;
49  planner_ = new QComboBox;
50  goal_checker_ = new QComboBox;
51  smoother_ = new QComboBox;
52  progress_checker_ = new QComboBox;
53  path_handler_ = new QComboBox;
54 
55  main_layout_->setContentsMargins(10, 10, 10, 10);
56 
57  row_1_label_layout_->addWidget(new QLabel("Controller"));
58  row_1_layout_->addWidget(controller_);
59  row_1_label_layout_->addWidget(new QLabel("Planner"));
60  row_1_layout_->addWidget(planner_);
61  row_2_label_layout_->addWidget(new QLabel("Goal Checker"));
62  row_2_layout_->addWidget(goal_checker_);
63  row_2_label_layout_->addWidget(new QLabel("Smoother"));
64  row_2_layout_->addWidget(smoother_);
65  row_3_label_layout_->addWidget(new QLabel("Progress Checker"));
66  row_3_layout_->addWidget(progress_checker_);
67  row_3_label_layout_->addWidget(new QLabel("Path Handler"));
68  row_3_layout_->addWidget(path_handler_);
69 
70  main_layout_->addLayout(row_1_label_layout_);
71  main_layout_->addLayout(row_1_layout_);
72  main_layout_->addLayout(row_2_label_layout_);
73  main_layout_->addLayout(row_2_layout_);
74  main_layout_->addLayout(row_3_label_layout_);
75  main_layout_->addLayout(row_3_layout_);
76 
77  setLayout(main_layout_);
78  loadPlugins();
79 
80  connect(
81  controller_, QOverload<int>::of(&QComboBox::activated), this,
82  &Selector::setController);
83 
84  connect(
85  planner_, QOverload<int>::of(&QComboBox::activated), this,
86  &Selector::setPlanner);
87 
88  connect(
89  goal_checker_, QOverload<int>::of(&QComboBox::activated), this,
90  &Selector::setGoalChecker);
91 
92  connect(
93  smoother_, QOverload<int>::of(&QComboBox::activated), this,
94  &Selector::setSmoother);
95 
96  connect(
97  progress_checker_, QOverload<int>::of(&QComboBox::activated), this,
98  &Selector::setProgressChecker);
99 
100  connect(
101  path_handler_, QOverload<int>::of(&QComboBox::activated), this,
102  &Selector::setPathHandler);
103 }
104 
105 Selector::~Selector()
106 {
107  if (load_plugins_thread_.joinable()) {
108  load_plugins_thread_.join();
109  }
110 }
111 
112 // Publish the selected controller or planner
113 void Selector::setSelection(
114  QComboBox * combo_box,
115  rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher) // nosemgrep
116 {
117  // If "default" option is selected, it gets removed and the next item is selected
118  if (combo_box->findText("Default") != -1) {
119  combo_box->removeItem(0);
120  }
121 
122  // if there are no plugins available, return
123  if (combo_box->count() == 0) {
124  return;
125  }
126 
127  auto msg = std::make_unique<std_msgs::msg::String>();
128  msg->data = combo_box->currentText().toStdString();
129 
130  publisher->publish(std::move(msg));
131 }
132 
133 // Call setSelection() for controller
134 void Selector::setController()
135 {
136  setSelection(controller_, pub_controller_);
137 }
138 
139 // Call setSelection() for planner
140 void Selector::setPlanner()
141 {
142  setSelection(planner_, pub_planner_);
143 }
144 
145 // Call setSelection() for goal checker
146 void Selector::setGoalChecker()
147 {
148  setSelection(goal_checker_, pub_goal_checker_);
149 }
150 
151 // Call setSelection() for smoother
152 void Selector::setSmoother()
153 {
154  setSelection(smoother_, pub_smoother_);
155 }
156 
157 void Selector::setProgressChecker()
158 {
159  setSelection(progress_checker_, pub_progress_checker_);
160 }
161 
162 void Selector::setPathHandler()
163 {
164  setSelection(path_handler_, pub_path_handler_);
165 }
166 
167 void
168 Selector::loadPlugins()
169 {
170  load_plugins_thread_ = std::thread(
171  [this]() {
172  rclcpp::Rate rate(0.2);
173  while (rclcpp::ok() && !plugins_loaded_) {
174  RCLCPP_INFO(client_node_->get_logger(), "Trying to load plugins...");
175  nav2_rviz_plugins::pluginLoader(
176  client_node_, server_failed_, "controller_server", "controller_plugins", controller_);
177  nav2_rviz_plugins::pluginLoader(
178  client_node_, server_failed_, "planner_server", "planner_plugins", planner_);
179  nav2_rviz_plugins::pluginLoader(
180  client_node_, server_failed_, "controller_server", "goal_checker_plugins",
181  goal_checker_);
182  nav2_rviz_plugins::pluginLoader(
183  client_node_, server_failed_, "smoother_server", "smoother_plugins", smoother_);
184  nav2_rviz_plugins::pluginLoader(
185  client_node_, server_failed_, "controller_server", "progress_checker_plugins",
186  progress_checker_);
187  nav2_rviz_plugins::pluginLoader(
188  client_node_, server_failed_, "controller_server", "path_handler_plugins",
189  path_handler_);
190  if (controller_->count() > 0 &&
191  planner_->count() > 0 &&
192  goal_checker_->count() > 0 &&
193  smoother_->count() > 0 &&
194  progress_checker_->count() > 0 &&
195  path_handler_->count() > 0)
196  {
197  plugins_loaded_ = true;
198  } else {
199  RCLCPP_INFO(client_node_->get_logger(), "Failed to load plugins. Retrying...");
200  }
201  rate.sleep();
202  }
203  });
204 }
205 
206 } // namespace nav2_rviz_plugins
207 #include "pluginlib/class_list_macros.hpp"
208 PLUGINLIB_EXPORT_CLASS(nav2_rviz_plugins::Selector, rviz_common::Panel)