moveit2
The MoveIt Motion Planning Framework for ROS 2.
setup_assistant_widget.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  * Copyright (c) 2012, Willow Garage, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above
14  * copyright notice, this list of conditions and the following
15  * disclaimer in the documentation and/or other materials provided
16  * with the distribution.
17  * * Neither the name of Willow Garage nor the names of its
18  * contributors may be used to endorse or promote products derived
19  * from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *********************************************************************/
34 
35 /* Author: Dave Coleman */
36 
37 // SA
39 
40 // Qt
41 #include <QApplication>
42 #include <QCloseEvent>
43 #include <QHBoxLayout>
44 #include <QMessageBox>
45 #include <QPushButton>
46 #include <QSplitter>
47 #include <QStackedWidget>
48 #include <QString>
49 #include <pluginlib/class_loader.hpp> // for loading all avail kinematic planners
50 
51 namespace moveit_setup
52 {
53 namespace assistant
54 {
55 // ******************************************************************************************
56 // Outer User Interface for MoveIt Configuration Assistant
57 // ******************************************************************************************
58 SetupAssistantWidget::SetupAssistantWidget(const rviz_common::ros_integration::RosNodeAbstractionIface::WeakPtr& node,
59  QWidget* parent, const boost::program_options::variables_map& args)
60  : QWidget(parent)
61  , node_abstraction_(node)
62  , node_(node_abstraction_.lock()->get_raw_node())
63  , widget_loader_("moveit_setup_framework", "moveit_setup::SetupStepWidget")
64 {
65  // Create object to hold all MoveIt configuration data
66  config_data_ = std::make_shared<DataWarehouse>(node_);
67 
68  // Set debug mode flag if necessary
69  if (args.count("debug"))
70  config_data_->debug = true;
71 
72  // Setting the window icon
73  auto icon_path = getSharePath("moveit_ros_visualization") / "icons/classes/MotionPlanning.png";
74  setWindowIcon(QIcon(icon_path.c_str()));
75 
76  // Basic widget container -----------------------------------------
77  QHBoxLayout* layout = new QHBoxLayout();
78  layout->setAlignment(Qt::AlignTop);
79 
80  // Create main content stack for various screens
81  main_content_ = new QStackedWidget();
82  current_index_ = -1;
83 
84  // Setup Steps --------------------------------------------------------
85  std::vector<std::string> setup_steps;
86  // TODO: The list of setup steps should be read from a parameter with some as the default
87  // TODO: (or be configured dynamically in some other step)
88  setup_steps.push_back("moveit_setup::core::StartScreenWidget");
89  setup_steps.push_back("moveit_setup::srdf_setup::DefaultCollisionsWidget");
90  setup_steps.push_back("moveit_setup::srdf_setup::VirtualJointsWidget");
91  setup_steps.push_back("moveit_setup::srdf_setup::PlanningGroupsWidget");
92  setup_steps.push_back("moveit_setup::srdf_setup::RobotPosesWidget");
93  setup_steps.push_back("moveit_setup::srdf_setup::EndEffectorsWidget");
94  setup_steps.push_back("moveit_setup::srdf_setup::PassiveJointsWidget");
95  setup_steps.push_back("moveit_setup::controllers::UrdfModificationsWidget");
96  setup_steps.push_back("moveit_setup::controllers::ROS2ControllersWidget");
97  setup_steps.push_back("moveit_setup::controllers::MoveItControllersWidget");
98  // setup_steps.push_back("moveit_setup::simulation::SimulationWidget");
99  setup_steps.push_back("moveit_setup::app::PerceptionWidget");
100  setup_steps.push_back("moveit_setup::app::LaunchesWidget");
101  setup_steps.push_back("moveit_setup::core::AuthorInformationWidget");
102  setup_steps.push_back("moveit_setup::core::ConfigurationFilesWidget");
103  node_->declare_parameter("setup_steps", setup_steps);
104  setup_steps = node_->get_parameter("setup_steps").as_string_array();
105 
106  // Rviz View Right Pane ---------------------------------------------------
107  rviz_panel_ = new RVizPanel(this, node_abstraction_, config_data_);
108  rviz_panel_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
109  rviz_panel_->hide(); // do not show until after the start screen
110 
111  for (const std::string& step_class : setup_steps)
112  {
113  auto widget = widget_loader_.createSharedInstance(step_class);
114  widget->initialize(node_, this, rviz_panel_, config_data_);
115 
116  connect(widget.get(), SIGNAL(dataUpdated()), this, SLOT(onDataUpdate()));
117  connect(widget.get(), SIGNAL(advanceRequest()), this, SLOT(onAdvanceRequest()));
118  connect(widget.get(), SIGNAL(setModalMode(bool)), this, SLOT(onModalModeUpdate(bool)));
119  const std::string name = widget->getSetupStep().getName();
120  steps_.push_back(widget);
121 
122  main_content_->addWidget(widget.get());
123 
124  nav_name_list_ << name.c_str();
125  }
126 
127  // Pass command arg values to start screen and show appropriate part of screen
128  if (args.count("urdf_path"))
129  {
130  config_data_->preloadWithURDFPath(args["urdf_path"].as<std::filesystem::path>());
131  }
132  if (args.count("config_pkg"))
133  {
134  config_data_->preloadWithFullConfig(args["config_pkg"].as<std::string>());
135  }
136 
137  // Navigation Left Pane --------------------------------------------------
138  navs_view_ = new NavigationWidget(this);
139  navs_view_->setNavs(nav_name_list_);
140  if (!steps_.empty())
141  {
142  navs_view_->setEnabled(0, true);
143  moveToScreen(0);
144  }
145 
146  // Split screen -----------------------------------------------------
147  splitter_ = new QSplitter(Qt::Horizontal, this);
148  splitter_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
149  splitter_->addWidget(navs_view_);
150  splitter_->addWidget(main_content_);
151  splitter_->addWidget(rviz_panel_);
152  splitter_->setHandleWidth(6);
153  // splitter_->setCollapsible( 0, false ); // don't let navigation collapse
154  layout->addWidget(splitter_);
155 
156  // Add event for switching between screens -------------------------
157  connect(navs_view_, SIGNAL(clicked(const QModelIndex&)), this, SLOT(navigationClicked(const QModelIndex&)));
158 
159  // Final Layout Setup ---------------------------------------------
160  setLayout(layout);
161 
162  // Title
163  setWindowTitle("MoveIt Setup Assistant"); // title of window
164 
165  // Show screen before message
166  QApplication::processEvents();
167 }
168 
169 // ******************************************************************************************
170 // Change screens of Setup Assistant
171 // ******************************************************************************************
172 void SetupAssistantWidget::navigationClicked(const QModelIndex& index)
173 {
174  // Convert QModelIndex to int
175  moveToScreen(index.row());
176 }
177 
178 void SetupAssistantWidget::onDataUpdate()
179 {
180  for (size_t index = 0; index < steps_.size(); index++)
181  {
182  bool ready = steps_[index]->isReady();
183  navs_view_->setEnabled(index, ready);
184  }
185 
186  if (rviz_panel_->isReadyForInitialization())
187  {
188  rviz_panel_->initialize();
189  // Replace logo with Rviz screen
190  rviz_panel_->show();
191  }
192 }
193 
194 void SetupAssistantWidget::onAdvanceRequest()
195 {
196  if (static_cast<unsigned int>(current_index_ + 1) < steps_.size())
197  {
198  moveToScreen(current_index_ + 1);
199  }
200 }
201 
202 // ******************************************************************************************
203 // Change screens
204 // ******************************************************************************************
206 {
207  std::scoped_lock slock(change_screen_lock_);
208  if (!navs_view_->isEnabled(index))
209  {
210  return;
211  }
212 
213  if (current_index_ != index)
214  {
215  // Send the focus lost command to the screen widget
216  if (current_index_ >= 0)
217  {
218  auto ssw = steps_[current_index_];
219  if (!ssw->focusLost())
220  {
221  navs_view_->setSelected(current_index_);
222  return; // switching not accepted
223  }
224  }
225 
226  current_index_ = index;
227 
228  // Unhighlight anything on robot
229  rviz_panel_->unhighlightAll();
230 
231  // Change screens
232  main_content_->setCurrentIndex(index);
233 
234  // Send the focus given command to the screen widget
235  steps_[current_index_]->focusGiven();
236 
237  // Change navigation selected option
238  navs_view_->setSelected(index);
239  }
240 }
241 
242 // ******************************************************************************************
243 // Ping ROS on interval
244 // ******************************************************************************************
245 void SetupAssistantWidget::updateTimer()
246 {
247  // TODO: Figure out if there's a ROS 2 equivalent of this that needs to be run
248  // ros::spinOnce(); // keep ROS node alive
249 }
250 
251 // ******************************************************************************************
252 // Qt close event function for reminding user to save
253 // ******************************************************************************************
254 void SetupAssistantWidget::closeEvent(QCloseEvent* event)
255 {
256  // Only prompt to close if not in debug mode
257  if (!config_data_->debug)
258  {
259  if (QMessageBox::question(this, "Exit Setup Assistant",
260  QString("Are you sure you want to exit the MoveIt Setup Assistant?"),
261  QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
262  {
263  event->ignore();
264  return;
265  }
266  }
267 
268  // Shutdown app
269  event->accept();
270 }
271 
272 // ******************************************************************************************
273 // Qt Error Handling - TODO
274 // ******************************************************************************************
275 bool SetupAssistantWidget::notify(QObject* /*receiver*/, QEvent* /*event*/)
276 {
277  QMessageBox::critical(this, "Error", "An error occurred and was caught by Qt notify event handler.", QMessageBox::Ok);
278 
279  return false;
280 }
281 
282 // ******************************************************************************************
283 // Change the widget modal state based on subwidgets state
284 // ******************************************************************************************
285 void SetupAssistantWidget::onModalModeUpdate(bool isModal)
286 {
287  navs_view_->setDisabled(isModal);
288 
289  for (int i = 0; i < nav_name_list_.count(); ++i)
290  {
291  navs_view_->setEnabled(i, !isModal && steps_[i]->isReady());
292  }
293 }
294 
295 } // namespace assistant
296 } // namespace moveit_setup
bool isReadyForInitialization() const
Definition: rviz_panel.hpp:65
void setNavs(const QList< QString > &navs)
void setEnabled(int index, bool enabled)
SetupAssistantWidget(const rviz_common::ros_integration::RosNodeAbstractionIface::WeakPtr &node, QWidget *parent, const boost::program_options::variables_map &args)
virtual bool notify(QObject *rec, QEvent *ev)
std::filesystem::path getSharePath(const std::string &package_name)
Return a path for the given package's share folder.
Definition: utilities.hpp:51
name
Definition: setup.py:7