38 #include <QVBoxLayout> 39 #include <QPushButton> 40 #include <QMessageBox> 41 #include <QApplication> 49 #include <boost/algorithm/string.hpp> 50 #include <boost/filesystem.hpp> 58 namespace fs = boost::filesystem;
66 moveit_setup_assistant::MoveItConfigDataPtr config_data)
67 :
SetupScreenWidget(parent), config_data_(config_data), has_generated_pkg_(false), first_focusGiven_(true)
70 QVBoxLayout* layout =
new QVBoxLayout();
76 "Create or update the configuration files package needed to run your robot with MoveIt. Uncheck " 77 "files to disable them from being generated - this is useful if you have made custom changes to " 78 "them. Files in orange have been automatically detected as changed.",
80 layout->addWidget(header);
86 "Specify the desired directory for the MoveIt! configuration package to be " 87 "generated. Overwriting an existing configuration package directory is acceptable. " 88 "Example: <i>/u/robot/ros/pr2_moveit_config</i>",
96 QLabel* generated_list =
new QLabel(
"Files to be generated: (checked)",
this);
97 layout->addWidget(generated_list);
99 QSplitter* splitter =
new QSplitter(Qt::Horizontal,
this);
100 splitter->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
104 action_list_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
114 action_label_->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
124 layout->addWidget(splitter);
127 QHBoxLayout* hlayout1 =
new QHBoxLayout();
137 btn_save_ =
new QPushButton(
"&Generate Package",
this);
144 layout->addLayout(hlayout1);
148 QHBoxLayout* hlayout3 =
new QHBoxLayout();
152 QFont success_label_font(QFont().defaultFamily(), 12, QFont::Bold);
155 success_label_->setText(
"Configuration package generated successfully!");
160 QPushButton* btn_exit =
new QPushButton(
"E&xit Setup Assistant",
this);
161 btn_exit->setMinimumWidth(180);
163 hlayout3->addWidget(btn_exit);
164 hlayout3->setAlignment(btn_exit, Qt::AlignRight);
166 layout->addLayout(hlayout3);
169 this->setLayout(layout);
178 std::string template_path;
184 fs::path template_package_path =
config_data_->setup_assistant_path_;
185 template_package_path /=
"templates";
186 template_package_path /=
"moveit_config_pkg_template";
187 config_data_->template_package_path_ = template_package_path.make_preferred().native().c_str();
189 if (!fs::is_directory(
config_data_->template_package_path_))
191 QMessageBox::critical(
192 this,
"Error Generating",
193 QString(
"Unable to find package template directory: ").
append(
config_data_->template_package_path_.c_str()));
216 file.
description_ =
"CMake build system configuration file";
224 std::string config_path =
"config";
229 file.
description_ =
"Folder containing all MoveIt! configuration files for your robot. This folder is required and " 230 "cannot be disabled.";
241 file.
description_ =
"SRDF (<a href='http://www.ros.org/wiki/srdf'>Semantic Robot Description Format</a>) is a " 242 "representation of semantic information about robots. This format is intended to represent " 243 "information about the robot that is not in the URDF file, but it is useful for a variety of " 244 "applications. The intention is to include information that has a semantic aspect to it.";
254 file.
description_ =
"Configures the OMPL (<a href='http://ompl.kavrakilab.org/'>Open Motion Planning Library</a>) " 255 "planning plugin. For every planning group defined in the SRDF, a number of planning " 256 "configurations are specified (under planner_configs). Additionally, default settings for the " 257 "state space to plan in for a particular group can be specified, such as the collision checking " 258 "resolution. Each planning configuration specified for a group must be defined under the " 259 "planner_configs tag. While defining a planner configuration, the only mandatory parameter is " 260 "'type', which is the name of the motion planner to be used. Any other planner-specific " 261 "parameters can be defined but are optional.";
269 file.
description_ =
"Specifies which chomp planning plugin parameters to be used for the CHOMP planner";
277 file.
description_ =
"Specifies which kinematic solver plugin to use for each planning group in the SRDF, as well as " 278 "the kinematic solver search resolution.";
286 file.
description_ =
"Contains additional information about joints that appear in your planning groups that is not " 287 "contained in the URDF, as well as allowing you to set maximum and minimum limits for velocity " 288 "and acceleration than those contained in your URDF. This information is used by our trajectory " 289 "filtering system to assign reasonable velocities and timing for the trajectory before it is " 290 "passed to the robots controllers.";
298 file.
description_ =
"Creates dummy configurations for controllers that correspond to defined groups. This is mostly " 299 "useful for testing.";
307 file.
description_ =
"Creates configurations for ros_controllers.";
315 file.
description_ =
"Creates configurations 3d sensors.";
323 std::string launch_path =
"launch";
324 const std::string template_launch_path =
config_data_->appendPaths(
config_data_->template_package_path_, launch_path);
330 "Folder containing all MoveIt! launch files for your robot. This folder is required and cannot be " 340 file.
description_ =
"Launches the move_group node that provides the MoveGroup action and other parameters <a " 341 "href='http://moveit.ros.org/doxygen/" 342 "classmoveit_1_1planning__interface_1_1MoveGroup.html#details'>MoveGroup action</a>";
351 file.
description_ =
"Loads settings for the ROS parameter server, required for running MoveIt. This includes the " 352 "SRDF, joints_limits.yaml file, ompl_planning.yaml file, optionally the URDF, etc";
361 file.
description_ =
"Visualize in Rviz the robot's planning groups running with interactive markers that allow goal " 369 file.
file_name_ =
"ompl_planning_pipeline.launch.xml";
372 file.
description_ =
"Intended to be included in other launch files that require the OMPL planning plugin. Defines " 373 "the proper plugin name on the parameter server and a default selection of planning request " 381 file.
file_name_ =
"chomp_planning_pipeline.launch.xml";
384 file.
description_ =
"Intended to be included in other launch files that require the CHOMP planning plugin. Defines " 385 "the proper plugin name on the parameter server and a default selection of planning request " 392 file.
file_name_ =
"planning_pipeline.launch.xml";
395 file.
description_ =
"Helper launch file that can choose between different planning pipelines to be loaded.";
401 file.
file_name_ =
"warehouse_settings.launch.xml";
404 file.
description_ =
"Helper launch file that specifies default settings for MongoDB.";
413 file.
description_ =
"Launch file for starting MongoDB.";
419 file.
file_name_ =
"default_warehouse_db.launch";
422 file.
description_ =
"Launch file for starting the warehouse with a default MongoDB.";
428 file.
file_name_ =
"run_benchmark_ompl.launch";
431 file.
description_ =
"Launch file for benchmarking OMPL planners";
437 file.
file_name_ =
"sensor_manager.launch.xml";
440 file.
description_ =
"Helper launch file that can choose between different sensor managers to be loaded.";
446 file.
file_name_ = robot_name +
"_moveit_controller_manager.launch.xml";
448 template_path =
config_data_->appendPaths(template_launch_path,
"moveit_controller_manager.launch.xml");
449 file.
description_ =
"Placeholder for settings specific to the MoveIt! controller manager implemented for you robot.";
455 file.
file_name_ = robot_name +
"_moveit_sensor_manager.launch.xml";
457 template_path =
config_data_->appendPaths(template_launch_path,
"moveit_sensor_manager.launch.xml");
458 file.
description_ =
"Placeholder for settings specific to the MoveIt! sensor manager implemented for you robot.";
464 file.
file_name_ =
"trajectory_execution.launch.xml";
467 file.
description_ =
"Loads settings for the ROS parameter server required for executing trajectories using the " 468 "trajectory_execution_manager::TrajectoryExecutionManager.";
474 file.
file_name_ =
"fake_moveit_controller_manager.launch.xml";
494 template_path =
config_data_->appendPaths(template_launch_path,
"gazebo.launch");
495 file.
description_ =
"Gazebo launch file which also launches ros_controllers and sends robot urdf to param server, " 496 "then using gazebo_ros pkg the robot is spawned to Gazebo";
504 file.
description_ =
"Run a demo of MoveIt with Gazebo and Rviz";
513 file.
description_ =
"Control the Rviz Motion Planning Plugin with a joystick";
522 template_launch_path,
"edit_configuration_package.launch");
524 file.
description_ =
"Launch file for easily re-starting the MoveIt! Setup Assistant to edit this robot's generated " 525 "configuration package.";
533 template_path =
config_data_->appendPaths(template_launch_path,
"ros_controllers.launch");
542 template_path =
config_data_->appendPaths(template_launch_path,
"moveit.rviz");
543 file.
description_ =
"Configuration file for Rviz with the Motion Planning Plugin already setup. Used by passing " 544 "roslaunch moveit_rviz.launch config:=true";
556 file.
description_ =
"MoveIt! Setup Assistant's hidden settings file. You should not need to edit this file.";
569 QStringList dependencies;
570 bool requiredActions =
false;
575 dependencies <<
"No robot model planning groups have been created";
581 dependencies <<
"No self-collisions have been disabled";
587 dependencies <<
"No end effectors have been added";
593 dependencies <<
"No virtual joints have been added";
597 if (
config_data_->author_name_.find_first_not_of(
' ') == std::string::npos)
600 dependencies <<
"<b>No author name added</b>";
601 requiredActions =
true;
605 QRegExp mailRegex(
"\\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,4}\\b");
606 mailRegex.setCaseSensitivity(Qt::CaseInsensitive);
607 mailRegex.setPatternSyntax(QRegExp::RegExp);
608 QString testEmail = QString::fromStdString(
config_data_->author_email_);
609 if (!mailRegex.exactMatch(testEmail))
611 dependencies <<
"<b>No valid email address added</b>";
612 requiredActions =
true;
616 if (dependencies.size())
620 if (!requiredActions)
622 dep_message =
"Some setup steps have not been completed. None of the steps are required, but here is a reminder " 623 "of what was not filled in, just in case something was forgotten:<br /><ul>";
627 dep_message =
"Some setup steps have not been completed. Please fix the required steps (printed in bold), " 628 "otherwise the setup cannot be completed:<br /><ul>";
631 for (
int i = 0; i < dependencies.size(); ++i)
633 dep_message.append(
"<li>").append(dependencies.at(i)).
append(
"</li>");
636 if (!requiredActions)
638 dep_message.append(
"</ul><br/>Press Ok to continue generating files.");
639 if (QMessageBox::question(
this,
"Incomplete MoveIt! Setup Assistant Steps", dep_message,
640 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
647 QMessageBox::warning(
this,
"Incomplete MoveIt! Setup Assistant Steps", dep_message);
666 QApplication::processEvents();
687 std::size_t
index = item->data(Qt::UserRole).toUInt();
688 bool generate = (item->checkState() == Qt::Checked);
692 QMessageBox::warning(
this,
"Package Generation",
"You should generate this file to ensure your changes will take " 727 QApplication::processEvents();
729 if (files_already_modified)
732 QString msg(
"Some files have been modified outside of the Setup Assistant (according to timestamp). " 733 "The Setup Assistant will not overwrite these changes by default because often changing configuration " 734 "files manually is necessary, " 735 "but we recommend you check the list and enable the checkbox next to files you would like to " 737 if (have_conflicting_changes)
738 msg +=
"<br/><font color='red'>Attention:</font> Some files (<font color='red'>marked red</font>) are changed " 739 "both, externally and in Setup Assistant.";
740 QMessageBox::information(
this,
"Files Modified", msg);
758 static const std::time_t TIME_MOD_TOLERANCE = 10;
761 bool found_modified =
false;
762 for (std::size_t i = 0; i <
gen_files_.size(); ++i)
769 if (fs::is_directory(file_path))
772 if (fs::is_regular_file(file_path))
774 std::time_t mod_time = fs::last_write_time(file_path);
779 if (mod_time >
config_data_->config_pkg_generated_timestamp_ + TIME_MOD_TOLERANCE ||
780 mod_time < config_data_->config_pkg_generated_timestamp_ - TIME_MOD_TOLERANCE)
789 found_modified =
true;
799 return found_modified;
807 bool have_conflicting_changes =
false;
811 for (std::size_t i = 0; i <
gen_files_.size(); ++i)
821 item->setCheckState(file->
generate_ ? Qt::Checked : Qt::Unchecked);
827 have_conflicting_changes =
true;
828 item->setForeground(QBrush(QColor(255, 0, 0)));
831 item->setForeground(QBrush(QColor(255, 135, 0)));
835 if (fs::is_directory(file_path))
837 item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
841 item->setData(Qt::UserRole, QVariant(static_cast<qulonglong>(i)));
850 return have_conflicting_changes;
886 if (new_package_path.empty())
888 QMessageBox::warning(
this,
"Error Generating",
"No package path provided. Please choose a directory location to " 889 "generate the MoveIt! configuration files.");
902 boost::trim(new_package_path);
907 const std::string setup_assistant_file =
config_data_->appendPaths(new_package_path, SETUP_ASSISTANT_FILE);
910 if (fs::is_directory(new_package_path) && !fs::is_empty(new_package_path))
913 if (!fs::is_regular_file(setup_assistant_file))
915 QMessageBox::warning(
916 this,
"Incorrect Folder/Package",
917 QString(
"The chosen package location already exists but was not previously created using this MoveIt! Setup " 919 "If this is a mistake, add the missing file: ")
920 .
append(setup_assistant_file.c_str()));
925 if (QMessageBox::question(
926 this,
"Confirm Package Update",
927 QString(
"Are you sure you want to overwrite this existing package with updated configurations?<br /><i>")
928 .
append(new_package_path.c_str())
930 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
940 fs::create_directory(new_package_path) && !fs::is_directory(new_package_path);
944 QMessageBox::critical(
this,
"Error Generating Files",
945 QString(
"Unable to create directory ").
append(new_package_path.c_str()));
951 std::string absolute_path;
953 for (std::size_t i = 0; i <
gen_files_.size(); ++i)
971 QMessageBox::critical(
this,
"Error Generating File", QString(
"Failed to generate folder or file: '")
973 .
append(
"' at location:\n")
974 .append(absolute_path.c_str()));
989 QMessageBox::question(
this,
"Exit Setup Assistant",
990 QString(
"Are you sure you want to exit the MoveIt! Setup Assistant?"),
991 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok)
993 QApplication::quit();
1003 if (!package_path.compare(package_path.size() - 1, 1,
"/"))
1005 package_path = package_path.substr(0, package_path.size() - 1);
1009 std::string package_name;
1010 fs::path fs_package_path = package_path;
1012 package_name = fs_package_path.filename().c_str();
1015 if (package_name.empty())
1016 package_name =
"unknown";
1018 return package_name;
1027 for (std::vector<srdf::Model::Group>::const_iterator group_it =
config_data_->srdf_->groups_.begin();
1028 group_it !=
config_data_->srdf_->groups_.end(); ++group_it)
1031 if (group_it->joints_.size())
1033 if (group_it->links_.size())
1035 if (group_it->chains_.size())
1037 if (group_it->subgroups_.size())
1041 QMessageBox::warning(
1042 this,
"Empty Group",
1043 QString(
"The planning group '")
1044 .
append(group_it->name_.c_str())
1045 .
append(
"' is empty and has no subcomponents associated with it (joints/links/chains/subgroups). You must " 1046 "edit or remove this planning group before this configuration package can be saved."));
1070 "command=\"xacro " +
config_data_->xacro_args_ +
" '" + urdf_location +
"'\"");
1072 addTemplateString(
"[URDF_LOAD_ATTRIBUTE]",
"textfile=\"" + urdf_location +
"\"");
1084 std::stringstream vjb;
1085 for (std::size_t i = 0; i <
config_data_->srdf_->virtual_joints_.size(); ++i)
1088 if (vj.
type_ !=
"fixed")
1089 vjb <<
" <node pkg=\"tf\" type=\"static_transform_publisher\" name=\"virtual_joint_broadcaster_" << i
1101 std::stringstream deps;
1102 deps <<
"<build_depend>" <<
config_data_->urdf_pkg_name_ <<
"</build_depend>\n";
1103 deps <<
" <run_depend>" <<
config_data_->urdf_pkg_name_ <<
"</run_depend>\n";
1114 std::stringstream controllers;
1115 for (std::vector<ROSControlConfig>::iterator controller_it =
config_data_->getROSControllers().begin();
1116 controller_it !=
config_data_->getROSControllers().end(); ++controller_it)
1119 if (controller_it->type_ !=
"FollowJointTrajectory")
1120 controllers << controller_it->name_ <<
" ";
1151 if (!fs::is_regular_file(template_path))
1158 std::ifstream template_stream(template_path.c_str());
1159 if (!template_stream.good())
1166 std::string template_string;
1167 template_stream.seekg(0, std::ios::end);
1168 template_string.reserve(template_stream.tellg());
1169 template_stream.seekg(0, std::ios::beg);
1170 template_string.assign((std::istreambuf_iterator<char>(template_stream)), std::istreambuf_iterator<char>());
1171 template_stream.close();
1180 std::ofstream output_stream(output_path.c_str(), std::ios_base::trunc);
1181 if (!output_stream.good())
1187 output_stream << template_string.c_str();
1188 output_stream.close();
1198 if (!fs::is_directory(output_path))
1200 if (!fs::create_directory(output_path))
1202 QMessageBox::critical(
this,
"Error Generating Files",
1203 QString(
"Unable to create directory ").
append(output_path.c_str()));
unsigned long write_on_changes
bool outputKinematicsYAML(const std::string &file_path)
bool outputSetupAssistantFile(const std::string &file_path)
bool outputCHOMPPlanningYAML(const std::string &file_path)
std::string parent_frame_
bool outputFakeControllersYAML(const std::string &file_path)
bool output3DSensorPluginYAML(const std::string &file_path)
bool writeSRDF(const std::string &file_path)
bool outputJointLimitsYAML(const std::string &file_path)
#define ROS_WARN_STREAM(args)
#define ROS_DEBUG_STREAM(args)
const std::string SETUP_ASSISTANT_FILE
bool outputROSControllersYAML(const std::string &file_path)
bool outputOMPLPlanningYAML(const std::string &file_path)
#define ROS_INFO_STREAM(args)
ROSCPP_DECL std::string append(const std::string &left, const std::string &right)
#define ROS_ERROR_STREAM(args)
boost::function< bool(std::string)> gen_func_