53 #include <boost/thread.hpp> 54 #include <boost/lexical_cast.hpp> 56 #include <QApplication> 58 #include <QVBoxLayout> 59 #include <QHBoxLayout> 61 #include <QPushButton> 62 #include <QMessageBox> 65 #include <QTreeWidgetItem> 66 #include <QHeaderView> 68 #include <boost/utility.hpp> 69 #include <boost/graph/adjacency_list.hpp> 70 #include <boost/graph/depth_first_search.hpp> 71 #include <boost/graph/visitors.hpp> 76 static const std::string
VIS_TOPIC_NAME =
"planning_components_visualization";
85 template <
class Edge,
class Graph>
102 QVBoxLayout* layout =
new QVBoxLayout();
106 "Define Planning Groups",
107 "Create and edit 'joint model' groups for your robot based on joint collections, " 108 "link collections, kinematic chains or subgroups. " 109 "A planning group defines the set of (joint, link) pairs considered for planning " 110 "and collision checking. Define individual groups for each subset of the robot you want to plan for." 111 "Note: when adding a link to the group, its parent joint is added too and vice versa.",
113 layout->addWidget(header);
173 QWidget* stacked_layout_widget =
new QWidget(
this);
176 layout->addWidget(stacked_layout_widget);
181 QApplication::processEvents();
190 QWidget* content_widget =
new QWidget(
this);
193 QVBoxLayout* layout =
new QVBoxLayout(
this);
205 QHBoxLayout* controls_layout =
new QHBoxLayout();
208 QLabel* expand_controls =
new QLabel(
this);
209 expand_controls->setText(
"<a href='expand'>Expand All</a> <a href='contract'>Collapse All</a>");
210 connect(expand_controls, SIGNAL(linkActivated(
const QString)),
this, SLOT(
alterTree(
const QString)));
211 controls_layout->addWidget(expand_controls);
214 QWidget* spacer =
new QWidget(
this);
215 spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
216 controls_layout->addWidget(spacer);
219 btn_delete_ =
new QPushButton(
"&Delete Selected",
this);
220 btn_delete_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
224 controls_layout->setAlignment(
btn_delete_, Qt::AlignRight);
227 btn_edit_ =
new QPushButton(
"&Edit Selected",
this);
228 btn_edit_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
233 controls_layout->setAlignment(
btn_edit_, Qt::AlignRight);
236 QPushButton* btn_add =
new QPushButton(
"&Add Group",
this);
237 btn_add->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
238 btn_add->setMaximumWidth(300);
239 connect(btn_add, SIGNAL(clicked()),
this, SLOT(
addGroup()));
240 controls_layout->addWidget(btn_add);
241 controls_layout->setAlignment(btn_add, Qt::AlignRight);
244 layout->addLayout(controls_layout);
247 content_widget->setLayout(layout);
249 return content_widget;
263 for (std::vector<srdf::Model::Group>::iterator group_it =
config_data_->srdf_->groups_.begin();
264 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
294 const QFont top_level_font(QFont().defaultFamily(), 11, QFont::Bold);
295 const QFont type_font(QFont().defaultFamily(), 11, QFont::Normal, QFont::StyleItalic);
297 QTreeWidgetItem*
group;
303 group->setText(0, group_it.
name_.c_str());
304 group->setFont(0, top_level_font);
305 group->setData(0, Qt::UserRole, QVariant::fromValue(
PlanGroupType(&group_it,
GROUP)));
310 group =
new QTreeWidgetItem(parent);
311 group->setText(0, group_it.
name_.c_str());
312 group->setFont(0, top_level_font);
313 group->setData(0, Qt::UserRole, QVariant::fromValue(
PlanGroupType(&group_it,
GROUP)));
314 parent->addChild(group);
318 QTreeWidgetItem* joints =
new QTreeWidgetItem(group);
319 joints->setText(0,
"Joints");
320 joints->setFont(0, type_font);
321 joints->setData(0, Qt::UserRole, QVariant::fromValue(
PlanGroupType(&group_it,
JOINT)));
322 group->addChild(joints);
325 const robot_model::RobotModelConstPtr& model =
config_data_->getRobotModel();
328 for (std::vector<std::string>::const_iterator joint_it = group_it.
joints_.begin(); joint_it != group_it.
joints_.end();
331 QTreeWidgetItem* j =
new QTreeWidgetItem(joints);
333 std::string joint_name;
336 const robot_model::JointModel* jm = model->getJointModel(*joint_it);
339 joint_name = *joint_it +
" - " + jm->getTypeName();
343 joint_name = *joint_it;
347 j->setText(0, joint_name.c_str());
352 QTreeWidgetItem* links =
new QTreeWidgetItem(group);
353 links->setText(0,
"Links");
354 links->setFont(0, type_font);
355 links->setData(0, Qt::UserRole, QVariant::fromValue(
PlanGroupType(&group_it,
LINK)));
356 group->addChild(links);
359 for (std::vector<std::string>::const_iterator joint_it = group_it.
links_.begin(); joint_it != group_it.
links_.end();
362 QTreeWidgetItem* j =
new QTreeWidgetItem(links);
363 j->setData(0, Qt::UserRole, QVariant::fromValue(
PlanGroupType(&group_it,
LINK)));
364 j->setText(0, joint_it->c_str());
369 QTreeWidgetItem* chains =
new QTreeWidgetItem(group);
370 chains->setText(0,
"Chain");
371 chains->setFont(0, type_font);
372 chains->setData(0, Qt::UserRole, QVariant::fromValue(
PlanGroupType(&group_it,
CHAIN)));
373 group->addChild(chains);
376 static bool warn_once =
true;
377 if (group_it.
chains_.size() > 1 && warn_once)
380 QMessageBox::warning(
this,
"Group with Multiple Kinematic Chains",
381 "Warning: this MoveIt! Setup Assistant is only designed to handle one kinematic chain per " 382 "group. The loaded SRDF has more than one kinematic chain for a group. A possible loss of " 387 for (std::vector<std::pair<std::string, std::string> >::const_iterator chain_it = group_it.
chains_.begin();
388 chain_it != group_it.
chains_.end(); ++chain_it)
390 QTreeWidgetItem* j =
new QTreeWidgetItem(chains);
392 j->setText(0, QString(chain_it->first.c_str()).
append(
" -> ").append(chain_it->second.c_str()));
397 QTreeWidgetItem* subgroups =
new QTreeWidgetItem(group);
398 subgroups->setText(0,
"Subgroups");
399 subgroups->setFont(0, type_font);
401 group->addChild(subgroups);
404 for (std::vector<std::string>::iterator subgroup_it = group_it.
subgroups_.begin();
405 subgroup_it != group_it.
subgroups_.end(); ++subgroup_it)
411 for (std::vector<srdf::Model::Group>::iterator group2_it =
config_data_->srdf_->groups_.begin();
412 group2_it !=
config_data_->srdf_->groups_.end(); ++group2_it)
414 if (group2_it->name_ == *subgroup_it)
416 searched_group = &(*group2_it);
422 if (searched_group ==
NULL)
424 QMessageBox::critical(
this,
"Error Loading SRDF", QString(
"Subgroup '")
425 .
append(subgroup_it->c_str())
427 .append(group_it.
name_.c_str())
428 .
append(
"' not found. Your SRDF is invalid"));
518 QMessageBox::critical(
this,
"Error Loading",
"An internal error has occured while loading.");
528 const robot_model::RobotModelConstPtr& model =
config_data_->getRobotModel();
531 const std::vector<std::string>& joints = model->getJointModelNames();
533 if (joints.size() == 0)
535 QMessageBox::critical(
this,
"Error Loading",
"No joints found for robot model");
547 QString(
"Edit '").
append(QString::fromUtf8(this_group->
name_.c_str())).append(
"' Joint Collection"));
560 const robot_model::RobotModelConstPtr& model =
config_data_->getRobotModel();
563 const std::vector<std::string>& links = model->getLinkModelNames();
565 if (links.size() == 0)
567 QMessageBox::critical(
this,
"Error Loading",
"No links found for robot model");
579 QString(
"Edit '").
append(QString::fromUtf8(this_group->
name_.c_str())).append(
"' Link Collection"));
595 if (this_group->
chains_.size() > 1)
597 QMessageBox::warning(
this,
"Multiple Kinematic Chains",
"Warning: This setup assistant is only designed to handle " 598 "one kinematic chain per group. The loaded SRDF has more " 599 "than one kinematic chain for a group. A possible loss of " 604 if (this_group->
chains_.size() > 0)
611 QString(
"Edit '").
append(QString::fromUtf8(this_group->
name_.c_str())).append(
"' Kinematic Chain"));
624 std::vector<std::string> subgroups;
627 for (std::vector<srdf::Model::Group>::iterator group_it =
config_data_->srdf_->groups_.begin();
628 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
630 if (group_it->name_ != this_group->
name_)
633 subgroups.push_back(group_it->name_);
645 QString(
"Edit '").
append(QString::fromUtf8(this_group->
name_.c_str())).append(
"' Subgroups"));
660 if (this_group ==
NULL)
711 if (QMessageBox::question(
712 this,
"Confirm Group Deletion",
713 QString(
"Are you sure you want to delete the planning group '")
715 .
append(
"'? This will also delete all references in subgroups, robot poses and end effectors."),
716 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
722 bool haveConfirmedGroupStateDeletion =
false;
723 bool haveDeletedGroupState =
true;
724 while (haveDeletedGroupState)
726 haveDeletedGroupState =
false;
727 for (std::vector<srdf::Model::GroupState>::iterator pose_it =
config_data_->srdf_->group_states_.begin();
728 pose_it !=
config_data_->srdf_->group_states_.end(); ++pose_it)
731 if (pose_it->group_ == searched_group->
name_)
733 if (!haveConfirmedGroupStateDeletion)
735 haveConfirmedGroupStateDeletion =
true;
738 if (QMessageBox::question(
739 this,
"Confirm Group State Deletion",
740 QString(
"The group that is about to be deleted has robot poses (robot states) that depend on this " 741 "group. Are you sure you want to delete this group as well as all dependend robot poses?"),
742 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
751 haveDeletedGroupState =
true;
758 bool haveConfirmedEndEffectorDeletion =
false;
759 bool haveDeletedEndEffector =
true;
760 while (haveDeletedEndEffector)
762 haveDeletedEndEffector =
false;
763 for (std::vector<srdf::Model::EndEffector>::iterator effector_it =
config_data_->srdf_->end_effectors_.begin();
764 effector_it !=
config_data_->srdf_->end_effectors_.end(); ++effector_it)
767 if (effector_it->component_group_ == searched_group->
name_)
769 if (!haveConfirmedEndEffectorDeletion)
771 haveConfirmedEndEffectorDeletion =
true;
774 if (QMessageBox::question(
775 this,
"Confirm End Effector Deletion",
776 QString(
"The group that is about to be deleted has end effectors (grippers) that depend on this " 777 "group. Are you sure you want to delete this group as well as all dependend end effectors?"),
778 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
787 haveDeletedEndEffector =
true;
796 for (std::vector<srdf::Model::Group>::iterator group_it =
config_data_->srdf_->groups_.begin();
797 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
800 if (group_it->name_ == group)
808 for (std::vector<srdf::Model::Group>::iterator group_it =
config_data_->srdf_->groups_.begin();
809 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
812 bool deleted_subgroup =
true;
813 while (deleted_subgroup)
815 deleted_subgroup =
false;
818 for (std::vector<std::string>::iterator subgroup_it = group_it->subgroups_.begin();
819 subgroup_it != group_it->subgroups_.end(); ++subgroup_it)
822 if (subgroup_it->compare(group) == 0)
824 group_it->subgroups_.erase(subgroup_it);
825 deleted_subgroup =
true;
865 searched_group->
joints_.clear();
894 searched_group->
links_.clear();
926 if ((!tip.empty() && base.empty()) || (tip.empty() && !base.empty()))
928 QMessageBox::warning(
this,
"Error Saving",
"You must specify a link for both the base and tip, or leave both " 934 if (!tip.empty() && !base.empty())
937 if (tip.compare(base) == 0)
939 QMessageBox::warning(
this,
"Error Saving",
"Tip and base link cannot be the same link.");
943 bool found_tip =
false;
944 bool found_base =
false;
945 const std::vector<std::string>& links =
config_data_->getRobotModel()->getLinkModelNames();
947 for (std::vector<std::string>::const_iterator link_it = links.begin(); link_it != links.end(); ++link_it)
950 if (link_it->compare(tip) == 0)
952 else if (link_it->compare(base) == 0)
956 if (found_tip && found_base)
961 if (!found_tip || !found_base)
963 QMessageBox::warning(
this,
"Error Saving",
"Tip or base link(s) were not found in kinematic chain.");
969 searched_group->
chains_.clear();
972 if (!tip.empty() && !base.empty())
974 searched_group->
chains_.push_back(std::pair<std::string, std::string>(base, tip));
999 std::map<std::string, int> group_nodes;
1003 for (std::vector<srdf::Model::Group>::iterator group_it =
config_data_->srdf_->groups_.begin();
1004 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
1007 group_nodes.insert(std::pair<std::string, int>(group_it->name_, node_id));
1012 typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::bidirectionalS> Graph;
1013 Graph g(group_nodes.size());
1017 for (std::vector<srdf::Model::Group>::iterator group_it =
config_data_->srdf_->groups_.begin();
1018 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
1021 if (group_it->name_ == searched_group->
name_)
1030 int to_id = group_nodes[to_string];
1033 add_edge(from_id, to_id, g);
1039 for (
unsigned int i = 0; i < group_it->subgroups_.size(); ++i)
1042 const std::string to_string = group_it->subgroups_.at(i);
1045 int to_id = group_nodes[to_string];
1048 add_edge(from_id, to_id, g);
1056 bool has_cycle =
false;
1058 boost::depth_first_search(g, visitor(vis));
1063 QMessageBox::warning(
this,
"Error Saving",
"Depth first search reveals a cycle in the subgroups");
1104 if (group_name.empty())
1106 QMessageBox::warning(
this,
"Error Saving",
"A name must be given for the group!");
1118 for (std::vector<srdf::Model::Group>::const_iterator group_it =
config_data_->srdf_->groups_.begin();
1119 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
1121 if (group_it->name_.compare(group_name) == 0)
1124 if (&(*group_it) != searched_group)
1126 QMessageBox::warning(
this,
"Error Saving",
"A group already exists with that name!");
1133 double kinematics_resolution_double;
1136 kinematics_resolution_double = boost::lexical_cast<
double>(kinematics_resolution);
1138 catch (boost::bad_lexical_cast&)
1140 QMessageBox::warning(
this,
"Error Saving",
"Unable to convert kinematics resolution to a double number.");
1145 double kinematics_timeout_double;
1148 kinematics_timeout_double = boost::lexical_cast<
double>(kinematics_timeout);
1150 catch (boost::bad_lexical_cast&)
1152 QMessageBox::warning(
this,
"Error Saving",
"Unable to convert kinematics solver timeout to a double number.");
1157 int kinematics_attempts_int;
1160 kinematics_attempts_int = boost::lexical_cast<
int>(kinematics_attempts);
1162 catch (boost::bad_lexical_cast&)
1164 QMessageBox::warning(
this,
"Error Saving",
"Unable to convert kinematics solver attempts to an int number.");
1169 if (kinematics_resolution_double <= 0)
1171 QMessageBox::warning(
this,
"Error Saving",
"Kinematics solver search resolution must be greater than 0.");
1174 if (kinematics_timeout_double <= 0)
1176 QMessageBox::warning(
this,
"Error Saving",
"Kinematics solver search timeout must be greater than 0.");
1179 if (kinematics_attempts_int <= 0)
1181 QMessageBox::warning(
this,
"Error Saving",
"Kinematics solver attempts must be greater than 0.");
1188 if (searched_group ==
NULL)
1191 new_group.
name_ = group_name;
1199 const std::string old_group_name = searched_group->
name_;
1202 searched_group->
name_ = group_name;
1206 for (std::vector<srdf::Model::Group>::iterator group_it =
config_data_->srdf_->groups_.begin();
1207 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
1210 for (std::vector<std::string>::iterator subgroup_it = group_it->subgroups_.begin();
1211 subgroup_it != group_it->subgroups_.end(); ++subgroup_it)
1214 if (subgroup_it->compare(old_group_name) == 0)
1216 subgroup_it->assign(group_name);
1223 for (std::vector<srdf::Model::EndEffector>::iterator eef_it =
config_data_->srdf_->end_effectors_.begin();
1224 eef_it !=
config_data_->srdf_->end_effectors_.end(); ++eef_it)
1227 if (eef_it->parent_group_.compare(old_group_name) == 0)
1229 ROS_DEBUG_STREAM_NAMED(
"setup_assistant",
"Changed eef '" << eef_it->name_ <<
"' to new parent group name " 1231 eef_it->parent_group_ = group_name;
1236 if (eef_it->component_group_.compare(old_group_name) == 0)
1240 eef_it->component_group_ = group_name;
1246 for (std::vector<srdf::Model::GroupState>::iterator state_it =
config_data_->srdf_->group_states_.begin();
1247 state_it !=
config_data_->srdf_->group_states_.end(); ++state_it)
1250 if (state_it->group_.compare(old_group_name) == 0)
1253 <<
"' to new parent group name " 1255 state_it->group_ = group_name;
1265 config_data_->group_meta_data_[group_name].kinematics_solver_ = kinematics_solver;
1266 config_data_->group_meta_data_[group_name].kinematics_solver_search_resolution_ = kinematics_resolution_double;
1267 config_data_->group_meta_data_[group_name].kinematics_solver_timeout_ = kinematics_timeout_double;
1268 config_data_->group_meta_data_[group_name].kinematics_solver_attempts_ = kinematics_attempts_int;
1269 config_data_->group_meta_data_[group_name].default_planner_ = default_planner;
1366 if (editing && editing->
joints_.empty() && editing->
links_.empty() && editing->
chains_.empty() &&
1370 for (std::vector<srdf::Model::Group>::iterator group_it =
config_data_->srdf_->groups_.begin();
1371 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
1372 if (&(*group_it) == editing)
1404 if (link.contains(
"expand"))
1440 for (std::size_t i = 0; i < links.size(); ++i)
1442 if (links[i].empty())
1460 for (std::size_t i = 0; i < joints.size(); ++i)
1462 const robot_model::JointModel* joint_model =
config_data_->getRobotModel()->getJointModel(joints[i]);
1471 const std::string link = joint_model->getChildLinkModel()->getName();
1491 for (std::size_t i = 0; i < groups.size(); ++i)
1507 : group_(group), type_(type)
std::vector< std::string > subgroups_
MatrixDerived base(const Eigen::MatrixBase< MatrixDerived > &m)
#define ROS_DEBUG_STREAM_NAMED(name, args)
std::vector< std::pair< std::string, std::string > > chains_
cycle_detector(bool &has_cycle)
srdf::Model::Group * group_
static const std::string VIS_TOPIC_NAME
void back_edge(Edge, Graph &)
std::vector< std::string > links_
std::vector< std::string > joints_
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
moveit_setup_assistant::GroupType type_