moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
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 <QMessageBox>
45#include <QPushButton>
46#include <QString>
47#include <QVBoxLayout>
48
50
51namespace moveit_setup
52{
53namespace srdf_setup
54{
55// ******************************************************************************************
56//
57// ******************************************************************************************
58GroupEditWidget::GroupEditWidget(QWidget* parent, PlanningGroups& setup_step) : QWidget(parent), setup_step_(setup_step)
59{
60 // Basic widget container
61 QVBoxLayout* layout = new QVBoxLayout();
62
63 QGroupBox* group1 = new QGroupBox("Kinematics");
64 QGroupBox* group2 = new QGroupBox("OMPL Planning");
65
66 // Label ------------------------------------------------
67 title_ = new QLabel(this); // specify the title from the parent widget
68 QFont group_title_font(QFont().defaultFamily(), 12, QFont::Bold);
69 title_->setFont(group_title_font);
70 layout->addWidget(title_);
71
72 // Kinematic form -------------------------------------------
73 QFormLayout* form_layout = new QFormLayout();
74 form_layout->setContentsMargins(0, 12, 0, 12);
75
76 // Name input
77 group_name_field_ = new QLineEdit(this);
78 group_name_field_->setMaximumWidth(400);
79 form_layout->addRow("Group Name:", group_name_field_);
80
81 // Kinematic solver
82 kinematics_solver_field_ = new QComboBox(this);
83 kinematics_solver_field_->setEditable(false);
84 kinematics_solver_field_->setMaximumWidth(400);
85 form_layout->addRow("Kinematic Solver:", kinematics_solver_field_);
86
87 // resolution to use with solver
88 kinematics_resolution_field_ = new QLineEdit(this);
89 kinematics_resolution_field_->setMaximumWidth(400);
90 form_layout->addRow("Kin. Search Resolution:", kinematics_resolution_field_);
91
92 // resolution to use with solver
93 kinematics_timeout_field_ = new QLineEdit(this);
94 kinematics_timeout_field_->setMaximumWidth(400);
95 form_layout->addRow("Kin. Search Timeout (sec):", kinematics_timeout_field_);
96
97 // file to load additional parameters from
98 kinematics_parameters_file_field_ = new QLineEdit(this);
99 kinematics_parameters_file_field_->setMaximumWidth(400);
100 QPushButton* kinematics_parameters_file_button = new QPushButton("...", this);
101 kinematics_parameters_file_button->setMaximumWidth(50);
102 connect(kinematics_parameters_file_button, SIGNAL(clicked()), this, SLOT(selectKinematicsFile()));
103 QBoxLayout* kinematics_parameters_file_layout = new QHBoxLayout(this);
104 kinematics_parameters_file_layout->addWidget(kinematics_parameters_file_field_);
105 kinematics_parameters_file_layout->addWidget(kinematics_parameters_file_button);
106 kinematics_parameters_file_layout->setContentsMargins(0, 0, 0, 0);
107 QWidget* container = new QWidget(this);
108 container->setLayout(kinematics_parameters_file_layout);
109 form_layout->addRow("Kin. parameters file:", container);
110
111 group1->setLayout(form_layout);
112
113 // OMPL Planner form --------------------------------------------
114
115 QFormLayout* form_layout2 = new QFormLayout();
116 form_layout2->setContentsMargins(0, 12, 0, 12);
117
118 // Kinematic default planner
119 default_planner_field_ = new QComboBox(this);
120 default_planner_field_->setEditable(false);
121 default_planner_field_->setMaximumWidth(400);
122 form_layout2->addRow("Group Default Planner:", default_planner_field_);
123
124 group2->setLayout(form_layout2);
125
126 layout->addWidget(group1);
127 layout->addWidget(group2);
128
129 layout->setAlignment(Qt::AlignTop);
130
131 // New Group Options ---------------------------------------------------------
132 new_buttons_widget_ = new QWidget();
133
134 QVBoxLayout* new_buttons_layout_container = new QVBoxLayout();
135 QHBoxLayout* label_layout = new QHBoxLayout();
136 QHBoxLayout* recommended_options = new QHBoxLayout();
137 QHBoxLayout* advanced_options = new QHBoxLayout();
138
139 QLabel* save_and_add = new QLabel("Next, Add Components To Group:", this);
140 QFont save_and_add_font(QFont().defaultFamily(), 12, QFont::Bold);
141 save_and_add->setFont(save_and_add_font);
142 label_layout->addWidget(save_and_add);
143
144 // Recommended options
145 QLabel* add_subtitle = new QLabel("Recommended: ", this);
146 QFont add_subtitle_font(QFont().defaultFamily(), 10, QFont::Bold);
147 add_subtitle->setFont(add_subtitle_font);
148 recommended_options->addWidget(add_subtitle, 0, Qt::AlignLeft);
149
150 // Save and add chain
151 QPushButton* btn_save_chain = new QPushButton("Add Kin. Chain", this);
152 btn_save_chain->setMaximumWidth(200);
153 connect(btn_save_chain, SIGNAL(clicked()), this, SIGNAL(saveChain()));
154 recommended_options->addWidget(btn_save_chain);
155
156 // Save and add joints
157 QPushButton* btn_save_joints = new QPushButton("Add Joints", this);
158 btn_save_joints->setMaximumWidth(200);
159 connect(btn_save_joints, SIGNAL(clicked()), this, SIGNAL(saveJoints()));
160 recommended_options->addWidget(btn_save_joints);
161
162 // Advanced options
163 QLabel* add_subtitle2 = new QLabel("Advanced Options:", this);
164 add_subtitle2->setFont(add_subtitle_font);
165 advanced_options->addWidget(add_subtitle2, 0, Qt::AlignLeft);
166
167 // Save and add subgroups
168 QPushButton* btn_save_subgroups = new QPushButton("Add Subgroups", this);
169 btn_save_subgroups->setMaximumWidth(200);
170 connect(btn_save_subgroups, SIGNAL(clicked()), this, SIGNAL(saveSubgroups()));
171 advanced_options->addWidget(btn_save_subgroups);
172
173 // Save and add links
174 QPushButton* btn_save_links = new QPushButton("Add Links", this);
175 btn_save_links->setMaximumWidth(200);
176 connect(btn_save_links, SIGNAL(clicked()), this, SIGNAL(saveLinks()));
177 advanced_options->addWidget(btn_save_links);
178
179 // Add layouts
180 new_buttons_layout_container->addLayout(label_layout);
181 new_buttons_layout_container->addLayout(recommended_options);
182 new_buttons_layout_container->addLayout(advanced_options);
183
184 // Create widget and add to main layout
185 new_buttons_widget_->setLayout(new_buttons_layout_container);
186 layout->addWidget(new_buttons_widget_);
187
188 // Vertical Spacer
189 layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Minimum, QSizePolicy::Expanding));
190
191 // Bottom Controls ---------------------------------------------------------
192 QHBoxLayout* controls_layout = new QHBoxLayout();
193
194 // Delete
195 btn_delete_ = new QPushButton("&Delete Group", this);
196 btn_delete_->setMaximumWidth(200);
197 connect(btn_delete_, SIGNAL(clicked()), this, SIGNAL(deleteGroup()));
198 controls_layout->addWidget(btn_delete_);
199 controls_layout->setAlignment(btn_delete_, Qt::AlignRight);
200
201 // Horizontal Spacer
202 controls_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
203
204 // Save
205 btn_save_ = new QPushButton("&Save", this);
206 btn_save_->setMaximumWidth(200);
207 connect(btn_save_, SIGNAL(clicked()), this, SIGNAL(save()));
208 controls_layout->addWidget(btn_save_);
209 controls_layout->setAlignment(btn_save_, Qt::AlignRight);
210
211 // Cancel
212 QPushButton* btn_cancel = new QPushButton("&Cancel", this);
213 btn_cancel->setMaximumWidth(200);
214 connect(btn_cancel, SIGNAL(clicked()), this, SIGNAL(cancelEditing()));
215 controls_layout->addWidget(btn_cancel);
216 controls_layout->setAlignment(btn_cancel, Qt::AlignRight);
217
218 // Add layout
219 layout->addLayout(controls_layout);
220
221 // Finish Layout --------------------------------------------------
222 setLayout(layout);
223}
224
225// ******************************************************************************************
226// Set the link field with previous value
227// ******************************************************************************************
228void GroupEditWidget::setSelected(const std::string& group_name, const GroupMetaData& meta_data)
229{
230 group_name_field_->setText(QString(group_name.c_str()));
231
232 // Load properties from moveit_config_data.cpp ----------------------------------------------
233
234 // Load resolution
235 kinematics_resolution_field_->setText(QString::number(meta_data.kinematics_solver_search_resolution_));
236
237 // Load timeout
238 kinematics_timeout_field_->setText(QString::number(meta_data.kinematics_solver_timeout_));
239
240 // Set kin solver
241 std::string kin_solver = meta_data.kinematics_solver_;
242
243 // If this group doesn't have a solver, reset it to 'None'
244 if (kin_solver.empty())
245 {
246 kin_solver = "None";
247 }
248
249 // Set the kin solver combo box
250 int index = kinematics_solver_field_->findText(kin_solver.c_str());
251 if (index == -1)
252 {
253 QMessageBox::warning(this, "Missing Kinematic Solvers",
254 QString("Unable to find the kinematic solver '")
255 .append(kin_solver.c_str())
256 .append("'. Trying running rosmake for this package. Until fixed, this setting will be "
257 "lost the next time the MoveIt configuration files are generated"));
258 return;
259 }
260 else
261 {
262 kinematics_solver_field_->setCurrentIndex(index);
263 }
264
266
267 // Set default planner
268 std::string default_planner = meta_data.default_planner_;
269
270 // If this group doesn't have a solver, reset it to 'None'
271 if (default_planner.empty())
272 {
273 default_planner = "None";
274 }
275
276 index = default_planner_field_->findText(default_planner.c_str());
277 if (index == -1)
278 {
279 QMessageBox::warning(this, "Missing Default Planner",
280 QString("Unable to find the default planner '%1'").arg(default_planner.c_str()));
281 }
282 else
283 {
284 default_planner_field_->setCurrentIndex(index);
285 }
286}
287
288// ******************************************************************************************
289// Populate the combo dropdown box with kinematic planners
290// ******************************************************************************************
292{
293 // Only load this combo box once
294 static bool has_loaded = false;
295 if (has_loaded)
296 return;
297 has_loaded = true;
298
299 // Remove all old items
301 default_planner_field_->clear();
302
303 // Add none option, the default
304 kinematics_solver_field_->addItem("None");
305 default_planner_field_->addItem("None");
306
307 std::vector<std::string> classes;
308 try
309 {
310 classes = setup_step_.getKinematicPlanners();
311 }
312 catch (const std::runtime_error& ex)
313 {
314 QMessageBox::warning(this, "Missing Kinematic Solvers", QString(ex.what()));
315 RCLCPP_ERROR_STREAM(setup_step_.getLogger(), ex.what());
316 return;
317 }
318
319 // Loop through all planners and add to combo box
320 for (const std::string& kinematics_plugin_name : classes)
321 {
322 kinematics_solver_field_->addItem(kinematics_plugin_name.c_str());
323 }
324
325 for (const std::string& planner_name : setup_step_.getOMPLPlanners())
326 {
327 default_planner_field_->addItem(planner_name.c_str());
328 }
329}
330
331void GroupEditWidget::selectKinematicsFile()
332{
333 QString filename = QFileDialog::getOpenFileName(this, "Select a parameter file", "", "YAML files (*.yaml)");
334
335 if (filename.isEmpty())
336 {
337 return;
338 }
339
340 std::string package_name;
341 std::filesystem::path relative_filename;
342 bool package_found = extractPackageNameFromPath(filename.toStdString(), package_name, relative_filename);
343
344 QString lookup_path = filename;
345 if (package_found)
346 {
347 lookup_path = QString("$(find %1)/%2").arg(package_name.c_str()).arg(relative_filename.c_str());
348 }
349 kinematics_parameters_file_field_->setText(lookup_path);
350}
351
352} // namespace srdf_setup
353} // namespace moveit_setup
const rclcpp::Logger & getLogger() const
Makes a namespaced logger for this step available to the widget.
void deleteGroup()
Event sent when delete is being requested for group.
void saveLinks()
Button event for new groups, progressing to adding links.
void saveJoints()
Button event for new groups, progressing to adding joints.
void cancelEditing()
Event sent when user presses cancel button.
void loadKinematicPlannersComboBox()
Populate the combo dropdown box with kinematic planners.
void save()
Button event for just saving, when in edit mode.
void saveChain()
Button event for new groups, progressing to adding a chain.
void setSelected(const std::string &group_name, const GroupMetaData &meta_data)
Set the previous data.
void saveSubgroups()
Button event for new groups, progressing to adding subgroups.
GroupEditWidget(QWidget *parent, PlanningGroups &setup_step)
Constructor.
std::vector< std::string > getKinematicPlanners() const
std::vector< std::string > getOMPLPlanners() const
bool extractPackageNameFromPath(const std::filesystem::path &path, std::string &package_name, std::filesystem::path &relative_filepath)
Definition utilities.cpp:41