moveit2
The MoveIt Motion Planning Framework for ROS 2.
start_screen_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 // Qt
38 #include <QApplication>
39 #include <QFileDialog>
40 #include <QFont>
41 #include <QHBoxLayout>
42 #include <QLabel>
43 #include <QLineEdit>
44 #include <QMessageBox>
45 #include <QProgressBar>
46 #include <QPushButton>
47 #include <QString>
48 #include <QTextEdit>
49 #include <QTimer>
50 #include <QVBoxLayout>
51 
52 // SA
54 // C
55 #include <fstream> // for reading in urdf
56 #include <streambuf>
57 
58 namespace moveit_setup
59 {
60 namespace core
61 {
62 // ******************************************************************************************
63 // Start screen user interface for MoveIt Configuration Assistant
64 // ******************************************************************************************
66 {
67  // Basic widget container
68  QVBoxLayout* layout = new QVBoxLayout(this);
69 
70  // Horizontal layout splitter
71  QHBoxLayout* hlayout = new QHBoxLayout();
72  // Left side of screen
73  QVBoxLayout* left_layout = new QVBoxLayout();
74  // Right side of screen
75  QVBoxLayout* right_layout = new QVBoxLayout();
76 
77  // Right Image Area ----------------------------------------------
78  right_image_ = new QImage();
79  right_image_label_ = new QLabel(this);
80  auto image_path = getSharePath("moveit_setup_assistant") / "resources/MoveIt_Setup_Assistant2.png";
81 
82  if (right_image_->load(image_path.c_str()))
83  {
84  right_image_label_->setPixmap(QPixmap::fromImage(*right_image_));
85  right_image_label_->setMinimumHeight(384); // size of right_image_label_
86  }
87  else
88  {
89  RCLCPP_ERROR_STREAM(setup_step_.getLogger(), "FAILED TO LOAD " << image_path);
90  }
91 
92  right_layout->addWidget(right_image_label_);
93  right_layout->setAlignment(right_image_label_, Qt::AlignRight | Qt::AlignTop);
94 
95  // Top Label Area ---------------------------------------------------
96  HeaderWidget* header = new HeaderWidget(
97  "MoveIt Setup Assistant",
98  "These tools will assist you in creating a Semantic Robot Description Format (SRDF) file, various yaml "
99  "configuration and many roslaunch files for utilizing all aspects of MoveIt functionality.",
100  this);
101  layout->addWidget(header);
102 
103  // Select Mode Area -------------------------------------------------
104  select_mode_ = new SelectModeWidget(this);
105  connect(select_mode_->btn_new_, SIGNAL(clicked()), this, SLOT(showNewOptions()));
106  connect(select_mode_->btn_exist_, SIGNAL(clicked()), this, SLOT(showExistingOptions()));
107  left_layout->addWidget(select_mode_);
108 
109  // Path Box Area ----------------------------------------------------
110 
111  // Stack Path Dialog
112  stack_path_ = new LoadPathArgsWidget("Load MoveIt Configuration Package",
113  "Specify the package name or path of an existing MoveIt configuration package "
114  "to be edited for your robot. Example package name: <i>panda_moveit_config</i>",
115  "optional xacro arguments:", this, true); // directory
116  // user needs to select option before this is shown
117  stack_path_->hide();
118  stack_path_->setArgs("");
119  connect(stack_path_, SIGNAL(pathChanged(QString)), this, SLOT(onPackagePathChanged(QString)));
120  left_layout->addWidget(stack_path_);
121 
122  // URDF File Dialog
124  "Load a URDF or COLLADA Robot Model",
125  "Specify the location of an existing Universal Robot Description Format or COLLADA file for your robot",
126  "optional xacro arguments:", this, false, true); // no directory, load only
127  // user needs to select option before this is shown
128  urdf_file_->hide();
129  urdf_file_->setArgs("");
130  connect(urdf_file_, SIGNAL(pathChanged(QString)), this, SLOT(onUrdfPathChanged(QString)));
131  left_layout->addWidget(urdf_file_);
132 
133  // Load settings box ---------------------------------------------
134  QHBoxLayout* load_files_layout = new QHBoxLayout();
135 
136  progress_bar_ = new QProgressBar(this);
137  progress_bar_->setMaximum(100);
138  progress_bar_->setMinimum(0);
139  progress_bar_->hide();
140  load_files_layout->addWidget(progress_bar_);
141 
142  btn_load_ = new QPushButton("&Load Files", this);
143  btn_load_->setMinimumWidth(180);
144  btn_load_->setMinimumHeight(40);
145  btn_load_->hide();
146  load_files_layout->addWidget(btn_load_);
147  load_files_layout->setAlignment(btn_load_, Qt::AlignRight);
148  connect(btn_load_, SIGNAL(clicked()), this, SLOT(loadFilesClick()));
149 
150  // Next step instructions
151  next_label_ = new QLabel(this);
152  QFont next_label_font(QFont().defaultFamily(), 11, QFont::Bold);
153  next_label_->setFont(next_label_font);
154  next_label_->setText("Success! Use the left navigation pane to continue.");
155  next_label_->hide(); // only show once the files have been loaded.
156 
157  // Final Layout Setup ---------------------------------------------
158  // Alignment
159  layout->setAlignment(Qt::AlignTop);
160  hlayout->setAlignment(Qt::AlignTop);
161  left_layout->setAlignment(Qt::AlignTop);
162  right_layout->setAlignment(Qt::AlignTop);
163 
164  // Stretch
165  left_layout->setSpacing(10);
166 
167  // Attach Layouts
168  hlayout->addLayout(left_layout);
169  hlayout->addLayout(right_layout);
170  layout->addLayout(hlayout);
171 
172  // Vertical Spacer
173  layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
174 
175  // Attach bottom layout
176  layout->addWidget(next_label_);
177  layout->setAlignment(next_label_, Qt::AlignRight);
178  layout->addLayout(load_files_layout);
179 
180  setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
181  this->setLayout(layout);
182 
183  // Debug mode: auto load the configuration file by clicking button after a timeout
184  if (debug_)
185  {
186  // select_mode_->btn_exist_->click();
187 
188  QTimer* update_timer = new QTimer(this);
189  update_timer->setSingleShot(true); // only run once
190  connect(update_timer, SIGNAL(timeout()), btn_load_, SLOT(click()));
191  update_timer->start(100);
192  }
193 }
194 
195 // ******************************************************************************************
196 // Destructor
197 // ******************************************************************************************
199 {
200  delete right_image_; // does not have a parent passed to it
201 }
202 
204 {
205  std::filesystem::path pkg_path = setup_step_.getPackagePath();
206  if (!pkg_path.empty())
207  {
208  stack_path_->setPath(pkg_path);
209  select_mode_->btn_exist_->click();
210  return;
211  }
212 
213  std::filesystem::path urdf_path = setup_step_.getURDFPath();
214  if (!urdf_path.empty())
215  {
216  urdf_file_->setPath(urdf_path);
217  select_mode_->btn_new_->click();
218  }
219 }
220 
221 // ******************************************************************************************
222 // Show options for creating a new configuration package
223 // ******************************************************************************************
224 void StartScreenWidget::showNewOptions()
225 {
226  // Do GUI stuff
227  select_mode_->btn_exist_->setChecked(false);
228  select_mode_->btn_new_->setChecked(true);
230  urdf_file_->show();
231  stack_path_->hide();
232  btn_load_->show();
233 
234  // Remember choice
235  create_new_package_ = true;
236 }
237 
238 // ******************************************************************************************
239 // Show options for editing an existing configuration package
240 // ******************************************************************************************
241 void StartScreenWidget::showExistingOptions()
242 {
243  // Do GUI stuff
244  select_mode_->btn_exist_->setChecked(true);
245  select_mode_->btn_new_->setChecked(false);
247  urdf_file_->hide();
248  stack_path_->show();
249  btn_load_->show();
250 
251  // Remember choice
252  create_new_package_ = false;
253 }
254 
255 // ******************************************************************************************
256 // Load files to parameter server - CLICK
257 // ******************************************************************************************
258 void StartScreenWidget::loadFilesClick()
259 {
260  // Disable start screen GUI components from being changed
261  urdf_file_->setDisabled(true);
262  // srdf_file_->setDisabled(true);
263  stack_path_->setDisabled(true);
264  select_mode_->setDisabled(true);
265  btn_load_->setDisabled(true);
266  progress_bar_->show();
267 
268  bool result;
269 
270  // Decide if this is a new config package, or loading an old one
271  if (create_new_package_)
272  {
273  result = loadNewFiles();
274  }
275  else
276  {
277  result = loadExistingFiles();
278  }
279 
280  // Check if there was a failure loading files
281  if (!result)
282  {
283  // Renable components
284  urdf_file_->setDisabled(false);
285  // srdf_file_->setDisabled(false);
286  stack_path_->setDisabled(false);
287  select_mode_->setDisabled(false);
288  btn_load_->setDisabled(false);
289  progress_bar_->hide();
290  }
291  else
292  {
293  // Hide the logo image so that other screens can resize the rviz thing properly
294  right_image_label_->hide();
295  }
296 }
297 
298 void StartScreenWidget::onPackagePathChanged(const QString& /*path*/)
299 {
300  if (!loadPackageSettings(false))
301  return;
302  // set xacro args from loaded settings
303  stack_path_->setArgs(QString::fromStdString(setup_step_.getXacroArgs()));
304 }
305 
306 void StartScreenWidget::onUrdfPathChanged(const QString& path)
307 {
308  setup_step_.loadURDFFile(path.toStdString(), urdf_file_->getArgs().toStdString());
309  urdf_file_->setArgsEnabled(setup_step_.isXacroFile());
310 }
311 
312 bool StartScreenWidget::loadPackageSettings(bool show_warnings)
313 {
314  // Get the package path
315  std::filesystem::path package_path_input = stack_path_->getPath();
316 
317  try
318  {
319  setup_step_.loadExisting(package_path_input);
320  return true;
321  }
322  catch (const std::runtime_error& e)
323  {
324  if (show_warnings)
325  QMessageBox::warning(this, "Error Loading Files", e.what());
326  return false;
327  }
328 }
329 
330 // ******************************************************************************************
331 // Load existing package files
332 // ******************************************************************************************
333 bool StartScreenWidget::loadExistingFiles()
334 {
335  try
336  {
337  // Progress Indicator
338  progress_bar_->setValue(10);
339  QApplication::processEvents();
340 
341  if (!loadPackageSettings(true))
342  return false;
343  }
344  catch (const std::runtime_error& e)
345  {
346  QMessageBox::warning(this, "Error Loading SRDF", QString(e.what()));
347  RCLCPP_ERROR(setup_step_.getLogger(), "%s", e.what());
348  return false;
349  }
350 
351  // Progress Indicator
352  progress_bar_->setValue(100);
353  QApplication::processEvents();
354 
355  next_label_->show(); // only show once the files have been loaded
356  Q_EMIT dataUpdated();
357 
358  RCLCPP_INFO(setup_step_.getLogger(), "Loading Setup Assistant Complete");
359 
360  Q_EMIT advanceRequest();
361  return true; // success!
362 }
363 
364 // ******************************************************************************************
365 // Load chosen files for creating new package
366 // ******************************************************************************************
367 bool StartScreenWidget::loadNewFiles()
368 {
369  // Get URDF file path
370  std::filesystem::path urdf_path = urdf_file_->getPath();
371 
372  // Check that box is filled out
373  if (urdf_path.empty())
374  {
375  QMessageBox::warning(this, "Error Loading Files", "No robot model file specified");
376  return false;
377  }
378 
379  // Check that this file exits
380  if (!std::filesystem::is_regular_file(urdf_path))
381  {
382  QMessageBox::warning(this, "Error Loading Files",
383  QString("Unable to locate the URDF file: ").append(urdf_path.c_str()));
384  return false;
385  }
386 
387  // Progress Indicator
388  progress_bar_->setValue(20);
389  QApplication::processEvents();
390 
391  // use xacro args from GUI
392  std::string xacro_args = urdf_file_->getArgs().toStdString();
393  try
394  {
395  setup_step_.loadURDFFile(urdf_path, xacro_args);
396  }
397  catch (const std::runtime_error& e)
398  {
399  QMessageBox::warning(this, "Error Loading URDF", QString(e.what()));
400  return false;
401  }
402 
403  // Progress Indicator
404  progress_bar_->setValue(50);
405  QApplication::processEvents();
406 
407  // DONE LOADING --------------------------------------------------------------------------
408 
409  // Call a function that enables navigation
410  Q_EMIT dataUpdated();
411 
412  // Progress Indicator
413  progress_bar_->setValue(70);
414  QApplication::processEvents();
415 
416  // Progress Indicator
417  progress_bar_->setValue(100);
418  QApplication::processEvents();
419 
420  next_label_->show(); // only show once the files have been loaded
421 
422  RCLCPP_INFO(setup_step_.getLogger(), "Loading Setup Assistant Complete");
423  return true; // success!
424 }
425 
426 // ******************************************************************************************
427 // ******************************************************************************************
428 // Class for selecting which mode
429 // ******************************************************************************************
430 // ******************************************************************************************
431 
432 // ******************************************************************************************
433 // Create the widget
434 // ******************************************************************************************
435 SelectModeWidget::SelectModeWidget(QWidget* parent) : QFrame(parent)
436 {
437  // Set frame graphics
438  setFrameShape(QFrame::StyledPanel);
439  setFrameShadow(QFrame::Raised);
440  setLineWidth(1);
441  setMidLineWidth(0);
442 
443  // Basic widget container
444  QVBoxLayout* layout = new QVBoxLayout(this);
445 
446  // Horizontal layout splitter
447  QHBoxLayout* hlayout = new QHBoxLayout();
448 
449  // Widget Title
450  QLabel* widget_title = new QLabel(this);
451  widget_title->setText("Create new or edit existing?");
452  QFont widget_title_font(QFont().defaultFamily(), 12, QFont::Bold);
453  widget_title->setFont(widget_title_font);
454  layout->addWidget(widget_title);
455  layout->setAlignment(widget_title, Qt::AlignTop);
456 
457  // Widget Instructions
458  widget_instructions_ = new QLabel(this);
459  widget_instructions_->setAlignment(Qt::AlignLeft | Qt::AlignTop);
460  widget_instructions_->setWordWrap(true);
461  widget_instructions_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
462  widget_instructions_->setText(
463  "All settings for MoveIt are stored in the MoveIt configuration package. Here you have the option to create a "
464  "new configuration package or load an existing one. Note: changes to a MoveIt configuration package outside this "
465  "Setup Assistant are likely to be overwritten by this tool.");
466 
467  layout->addWidget(widget_instructions_);
468  layout->setAlignment(widget_instructions_, Qt::AlignTop);
469 
470  // New Button
471  btn_new_ = new QPushButton(this);
472  btn_new_->setText("Create &New MoveIt\nConfiguration Package");
473  hlayout->addWidget(btn_new_);
474 
475  // Exist Button
476  btn_exist_ = new QPushButton(this);
477  btn_exist_->setText("&Edit Existing MoveIt\nConfiguration Package");
478  btn_exist_->setCheckable(true);
479  hlayout->addWidget(btn_exist_);
480 
481  // Add horizontal layer to vertical layer
482  layout->addLayout(hlayout);
483  setLayout(layout);
484  btn_new_->setCheckable(true);
485 }
486 
487 } // namespace core
488 } // namespace moveit_setup
489 
490 #include <pluginlib/class_list_macros.hpp> // NOLINT
PLUGINLIB_EXPORT_CLASS(cached_ik_kinematics_plugin::CachedIKKinematicsPlugin< kdl_kinematics_plugin::KDLKinematicsPlugin >, kinematics::KinematicsBase)
Extend LoadPathWidget with additional line edit for arguments.
void setArgsEnabled(bool enabled=true)
void setArgs(const QString &args)
void setPath(const QString &path)
Set the path with QString.
std::string getPath() const
Returns the file path in std::string format.
The GUI code for one SetupStep.
void dataUpdated()
When the underlying data has been updated (which can cause other steps to become "Ready")
void advanceRequest()
When this signal is received, the GUI should attempt to advance to the next step.
const rclcpp::Logger & getLogger() const
Makes a namespaced logger for this step available to the widget.
Definition: setup_step.hpp:91
Start screen user interface for MoveIt Configuration Assistant.
void focusGiven() override
function called when widget is activated, allows to update/initialize GUI
std::filesystem::path getURDFPath()
void loadURDFFile(const std::filesystem::path &urdf_file_path, const std::string &xacro_args)
std::filesystem::path getPackagePath()
void loadExisting(const std::filesystem::path &package_path)
std::filesystem::path getSharePath(const std::string &package_name)
Return a path for the given package's share folder.
Definition: utilities.hpp:50
std::string append(const std::string &left, const std::string &right)