group_edit_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 #include <QComboBox>
38 #include <QFileDialog>
39 #include <QFormLayout>
40 #include <QGroupBox>
41 #include <QHBoxLayout>
42 #include <QLabel>
43 #include <QLineEdit>
44 #include <QDoubleSpinBox>
45 #include <QMessageBox>
46 #include <QPushButton>
47 #include <QString>
48 #include <QVBoxLayout>
49 
50 #include "group_edit_widget.h"
52 #include <pluginlib/class_loader.hpp> // for loading all avail kinematic planners
53 
54 namespace moveit_setup_assistant
55 {
56 // ******************************************************************************************
57 // Constructor
58 // ******************************************************************************************
59 GroupEditWidget::GroupEditWidget(QWidget* parent, const MoveItConfigDataPtr& config_data)
60  : QWidget(parent), config_data_(config_data)
61 {
62  auto add_line_edit = [this](QFormLayout* form, const QString& label) {
63  QLineEdit* field = new QLineEdit(this);
64  field->setMaximumWidth(FORM_CONTROL_WIDTH);
65  form->addRow(label, field);
66  return field;
67  };
68 
69  auto add_spin_box = [this](QFormLayout* form, const QString& label, double min, double max, double step,
70  int decimals) {
71  QDoubleSpinBox* field = new QDoubleSpinBox(this);
72  field->setMaximumWidth(FORM_CONTROL_WIDTH);
73  field->setRange(min, max);
74  field->setDecimals(decimals);
75  field->setSingleStep(step);
76  form->addRow(label, field);
77  return field;
78  };
79 
80  auto add_combo_box = [this](QFormLayout* form, const QString& label, bool editable = false) {
81  QComboBox* field = new QComboBox(this);
82  field->setEditable(editable);
83  field->setMaximumWidth(FORM_CONTROL_WIDTH);
84  form->addRow(label, field);
85  return field;
86  };
87 
88  // Basic widget container
89  QVBoxLayout* layout = new QVBoxLayout();
90 
91  QGroupBox* group1 = new QGroupBox("Kinematics");
92  QGroupBox* group2 = new QGroupBox("OMPL Planning");
93 
94  // Label ------------------------------------------------
95  title_ = new QLabel(this); // specify the title from the parent widget
96  QFont group_title_font(QFont().defaultFamily(), 12, QFont::Bold);
97  title_->setFont(group_title_font);
98  layout->addWidget(title_);
99 
100  // Kinematic form -------------------------------------------
101  QFormLayout* form_layout = new QFormLayout();
102  form_layout->setContentsMargins(0, 12, 0, 12);
103 
104  // Name input
105  group_name_field_ = add_line_edit(form_layout, "Group Name:");
106 
107  // Kinematic solver to use
108  kinematics_solver_field_ = add_combo_box(form_layout, "Kinematic Solver:");
109 
110  // Resolution to use with solver
111  kinematics_resolution_field_ = add_line_edit(form_layout, "Kin. Search Resolution:");
112 
113  // Timeout to use with solver
114  kinematics_timeout_field_ = add_line_edit(form_layout, "Kin. Search Timeout (sec):");
115 
116  // goal joint tolerance to use when planning with solver
117  goal_joint_tolerance_field_ = add_spin_box(form_layout, "Goal Joint Tolerance (m|rad):", MIN_TOLERANCE, MAX_TOLERANCE,
118  STEP_TOLERANCE, DECIMALS_TOLERANCE);
119 
120  // goal position tolerance to use when planning with solver
121  goal_position_tolerance_field_ = add_spin_box(form_layout, "Goal Position Tolerance (m):", MIN_TOLERANCE,
122  MAX_TOLERANCE, STEP_TOLERANCE, DECIMALS_TOLERANCE);
123 
124  // goal orientation tolerance to use when planning with solver
125  goal_orientation_tolerance_field_ = add_spin_box(form_layout, "Goal Orientation Tolerance (rad):", MIN_TOLERANCE,
126  MAX_TOLERANCE, STEP_TOLERANCE, DECIMALS_TOLERANCE);
127 
128  // file to load additional parameters from
129  kinematics_parameters_file_field_ = new QLineEdit(this);
130  QPushButton* kinematics_parameters_file_button = new QPushButton("...", this);
131  kinematics_parameters_file_button->setMaximumWidth(50);
132  kinematics_parameters_file_button->setMaximumHeight(42);
133  connect(kinematics_parameters_file_button, SIGNAL(clicked()), this, SLOT(selectKinematicsFile()));
134  QBoxLayout* kinematics_parameters_file_layout = new QHBoxLayout(this);
135  kinematics_parameters_file_layout->addWidget(kinematics_parameters_file_field_);
136  kinematics_parameters_file_layout->addWidget(kinematics_parameters_file_button);
137  kinematics_parameters_file_layout->setContentsMargins(0, 0, 0, 0);
138  QWidget* container = new QWidget(this);
139  container->setMaximumWidth(FORM_CONTROL_WIDTH);
140  container->setLayout(kinematics_parameters_file_layout);
141  form_layout->addRow("Kin. parameters file:", container);
142 
143  group1->setLayout(form_layout);
144 
145  // OMPL Planner form --------------------------------------------
146 
147  QFormLayout* form_layout2 = new QFormLayout();
148  form_layout2->setContentsMargins(0, 12, 0, 12);
149 
150  // Kinematic default planner
151  default_planner_field_ = add_combo_box(form_layout2, "Group Default Planner:");
152 
153  group2->setLayout(form_layout2);
154 
155  layout->addWidget(group1);
156  layout->addWidget(group2);
157 
158  layout->setAlignment(Qt::AlignTop);
159 
160  // New Group Options ---------------------------------------------------------
161  new_buttons_widget_ = new QWidget();
162 
163  QVBoxLayout* new_buttons_layout_container = new QVBoxLayout();
164  QHBoxLayout* label_layout = new QHBoxLayout();
165  QHBoxLayout* recommended_options = new QHBoxLayout();
166  QHBoxLayout* advanced_options = new QHBoxLayout();
167 
168  QLabel* save_and_add = new QLabel("Next, Add Components To Group:", this);
169  QFont save_and_add_font(QFont().defaultFamily(), 12, QFont::Bold);
170  save_and_add->setFont(save_and_add_font);
171  label_layout->addWidget(save_and_add);
172 
173  // Recommended options
174  QLabel* add_subtitle = new QLabel("Recommended: ", this);
175  QFont add_subtitle_font(QFont().defaultFamily(), 10, QFont::Bold);
176  add_subtitle->setFont(add_subtitle_font);
177  recommended_options->addWidget(add_subtitle, 0, Qt::AlignLeft);
178 
179  // Save and add chain
180  QPushButton* btn_save_chain = new QPushButton("Add Kin. Chain", this);
181  btn_save_chain->setMaximumWidth(200);
182  connect(btn_save_chain, SIGNAL(clicked()), this, SIGNAL(saveChain()));
183  recommended_options->addWidget(btn_save_chain);
184 
185  // Save and add joints
186  QPushButton* btn_save_joints = new QPushButton("Add Joints", this);
187  btn_save_joints->setMaximumWidth(200);
188  connect(btn_save_joints, SIGNAL(clicked()), this, SIGNAL(saveJoints()));
189  recommended_options->addWidget(btn_save_joints);
190 
191  // Advanced options
192  QLabel* add_subtitle2 = new QLabel("Advanced Options:", this);
193  add_subtitle2->setFont(add_subtitle_font);
194  advanced_options->addWidget(add_subtitle2, 0, Qt::AlignLeft);
195 
196  // Save and add subgroups
197  QPushButton* btn_save_subgroups = new QPushButton("Add Subgroups", this);
198  btn_save_subgroups->setMaximumWidth(200);
199  connect(btn_save_subgroups, SIGNAL(clicked()), this, SIGNAL(saveSubgroups()));
200  advanced_options->addWidget(btn_save_subgroups);
201 
202  // Save and add links
203  QPushButton* btn_save_links = new QPushButton("Add Links", this);
204  btn_save_links->setMaximumWidth(200);
205  connect(btn_save_links, SIGNAL(clicked()), this, SIGNAL(saveLinks()));
206  advanced_options->addWidget(btn_save_links);
207 
208  // Add layouts
209  new_buttons_layout_container->addLayout(label_layout);
210  new_buttons_layout_container->addLayout(recommended_options);
211  new_buttons_layout_container->addLayout(advanced_options);
212 
213  // Create widget and add to main layout
214  new_buttons_widget_->setLayout(new_buttons_layout_container);
215  layout->addWidget(new_buttons_widget_);
216 
217  // Vertical Spacer
218  layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
219 
220  // Bottom Controls ---------------------------------------------------------
221  QHBoxLayout* controls_layout = new QHBoxLayout();
222 
223  // Delete
224  btn_delete_ = new QPushButton("&Delete Group", this);
225  btn_delete_->setMaximumWidth(200);
226  connect(btn_delete_, SIGNAL(clicked()), this, SIGNAL(deleteGroup()));
227  controls_layout->addWidget(btn_delete_);
228  controls_layout->setAlignment(btn_delete_, Qt::AlignRight);
229 
230  // Horizontal Spacer
231  controls_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
232 
233  // Save
234  btn_save_ = new QPushButton("&Save", this);
235  btn_save_->setMaximumWidth(200);
236  connect(btn_save_, SIGNAL(clicked()), this, SIGNAL(save()));
237  controls_layout->addWidget(btn_save_);
238  controls_layout->setAlignment(btn_save_, Qt::AlignRight);
239 
240  // Cancel
241  QPushButton* btn_cancel = new QPushButton("&Cancel", this);
242  btn_cancel->setMaximumWidth(200);
243  connect(btn_cancel, SIGNAL(clicked()), this, SIGNAL(cancelEditing()));
244  controls_layout->addWidget(btn_cancel);
245  controls_layout->setAlignment(btn_cancel, Qt::AlignRight);
246 
247  // Add layout
248  layout->addLayout(controls_layout);
249 
250  // Finish Layout --------------------------------------------------
251  this->setLayout(layout);
252 }
253 
254 // ******************************************************************************************
255 // Set the link field with previous value
256 // ******************************************************************************************
257 void GroupEditWidget::setSelected(const std::string& group_name)
258 {
259  group_name_field_->setText(QString(group_name.c_str()));
260 
261  // Load properties from moveit_config_data.cpp ----------------------------------------------
262  auto set_spin_box_value = [](double& value, const double defaultValue, QDoubleSpinBox* widget) {
263  if (value <= 0)
264  value = defaultValue;
265 
266  widget->setValue(value);
267  };
268 
269  auto set_line_edit_value = [](double& value, const double defaultValue, QLineEdit* widget) {
270  if (value <= 0)
271  value = defaultValue;
272 
273  widget->setText(QString::number(value));
274  };
275 
276  GroupMetaData& group_metadata = config_data_->group_meta_data_[group_name];
277 
278  // Load resolution
279  set_line_edit_value(group_metadata.kinematics_solver_search_resolution_, DEFAULT_KIN_SOLVER_SEARCH_RESOLUTION,
281 
282  // Load timeout
283  set_line_edit_value(group_metadata.kinematics_solver_timeout_, DEFAULT_KIN_SOLVER_TIMEOUT, kinematics_timeout_field_);
284 
285  // Load goal joint tolerance
286  set_spin_box_value(group_metadata.goal_joint_tolerance_,
289 
290  // Load goal position tolerance
291  set_spin_box_value(group_metadata.goal_position_tolerance_,
294 
295  // Load goal orientation tolerance
296  set_spin_box_value(group_metadata.goal_orientation_tolerance_,
299 
300  // Set kin solver
301  std::string kin_solver = group_metadata.kinematics_solver_;
302 
303  // If this group doesn't have a solver, reset it to 'None'
304  if (kin_solver.empty())
305  {
306  kin_solver = "None";
307  }
308 
309  // Set the kin solver combo box
310  int index = kinematics_solver_field_->findText(kin_solver.c_str());
311  if (index == -1)
312  {
313  QMessageBox::warning(this, "Missing Kinematic Solvers",
314  QString("Unable to find the kinematic solver '")
315  .append(kin_solver.c_str())
316  .append("'. Trying running rosmake for this package. Until fixed, this setting will be "
317  "lost the next time the MoveIt configuration files are generated"));
318  return;
319  }
320  else
321  {
322  kinematics_solver_field_->setCurrentIndex(index);
323  }
324 
325  kinematics_parameters_file_field_->setText(group_metadata.kinematics_parameters_file_.c_str());
326 
327  // Set default planner
328  std::string default_planner = group_metadata.default_planner_;
329 
330  // If this group doesn't have a solver, reset it to 'None'
331  if (default_planner.empty())
332  {
333  default_planner = "None";
334  }
335 
336  index = default_planner_field_->findText(default_planner.c_str());
337  if (index == -1)
338  {
339  QMessageBox::warning(this, "Missing Default Planner",
340  QString("Unable to find the default planner '%1'").arg(default_planner.c_str()));
341  }
342  else
343  {
344  default_planner_field_->setCurrentIndex(index);
345  }
346 }
347 
348 // ******************************************************************************************
349 // Populate the combo dropdown box with kinematic planners
350 // ******************************************************************************************
352 {
353  // Only load this combo box once
354  static bool has_loaded = false;
355  if (has_loaded)
356  return;
357  has_loaded = true;
358 
359  // Remove all old items
360  kinematics_solver_field_->clear();
361  default_planner_field_->clear();
362 
363  // Add none option, the default
364  kinematics_solver_field_->addItem("None");
365  default_planner_field_->addItem("None");
366 
367  // load all avail kin planners
368  std::unique_ptr<pluginlib::ClassLoader<kinematics::KinematicsBase>> loader;
369  try
370  {
371  loader = std::make_unique<pluginlib::ClassLoader<kinematics::KinematicsBase>>("moveit_core",
372  "kinematics::KinematicsBase");
373  }
375  {
376  QMessageBox::warning(this, "Missing Kinematic Solvers",
377  "Exception while creating class loader for kinematic "
378  "solver plugins");
379  ROS_ERROR_STREAM(ex.what());
380  return;
381  }
382 
383  // Get classes
384  const std::vector<std::string>& classes = loader->getDeclaredClasses();
385 
386  // Warn if no plugins are found
387  if (classes.empty())
388  {
389  QMessageBox::warning(this, "Missing Kinematic Solvers",
390  "No MoveIt-compatible kinematics solvers found. Try "
391  "installing moveit_kinematics (sudo apt-get install "
392  "ros-${ROS_DISTRO}-moveit-kinematics)");
393  return;
394  }
395 
396  // Loop through all planners and add to combo box
397  for (const std::string& kinematics_plugin_name : classes)
398  {
399  kinematics_solver_field_->addItem(kinematics_plugin_name.c_str());
400  }
401 
402  std::vector<OMPLPlannerDescription> planners = config_data_->getOMPLPlanners();
403  for (OMPLPlannerDescription& planner : planners)
404  {
405  std::string planner_name = planner.name_;
406  default_planner_field_->addItem(planner_name.c_str());
407  }
408 }
409 
411 {
412  QString filename = QFileDialog::getOpenFileName(this, "Select a parameter file", "", "YAML files (*.yaml)");
413 
414  if (filename.isEmpty())
415  {
416  return;
417  }
418 
419  std::string package_name;
420  std::string relative_filename;
421  bool package_found =
422  config_data_->extractPackageNameFromPath(filename.toStdString(), package_name, relative_filename);
423 
424  QString lookup_path = filename;
425  if (package_found)
426  {
427  lookup_path = QString("$(find %1)/%2").arg(package_name.c_str()).arg(relative_filename.c_str());
428  }
429  kinematics_parameters_file_field_->setText(lookup_path);
430 }
431 
432 } // namespace moveit_setup_assistant
min
int min(int a, int b)
moveit_setup_assistant::GroupEditWidget::kinematics_resolution_field_
QLineEdit * kinematics_resolution_field_
Definition: group_edit_widget.h:84
moveit_setup_assistant::EndEffectorsWidget::cancelEditing
void cancelEditing()
Cancel changes.
Definition: end_effectors_widget.cpp:620
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(args)
moveit_setup_assistant::GroupEditWidget::goal_joint_tolerance_field_
QDoubleSpinBox * goal_joint_tolerance_field_
Definition: group_edit_widget.h:86
moveit_setup_assistant::GroupEditWidget::kinematics_solver_field_
QComboBox * kinematics_solver_field_
Definition: group_edit_widget.h:83
moveit_setup_assistant::GroupEditWidget::config_data_
moveit_setup_assistant::MoveItConfigDataPtr config_data_
Contains all the configuration data for the setup assistant.
Definition: group_edit_widget.h:137
step
unsigned int step
moveit_setup_assistant::GroupEditWidget::kinematics_timeout_field_
QLineEdit * kinematics_timeout_field_
Definition: group_edit_widget.h:85
moveit::planning_interface::MoveGroupInterface::DEFAULT_GOAL_POSITION_TOLERANCE
static constexpr double DEFAULT_GOAL_POSITION_TOLERANCE
moveit_setup_assistant::GroupEditWidget::loadKinematicPlannersComboBox
void loadKinematicPlannersComboBox()
Populate the combo dropdown box with kinematic planners.
Definition: group_edit_widget.cpp:383
label
string label
moveit_setup_assistant::GroupEditWidget::goal_position_tolerance_field_
QDoubleSpinBox * goal_position_tolerance_field_
Definition: group_edit_widget.h:87
moveit::planning_interface::MoveGroupInterface::DEFAULT_GOAL_ORIENTATION_TOLERANCE
static constexpr double DEFAULT_GOAL_ORIENTATION_TOLERANCE
pluginlib::PluginlibException
moveit_setup_assistant::GroupEditWidget::GroupEditWidget
GroupEditWidget(QWidget *parent, const MoveItConfigDataPtr &config_data)
Constructor.
Definition: group_edit_widget.cpp:91
moveit_setup_assistant::EndEffectorsWidget::group_name_field_
QComboBox * group_name_field_
Definition: end_effectors_widget.h:81
group_edit_widget.h
value
float value
moveit_setup_assistant::GroupEditWidget::goal_orientation_tolerance_field_
QDoubleSpinBox * goal_orientation_tolerance_field_
Definition: group_edit_widget.h:88
moveit_setup_assistant::GroupEditWidget::kinematics_parameters_file_field_
QLineEdit * kinematics_parameters_file_field_
Definition: group_edit_widget.h:89
moveit_setup_assistant::GroupEditWidget::group_name_field_
QLineEdit * group_name_field_
Definition: group_edit_widget.h:82
class_loader.hpp
moveit::planning_interface::MoveGroupInterface::DEFAULT_GOAL_JOINT_TOLERANCE
static constexpr double DEFAULT_GOAL_JOINT_TOLERANCE
moveit_setup_assistant
Definition: compute_default_collisions.h:46
move_group_interface.h
moveit_setup_assistant::DEFAULT_KIN_SOLVER_TIMEOUT
static const double DEFAULT_KIN_SOLVER_TIMEOUT
Definition: moveit_config_data.h:91
moveit_setup_assistant::EndEffectorsWidget::btn_save_
QPushButton * btn_save_
Definition: end_effectors_widget.h:75
append
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
moveit_setup_assistant::GroupEditWidget::selectKinematicsFile
void selectKinematicsFile()
Shows a file dialog to select an additional parameter file for kinematics.
Definition: group_edit_widget.cpp:442
index
unsigned int index
moveit_setup_assistant::GroupEditWidget::default_planner_field_
QComboBox * default_planner_field_
Definition: group_edit_widget.h:90
moveit_setup_assistant::EndEffectorsWidget::btn_delete_
QPushButton * btn_delete_
Definition: end_effectors_widget.h:74
moveit_setup_assistant::GroupEditWidget::setSelected
void setSelected(const std::string &group_name)
Set the previous data.
Definition: group_edit_widget.cpp:289
moveit_setup_assistant::DEFAULT_KIN_SOLVER_SEARCH_RESOLUTION
static const double DEFAULT_KIN_SOLVER_SEARCH_RESOLUTION
Definition: moveit_config_data.h:90


moveit_setup_assistant
Author(s): Dave Coleman
autogenerated on Sat May 3 2025 02:28:04