moveit2
The MoveIt Motion Planning Framework for ROS 2.
Loading...
Searching...
No Matches
virtual_joints_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
39
40// Qt
41#include <QApplication>
42#include <QFormLayout>
43#include <QHBoxLayout>
44#include <QMessageBox>
45#include <QString>
46#include <QVBoxLayout>
47
48namespace moveit_setup
49{
50namespace srdf_setup
51{
53{
54 // Basic widget container
55 QVBoxLayout* layout = new QVBoxLayout();
56
57 // Top Header Area ------------------------------------------------
58
59 auto header = new HeaderWidget("Define Virtual Joints",
60 "Create a virtual joint between the base robot link and an external frame of "
61 "reference. This allows to place the robot in the world or on a mobile platform.",
62 this);
63 layout->addWidget(header);
64
65 // Create contents screens ---------------------------------------
66
67 vjoint_list_widget_ = createContentsWidget();
68 vjoint_edit_widget_ = createEditWidget();
69
70 // Create Widget wrapper for layout
71 stacked_widget_ = new QStackedWidget(this);
72 stacked_widget_->addWidget(vjoint_list_widget_); // screen index 0
73 stacked_widget_->addWidget(vjoint_edit_widget_); // screen index 1
74 layout->addWidget(stacked_widget_);
75
76 // Finish Layout --------------------------------------------------
77 setLayout(layout);
78}
79
80// ******************************************************************************************
81// Create the main content widget
82// ******************************************************************************************
83QWidget* VirtualJointsWidget::createContentsWidget()
84{
85 // Main widget
86 QWidget* content_widget = new QWidget(this);
87
88 // Basic widget container
89 QVBoxLayout* layout = new QVBoxLayout(this);
90
91 // Table ------------ ------------------------------------------------
92
93 data_table_ = new QTableWidget(this);
94 data_table_->setColumnCount(4);
95 data_table_->setSortingEnabled(true);
96 data_table_->setSelectionBehavior(QAbstractItemView::SelectRows);
97 connect(data_table_, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(editDoubleClicked(int, int)));
98 connect(data_table_, SIGNAL(cellClicked(int, int)), this, SLOT(previewClicked(int, int)));
99 layout->addWidget(data_table_);
100
101 // Set header labels
102 QStringList header_list;
103 header_list.append("Virtual Joint Name");
104 header_list.append("Child Link");
105 header_list.append("Parent Frame");
106 header_list.append("Type");
107 data_table_->setHorizontalHeaderLabels(header_list);
108
109 // Bottom Buttons --------------------------------------------------
110
111 QHBoxLayout* controls_layout = new QHBoxLayout();
112
113 // Spacer
114 controls_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
115
116 // Edit Selected Button
117 btn_edit_ = new QPushButton("&Edit Selected", this);
118 btn_edit_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
119 btn_edit_->setMaximumWidth(300);
120 btn_edit_->hide(); // show once we know if there are existing poses
121 connect(btn_edit_, SIGNAL(clicked()), this, SLOT(editSelected()));
122 controls_layout->addWidget(btn_edit_);
123 controls_layout->setAlignment(btn_edit_, Qt::AlignRight);
124
125 // Delete Selected Button
126 btn_delete_ = new QPushButton("&Delete Selected", this);
127 connect(btn_delete_, SIGNAL(clicked()), this, SLOT(deleteSelected()));
128 controls_layout->addWidget(btn_delete_);
129 controls_layout->setAlignment(btn_delete_, Qt::AlignRight);
130
131 // Add VJoint Button
132 QPushButton* btn_add = new QPushButton("&Add Virtual Joint", this);
133 btn_add->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
134 btn_add->setMaximumWidth(300);
135 connect(btn_add, SIGNAL(clicked()), this, SLOT(showNewScreen()));
136 controls_layout->addWidget(btn_add);
137 controls_layout->setAlignment(btn_add, Qt::AlignRight);
138
139 // Add layout
140 layout->addLayout(controls_layout);
141
142 // Set layout -----------------------------------------------------
143 content_widget->setLayout(layout);
144
145 return content_widget;
146}
147
148// ******************************************************************************************
149// Create the edit widget
150// ******************************************************************************************
151QWidget* VirtualJointsWidget::createEditWidget()
152{
153 // Main widget
154 QWidget* edit_widget = new QWidget(this);
155 // Layout
156 QVBoxLayout* layout = new QVBoxLayout();
157
158 // Simple form -------------------------------------------
159 QFormLayout* form_layout = new QFormLayout();
160 // form_layout->setContentsMargins( 0, 15, 0, 15 );
161 form_layout->setRowWrapPolicy(QFormLayout::WrapAllRows);
162
163 // Name input
164 vjoint_name_field_ = new QLineEdit(this);
165 form_layout->addRow("Virtual Joint Name:", vjoint_name_field_);
166
167 // Child Link input
168 child_link_field_ = new QComboBox(this);
169 child_link_field_->setEditable(false);
170 form_layout->addRow("Child Link:", child_link_field_);
171
172 // Parent frame name input
173 parent_name_field_ = new QLineEdit(this);
174 form_layout->addRow("Parent Frame Name:", parent_name_field_);
175
176 // Type input
177 joint_type_field_ = new QComboBox(this);
178 joint_type_field_->setEditable(false);
179 loadJointTypesComboBox(); // only do this once
180 // connect( joint_type_field_, SIGNAL( currentIndexChanged( const QString & ) ),
181 // this, SLOT( loadJoinSliders( const QString & ) ) );
182 form_layout->addRow("Joint Type:", joint_type_field_);
183
184 layout->addLayout(form_layout);
185
186 // Bottom Buttons --------------------------------------------------
187
188 QHBoxLayout* controls_layout = new QHBoxLayout();
189 controls_layout->setContentsMargins(0, 25, 0, 15);
190
191 // Spacer
192 controls_layout->addItem(new QSpacerItem(20, 20, QSizePolicy::Expanding, QSizePolicy::Minimum));
193
194 // Save
195 QPushButton* btn_save = new QPushButton("&Save", this);
196 btn_save->setMaximumWidth(200);
197 connect(btn_save, SIGNAL(clicked()), this, SLOT(doneEditing()));
198 controls_layout->addWidget(btn_save);
199 controls_layout->setAlignment(btn_save, Qt::AlignRight);
200
201 // Cancel
202 QPushButton* btn_cancel = new QPushButton("&Cancel", this);
203 btn_cancel->setMaximumWidth(200);
204 connect(btn_cancel, SIGNAL(clicked()), this, SLOT(cancelEditing()));
205 controls_layout->addWidget(btn_cancel);
206 controls_layout->setAlignment(btn_cancel, Qt::AlignRight);
207
208 // Add layout
209 layout->addLayout(controls_layout);
210
211 // Set layout -----------------------------------------------------
212 edit_widget->setLayout(layout);
213
214 return edit_widget;
215}
216
217// ******************************************************************************************
218// Show edit screen for creating a new vjoint
219// ******************************************************************************************
220void VirtualJointsWidget::showNewScreen()
221{
222 // Remember that this is a new vjoint
223 current_edit_vjoint_.clear();
224
225 // Clear previous data
226 vjoint_name_field_->setText("");
227 parent_name_field_->setText("");
228 child_link_field_->clearEditText();
229 joint_type_field_->clearEditText(); // actually this just chooses first option
230
231 // Switch to screen
232 stacked_widget_->setCurrentIndex(1);
233
234 // Announce that this widget is in modal mode
235 Q_EMIT setModalMode(true);
236}
237
238// ******************************************************************************************
239// Edit whatever element is selected
240// ******************************************************************************************
241void VirtualJointsWidget::editDoubleClicked(int /*row*/, int /*column*/)
242{
243 editSelected();
244}
245
246// ******************************************************************************************
247// Preview whatever element is selected
248// ******************************************************************************************
249void VirtualJointsWidget::previewClicked(int /*row*/, int /*column*/)
250{
251}
252
253// ******************************************************************************************
254// Edit whatever element is selected
255// ******************************************************************************************
256void VirtualJointsWidget::editSelected()
257{
258 // Get list of all selected items
259 QList<QTableWidgetItem*> selected = data_table_->selectedItems();
260
261 // Check that an element was selected
262 if (selected.empty())
263 return;
264
265 // Get selected name and edit it
266 edit(selected[0]->text().toStdString());
267}
268
269// ******************************************************************************************
270// Edit vjoint
271// ******************************************************************************************
272void VirtualJointsWidget::edit(const std::string& name)
273{
274 // Remember what we are editing
275 current_edit_vjoint_ = name;
276
277 // Find the selected in datastruture
278 srdf::Model::VirtualJoint* vjoint = setup_step_.find(name);
279
280 // Check if vjoint was found
281 if (vjoint == nullptr) // not found
282 {
283 QMessageBox::critical(this, "Error Saving", "An internal error has occurred while saving. Quitting.");
284 QApplication::quit();
285 }
286
287 // Set vjoint name
288 vjoint_name_field_->setText(vjoint->name_.c_str());
289 parent_name_field_->setText(vjoint->parent_frame_.c_str());
290
291 // Set vjoint child link
292 int index = child_link_field_->findText(vjoint->child_link_.c_str());
293 if (index == -1)
294 {
295 QMessageBox::critical(this, "Error Loading", "Unable to find child link in drop down box");
296 return;
297 }
298 child_link_field_->setCurrentIndex(index);
299
300 // Set joint type
301 index = joint_type_field_->findText(vjoint->type_.c_str());
302 if (index == -1)
303 {
304 QMessageBox::critical(this, "Error Loading", "Unable to find joint type in drop down box");
305 return;
306 }
307 joint_type_field_->setCurrentIndex(index);
308
309 // Switch to screen
310 stacked_widget_->setCurrentIndex(1);
311
312 // Announce that this widget is in modal mode
313 Q_EMIT setModalMode(true);
314}
315
316// ******************************************************************************************
317// Populate the combo dropdown box with joint types
318// ******************************************************************************************
319void VirtualJointsWidget::loadJointTypesComboBox()
320{
321 // Remove all old items
322 joint_type_field_->clear();
323
324 // joint types (hard coded)
325 joint_type_field_->addItem("fixed");
326 joint_type_field_->addItem("floating");
327 joint_type_field_->addItem("planar");
328}
329
330// ******************************************************************************************
331// Populate the combo dropdown box with avail child links
332// ******************************************************************************************
333void VirtualJointsWidget::loadChildLinksComboBox()
334{
335 // Remove all old links
336 child_link_field_->clear();
337
338 // Add all links to combo box
339 for (const auto& link_name : setup_step_.getLinkNames())
340 {
341 child_link_field_->addItem(link_name.c_str());
342 }
343}
344
345// ******************************************************************************************
346// Delete currently editing item
347// ******************************************************************************************
348void VirtualJointsWidget::deleteSelected()
349{
350 // Get list of all selected items
351 QList<QTableWidgetItem*> selected = data_table_->selectedItems();
352
353 // Check that an element was selected
354 if (selected.empty())
355 return;
356
357 // Get selected name and edit it
358 current_edit_vjoint_ = selected[0]->text().toStdString();
359
360 // Confirm user wants to delete group
361 if (QMessageBox::question(this, "Confirm Virtual Joint Deletion",
362 QString("Are you sure you want to delete the virtual joint '")
363 .append(current_edit_vjoint_.c_str())
364 .append("'?"),
365 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
366 {
367 return;
368 }
369
370 // Delete vjoint from vector
371 setup_step_.remove(current_edit_vjoint_);
372
373 // Reload main screen table
374 loadDataTable();
376}
377
378// ******************************************************************************************
379// Save editing changes
380// ******************************************************************************************
381void VirtualJointsWidget::doneEditing()
382{
383 // Get a reference to the supplied strings
384 const std::string vjoint_name = vjoint_name_field_->text().trimmed().toStdString();
385 const std::string parent_name = parent_name_field_->text().trimmed().toStdString();
386 const std::string child_link = child_link_field_->currentText().trimmed().toStdString();
387 const std::string joint_type = joint_type_field_->currentText().trimmed().toStdString();
388
389 // Check that name field is not empty
390 if (vjoint_name.empty())
391 {
392 QMessageBox::warning(this, "Error Saving", "A name must be given for the virtual joint!");
393 return;
394 }
395
396 // Check that parent frame name field is not empty
397 if (parent_name.empty())
398 {
399 QMessageBox::warning(this, "Error Saving", "A name must be given for the parent frame");
400 return;
401 }
402
403 // Check that a joint type was selected
404 if (joint_type.empty())
405 {
406 QMessageBox::warning(this, "Error Saving", "A joint type must be chosen!");
407 return;
408 }
409
410 // Check that a child link was selected
411 if (child_link.empty())
412 {
413 QMessageBox::warning(this, "Error Saving", "A child link must be chosen!");
414 return;
415 }
416
417 try
418 {
419 srdf::Model::VirtualJoint* vj = setup_step_.get(vjoint_name, current_edit_vjoint_);
420 setup_step_.setProperties(vj, parent_name, child_link, joint_type);
421 }
422 catch (const std::runtime_error& e)
423 {
424 QMessageBox::warning(this, "Error Saving", e.what());
425 return;
426 }
427
428 // Finish up ------------------------------------------------------
429
430 // Reload main screen table
431 loadDataTable();
432
433 // Switch to screen
434 stacked_widget_->setCurrentIndex(0);
435
436 // Announce that this widget is not in modal mode
437 Q_EMIT setModalMode(false);
438
440}
441
442// ******************************************************************************************
443// Cancel changes
444// ******************************************************************************************
445void VirtualJointsWidget::cancelEditing()
446{
447 // Switch to screen
448 stacked_widget_->setCurrentIndex(0);
449
450 // Announce that this widget is not in modal mode
451 Q_EMIT setModalMode(false);
452}
453
454// ******************************************************************************************
455// Load the virtual joints into the table
456// ******************************************************************************************
457void VirtualJointsWidget::loadDataTable()
458{
459 // Disable Table
460 data_table_->setUpdatesEnabled(false); // prevent table from updating until we are completely done
461 data_table_->setDisabled(true); // make sure we disable it so that the cellChanged event is not called
462 data_table_->clearContents();
463
464 const auto& virtual_joints = setup_step_.getContainer();
465
466 // Set size of datatable
467 data_table_->setRowCount(virtual_joints.size());
468
469 // Loop through every virtual joint
470 int row = 0;
471 for (const auto& virtual_joint : virtual_joints)
472 {
473 // Create row elements
474 QTableWidgetItem* data_name = new QTableWidgetItem(virtual_joint.name_.c_str());
475 data_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
476 QTableWidgetItem* child_link_name = new QTableWidgetItem(virtual_joint.child_link_.c_str());
477 child_link_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
478 QTableWidgetItem* parent_frame_name = new QTableWidgetItem(virtual_joint.parent_frame_.c_str());
479 parent_frame_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
480 QTableWidgetItem* type_name = new QTableWidgetItem(virtual_joint.type_.c_str());
481 type_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
482
483 // Add to table
484 data_table_->setItem(row, 0, data_name);
485 data_table_->setItem(row, 1, child_link_name);
486 data_table_->setItem(row, 2, parent_frame_name);
487 data_table_->setItem(row, 3, type_name);
488
489 // Increment counter
490 ++row;
491 }
492
493 // Re-enable
494 data_table_->setUpdatesEnabled(true); // prevent table from updating until we are completely done
495 data_table_->setDisabled(false); // make sure we disable it so that the cellChanged event is not called
496
497 // Resize header
498 data_table_->resizeColumnToContents(0);
499 data_table_->resizeColumnToContents(1);
500 data_table_->resizeColumnToContents(2);
501 data_table_->resizeColumnToContents(3);
502
503 // Show edit button if applicable
504 if (!virtual_joints.empty())
505 btn_edit_->show();
506}
507
508// ******************************************************************************************
509// Called when setup assistant navigation switches to this screen
510// ******************************************************************************************
512{
513 // Show the current vjoints screen
514 stacked_widget_->setCurrentIndex(0);
515
516 // Load the data to the tree
517 loadDataTable();
518
519 // Load the avail groups to the combo box
520 loadChildLinksComboBox();
521}
522
523} // namespace srdf_setup
524} // namespace moveit_setup
525
526#include <pluginlib/class_list_macros.hpp> // NOLINT
PLUGINLIB_EXPORT_CLASS(cached_ik_kinematics_plugin::CachedIKKinematicsPlugin< kdl_kinematics_plugin::KDLKinematicsPlugin >, kinematics::KinematicsBase)
The GUI code for one SetupStep.
void setModalMode(bool isModal)
Event for when the current screen is in modal view. Disables the left navigation.
T * get(const std::string &name, const std::string &old_name="")
Get a pointer to an item with the given name, creating if necessary. If old_name is provided (and is ...
T * find(const std::string &name)
Return a pointer to an item with the given name if it exists, otherwise null.
Definition srdf_step.hpp:98
bool remove(const std::string &name)
Delete an item with the given name from the list.
void focusGiven() override
Received when this widget is chosen from the navigation menu.
std::vector< srdf::Model::VirtualJoint > & getContainer() override
Returns the reference to the vector in the SRDF.
void setProperties(srdf::Model::VirtualJoint *vj, const std::string &parent_name, const std::string &child_name, const std::string &joint_type)
std::string append(const std::string &left, const std::string &right)
name
Definition setup.py:7