end_effectors_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
38 #include "end_effectors_widget.h"
39 // Qt
40 #include <QFormLayout>
41 #include <QMessageBox>
42 #include <QApplication>
43 
44 namespace moveit_setup_assistant
45 {
46 // ******************************************************************************************
47 // Constructor
48 // ******************************************************************************************
49 EndEffectorsWidget::EndEffectorsWidget(QWidget* parent, moveit_setup_assistant::MoveItConfigDataPtr config_data)
50  : SetupScreenWidget(parent), config_data_(config_data)
51 {
52  // Basic widget container
53  QVBoxLayout* layout = new QVBoxLayout();
54 
55  // Top Header Area ------------------------------------------------
56 
58  new HeaderWidget("Define End Effectors", "Setup your robot's end effectors. These are planning groups "
59  "corresponding to grippers or tools, attached to a parent "
60  "planning group (an arm). The specified parent link is used as the "
61  "reference frame for IK attempts.",
62  this);
63  layout->addWidget(header);
64 
65  // Create contents screens ---------------------------------------
66 
69 
70  // Create stacked layout -----------------------------------------
71  stacked_layout_ = new QStackedLayout(this);
72  stacked_layout_->addWidget(effector_list_widget_); // screen index 0
73  stacked_layout_->addWidget(effector_edit_widget_); // screen index 1
74 
75  // Create Widget wrapper for layout
76  QWidget* stacked_layout_widget = new QWidget(this);
77  stacked_layout_widget->setLayout(stacked_layout_);
78 
79  layout->addWidget(stacked_layout_widget);
80 
81  // Finish Layout --------------------------------------------------
82  this->setLayout(layout);
83 }
84 
85 // ******************************************************************************************
86 // Create the main content widget
87 // ******************************************************************************************
89 {
90  // Main widget
91  QWidget* content_widget = new QWidget(this);
92 
93  // Basic widget container
94  QVBoxLayout* layout = new QVBoxLayout(this);
95 
96  // Table ------------ ------------------------------------------------
97 
98  data_table_ = new QTableWidget(this);
99  data_table_->setColumnCount(4);
100  data_table_->setSortingEnabled(true);
101  data_table_->setSelectionBehavior(QAbstractItemView::SelectRows);
102  connect(data_table_, SIGNAL(cellDoubleClicked(int, int)), this, SLOT(editDoubleClicked(int, int)));
103  connect(data_table_, SIGNAL(cellClicked(int, int)), this, SLOT(previewClicked(int, int)));
104  layout->addWidget(data_table_);
105 
106  // Set header labels
107  QStringList header_list;
108  header_list.append("End Effector Name");
109  header_list.append("Group Name");
110  header_list.append("Parent Link");
111  header_list.append("Parent Group");
112  data_table_->setHorizontalHeaderLabels(header_list);
113 
114  // Bottom Buttons --------------------------------------------------
115 
116  QHBoxLayout* controls_layout = new QHBoxLayout();
117 
118  // Spacer
119  QWidget* spacer = new QWidget(this);
120  spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
121  controls_layout->addWidget(spacer);
122 
123  // Edit Selected Button
124  btn_edit_ = new QPushButton("&Edit Selected", this);
125  btn_edit_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
126  btn_edit_->setMaximumWidth(300);
127  btn_edit_->hide(); // show once we know if there are existing poses
128  connect(btn_edit_, SIGNAL(clicked()), this, SLOT(editSelected()));
129  controls_layout->addWidget(btn_edit_);
130  controls_layout->setAlignment(btn_edit_, Qt::AlignRight);
131 
132  // Delete Selected Button
133  btn_delete_ = new QPushButton("&Delete Selected", this);
134  connect(btn_delete_, SIGNAL(clicked()), this, SLOT(deleteSelected()));
135  controls_layout->addWidget(btn_delete_);
136  controls_layout->setAlignment(btn_delete_, Qt::AlignRight);
137 
138  // Add end effector Button
139  QPushButton* btn_add = new QPushButton("&Add End Effector", this);
140  btn_add->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
141  btn_add->setMaximumWidth(300);
142  connect(btn_add, SIGNAL(clicked()), this, SLOT(showNewScreen()));
143  controls_layout->addWidget(btn_add);
144  controls_layout->setAlignment(btn_add, Qt::AlignRight);
145 
146  // Add layout
147  layout->addLayout(controls_layout);
148 
149  // Set layout -----------------------------------------------------
150  content_widget->setLayout(layout);
151 
152  return content_widget;
153 }
154 
155 // ******************************************************************************************
156 // Create the edit widget
157 // ******************************************************************************************
159 {
160  // Main widget
161  QWidget* edit_widget = new QWidget(this);
162  // Layout
163  QVBoxLayout* layout = new QVBoxLayout();
164 
165  // Simple form -------------------------------------------
166  QFormLayout* form_layout = new QFormLayout();
167  // form_layout->setContentsMargins( 0, 15, 0, 15 );
168  form_layout->setRowWrapPolicy(QFormLayout::WrapAllRows);
169 
170  // Name input
171  effector_name_field_ = new QLineEdit(this);
172  form_layout->addRow("End Effector Name:", effector_name_field_);
173 
174  // Group input
175  group_name_field_ = new QComboBox(this);
176  group_name_field_->setEditable(false);
177  form_layout->addRow("End Effector Group:", group_name_field_);
178  connect(group_name_field_, SIGNAL(currentIndexChanged(const QString&)), this,
179  SLOT(previewClickedString(const QString&)));
180 
181  // Parent Link input
182  parent_name_field_ = new QComboBox(this);
183  parent_name_field_->setEditable(false);
184  form_layout->addRow("Parent Link (usually part of the arm):", parent_name_field_);
185 
186  // Parent Group input
187  parent_group_name_field_ = new QComboBox(this);
188  parent_group_name_field_->setEditable(false);
189  form_layout->addRow("Parent Group (optional):", parent_group_name_field_);
190 
191  layout->addLayout(form_layout);
192 
193  // Bottom Buttons --------------------------------------------------
194 
195  QHBoxLayout* controls_layout = new QHBoxLayout();
196  controls_layout->setContentsMargins(0, 25, 0, 15);
197 
198  // Spacer
199  QWidget* spacer = new QWidget(this);
200  spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
201  controls_layout->addWidget(spacer);
202 
203  // Save
204  QPushButton* btn_save_ = new QPushButton("&Save", this);
205  btn_save_->setMaximumWidth(200);
206  connect(btn_save_, SIGNAL(clicked()), this, SLOT(doneEditing()));
207  controls_layout->addWidget(btn_save_);
208  controls_layout->setAlignment(btn_save_, Qt::AlignRight);
209 
210  // Cancel
211  QPushButton* btn_cancel_ = new QPushButton("&Cancel", this);
212  btn_cancel_->setMaximumWidth(200);
213  connect(btn_cancel_, SIGNAL(clicked()), this, SLOT(cancelEditing()));
214  controls_layout->addWidget(btn_cancel_);
215  controls_layout->setAlignment(btn_cancel_, Qt::AlignRight);
216 
217  // Add layout
218  layout->addLayout(controls_layout);
219 
220  // Set layout -----------------------------------------------------
221  edit_widget->setLayout(layout);
222 
223  return edit_widget;
224 }
225 
226 // ******************************************************************************************
227 // Show edit screen for creating a new effector
228 // ******************************************************************************************
230 {
231  // Remember that this is a new effector
232  current_edit_effector_.clear();
233 
234  // Clear previous data
235  effector_name_field_->setText("");
236  parent_name_field_->clearEditText();
237  group_name_field_->clearEditText(); // actually this just chooses first option
238  parent_group_name_field_->clearEditText(); // actually this just chooses first option
239 
240  // Switch to screen
241  stacked_layout_->setCurrentIndex(1);
242 
243  // Announce that this widget is in modal mode
244  Q_EMIT isModal(true);
245 }
246 
247 // ******************************************************************************************
248 // Edit whatever element is selected
249 // ******************************************************************************************
250 void EndEffectorsWidget::editDoubleClicked(int row, int column)
251 {
252  editSelected();
253 }
254 
255 // ******************************************************************************************
256 // Preview whatever element is selected
257 // ******************************************************************************************
258 void EndEffectorsWidget::previewClicked(int row, int column)
259 {
260  // Get list of all selected items
261  QList<QTableWidgetItem*> selected = data_table_->selectedItems();
262 
263  // Check that an element was selected
264  if (!selected.size())
265  return;
266 
267  // Find the selected in datastructure
268  srdf::Model::EndEffector* effector = findEffectorByName(selected[0]->text().toStdString());
269 
270  // Unhighlight all links
271  Q_EMIT unhighlightAll();
272 
273  // Highlight group
274  Q_EMIT highlightGroup(effector->component_group_);
275 }
276 
277 // ******************************************************************************************
278 // Preview the planning group that is selected
279 // ******************************************************************************************
281 {
282  // Don't highlight if we are on the overview end effectors screen. we are just populating drop down box
283  if (stacked_layout_->currentIndex() == 0)
284  return;
285 
286  // Unhighlight all links
287  Q_EMIT unhighlightAll();
288 
289  // Highlight group
290  Q_EMIT highlightGroup(name.toStdString());
291 }
292 
293 // ******************************************************************************************
294 // Edit whatever element is selected
295 // ******************************************************************************************
297 {
298  // Get list of all selected items
299  QList<QTableWidgetItem*> selected = data_table_->selectedItems();
300 
301  // Check that an element was selected
302  if (!selected.size())
303  return;
304 
305  // Get selected name and edit it
306  edit(selected[0]->text().toStdString());
307 }
308 
309 // ******************************************************************************************
310 // Edit effector
311 // ******************************************************************************************
312 void EndEffectorsWidget::edit(const std::string& name)
313 {
314  // Remember what we are editing
315  current_edit_effector_ = name;
316 
317  // Find the selected in datastruture
319 
320  // Set effector name
321  effector_name_field_->setText(effector->name_.c_str());
322 
323  // Set effector parent link
324  int index = parent_name_field_->findText(effector->parent_link_.c_str());
325  if (index == -1)
326  {
327  QMessageBox::critical(this, "Error Loading", "Unable to find parent link in drop down box");
328  return;
329  }
330  parent_name_field_->setCurrentIndex(index);
331 
332  // Set group:
333  index = group_name_field_->findText(effector->component_group_.c_str());
334  if (index == -1)
335  {
336  QMessageBox::critical(this, "Error Loading", "Unable to find group name in drop down box");
337  return;
338  }
339  group_name_field_->setCurrentIndex(index);
340 
341  // Set parent group:
342  index = parent_group_name_field_->findText(effector->parent_group_.c_str());
343  if (index == -1)
344  {
345  QMessageBox::critical(this, "Error Loading", "Unable to find parent group name in drop down box");
346  return;
347  }
348  parent_group_name_field_->setCurrentIndex(index);
349 
350  // Switch to screen
351  stacked_layout_->setCurrentIndex(1);
352 
353  // Announce that this widget is in modal mode
354  Q_EMIT isModal(true);
355 }
356 
357 // ******************************************************************************************
358 // Populate the combo dropdown box with avail group names
359 // ******************************************************************************************
361 {
362  // Remove all old groups
363  group_name_field_->clear();
364  parent_group_name_field_->clear();
365  parent_group_name_field_->addItem(""); // optional setting
366 
367  // Add all group names to combo box
368  for (std::vector<srdf::Model::Group>::iterator group_it = config_data_->srdf_->groups_.begin();
369  group_it != config_data_->srdf_->groups_.end(); ++group_it)
370  {
371  group_name_field_->addItem(group_it->name_.c_str());
372  parent_group_name_field_->addItem(group_it->name_.c_str());
373  }
374 }
375 
376 // ******************************************************************************************
377 // Populate the combo dropdown box with avail parent links
378 // ******************************************************************************************
380 {
381  // Remove all old groups
382  parent_name_field_->clear();
383 
384  // Get all links in robot model
385  std::vector<const robot_model::LinkModel*> link_models = config_data_->getRobotModel()->getLinkModels();
386 
387  // Add all links to combo box
388  for (std::vector<const robot_model::LinkModel*>::const_iterator link_it = link_models.begin();
389  link_it < link_models.end(); ++link_it)
390  {
391  parent_name_field_->addItem((*link_it)->getName().c_str());
392  }
393 }
394 
395 // ******************************************************************************************
396 // Find the associated data by name
397 // ******************************************************************************************
399 {
400  // Find the group state we are editing based on the effector name
401  srdf::Model::EndEffector* searched_group = NULL; // used for holding our search results
402 
403  for (std::vector<srdf::Model::EndEffector>::iterator effector_it = config_data_->srdf_->end_effectors_.begin();
404  effector_it != config_data_->srdf_->end_effectors_.end(); ++effector_it)
405  {
406  if (effector_it->name_ == name) // string match
407  {
408  searched_group = &(*effector_it); // convert to pointer from iterator
409  break; // we are done searching
410  }
411  }
412 
413  // Check if effector was found
414  if (searched_group == NULL) // not found
415  {
416  QMessageBox::critical(this, "Error Saving", "An internal error has occured while saving. Quitting.");
417  QApplication::quit();
418  }
419 
420  return searched_group;
421 }
422 
423 // ******************************************************************************************
424 // Delete currently editing item
425 // ******************************************************************************************
427 {
428  // Get list of all selected items
429  QList<QTableWidgetItem*> selected = data_table_->selectedItems();
430 
431  // Check that an element was selected
432  if (!selected.size())
433  return;
434 
435  // Get selected name and edit it
436  current_edit_effector_ = selected[0]->text().toStdString();
437 
438  // Confirm user wants to delete group
439  if (QMessageBox::question(this, "Confirm End Effector Deletion",
440  QString("Are you sure you want to delete the end effector '")
442  .append("'?"),
443  QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
444  {
445  return;
446  }
447 
448  // Delete effector from vector
449  for (std::vector<srdf::Model::EndEffector>::iterator effector_it = config_data_->srdf_->end_effectors_.begin();
450  effector_it != config_data_->srdf_->end_effectors_.end(); ++effector_it)
451  {
452  // check if this is the group we want to delete
453  if (effector_it->name_ == current_edit_effector_) // string match
454  {
455  config_data_->srdf_->end_effectors_.erase(effector_it);
456  break;
457  }
458  }
459 
460  // Reload main screen table
461  loadDataTable();
463 }
464 
465 // ******************************************************************************************
466 // Save editing changes
467 // ******************************************************************************************
469 {
470  // Get a reference to the supplied strings
471  const std::string effector_name = effector_name_field_->text().toStdString();
472 
473  // Used for editing existing groups
474  srdf::Model::EndEffector* searched_data = NULL;
475 
476  // Check that name field is not empty
477  if (effector_name.empty())
478  {
479  QMessageBox::warning(this, "Error Saving", "A name must be specified for the end effector!");
480  return;
481  }
482 
483  // Check if this is an existing group
484  if (!current_edit_effector_.empty())
485  {
486  // Find the group we are editing based on the goup name string
488  }
489 
490  // Check that the effector name is unique
491  for (std::vector<srdf::Model::EndEffector>::const_iterator data_it = config_data_->srdf_->end_effectors_.begin();
492  data_it != config_data_->srdf_->end_effectors_.end(); ++data_it)
493  {
494  if (data_it->name_.compare(effector_name) == 0) // the names are the same
495  {
496  // is this our existing effector? check if effector pointers are same
497  if (&(*data_it) != searched_data)
498  {
499  QMessageBox::warning(
500  this, "Error Saving",
501  QString("An end-effector named '").append(effector_name.c_str()).append("'already exists!"));
502  return;
503  }
504  }
505  }
506 
507  // Check that a group was selected
508  if (group_name_field_->currentText().isEmpty())
509  {
510  QMessageBox::warning(this, "Error Saving", "A group that contains the links of the end-effector must be chosen!");
511  return;
512  }
513 
514  // Check that a parent link was selected
515  if (parent_name_field_->currentText().isEmpty())
516  {
517  QMessageBox::warning(this, "Error Saving", "A parent link must be chosen!");
518  return;
519  }
520 
521  const robot_model::JointModelGroup* jmg =
522  config_data_->getRobotModel()->getJointModelGroup(group_name_field_->currentText().toStdString());
523  /*
524  if (jmg->hasLinkModel(parent_name_field_->currentText().toStdString()))
525  {
526  QMessageBox::warning( this, "Error Saving", QString::fromStdString("Group " +
527  group_name_field_->currentText().toStdString() + " contains the link " +
528  parent_name_field_->currentText().toStdString() + ". However, the parent link of the end-effector should not belong to
529  the group for the end-effector itself."));
530  return;
531  }
532  */
533  if (!parent_group_name_field_->currentText().isEmpty())
534  {
535  jmg = config_data_->getRobotModel()->getJointModelGroup(parent_group_name_field_->currentText().toStdString());
536  if (!jmg->hasLinkModel(parent_name_field_->currentText().toStdString()))
537  {
538  QMessageBox::warning(this, "Error Saving",
539  QString::fromStdString("The specified parent group '" +
540  parent_group_name_field_->currentText().toStdString() +
541  "' must contain the specified parent link '" +
542  parent_name_field_->currentText().toStdString() + "'."));
543  return;
544  }
545  }
546 
548 
549  // Save the new effector name or create the new effector ----------------------------
550  bool isNew = false;
551 
552  if (searched_data == NULL) // create new
553  {
554  isNew = true;
555 
556  searched_data = new srdf::Model::EndEffector();
557  }
558 
559  // Copy name data ----------------------------------------------------
560  searched_data->name_ = effector_name;
561  searched_data->parent_link_ = parent_name_field_->currentText().toStdString();
562  searched_data->component_group_ = group_name_field_->currentText().toStdString();
563  searched_data->parent_group_ = parent_group_name_field_->currentText().toStdString();
564 
565  // Insert new effectors into group state vector --------------------------
566  if (isNew)
567  {
568  config_data_->srdf_->end_effectors_.push_back(*searched_data);
569  }
570 
571  // Finish up ------------------------------------------------------
572 
573  // Reload main screen table
574  loadDataTable();
575 
576  // Switch to screen
577  stacked_layout_->setCurrentIndex(0);
578 
579  // Announce that this widget is not in modal mode
580  Q_EMIT isModal(false);
581 }
582 
583 // ******************************************************************************************
584 // Cancel changes
585 // ******************************************************************************************
587 {
588  // Switch to screen
589  stacked_layout_->setCurrentIndex(0);
590 
591  // Re-highlight the currently selected end effector group
592  previewClicked(0, 0); // the number parameters are actually meaningless
593 
594  // Announce that this widget is not in modal mode
595  Q_EMIT isModal(false);
596 }
597 
598 // ******************************************************************************************
599 // Load the end effectors into the table
600 // ******************************************************************************************
602 {
603  // Disable Table
604  data_table_->setUpdatesEnabled(false); // prevent table from updating until we are completely done
605  data_table_->setDisabled(true); // make sure we disable it so that the cellChanged event is not called
606  data_table_->clearContents();
607 
608  // Set size of datatable
609  data_table_->setRowCount(config_data_->srdf_->end_effectors_.size());
610 
611  // Loop through every end effector
612  int row = 0;
613  for (std::vector<srdf::Model::EndEffector>::const_iterator data_it = config_data_->srdf_->end_effectors_.begin();
614  data_it != config_data_->srdf_->end_effectors_.end(); ++data_it)
615  {
616  // Create row elements
617  QTableWidgetItem* data_name = new QTableWidgetItem(data_it->name_.c_str());
618  data_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
619  QTableWidgetItem* group_name = new QTableWidgetItem(data_it->component_group_.c_str());
620  group_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
621  QTableWidgetItem* parent_name = new QTableWidgetItem(data_it->parent_link_.c_str());
622  group_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
623  QTableWidgetItem* parent_group_name = new QTableWidgetItem(data_it->parent_group_.c_str());
624  parent_group_name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
625 
626  // Add to table
627  data_table_->setItem(row, 0, data_name);
628  data_table_->setItem(row, 1, group_name);
629  data_table_->setItem(row, 2, parent_name);
630  data_table_->setItem(row, 3, parent_group_name);
631 
632  // Increment counter
633  ++row;
634  }
635 
636  // Reenable
637  data_table_->setUpdatesEnabled(true); // prevent table from updating until we are completely done
638  data_table_->setDisabled(false); // make sure we disable it so that the cellChanged event is not called
639 
640  // Resize header
641  data_table_->resizeColumnToContents(0);
642  data_table_->resizeColumnToContents(1);
643  data_table_->resizeColumnToContents(2);
644  data_table_->resizeColumnToContents(3);
645 
646  // Show edit button if applicable
647  if (config_data_->srdf_->end_effectors_.size() > 0)
648  btn_edit_->show();
649 }
650 
651 // ******************************************************************************************
652 // Called when setup assistant navigation switches to this screen
653 // ******************************************************************************************
655 {
656  // Show the current effectors screen
657  stacked_layout_->setCurrentIndex(0);
658 
659  // Load the data to the tree
660  loadDataTable();
661 
662  // Load the avail groups to the combo box
665 }
666 
667 } // namespace
#define NULL
void editSelected()
Edit whatever element is selected.
void isModal(bool isModal)
Event for when the current screen is in modal view. Essential disabled the left navigation.
srdf::Model::EndEffector * findEffectorByName(const std::string &name)
text
EndEffectorsWidget(QWidget *parent, moveit_setup_assistant::MoveItConfigDataPtr config_data)
void deleteSelected()
Delete currently editing ite.
void unhighlightAll()
Event for telling rviz to unhighlight all links of the robot.
unsigned int index
void previewClicked(int row, int column)
Preview whatever element is selected.
void previewClickedString(const QString &name)
Preview the planning group that is selected.
virtual void focusGiven()
Received when this widget is chosen from the navigation menu.
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
void editDoubleClicked(int row, int column)
Edit the double clicked element.
std::string current_edit_effector_
Orignal name of effector currently being edited. This is used to find the element in the vector...
const std::string header
moveit_setup_assistant::MoveItConfigDataPtr config_data_
Contains all the configuration data for the setup assistant.
void highlightGroup(const std::string &name)
Event for telling rviz to highlight a group of the robot.
std::string component_group_


moveit_setup_assistant
Author(s): Dave Coleman
autogenerated on Wed Jul 10 2019 04:04:34