$search
00001 /* 00002 * Copyright (c) 2011, Willow Garage, Inc. 00003 * All rights reserved. 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * * Redistributions of source code must retain the above copyright 00009 * notice, this list of conditions and the following disclaimer. 00010 * * Redistributions in binary form must reproduce the above copyright 00011 * notice, this list of conditions and the following disclaimer in the 00012 * documentation and/or other materials provided with the distribution. 00013 * * Neither the name of the <ORGANIZATION> nor the names of its 00014 * contributors may be used to endorse or promote products derived from 00015 * this software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 */ 00029 00030 // Author: E. Gil Jones 00031 00032 #include <planning_environment/tools/planning_description_configuration_wizard.h> 00033 #include <qt4/QtGui/qapplication.h> 00034 #include <qt4/QtGui/qradiobutton.h> 00035 #include <qt4/QtGui/qdialogbuttonbox.h> 00036 #include <qt4/QtCore/qtextstream.h> 00037 #include <QHeaderView> 00038 #include <boost/thread.hpp> 00039 00040 using namespace std; 00041 using namespace planning_environment; 00042 using namespace planning_models; 00043 using namespace visualization_msgs; 00044 using namespace collision_space; 00045 00046 PlanningDescriptionConfigurationWizard::PlanningDescriptionConfigurationWizard(const string& urdf_package, 00047 const string& urdf_path, QWidget* parent) : 00048 QWizard(parent), inited_(false), world_joint_config_("world_joint"), urdf_package_(urdf_package), 00049 urdf_path_(urdf_path) 00050 { 00051 setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 00052 emitter_ = NULL; 00053 progress_ = 0; 00054 package_directory_ = ""; 00055 string full_urdf_path = ros::package::getPath(urdf_package_)+"/"+urdf_path_; 00056 00057 ROS_INFO_STREAM("full path name is " << full_urdf_path); 00058 00059 urdf_ = boost::shared_ptr<urdf::Model>(new urdf::Model()); 00060 bool urdf_ok = urdf_->initFile(full_urdf_path); 00061 00062 if(!urdf_ok) 00063 { 00064 ROS_WARN_STREAM("Urdf file " << full_urdf_path << " not ok"); 00065 return; 00066 } 00067 00068 //making directories 00069 dir_name_ = getRobotName() + "_arm_navigation"; 00070 00071 yaml_outfile_name_ = getRobotName() + "_planning_description.yaml"; 00072 full_yaml_outfile_name_ = dir_name_ + "/config/" + yaml_outfile_name_; 00073 launch_outfile_name_ = getRobotName() + "_planning_environment.launch"; 00074 full_launch_outfile_name_ = dir_name_ + "/launch/" + launch_outfile_name_; 00075 00076 //pushing to the param server 00077 string com = "rosparam set robot_description -t " + full_urdf_path; 00078 00079 int ok = system(com.c_str()); 00080 00081 if(ok != 0) 00082 { 00083 ROS_WARN_STREAM("Setting parameter system call not ok"); 00084 return; 00085 } 00086 00087 kmodel_ = NULL; 00088 cm_ = NULL; 00089 ops_gen_ = NULL; 00090 robot_state_ = NULL; 00091 ode_collision_model_ = NULL; 00092 00093 if(!setupWithWorldFixedFrame("", "Floating")) 00094 { 00095 return; 00096 } 00097 00098 outputConfigAndLaunchRviz(); 00099 00100 vis_marker_publisher_ = nh_.advertise<Marker> (VIS_TOPIC_NAME, 128); 00101 vis_marker_array_publisher_ = nh_.advertise<MarkerArray> (VIS_TOPIC_NAME + "_array", 128); 00102 00103 wizard_mode_ = PlanningDescriptionConfigurationWizard::Easy; 00104 ode_collision_model_ = new EnvironmentModelODE(); 00105 00106 const vector<KinematicModel::LinkModel*>& coll_links = kmodel_->getLinkModelsWithCollisionGeometry(); 00107 00108 vector<string> coll_names; 00109 for(unsigned int i = 0; i < coll_links.size(); i++) 00110 { 00111 coll_names.push_back(coll_links[i]->getName()); 00112 } 00113 EnvironmentModel::AllowedCollisionMatrix default_collision_matrix(coll_names, false); 00114 map<string, double> default_link_padding_map; 00115 ode_collision_model_->setRobotModel(kmodel_, default_collision_matrix, default_link_padding_map, 0.0, 1.0); 00116 00117 cm_ = new CollisionModels(urdf_, kmodel_, ode_collision_model_); 00118 ops_gen_ = new CollisionOperationsGenerator(cm_); 00119 00120 00121 setupQtPages(); 00122 inited_ = true; 00123 } 00124 00125 PlanningDescriptionConfigurationWizard::~PlanningDescriptionConfigurationWizard() 00126 { 00127 if(cm_ != NULL) 00128 { 00129 delete cm_; 00130 } 00131 if(ops_gen_ != NULL) 00132 { 00133 delete ops_gen_; 00134 } 00135 if(emitter_ != NULL) { 00136 delete emitter_; 00137 } 00138 } 00139 00140 void PlanningDescriptionConfigurationWizard::deleteKinematicStates() 00141 { 00142 if(robot_state_ != NULL) 00143 { 00144 delete robot_state_; 00145 robot_state_ = NULL; 00146 } 00147 } 00148 00149 bool PlanningDescriptionConfigurationWizard::setupWithWorldFixedFrame(const string& world_fixed_frame, 00150 const string& joint_type) 00151 { 00152 lock_.lock(); 00153 00154 vector<KinematicModel::GroupConfig> gcs; 00155 vector<KinematicModel::MultiDofConfig> multi_dof_configs; 00156 const urdf::Link *root = urdf_->getRoot().get(); 00157 00158 string ff; 00159 00160 if(world_fixed_frame.empty()) 00161 { 00162 ff = root->name; 00163 } 00164 else 00165 { 00166 ff = world_fixed_frame; 00167 } 00168 00169 ROS_INFO_STREAM("Setting world frame to " << ff); 00170 00171 //now this should work with an n=on-identity transform 00172 world_joint_config_.type = joint_type; 00173 world_joint_config_.parent_frame_id = ff; 00174 world_joint_config_.child_frame_id = root->name; 00175 multi_dof_configs.push_back(world_joint_config_); 00176 00177 deleteKinematicStates(); 00178 00179 if(cm_ != NULL) 00180 { 00181 delete cm_; 00182 } 00183 if(ops_gen_ != NULL) 00184 { 00185 delete ops_gen_; 00186 } 00187 kmodel_ = new KinematicModel(*urdf_, gcs, multi_dof_configs); 00188 00189 if(kmodel_->getRoot() == NULL) 00190 { 00191 ROS_INFO_STREAM("Kinematic root is NULL"); 00192 lock_.unlock(); 00193 return false; 00194 } 00195 00196 robot_state_ = new KinematicState(kmodel_); 00197 robot_state_->setKinematicStateToDefault(); 00198 00199 lock_.unlock(); 00200 00201 return true; 00202 } 00203 00204 void PlanningDescriptionConfigurationWizard::emitWorldJointYAML() 00205 { 00206 00207 (*emitter_) << YAML::Key << "multi_dof_joints"; 00208 (*emitter_) << YAML::Value << YAML::BeginSeq; 00209 (*emitter_) << YAML::BeginMap; 00210 (*emitter_) << YAML::Key << "name" << YAML::Value << world_joint_config_.name; 00211 (*emitter_) << YAML::Key << "type" << YAML::Value << world_joint_config_.type; 00212 (*emitter_) << YAML::Key << "parent_frame_id" << YAML::Value << world_joint_config_.parent_frame_id; 00213 (*emitter_) << YAML::Key << "child_frame_id" << YAML::Value << world_joint_config_.child_frame_id; 00214 (*emitter_) << YAML::EndMap; 00215 (*emitter_) << YAML::EndSeq; 00216 } 00217 00218 void PlanningDescriptionConfigurationWizard::outputConfigAndLaunchRviz() 00219 { 00220 00221 string template_name = ros::package::getPath("planning_environment") 00222 + "/config/planning_description_configuration_wizard.vcg"; 00223 00224 ifstream template_file(template_name.c_str()); 00225 00226 ofstream ofile("planning_description_configuration_wizard.vcg"); 00227 00228 char ch; 00229 char buf[80]; 00230 while(template_file && template_file.get(ch)) 00231 { 00232 if(ch != '$') 00233 { 00234 ofile.put(ch); 00235 } 00236 else 00237 { 00238 template_file.getline(buf, 80, '$'); 00239 if(template_file.eof() || template_file.bad()) 00240 { 00241 ROS_ERROR_STREAM("Bad template file"); 00242 break; 00243 } 00244 ofile << kmodel_->getRoot()->getParentFrameId(); 00245 } 00246 } 00247 00248 ofstream touch_file("vcg_ready"); 00249 } 00250 00251 PlanningDescriptionConfigurationWizard::GroupAddStatus 00252 PlanningDescriptionConfigurationWizard::addGroup(const KinematicModel::GroupConfig& group_config) 00253 { 00254 lock_.lock(); 00255 00256 if(kmodel_->hasModelGroup(group_config.name_)) 00257 { 00258 QString t; 00259 QTextStream(&t) << "There is already a planning group named " << group_config.name_.c_str() << ". Replace this group?"; 00260 confirm_group_text_->setText(t); 00261 int val = confirm_group_replace_dialog_->exec(); 00262 if(val == QDialog::Rejected) { 00263 lock_.unlock(); 00264 return GroupAddCancel; 00265 } 00266 kmodel_->removeModelGroup(group_config.name_); 00267 } 00268 deleteKinematicStates(); 00269 bool group_ok = kmodel_->addModelGroup(group_config); 00270 robot_state_ = new KinematicState(kmodel_); 00271 robot_state_->setKinematicStateToDefault(); 00272 00273 if(group_ok) 00274 { 00275 setup_groups_page_->updateGroupTable(); 00276 current_show_group_ = group_config.name_; 00277 } 00278 else 00279 { 00280 current_show_group_ = ""; 00281 } 00282 00283 lock_.unlock(); 00284 if(group_ok) { 00285 return GroupAddSuccess; 00286 } 00287 return GroupAddFailed; 00288 } 00289 00290 void PlanningDescriptionConfigurationWizard::removeGroup(const std::string& name) 00291 { 00292 lock_.lock(); 00293 if(!kmodel_->hasModelGroup(name)) { 00294 lock_.unlock(); 00295 return; 00296 } 00297 deleteKinematicStates(); 00298 kmodel_->removeModelGroup(name); 00299 00300 robot_state_ = new KinematicState(kmodel_); 00301 robot_state_->setKinematicStateToDefault(); 00302 00303 if(current_show_group_ == name) { 00304 current_show_group_ = ""; 00305 } 00306 00307 lock_.unlock(); 00308 } 00309 00310 void PlanningDescriptionConfigurationWizard::popupFileFailure(const char* reason) 00311 { 00312 file_failure_reason_->setText(reason); 00313 file_failure_dialog_->exec(); 00314 } 00315 00316 void PlanningDescriptionConfigurationWizard::emitGroupYAML() 00317 { 00318 (*emitter_) << YAML::Key << "groups"; 00319 (*emitter_) << YAML::Value << YAML::BeginSeq; 00320 00321 const map<string, KinematicModel::GroupConfig>& group_config_map = kmodel_->getJointModelGroupConfigMap(); 00322 00323 for(map<string, KinematicModel::GroupConfig>::const_iterator it = group_config_map.begin(); it 00324 != group_config_map.end(); it++) 00325 { 00326 (*emitter_) << YAML::BeginMap; 00327 (*emitter_) << YAML::Key << "name" << YAML::Value << it->first; 00328 if(!it->second.base_link_.empty()) 00329 { 00330 (*emitter_) << YAML::Key << "base_link" << YAML::Value << it->second.base_link_; 00331 (*emitter_) << YAML::Key << "tip_link" << YAML::Value << it->second.tip_link_; 00332 } 00333 else 00334 { 00335 if(!it->second.subgroups_.empty()) 00336 { 00337 (*emitter_) << YAML::Key << "subgroups"; 00338 (*emitter_) << YAML::Value << YAML::BeginSeq; 00339 for(unsigned int i = 0; i < it->second.subgroups_.size(); i++) 00340 { 00341 (*emitter_) << it->second.subgroups_[i]; 00342 } 00343 (*emitter_) << YAML::EndSeq; 00344 } 00345 if(!it->second.joints_.empty()) 00346 { 00347 (*emitter_) << YAML::Key << "joints"; 00348 (*emitter_) << YAML::Value << YAML::BeginSeq; 00349 for(unsigned int i = 0; i < it->second.joints_.size(); i++) 00350 { 00351 (*emitter_) << it->second.joints_[i]; 00352 } 00353 (*emitter_) << YAML::EndSeq; 00354 } 00355 } 00356 (*emitter_) << YAML::EndMap; 00357 } 00358 (*emitter_) << YAML::EndSeq; 00359 } 00360 00361 // void setupGroupSubgroupCollection(const string& new_group_name) { 00362 // while(1) { 00363 // clear(); 00364 // vector<string> group_names; 00365 // kmodel_->getModelGroupNames(group_names); 00366 // vector<bool> is_included(group_names.size(), false); 00367 // for(unsigned int i = 0; i < group_names.size(); i++) { 00368 // printw("%d) ", i); 00369 // if(is_included[i]) { 00370 // printw("(X)"); 00371 // } else { 00372 // printw("( )"); 00373 // } 00374 // printw(" %s ", group_names[i].c_str()); 00375 // } 00376 // printw("Enter a subgroup number to toggle inclusion "); 00377 // printw("Enter 'v' to visualize current subgroup "); 00378 // printw("Enter 'x' to accept current subgroup "); 00379 // refresh(); 00380 // char str[80]; 00381 // getstr(str); 00382 // unsigned int entry; 00383 // stringstream ss(str); 00384 // ss >> entry; 00385 // if(entry == 0) { 00386 00387 // } 00388 // } 00389 // } 00390 00391 void PlanningDescriptionConfigurationWizard::outputJointLimitsYAML() 00392 { 00393 map<string, bool> already; 00394 boost::shared_ptr<urdf::Model> robot_model = urdf_; 00395 YAML::Emitter emitter; 00396 emitter << YAML::BeginMap; 00397 emitter << YAML::Key << "joint_limits"; 00398 emitter << YAML::Value << YAML::BeginMap; 00399 const map<string, KinematicModel::JointModelGroup*>& group_map = kmodel_->getJointModelGroupMap(); 00400 for(map<string, KinematicModel::JointModelGroup*>::const_iterator it = group_map.begin(); it != group_map.end(); it++) 00401 { 00402 const vector<const KinematicModel::JointModel*>& jmv = it->second->getJointModels(); 00403 00404 for(unsigned int i = 0; i < jmv.size(); i++) 00405 { 00406 boost::shared_ptr<const urdf::Joint> urdf_joint = robot_model->getJoint(jmv[i]->getName()); 00407 double max_vel = 0.0; 00408 if(urdf_joint && urdf_joint->limits) 00409 { 00410 max_vel = urdf_joint->limits->velocity; 00411 } 00412 const map<string, pair<double, double> >& bounds_map = jmv[i]->getAllVariableBounds(); 00413 for(map<string, pair<double, double> >::const_iterator it2 = bounds_map.begin(); it2 != bounds_map.end(); it2++) 00414 { 00415 if(already.find(it2->first) == already.end()) 00416 { 00417 already[it2->first] = true; 00418 emitter << YAML::Key << it2->first; 00419 emitter << YAML::Value << YAML::BeginMap; 00420 emitter << YAML::Key << "has_position_limits"; 00421 const KinematicModel::RevoluteJointModel* rev = 00422 dynamic_cast<const KinematicModel::RevoluteJointModel*> (jmv[i]); 00423 bool has_limits = (rev == NULL || !rev->continuous_); 00424 emitter << YAML::Value << has_limits; 00425 if(max_vel > 0.0) { 00426 emitter << YAML::Key << "has_velocity_limits" << YAML::Value << "true"; 00427 emitter << YAML::Key << "max_velocity" << YAML::Value << max_vel; 00428 emitter << YAML::Key << "has_acceleration_limits" << YAML::Value << "true"; 00429 emitter << YAML::Key << "max_acceleration" << YAML::Value << DEFAULT_ACCELERATION; 00430 } else { 00431 emitter << YAML::Key << "has_velocity_limits" << YAML::Value << "false"; 00432 emitter << YAML::Key << "has_acceleration_limits" << YAML::Value << "false"; 00433 } 00434 emitter << YAML::Key << "angle_wraparound" << YAML::Value << !has_limits; 00435 emitter << YAML::EndMap; 00436 } 00437 } 00438 } 00439 } 00440 emitter << YAML::EndMap; 00441 emitter << YAML::EndMap; 00442 ofstream outf((dir_name_ + "/config/joint_limits.yaml").c_str(), ios_base::trunc); 00443 00444 outf << emitter.c_str(); 00445 } 00446 00447 Marker PlanningDescriptionConfigurationWizard::transformEnvironmentModelContactInfoMarker(const EnvironmentModel::Contact& c) 00448 { 00449 string ns_name; 00450 ns_name = c.body_name_1; 00451 ns_name += "+"; 00452 ns_name += c.body_name_2; 00453 Marker mk; 00454 mk.header.stamp = ros::Time::now(); 00455 mk.header.frame_id = cm_->getWorldFrameId(); 00456 mk.ns = ns_name; 00457 mk.id = 0; 00458 mk.type = Marker::SPHERE; 00459 mk.action = Marker::ADD; 00460 mk.pose.position.x = c.pos.x(); 00461 mk.pose.position.y = c.pos.y(); 00462 mk.pose.position.z = c.pos.z(); 00463 mk.pose.orientation.w = 1.0; 00464 00465 mk.scale.x = mk.scale.y = mk.scale.z = 0.05; 00466 return mk; 00467 } 00468 00469 00470 void PlanningDescriptionConfigurationWizard::outputPlanningDescriptionYAML() 00471 { 00472 //initial map 00473 if(emitter_ != NULL) { 00474 delete emitter_; 00475 } 00476 emitter_ = new YAML::Emitter; 00477 (*emitter_) << YAML::BeginMap; 00478 emitWorldJointYAML(); 00479 emitGroupYAML(); 00480 //ops_gen_->performanceTestSavedResults(disable_map_); 00481 ops_gen_->outputYamlStringOfSavedResults((*emitter_), disable_map_); 00482 //end map 00483 (*emitter_) << YAML::EndMap; 00484 ofstream outf(full_yaml_outfile_name_.c_str(), ios_base::trunc); 00485 00486 outf << emitter_->c_str(); 00487 } 00488 00489 void PlanningDescriptionConfigurationWizard::outputOMPLGroupYAML() 00490 { 00491 YAML::Emitter emitter; 00492 emitter << YAML::BeginMap; 00493 emitter << YAML::Key << "planner_configs"; 00494 00495 emitter << YAML::Value << YAML::BeginMap; 00496 00497 emitter << YAML::Key << "SBLkConfig1"; 00498 emitter << YAML::Value << YAML::BeginMap; 00499 emitter << YAML::Key << "type" << YAML::Value << "kinematic::SBL"; 00500 emitter << YAML::EndMap; 00501 00502 emitter << YAML::Key << "LBKPIECEkConfig1"; 00503 emitter << YAML::Value << YAML::BeginMap; 00504 emitter << YAML::Key << "type" << YAML::Value << "kinematic::LBKPIECE"; 00505 emitter << YAML::EndMap; 00506 00507 emitter << YAML::EndMap; 00508 00509 emitter << YAML::Key << "groups"; 00510 const std::map<std::string, planning_models::KinematicModel::GroupConfig>& group_config_map = kmodel_->getJointModelGroupConfigMap(); 00511 00512 emitter << YAML::Value << YAML::BeginSeq; 00513 for(std::map<std::string, planning_models::KinematicModel::GroupConfig>::const_iterator it = group_config_map.begin(); 00514 it != group_config_map.end(); 00515 it++) { 00516 emitter << it->first; 00517 if(!it->second.base_link_.empty()) { 00518 emitter << it->first+"_cartesian"; 00519 } 00520 } 00521 emitter << YAML::EndSeq; 00522 00523 for(std::map<std::string, planning_models::KinematicModel::GroupConfig>::const_iterator it = group_config_map.begin(); 00524 it != group_config_map.end(); 00525 it++) { 00526 emitter << YAML::Key << it->first; 00527 emitter << YAML::Value << YAML::BeginMap; 00528 emitter << YAML::Key << "planner_type" << YAML::Value << "JointPlanner"; 00529 emitter << YAML::Key << "planner_configs" << YAML::Value << YAML::BeginSeq; 00530 emitter << "SBLkConfig1" << "LBKPIECEkConfig1" << YAML::EndSeq; 00531 emitter << YAML::Key << "projection_evaluator" << YAML::Value << "joint_state"; 00532 emitter << YAML::EndMap; 00533 } 00534 00535 //now doing cartesian for any groups that are kinematic chains 00536 for(std::map<std::string, planning_models::KinematicModel::GroupConfig>::const_iterator it = group_config_map.begin(); 00537 it != group_config_map.end(); 00538 it++) { 00539 if(!it->second.base_link_.empty()) { 00540 emitter << YAML::Key << it->first+"_cartesian"; 00541 emitter << YAML::Value << YAML::BeginMap; 00542 emitter << YAML::Key << "parent_frame" << YAML::Value << it->second.base_link_; 00543 emitter << YAML::Key << "physical_group" << YAML::Value << it->first; 00544 emitter << YAML::Key << "planner_type" << YAML::Value << "RPYIKTaskSpacePlanner"; 00545 00546 emitter << YAML::Key << "state_spaces" << YAML::Value << YAML::BeginSeq; 00547 emitter << "x" << "y" << "z" << "roll" << "pitch" << "yaw" << YAML::EndSeq; 00548 00549 emitter << YAML::Key << "x" << YAML::Value << YAML::BeginMap; 00550 emitter << YAML::Key << "type" << YAML::Value << "Linear"; 00551 emitter << YAML::Key << "min" << YAML::Value << "-2.0"; 00552 emitter << YAML::Key << "max" << YAML::Value << "2.0"; 00553 emitter << YAML::EndMap; 00554 00555 emitter << YAML::Key << "y" << YAML::Value << YAML::BeginMap; 00556 emitter << YAML::Key << "type" << YAML::Value << "Linear"; 00557 emitter << YAML::Key << "min" << YAML::Value << "-2.0"; 00558 emitter << YAML::Key << "max" << YAML::Value << "2.0"; 00559 emitter << YAML::EndMap; 00560 00561 emitter << YAML::Key << "z" << YAML::Value << YAML::BeginMap; 00562 emitter << YAML::Key << "type" << YAML::Value << "Linear"; 00563 emitter << YAML::Key << "min" << YAML::Value << "-2.0"; 00564 emitter << YAML::Key << "max" << YAML::Value << "2.0"; 00565 emitter << YAML::EndMap; 00566 00567 emitter << YAML::Key << "roll" << YAML::Value << YAML::BeginMap; 00568 emitter << YAML::Key << "type" << YAML::Value << "Revolute"; 00569 emitter << YAML::EndMap; 00570 00571 emitter << YAML::Key << "pitch" << YAML::Value << YAML::BeginMap; 00572 emitter << YAML::Key << "type" << YAML::Value << "Revolute"; 00573 emitter << YAML::EndMap; 00574 00575 emitter << YAML::Key << "yaw" << YAML::Value << YAML::BeginMap; 00576 emitter << YAML::Key << "type" << YAML::Value << "Revolute"; 00577 emitter << YAML::EndMap; 00578 00579 emitter << YAML::Key << "planner_configs" << YAML::Value << YAML::BeginSeq; 00580 emitter << "SBLkConfig1" << "LBKPIECEkConfig1" << YAML::EndSeq; 00581 00582 emitter << YAML::Key << "kinematics_solver" << YAML::Value 00583 << "arm_kinematics_constraint_aware/KDLArmKinematicsPlugin"; 00584 emitter << YAML::Key << "tip_name" << YAML::Value << it->second.tip_link_; 00585 emitter << YAML::Key << "root_name" << YAML::Value << it->second.base_link_; 00586 emitter << YAML::Key << "projection_evaluator" << YAML::Value << "joint_state"; 00587 emitter << YAML::Key << "longest_valid_segment_fraction" << YAML::Value << "0.001"; 00588 emitter << YAML::EndMap; 00589 } 00590 } 00591 emitter << YAML::EndMap; 00592 std::ofstream outf((dir_name_+"/config/ompl_planning.yaml").c_str(), std::ios_base::trunc); 00593 00594 outf << emitter.c_str(); 00595 } 00596 00597 void PlanningDescriptionConfigurationWizard::outputOMPLLaunchFile() 00598 { 00599 TiXmlDocument doc; 00600 TiXmlElement* launch_root = new TiXmlElement("launch"); 00601 doc.LinkEndChild(launch_root); 00602 00603 TiXmlElement *inc = new TiXmlElement("include"); 00604 launch_root->LinkEndChild(inc); 00605 inc->SetAttribute("file", "$(find " + dir_name_ + ")/launch/" + launch_outfile_name_); 00606 00607 TiXmlElement *node = new TiXmlElement("node"); 00608 launch_root->LinkEndChild(node); 00609 node->SetAttribute("pkg", "ompl_ros_interface"); 00610 node->SetAttribute("type", "ompl_ros"); 00611 node->SetAttribute("name", "ompl_planning"); 00612 00613 TiXmlElement *p = new TiXmlElement("param"); 00614 node->LinkEndChild(p); 00615 p->SetAttribute("name", "default_planner_config"); 00616 p->SetAttribute("type", "string"); 00617 p->SetAttribute("value", "SBLkConfig1"); 00618 00619 TiXmlElement *rp = new TiXmlElement("rosparam"); 00620 node->LinkEndChild(rp); 00621 rp->SetAttribute("command", "load"); 00622 rp->SetAttribute("file", "$(find " + dir_name_ + ")/config/ompl_planning.yaml"); 00623 doc.SaveFile(dir_name_ + "/launch/ompl_planning.launch"); 00624 } 00625 00626 void PlanningDescriptionConfigurationWizard::outputTrajectoryFilterLaunch() 00627 { 00628 TiXmlDocument doc; 00629 TiXmlElement* launch_root = new TiXmlElement("launch"); 00630 doc.LinkEndChild(launch_root); 00631 00632 TiXmlElement *inc = new TiXmlElement("include"); 00633 launch_root->LinkEndChild(inc); 00634 inc->SetAttribute("file", "$(find " + dir_name_ + ")/launch/" + launch_outfile_name_); 00635 00636 TiXmlElement *node = new TiXmlElement("node"); 00637 launch_root->LinkEndChild(node); 00638 node->SetAttribute("pkg", "trajectory_filter_server"); 00639 node->SetAttribute("type", "trajectory_filter_server"); 00640 node->SetAttribute("name", "trajectory_filter_server"); 00641 00642 TiXmlElement *rp = new TiXmlElement("rosparam"); 00643 node->LinkEndChild(rp); 00644 rp->SetAttribute("command", "load"); 00645 rp->SetAttribute("file", "$(find trajectory_filter_server)/config/filters.yaml"); 00646 00647 TiXmlElement *rp2 = new TiXmlElement("rosparam"); 00648 node->LinkEndChild(rp2); 00649 rp2->SetAttribute("command", "load"); 00650 rp2->SetAttribute("file", "$(find " + dir_name_ + ")/config/joint_limits.yaml"); 00651 00652 doc.SaveFile(dir_name_ + "/launch/trajectory_filter_server.launch"); 00653 } 00654 00655 void PlanningDescriptionConfigurationWizard::outputPlanningEnvironmentLaunch() 00656 { 00657 TiXmlDocument doc; 00658 TiXmlElement* launch_root = new TiXmlElement("launch"); 00659 doc.LinkEndChild(launch_root); 00660 00661 TiXmlElement *rd = new TiXmlElement("param"); 00662 launch_root->LinkEndChild(rd); 00663 rd->SetAttribute("name", "robot_description"); 00664 rd->SetAttribute("textfile", "$(find " + urdf_package_ + ")/" + urdf_path_); 00665 00666 TiXmlElement *rp = new TiXmlElement("rosparam"); 00667 launch_root->LinkEndChild(rp); 00668 rp->SetAttribute("command", "load"); 00669 rp->SetAttribute("ns", "robot_description_planning"); 00670 rp->SetAttribute("file", "$(find " + dir_name_ + ")/config/" + yaml_outfile_name_); 00671 doc.SaveFile(full_launch_outfile_name_); 00672 00673 } 00674 00675 void PlanningDescriptionConfigurationWizard::outputKinematicsLaunchFiles() 00676 { 00677 TiXmlDocument doc; 00678 TiXmlElement* launch_root = new TiXmlElement("launch"); 00679 doc.LinkEndChild(launch_root); 00680 00681 TiXmlElement *inc = new TiXmlElement("include"); 00682 launch_root->LinkEndChild(inc); 00683 inc->SetAttribute("file", "$(find " + dir_name_ + ")/launch/" + launch_outfile_name_); 00684 00685 const map<string, KinematicModel::GroupConfig>& group_config_map = kmodel_->getJointModelGroupConfigMap(); 00686 00687 for(map<string, KinematicModel::GroupConfig>::const_iterator it = group_config_map.begin(); it 00688 != group_config_map.end(); it++) 00689 { 00690 if(!it->second.base_link_.empty()) 00691 { 00692 TiXmlElement *node = new TiXmlElement("node"); 00693 launch_root->LinkEndChild(node); 00694 node->SetAttribute("pkg", "arm_kinematics_constraint_aware"); 00695 node->SetAttribute("type", "arm_kinematics_constraint_aware"); 00696 node->SetAttribute("name", getRobotName() + "_" + it->first + "_kinematics"); 00697 00698 TiXmlElement *group_param = new TiXmlElement("param"); 00699 node->LinkEndChild(group_param); 00700 group_param->SetAttribute("name", "group"); 00701 group_param->SetAttribute("type", "string"); 00702 group_param->SetAttribute("value", it->first); 00703 00704 TiXmlElement *base_param = new TiXmlElement("param"); 00705 node->LinkEndChild(base_param); 00706 base_param->SetAttribute("name", it->first + "/root_name"); 00707 base_param->SetAttribute("type", "string"); 00708 base_param->SetAttribute("value", it->second.base_link_); 00709 00710 TiXmlElement *tip_param = new TiXmlElement("param"); 00711 node->LinkEndChild(tip_param); 00712 tip_param->SetAttribute("name", it->first + "/tip_name"); 00713 tip_param->SetAttribute("type", "string"); 00714 tip_param->SetAttribute("value", it->second.tip_link_); 00715 00716 TiXmlElement *solver_param = new TiXmlElement("param"); 00717 node->LinkEndChild(solver_param); 00718 solver_param->SetAttribute("name", "kinematics_solver"); 00719 solver_param->SetAttribute("type", "string"); 00720 solver_param->SetAttribute("value", "arm_kinematics_constraint_aware/KDLArmKinematicsPlugin"); 00721 } 00722 } 00723 00724 doc.SaveFile(dir_name_ + "/launch/constraint_aware_kinematics.launch"); 00725 } 00726 00727 void PlanningDescriptionConfigurationWizard::outputMoveGroupLaunchFiles() 00728 { 00729 TiXmlDocument doc; 00730 TiXmlElement* launch_root = new TiXmlElement("launch"); 00731 doc.LinkEndChild(launch_root); 00732 00733 const map<string, KinematicModel::GroupConfig>& group_config_map = kmodel_->getJointModelGroupConfigMap(); 00734 00735 for(map<string, KinematicModel::GroupConfig>::const_iterator it = group_config_map.begin(); it 00736 != group_config_map.end(); it++) 00737 { 00738 TiXmlElement *inc = new TiXmlElement("include"); 00739 launch_root->LinkEndChild(inc); 00740 inc->SetAttribute("file", "$(find " + dir_name_ + ")/launch/move_"+it->first+".launch"); 00741 00742 TiXmlDocument group_doc; 00743 TiXmlElement* group_launch_root = new TiXmlElement("launch"); 00744 group_doc.LinkEndChild(group_launch_root); 00745 00746 TiXmlElement *node = new TiXmlElement("node"); 00747 group_launch_root->LinkEndChild(node); 00748 node->SetAttribute("pkg", "move_arm"); 00749 node->SetAttribute("type", "move_arm_simple_action"); 00750 node->SetAttribute("name", getRobotName() + "_move_" + it->first); 00751 00752 TiXmlElement *group_param = new TiXmlElement("param"); 00753 node->LinkEndChild(group_param); 00754 group_param->SetAttribute("name", "group"); 00755 group_param->SetAttribute("type", "string"); 00756 group_param->SetAttribute("value", it->first); 00757 00758 TiXmlElement *remap1 = new TiXmlElement("remap"); 00759 node->LinkEndChild(remap1); 00760 remap1->SetAttribute("from", "arm_ik"); 00761 remap1->SetAttribute("to", getRobotName()+"_"+it->first+"_kinematics/get_constraint_aware_ik"); 00762 00763 TiXmlElement *base_param = new TiXmlElement("param"); 00764 node->LinkEndChild(base_param); 00765 base_param->SetAttribute("name", "controller_action_name"); 00766 base_param->SetAttribute("type", "string"); 00767 base_param->SetAttribute("value", it->first+"_controller/follow_joint_trajectory"); 00768 group_doc.SaveFile(dir_name_ + "/launch/move_"+it->first+".launch"); 00769 } 00770 doc.SaveFile(dir_name_ + "/launch/move_groups.launch"); 00771 } 00772 00773 void PlanningDescriptionConfigurationWizard::outputPlanningComponentVisualizerLaunchFile() 00774 { 00775 //now doing planning components .vcg file 00776 string template_name_2 = ros::package::getPath("planning_environment") + "/config/planning_components_visualizer.vcg"; 00777 00778 ifstream template_file_2(template_name_2.c_str()); 00779 00780 ofstream ofile_2((dir_name_ + "/config/planning_components_visualizer.vcg").c_str()); 00781 00782 char ch; 00783 char buf[80]; 00784 while(template_file_2 && template_file_2.get(ch)) 00785 { 00786 if(ch != '$') 00787 { 00788 ofile_2.put(ch); 00789 } 00790 else 00791 { 00792 template_file_2.getline(buf, 80, '$'); 00793 if(template_file_2.eof() || template_file_2.bad()) 00794 { 00795 ROS_ERROR_STREAM("Bad template file"); 00796 break; 00797 } 00798 ofile_2 << kmodel_->getRoot()->getParentFrameId(); 00799 } 00800 } 00801 00802 TiXmlDocument doc; 00803 TiXmlElement* launch_root = new TiXmlElement("launch"); 00804 doc.LinkEndChild(launch_root); 00805 00806 TiXmlElement *inc = new TiXmlElement("include"); 00807 launch_root->LinkEndChild(inc); 00808 inc->SetAttribute("file", "$(find " + dir_name_ + ")/launch/" + launch_outfile_name_); 00809 00810 TiXmlElement *pre = new TiXmlElement("include"); 00811 launch_root->LinkEndChild(pre); 00812 pre->SetAttribute("file", 00813 "$(find planning_environment)/launch/planning_environment_visualization_prerequisites.launch"); 00814 00815 TiXmlElement *kin = new TiXmlElement("include"); 00816 launch_root->LinkEndChild(kin); 00817 kin->SetAttribute("file", "$(find " + dir_name_ + ")/launch/constraint_aware_kinematics.launch"); 00818 00819 TiXmlElement *ompl = new TiXmlElement("include"); 00820 launch_root->LinkEndChild(ompl); 00821 ompl->SetAttribute("file", "$(find " + dir_name_ + ")/launch/ompl_planning.launch"); 00822 00823 TiXmlElement *fil = new TiXmlElement("include"); 00824 launch_root->LinkEndChild(fil); 00825 fil->SetAttribute("file", "$(find " + dir_name_ + ")/launch/trajectory_filter_server.launch"); 00826 00827 TiXmlElement *rviz = new TiXmlElement("node"); 00828 launch_root->LinkEndChild(rviz); 00829 rviz->SetAttribute("pkg", "rviz"); 00830 rviz->SetAttribute("type", "rviz"); 00831 rviz->SetAttribute("name", "rviz_planning_components"); 00832 rviz->SetAttribute("args", "-d $(find " + dir_name_ + ")/config/planning_components_visualizer.vcg"); 00833 00834 TiXmlElement *vis = new TiXmlElement("node"); 00835 launch_root->LinkEndChild(vis); 00836 vis->SetAttribute("pkg", "move_arm"); 00837 vis->SetAttribute("type", "planning_components_visualizer"); 00838 vis->SetAttribute("name", "planning_components_visualizer"); 00839 vis->SetAttribute("output", "screen"); 00840 00841 TiXmlElement *state_publisher = new TiXmlElement("node"); 00842 launch_root->LinkEndChild(state_publisher); 00843 state_publisher->SetAttribute("pkg", "robot_state_publisher"); 00844 state_publisher->SetAttribute("type", "state_publisher"); 00845 state_publisher->SetAttribute("name", "rob_st_pub"); 00846 00847 doc.SaveFile(dir_name_ + "/launch/planning_components_visualizer.launch"); 00848 } 00849 00850 void PlanningDescriptionConfigurationWizard::outputArmNavigationLaunchFile() 00851 { 00852 TiXmlDocument doc; 00853 TiXmlElement* launch_root = new TiXmlElement("launch"); 00854 doc.LinkEndChild(launch_root); 00855 00856 TiXmlElement *inc = new TiXmlElement("include"); 00857 launch_root->LinkEndChild(inc); 00858 inc->SetAttribute("file", "$(find " + dir_name_ + ")/launch/" + launch_outfile_name_); 00859 00860 TiXmlElement *inc_env = new TiXmlElement("include"); 00861 launch_root->LinkEndChild(inc_env); 00862 inc_env->SetAttribute("file", "$(find planning_environment)/launch/environment_server.launch"); 00863 00864 TiXmlElement *arg1 = new TiXmlElement("arg"); 00865 inc_env->LinkEndChild(arg1); 00866 arg1->SetAttribute("name", "use_monitor"); 00867 arg1->SetAttribute("value", "true"); 00868 00869 TiXmlElement *arg2 = new TiXmlElement("arg"); 00870 inc_env->LinkEndChild(arg2); 00871 arg2->SetAttribute("name", "use_collision_map"); 00872 arg2->SetAttribute("value", "false"); 00873 00874 TiXmlElement *kin = new TiXmlElement("include"); 00875 launch_root->LinkEndChild(kin); 00876 kin->SetAttribute("file", "$(find " + dir_name_ + ")/launch/constraint_aware_kinematics.launch"); 00877 00878 TiXmlElement *ompl = new TiXmlElement("include"); 00879 launch_root->LinkEndChild(ompl); 00880 ompl->SetAttribute("file", "$(find " + dir_name_ + ")/launch/ompl_planning.launch"); 00881 00882 TiXmlElement *fil = new TiXmlElement("include"); 00883 launch_root->LinkEndChild(fil); 00884 fil->SetAttribute("file", "$(find " + dir_name_ + ")/launch/trajectory_filter_server.launch"); 00885 00886 TiXmlElement *incgr = new TiXmlElement("include"); 00887 launch_root->LinkEndChild(incgr); 00888 incgr->SetAttribute("file", "$(find " + dir_name_ + ")/launch/move_groups.launch"); 00889 00890 doc.SaveFile(dir_name_ + "/launch/"+getRobotName()+"_arm_navigation.launch"); 00891 } 00892 00893 void PlanningDescriptionConfigurationWizard::updateCollisionsInCurrentState() 00894 { 00895 lock_.lock(); 00896 std_msgs::ColorRGBA default_color; 00897 default_color.a = 1.0; 00898 default_color.r = 0.0; 00899 default_color.g = .8; 00900 default_color.b = 0.04; 00901 00902 collision_markers_.markers.clear(); 00903 00904 cm_->getAllCollisionPointMarkers(*robot_state_, collision_markers_, default_color, ros::Duration(.2)); 00905 lock_.unlock(); 00906 } 00907 00908 void PlanningDescriptionConfigurationWizard::sendMarkers() 00909 { 00910 lock_.lock(); 00911 vis_marker_array_publisher_.publish(collision_markers_); 00912 if(!current_show_group_.empty()) 00913 { 00914 MarkerArray arr; 00915 std_msgs::ColorRGBA default_color; 00916 default_color.a = 1.0; 00917 default_color.r = 0.0; 00918 default_color.g = .8; 00919 default_color.b = 0.04; 00920 00921 std_msgs::ColorRGBA color; 00922 color.a = 1.0; 00923 color.r = 1.0; 00924 color.g = 0.0; 00925 color.b = 1.0; 00926 00927 const KinematicModel::JointModelGroup* jmg = kmodel_->getModelGroup(current_show_group_); 00928 00929 if(jmg != NULL) 00930 { 00931 vector<string> group_link_names = jmg->getGroupLinkNames(); 00932 cm_->getRobotMarkersGivenState(*robot_state_, arr, default_color, current_show_group_, ros::Duration(.2), 00933 &group_link_names, 1.02); 00934 00935 vector<string> updated_link_model_names = jmg->getUpdatedLinkModelNames(); 00936 map<string, bool> dont_include; 00937 for(unsigned int i = 0; i < group_link_names.size(); i++) 00938 { 00939 dont_include[group_link_names[i]] = true; 00940 } 00941 00942 vector<string> ex_list; 00943 for(unsigned int i = 0; i < updated_link_model_names.size(); i++) 00944 { 00945 if(dont_include.find(updated_link_model_names[i]) == dont_include.end()) 00946 { 00947 ex_list.push_back(updated_link_model_names[i]); 00948 } 00949 } 00950 cm_->getRobotMarkersGivenState(*robot_state_, arr, color, current_show_group_ + "_updated_links", 00951 ros::Duration(.2), &ex_list); 00952 vis_marker_array_publisher_.publish(arr); 00953 } 00954 else 00955 { 00956 ROS_ERROR("The joint model group %s did not exist!", current_show_group_.c_str()); 00957 } 00958 } else if(!current_show_link_.empty()) { 00959 MarkerArray arr; 00960 std_msgs::ColorRGBA default_color; 00961 default_color.a = 1.0; 00962 default_color.r = 0.0; 00963 default_color.g = 0.0; 00964 default_color.b = 1.0; 00965 00966 vector<string> single_link_name(1, current_show_link_); 00967 cm_->getRobotPaddedMarkersGivenState(*robot_state_, arr, default_color, current_show_link_, ros::Duration(.2), 00968 &single_link_name); 00969 vis_marker_array_publisher_.publish(arr); 00970 } 00971 lock_.unlock(); 00972 } 00973 00974 void PlanningDescriptionConfigurationWizard::sendTransforms() 00975 { 00976 lock_.lock(); 00977 ros::WallTime cur_time = ros::WallTime::now(); 00978 rosgraph_msgs::Clock c; 00979 c.clock.nsec = cur_time.nsec; 00980 c.clock.sec = cur_time.sec; 00981 vector<geometry_msgs::TransformStamped> trans_vector; 00982 getAllKinematicStateStampedTransforms(*robot_state_, trans_vector, c.clock); 00983 transform_broadcaster_.sendTransform(trans_vector); 00984 lock_.unlock(); 00985 } 00986 ; 00987 00988 bool PlanningDescriptionConfigurationWizard::isInited() const 00989 { 00990 return inited_; 00991 } 00992 00993 CollisionOperationsGenerator* PlanningDescriptionConfigurationWizard::getOperationsGenerator() 00994 { 00995 return ops_gen_; 00996 } 00997 00998 string PlanningDescriptionConfigurationWizard::getRobotName() 00999 { 01000 return urdf_->getName(); 01001 } 01002 01003 void PlanningDescriptionConfigurationWizard::dofTogglePushed() 01004 { 01005 ROS_INFO_STREAM("Pushed"); 01006 unsigned int column = 3; 01007 vector<int> rows = getSelectedRows(dof_selection_table_); 01008 for(size_t i = 0; i < rows.size(); i++) 01009 { 01010 QCheckBox* box = dynamic_cast<QCheckBox*> (dof_selection_table_->cellWidget(rows[i], column)); 01011 01012 if(box != NULL) 01013 { 01014 if(box->isChecked()) 01015 { 01016 box->setChecked(false); 01017 } 01018 else 01019 { 01020 box->setChecked(true); 01021 } 01022 } 01023 } 01024 dofSelectionTableChanged(); 01025 } 01026 01027 void PlanningDescriptionConfigurationWizard::dofSelectionTableChanged() 01028 { 01029 int xind = 0; 01030 map<string, bool> cdof_map; 01031 const vector<KinematicModel::JointModel*>& jmv = cm_->getKinematicModel()->getJointModels(); 01032 for(unsigned int i = 1; i < jmv.size(); i++) 01033 { 01034 const map<string, pair<double, double> >& joint_bounds = jmv[i]->getAllVariableBounds(); 01035 for(map<string, pair<double, double> >::const_iterator it = joint_bounds.begin(); it != joint_bounds.end(); it++) 01036 { 01037 QCheckBox* checkBox = dynamic_cast<QCheckBox*> (dof_selection_table_->cellWidget(xind, 3)); 01038 01039 if(checkBox != NULL) 01040 { 01041 cdof_map[it->first] = checkBox->isChecked(); 01042 } 01043 xind++; 01044 } 01045 } 01046 ops_gen_->generateSamplingStructures(cdof_map); 01047 } 01048 01049 void PlanningDescriptionConfigurationWizard::popupGenericWarning(const char* text) 01050 { 01051 generic_dialog_label_->setText(text); 01052 generic_dialog_->show(); 01053 generic_dialog_->setVisible(true); 01054 generic_dialog_->setModal(true); 01055 ROS_INFO("Showing warning: %s", text); 01056 } 01057 01058 void PlanningDescriptionConfigurationWizard::writeFiles() 01059 { 01060 package_directory_ = output_wizard_page_->getPackagePathField(); 01061 int ok = chdir(package_directory_.c_str()); 01062 01063 if(ok != 0) 01064 { 01065 ROS_WARN("Unable to change directory to %s", package_directory_.c_str()); 01066 string warning = "Failed to change directory to "; 01067 warning += package_directory_; 01068 popupFileFailure(warning.c_str()); 01069 return; 01070 } 01071 01072 string del_com = "rm -rf " + dir_name_; 01073 ok = system(del_com.c_str()); 01074 01075 if(ok != 0) 01076 { 01077 ROS_WARN_STREAM("Failed to delete old package!"); 01078 popupFileFailure("Failed to delete existing package."); 01079 } 01080 01081 string mdir = "roscreate-pkg " + dir_name_; 01082 mdir += " planning_environment arm_kinematics_constraint_aware ompl_ros_interface "; 01083 mdir += "trajectory_filter_server constraint_aware_spline_smoother move_arm"; 01084 ok = system(mdir.c_str()); 01085 01086 if(ok != 0) 01087 { 01088 ROS_WARN_STREAM("Failed to create ros package!"); 01089 popupFileFailure("Creating ros package failed."); 01090 return; 01091 } 01092 01093 mdir = "mkdir -p " + dir_name_ + "/config"; 01094 ok = system(mdir.c_str()); 01095 if(ok != 0) 01096 { 01097 ROS_WARN_STREAM("Making subdirectory not ok"); 01098 popupFileFailure("Creating subdirectory /config failed."); 01099 return; 01100 } 01101 01102 mdir = "mkdir -p " + dir_name_ + "/launch"; 01103 ok = system(mdir.c_str()); 01104 if(ok != 0) 01105 { 01106 ROS_WARN_STREAM("Making subdirectory not ok"); 01107 popupFileFailure("Creating subdirectory /launch failed"); 01108 return; 01109 } 01110 01111 if(wizard_mode_ == PlanningDescriptionConfigurationWizard::Easy) 01112 { 01113 ROS_INFO("Automatically configuring."); 01114 AutoConfigureThread* thread = new AutoConfigureThread(this); 01115 thread->start(); 01116 } 01117 01118 else 01119 { 01120 outputJointLimitsYAML(); 01121 output_wizard_page_->updateProgressBar(10); 01122 outputOMPLGroupYAML(); 01123 output_wizard_page_->updateProgressBar(20); 01124 outputPlanningDescriptionYAML(); 01125 output_wizard_page_->updateProgressBar(30); 01126 outputOMPLLaunchFile(); 01127 output_wizard_page_->updateProgressBar(40); 01128 outputKinematicsLaunchFiles(); 01129 output_wizard_page_->updateProgressBar(50); 01130 outputTrajectoryFilterLaunch(); 01131 output_wizard_page_->updateProgressBar(65); 01132 outputPlanningEnvironmentLaunch(); 01133 output_wizard_page_->updateProgressBar(75); 01134 outputMoveGroupLaunchFiles(); 01135 outputArmNavigationLaunchFile(); 01136 outputPlanningComponentVisualizerLaunchFile(); 01137 output_wizard_page_->updateProgressBar(100); 01138 01139 output_wizard_page_->setSuccessfulGeneration(); 01140 } 01141 } 01142 01143 void PlanningDescriptionConfigurationWizard::labelChanged(const char* label) 01144 { 01145 output_wizard_page_->setProgressLabel(label); 01146 } 01147 01148 void PlanningDescriptionConfigurationWizard::autoConfigure() 01149 { 01150 progress_ = 0; 01152 // SETUP JOINTS 01154 const vector<KinematicModel::JointModel*>& jmv = cm_->getKinematicModel()->getJointModels(); 01155 vector<bool> consider_dof; 01156 //assuming that 0th is world joint, which we don't want to include 01157 for(unsigned int i = 1; i < jmv.size(); i++) 01158 { 01159 const map<string, pair<double, double> >& joint_bounds = jmv[i]->getAllVariableBounds(); 01160 for(map<string, pair<double, double> >::const_iterator it = joint_bounds.begin(); it != joint_bounds.end(); it++) 01161 { 01162 consider_dof.push_back(true); 01163 } 01164 } 01165 int xind = 0; 01166 map<string, bool> cdof_map; 01167 for(unsigned int i = 1; i < jmv.size(); i++) 01168 { 01169 const map<string, pair<double, double> >& joint_bounds = jmv[i]->getAllVariableBounds(); 01170 for(map<string, pair<double, double> >::const_iterator it = joint_bounds.begin(); it != joint_bounds.end(); it++) 01171 { 01172 cdof_map[it->first] = consider_dof[xind++]; 01173 } 01174 } 01175 ops_gen_->generateSamplingStructures(cdof_map); 01176 01177 progress_ = 1; 01178 emit changeProgress(1); 01180 // ADJACENT PAIRS IN COLLISION 01182 vector<CollisionOperationsGenerator::StringPair> adj_links; 01183 ops_gen_->generateAdjacentInCollisionPairs(adj_links); 01184 ops_gen_->disablePairCollisionChecking(adj_links); 01185 disable_map_[CollisionOperationsGenerator::ADJACENT] = adj_links; 01186 01187 emit changeLabel("Finding always in collision pairs...."); 01189 // ALWAYS-DEFAULT IN COLLISION 01191 01192 vector<CollisionOperationsGenerator::StringPair> always_in_collision; 01193 vector<CollisionOperationsGenerator::CollidingJointValues> in_collision_joint_values; 01194 01195 ops_gen_->generateAlwaysInCollisionPairs(always_in_collision, in_collision_joint_values); 01196 01197 lock_.lock(); 01198 robot_state_->setKinematicStateToDefault(); 01199 lock_.unlock(); 01200 01201 progress_ = 10; 01202 emit changeProgress(10); 01203 emit changeLabel("Finding Default In Collision Pairs...."); 01204 01205 ops_gen_->disablePairCollisionChecking(always_in_collision); 01206 disable_map_[CollisionOperationsGenerator::ALWAYS] = always_in_collision; 01207 vector<CollisionOperationsGenerator::StringPair> default_in_collision; 01208 ops_gen_->generateDefaultInCollisionPairs(default_in_collision, in_collision_joint_values); 01209 ops_gen_->disablePairCollisionChecking(default_in_collision); 01210 disable_map_[CollisionOperationsGenerator::DEFAULT] = default_in_collision; 01211 01212 progress_ = 33; 01213 emit changeProgress(33); 01214 emit changeLabel("Finding Often In Collision Pairs...."); 01216 // OFTEN IN COLLISION 01218 01219 vector<CollisionOperationsGenerator::StringPair> often_in_collision; 01220 vector<double> percentages; 01221 ops_gen_->generateOftenInCollisionPairs(often_in_collision, percentages, in_collision_joint_values); 01222 ops_gen_->disablePairCollisionChecking(often_in_collision); 01223 disable_map_[CollisionOperationsGenerator::OFTEN] = often_in_collision; 01224 01225 progress_ = 60; 01226 emit changeProgress(60); 01227 emit changeLabel("Finding Never In Collision Pairs...."); 01229 // OCC-NEVER IN COLLISION 01231 01232 vector<CollisionOperationsGenerator::StringPair> in_collision; 01233 vector<CollisionOperationsGenerator::StringPair> not_in_collision; 01234 01235 ops_gen_->generateOccasionallyAndNeverInCollisionPairs(in_collision, not_in_collision, percentages, 01236 in_collision_joint_values); 01237 disable_map_[CollisionOperationsGenerator::NEVER] = not_in_collision; 01238 ops_gen_->disablePairCollisionChecking(not_in_collision); 01239 progress_ = 90; 01240 emit changeProgress(90); 01241 emit changeLabel("Writing Files...."); 01242 01243 outputJointLimitsYAML(); 01244 outputOMPLGroupYAML(); 01245 outputPlanningDescriptionYAML(); 01246 outputOMPLLaunchFile(); 01247 outputKinematicsLaunchFiles(); 01248 outputTrajectoryFilterLaunch(); 01249 outputPlanningEnvironmentLaunch(); 01250 outputMoveGroupLaunchFiles(); 01251 outputArmNavigationLaunchFile(); 01252 outputPlanningComponentVisualizerLaunchFile(); 01253 progress_ = 100; 01254 emit changeProgress(100); 01255 } 01256 01257 int PlanningDescriptionConfigurationWizard::nextId() const 01258 { 01259 switch (currentId()) 01260 { 01261 case StartPage: 01262 return SetupGroupsPage; 01263 case SetupGroupsPage: 01264 return setup_groups_page_->nextId(); 01265 case KinematicChainsPage: 01266 { 01267 if(!kinematic_chain_page_->getReturnToGroups()) { 01268 if(wizard_mode_ == PlanningDescriptionConfigurationWizard::Advanced) 01269 { 01270 return SelectDOFPage; 01271 } 01272 else 01273 { 01274 return OutputFilesPage; 01275 } 01276 } else { 01277 return SetupGroupsPage; 01278 } 01279 } 01280 case JointCollectionsPage: 01281 { 01282 if(!joint_collections_page_->getReturnToGroups()) { 01283 if(wizard_mode_ == PlanningDescriptionConfigurationWizard::Advanced) 01284 { 01285 return SelectDOFPage; 01286 } 01287 else 01288 { 01289 return OutputFilesPage; 01290 } 01291 } else { 01292 return SetupGroupsPage; 01293 } 01294 } 01295 case SelectDOFPage: 01296 return AdjacentLinkPage; 01297 01298 case AdjacentLinkPage: 01299 return AlwaysInCollisionPage; 01300 01301 case AlwaysInCollisionPage: 01302 return DefaultInCollisionPage; 01303 01304 case DefaultInCollisionPage: 01305 return OftenInCollisionPage; 01306 01307 case OftenInCollisionPage: 01308 return OccasionallyInCollisionPage; 01309 01310 case OccasionallyInCollisionPage: 01311 return OutputFilesPage; 01312 01313 case OutputFilesPage: 01314 return -1; 01315 01316 default: 01317 return -1; 01318 } 01319 } 01320 01321 void PlanningDescriptionConfigurationWizard::update() 01322 { 01323 output_wizard_page_->updateProgressBar(progress_); 01324 if(progress_ >= 100) 01325 { 01326 output_wizard_page_->setSuccessfulGeneration(); 01327 } 01328 01329 QWizard::update(); 01330 } 01331 01332 void PlanningDescriptionConfigurationWizard::easyButtonToggled(bool checkState) 01333 { 01334 if(checkState) 01335 { 01336 wizard_mode_ = PlanningDescriptionConfigurationWizard::Easy; 01337 } 01338 } 01339 01340 void PlanningDescriptionConfigurationWizard::hardButtonToggled(bool checkState) 01341 { 01342 if(checkState) 01343 { 01344 wizard_mode_ = PlanningDescriptionConfigurationWizard::Advanced; 01345 } 01346 } 01347 01348 void PlanningDescriptionConfigurationWizard::verySafeButtonToggled(bool checkState) 01349 { 01350 if(checkState) 01351 { 01352 ops_gen_->setSafety(CollisionOperationsGenerator::VerySafe); 01353 } 01354 } 01355 01356 void PlanningDescriptionConfigurationWizard::safeButtonToggled(bool checkState) 01357 { 01358 if(checkState) 01359 { 01360 ops_gen_->setSafety(CollisionOperationsGenerator::Safe); 01361 } 01362 } 01363 01364 void PlanningDescriptionConfigurationWizard::normalButtonToggled(bool checkState) 01365 { 01366 if(checkState) 01367 { 01368 ops_gen_->setSafety(CollisionOperationsGenerator::Normal); 01369 } 01370 } 01371 01372 void PlanningDescriptionConfigurationWizard::fastButtonToggled(bool checkState) 01373 { 01374 if(checkState) 01375 { 01376 ops_gen_->setSafety(CollisionOperationsGenerator::Fast); 01377 } 01378 } 01379 01380 void PlanningDescriptionConfigurationWizard::veryFastButtonToggled(bool checkState) 01381 { 01382 if(checkState) 01383 { 01384 ops_gen_->setSafety(CollisionOperationsGenerator::VeryFast); 01385 } 01386 } 01387 01388 void PlanningDescriptionConfigurationWizard::visualizeCollision(vector<CollisionOperationsGenerator::CollidingJointValues>& jointValues, 01389 vector<CollisionOperationsGenerator::StringPair>& pairs, 01390 int& index, std_msgs::ColorRGBA& color) 01391 { 01392 01393 if(index >= (int)(pairs.size()) || index < 0 || pairs.size() == 0) 01394 { 01395 return; 01396 } 01397 lock_.lock(); 01398 01399 robot_state_->setKinematicState(jointValues[index]); 01400 01401 if(!cm_->isKinematicStateInCollision(*robot_state_)) 01402 { 01403 ROS_INFO_STREAM("Really should be in collision"); 01404 } 01405 01406 collision_markers_.markers.clear(); 01407 01408 vector<EnvironmentModel::Contact> coll_space_contacts; 01409 cm_->getCollisionSpace()->getAllCollisionContacts(coll_space_contacts, 1); 01410 01411 Marker marker; 01412 Marker marker2; 01413 for(unsigned int j = 0; j < coll_space_contacts.size(); j++) 01414 { 01415 if((coll_space_contacts[j].body_name_1 == pairs[index].first && coll_space_contacts[j].body_name_2 01416 == pairs[index].second) || (coll_space_contacts[j].body_name_1 == pairs[index].second 01417 && coll_space_contacts[j].body_name_2 == pairs[index].first)) 01418 { 01419 marker = transformEnvironmentModelContactInfoMarker(coll_space_contacts[j]); 01420 marker2 = transformEnvironmentModelContactInfoMarker(coll_space_contacts[j]); 01421 marker.id = 0; 01422 marker.id = 1; 01423 marker.color = color; 01424 marker.lifetime = ros::Duration(0.2); 01425 marker2.type = Marker::ARROW; 01426 marker2.color.r = 1.0; 01427 marker2.color.g = 0.0; 01428 marker2.color.b = 0.0; 01429 marker2.color.a = 1.0; 01430 marker2.scale.x = 0.5; 01431 marker2.scale.y = 0.5; 01432 marker2.scale.z = 0.5; 01433 marker2.pose.position.z = marker2.pose.position.z+.65; 01434 marker2.pose.orientation.x = 0.0; 01435 marker2.pose.orientation.y = 1.0; 01436 marker2.pose.orientation.z = 0.0; 01437 marker2.pose.orientation.w = 1.0; 01438 marker2.lifetime = ros::Duration(0.2); 01439 collision_markers_.markers.push_back(marker); 01440 collision_markers_.markers.push_back(marker2); 01441 } 01442 } 01443 lock_.unlock(); 01444 01445 } 01446 01447 void PlanningDescriptionConfigurationWizard::setupQtPages() 01448 { 01449 initStartPage(); 01450 01451 setup_groups_page_ = new SetupGroupsWizardPage(this); 01452 setPage(SetupGroupsPage, setup_groups_page_); 01453 01454 kinematic_chain_page_ = new KinematicChainWizardPage(this); 01455 setPage(KinematicChainsPage, kinematic_chain_page_); 01456 01457 joint_collections_page_ = new JointCollectionWizardPage(this); 01458 setPage(JointCollectionsPage, joint_collections_page_); 01459 01460 initSelectDofPage(); 01461 01462 adjacent_link_page_ = new CollisionsWizardPage(this, CollisionOperationsGenerator::ADJACENT); 01463 setPage(AdjacentLinkPage, adjacent_link_page_); 01464 01465 always_in_collision_page_ = new CollisionsWizardPage(this, CollisionOperationsGenerator::ALWAYS); 01466 setPage(AlwaysInCollisionPage, always_in_collision_page_); 01467 01468 default_in_collision_page_ = new CollisionsWizardPage(this, CollisionOperationsGenerator::DEFAULT); 01469 setPage(DefaultInCollisionPage, default_in_collision_page_); 01470 01471 often_in_collision_page_ = new CollisionsWizardPage(this, CollisionOperationsGenerator::OFTEN); 01472 setPage(OftenInCollisionPage, often_in_collision_page_); 01473 01474 occasionally_in_collision_page_ = new CollisionsWizardPage(this, CollisionOperationsGenerator::NEVER); 01475 setPage(OccasionallyInCollisionPage, occasionally_in_collision_page_); 01476 01477 output_wizard_page_ = new OutputWizardPage(this); 01478 setPage(OutputFilesPage, output_wizard_page_); 01479 01480 generic_dialog_ = new QDialog(this); 01481 QVBoxLayout* gDialogLayout = new QVBoxLayout(generic_dialog_); 01482 generic_dialog_label_ = new QLabel(generic_dialog_); 01483 generic_dialog_label_->setText("Warning!"); 01484 gDialogLayout->addWidget(generic_dialog_label_); 01485 generic_dialog_->setLayout(gDialogLayout); 01486 01487 file_failure_dialog_ = new QDialog(this); 01488 QVBoxLayout* filefailureLayout = new QVBoxLayout(file_failure_dialog_); 01489 QLabel* fileFailureText = new QLabel(file_failure_dialog_); 01490 fileFailureText->setText("Failed to create files! Reason: "); 01491 file_failure_reason_ = new QLabel(this); 01492 file_failure_reason_->setText("unspecified."); 01493 filefailureLayout->addWidget(fileFailureText); 01494 filefailureLayout->addWidget(file_failure_reason_); 01495 QDialogButtonBox* file_failure_box = new QDialogButtonBox(QDialogButtonBox::Ok); 01496 filefailureLayout->addWidget(file_failure_box); 01497 connect(file_failure_box, SIGNAL(accepted()), file_failure_dialog_, SLOT(accept())); 01498 file_failure_dialog_->setLayout(filefailureLayout); 01499 01500 confirm_group_replace_dialog_ = new QDialog(this); 01501 QVBoxLayout* confirm_group_replace_layout = new QVBoxLayout(confirm_group_replace_dialog_); 01502 confirm_group_text_ = new QLabel(this); 01503 confirm_group_text_->setText("Really replace group "); 01504 confirm_group_replace_layout->addWidget(confirm_group_text_); 01505 QDialogButtonBox* group_button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); 01506 confirm_group_replace_layout->addWidget(group_button_box); 01507 connect(group_button_box, SIGNAL(accepted()), confirm_group_replace_dialog_, SLOT(accept())); 01508 connect(group_button_box, SIGNAL(rejected()), confirm_group_replace_dialog_, SLOT(reject())); 01509 confirm_group_replace_dialog_->setLayout(confirm_group_replace_layout); 01510 } 01511 01512 void PlanningDescriptionConfigurationWizard::initStartPage() 01513 { 01514 start_page_ = new QWizardPage(this); 01515 start_page_->setTitle("Planning Components Configuration Wizard"); 01516 QHBoxLayout* layout = new QHBoxLayout(start_page_); 01517 01518 QImage* image = new QImage(); 01519 if(chdir(ros::package::getPath("planning_environment").c_str()) != 0) 01520 { 01521 ROS_ERROR("FAILED TO CHANGE PACKAGE TO %s", ros::package::getPath("planning_environment").c_str()); 01522 } 01523 01524 if(!image->load("./resources/wizard.png")) 01525 { 01526 ROS_ERROR("FAILED TO LOAD ./resources/wizard.png"); 01527 } 01528 ROS_INFO("Loaded Image with %d bytes.", image->byteCount()); 01529 01530 QLabel* imageLabel = new QLabel(start_page_); 01531 imageLabel->setPixmap(QPixmap::fromImage(*image)); 01532 layout->addWidget(imageLabel); 01533 imageLabel->setMinimumHeight(10); 01534 imageLabel->setMinimumWidth(10); 01535 start_page_->setSubTitle( 01536 "Welcome to the ROS planning components configuration wizard! This wizard will guide you through" 01537 " creating a planning configuration for your robot.\nThe robot's URDF location should have been passed into the" 01538 " program as a command line on startup."); 01539 01540 QGroupBox* descBox = new QGroupBox(start_page_); 01541 01542 QLabel* label = new QLabel(descBox); 01543 QVBoxLayout* descLayout = new QVBoxLayout(descBox); 01544 label->setText("After you've selected your robot's planning groups," 01545 "\nand set up collision information this wizard will" 01546 "\nautomatically generate a planning stack for your" 01547 "\nrobot, and in no time your robot's arms will be " 01548 "\nable to plan around obstacles efficiently!"); 01549 //label->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); 01550 label->setMinimumWidth(1); 01551 label->setMinimumHeight(1); 01552 01553 layout->addWidget(imageLabel); 01554 descLayout->addWidget(label); 01555 01556 label->setAlignment(Qt::AlignTop); 01557 01558 //descBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum); 01559 descBox->setAlignment(Qt::AlignTop); 01560 01561 QGroupBox* modeGroupBox = new QGroupBox(descBox); 01562 modeGroupBox->setTitle("Select Mode"); 01563 01564 QVBoxLayout* modeGroupBoxLayout = new QVBoxLayout(modeGroupBox); 01565 QLabel* modeGroupBoxDesc = new QLabel(modeGroupBox); 01566 modeGroupBoxDesc->setMinimumWidth(1); 01567 modeGroupBoxDesc->setMinimumHeight(1); 01568 modeGroupBoxDesc->setText("In Easy mode, your robot will be automatically tested for self-collisions,\nand a planning" 01569 " parameter file will be automatically generated.\nAdvanced mode allows you to manually configure collision checking."); 01570 modeGroupBoxLayout->addWidget(modeGroupBoxDesc); 01571 01572 QRadioButton* easyButton = new QRadioButton(modeGroupBox); 01573 easyButton->setText("Easy"); 01574 modeGroupBoxLayout->addWidget(easyButton); 01575 easyButton->setChecked(true); 01576 01577 connect(easyButton, SIGNAL(toggled(bool)), this, SLOT(easyButtonToggled(bool))); 01578 01579 QRadioButton* hardButton = new QRadioButton(modeGroupBox); 01580 hardButton->setText("Advanced"); 01581 modeGroupBoxLayout->addWidget(hardButton); 01582 01583 connect(hardButton, SIGNAL(toggled(bool)), this, SLOT(hardButtonToggled(bool))); 01584 01585 modeGroupBox->setLayout(modeGroupBoxLayout); 01586 modeGroupBox->setAlignment(Qt::AlignTop | Qt::AlignLeft); 01587 01588 descLayout->addWidget(modeGroupBox); 01589 modeGroupBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum); 01590 01591 QGroupBox* safetyGroupBox = new QGroupBox(descBox); 01592 safetyGroupBox->setTitle("Select Self-collision Sampling Density"); 01593 01594 QVBoxLayout* safetyGroupBoxLayout = new QVBoxLayout(safetyGroupBox); 01595 QLabel* safetyGroupBoxDesc = new QLabel(safetyGroupBox); 01596 safetyGroupBoxDesc->setText("Parameterizes the number of joint space samples used to " 01597 "\ndetermine whether certain robot poses are in collision." 01598 "\nDenser setting swill sample longer, while sparser settings" 01599 "\nare more likely to give efficient collision checking that " 01600 "\nmay not detect rare self-collisions."); 01601 01602 safetyGroupBoxDesc->setMinimumWidth(1); 01603 safetyGroupBoxDesc->setMinimumHeight(1); 01604 safetyGroupBoxDesc->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 01605 safetyGroupBoxLayout->addWidget(safetyGroupBoxDesc); 01606 01607 QRadioButton* verySafeButton = new QRadioButton(safetyGroupBox); 01608 verySafeButton->setText("Very Dense"); 01609 safetyGroupBoxLayout->addWidget(verySafeButton); 01610 verySafeButton->setChecked(true); 01611 01612 connect(verySafeButton, SIGNAL(toggled(bool)), this, SLOT(verySafeButtonToggled(bool))); 01613 01614 QRadioButton* safeButton = new QRadioButton(safetyGroupBox); 01615 safeButton->setText("Dense"); 01616 safetyGroupBoxLayout->addWidget(safeButton); 01617 01618 connect(safeButton, SIGNAL(toggled(bool)), this, SLOT(safeButtonToggled(bool))); 01619 01620 QRadioButton* normalButton = new QRadioButton(safetyGroupBox); 01621 normalButton->setText("Normal"); 01622 safetyGroupBoxLayout->addWidget(normalButton); 01623 normalButton->setChecked(true); 01624 01625 connect(normalButton, SIGNAL(toggled(bool)), this, SLOT(normalButtonToggled(bool))); 01626 01627 QRadioButton* fastButton = new QRadioButton(safetyGroupBox); 01628 fastButton->setText("Sparse"); 01629 safetyGroupBoxLayout->addWidget(fastButton); 01630 01631 connect(fastButton, SIGNAL(toggled(bool)), this, SLOT(fastButtonToggled(bool))); 01632 01633 QRadioButton* veryFastButton = new QRadioButton(safetyGroupBox); 01634 veryFastButton->setText("Very Sparse"); 01635 safetyGroupBoxLayout->addWidget(veryFastButton); 01636 01637 connect(veryFastButton, SIGNAL(toggled(bool)), this, SLOT(veryFastButtonToggled(bool))); 01638 01639 01640 safetyGroupBox->setLayout(safetyGroupBoxLayout); 01641 safetyGroupBox->setAlignment(Qt::AlignTop | Qt::AlignLeft); 01642 01643 descLayout->addWidget(safetyGroupBox); 01644 //safetyGroupBox->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Maximum); 01645 01646 layout->addWidget(descBox); 01647 01648 setPage(StartPage, start_page_); 01649 start_page_->setLayout(layout); 01650 start_page_->setMinimumWidth(400); 01651 start_page_->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 01652 } 01653 01654 void PlanningDescriptionConfigurationWizard::initSelectDofPage() 01655 { 01656 select_dof_page_ = new QWizardPage(this); 01657 select_dof_page_->setTitle("DOF Sampling"); 01658 QVBoxLayout* layout = new QVBoxLayout(select_dof_page_); 01659 select_dof_page_->setSubTitle("Select degrees of freedom to sample for collisions. The wizard will run your robot" 01660 " through a set of subsamples of these joints and check each pair of links for" 01661 " collisions. Unselected joints will remain in their default positions" 01662 " during these tests."); 01663 01664 dof_selection_table_ = new QTableWidget(select_dof_page_); 01665 layout->addWidget(dof_selection_table_); 01666 01667 QPushButton* toggleSelected = new QPushButton(select_dof_page_); 01668 toggleSelected->setText("Toggle Selected"); 01669 layout->addWidget(toggleSelected); 01670 toggleSelected->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 01671 01672 connect(toggleSelected, SIGNAL(clicked()), this, SLOT(dofTogglePushed())); 01673 01674 setPage(SelectDOFPage, select_dof_page_); 01675 select_dof_page_->setLayout(layout); 01676 01677 createDofPageTable(); 01678 01679 } 01680 01681 void PlanningDescriptionConfigurationWizard::createDofPageTable() 01682 { 01683 const vector<KinematicModel::JointModel*>& jmv = cm_->getKinematicModel()->getJointModels(); 01684 vector<bool> consider_dof; 01685 01686 int numDofs = 0; 01687 //assuming that 0th is world joint, which we don't want to include 01688 for(unsigned int i = 1; i < jmv.size(); i++) 01689 { 01690 const map<string, pair<double, double> >& joint_bounds = jmv[i]->getAllVariableBounds(); 01691 for(map<string, pair<double, double> >::const_iterator it = joint_bounds.begin(); it != joint_bounds.end(); it++) 01692 { 01693 consider_dof.push_back(true); 01694 numDofs++; 01695 } 01696 } 01697 01698 dof_selection_table_->clear(); 01699 dof_selection_table_->setRowCount(numDofs); 01700 dof_selection_table_->setColumnCount(4); 01701 dof_selection_table_->setColumnWidth(0, 300); 01702 dof_selection_table_->setColumnWidth(1, 300); 01703 dof_selection_table_->setColumnWidth(2, 300); 01704 dof_selection_table_->setColumnWidth(3, 300); 01705 01706 QStringList horizontalLabels; 01707 horizontalLabels.append("DOF Name"); 01708 horizontalLabels.append("Lower Bound (radians)"); 01709 horizontalLabels.append("Upper Bound (radians)"); 01710 horizontalLabels.append("Consider DOF?"); 01711 dof_selection_table_->setHorizontalHeaderLabels(horizontalLabels); 01712 01713 int ind = 1; 01714 for(unsigned int i = 1; i < jmv.size(); i++) 01715 { 01716 const map<string, pair<double, double> >& joint_bounds = jmv[i]->getAllVariableBounds(); 01717 01718 for(map<string, pair<double, double> >::const_iterator it = joint_bounds.begin(); it != joint_bounds.end(); it++) 01719 { 01720 stringstream lowerStream; 01721 stringstream upperStream; 01722 lowerStream << it->second.first; 01723 upperStream << it->second.second; 01724 01725 QTableWidgetItem* nameItem = new QTableWidgetItem(it->first.c_str()); 01726 nameItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 01727 01728 QTableWidgetItem* lowerItem = new QTableWidgetItem(lowerStream.str().c_str()); 01729 lowerItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 01730 01731 QTableWidgetItem* upperItem = new QTableWidgetItem(upperStream.str().c_str()); 01732 upperItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 01733 01734 QCheckBox* check = new QCheckBox(dof_selection_table_); 01735 check->setChecked(consider_dof[ind - 1]); 01736 01737 connect(check, SIGNAL(toggled(bool)), this, SLOT(dofSelectionTableChanged())); 01738 dof_selection_table_->setItem(ind - 1, 0, nameItem); 01739 dof_selection_table_->setItem(ind - 1, 1, lowerItem); 01740 dof_selection_table_->setItem(ind - 1, 2, upperItem); 01741 dof_selection_table_->setCellWidget(ind - 1, 3, check); 01742 ind++; 01743 } 01744 } 01745 01746 dofSelectionTableChanged(); 01747 } 01748 01749 SetupGroupsWizardPage::SetupGroupsWizardPage(PlanningDescriptionConfigurationWizard *parent) 01750 : QWizardPage(parent), next_from_groups_id_(PlanningDescriptionConfigurationWizard::OutputFilesPage) 01751 { 01752 parent_ = parent; 01753 01754 setTitle("Planning Group Setup"); 01755 01756 QGridLayout* layout = new QGridLayout(this); 01757 setSubTitle("Select planning groups for your robot based on kinematic chains, or joint collections." 01758 " When you are finished, please check the checkbox and you can move on by pressing Next."); 01759 01760 QGroupBox* selectGroupsBox = new QGroupBox(this); 01761 selectGroupsBox->setTitle("Current Groups"); 01762 01763 current_group_table_ = new QTableWidget(selectGroupsBox); 01764 QVBoxLayout* groupBoxLayout = new QVBoxLayout(selectGroupsBox); 01765 groupBoxLayout->addWidget(current_group_table_); 01766 selectGroupsBox->setLayout(groupBoxLayout); 01767 layout->addWidget(selectGroupsBox, 0, 0, 1, 1); 01768 QPushButton* deleteButton = new QPushButton(selectGroupsBox); 01769 deleteButton->setText("Delete"); 01770 groupBoxLayout->addWidget(deleteButton); 01771 deleteButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 01772 01773 connect(current_group_table_, SIGNAL(itemClicked(QTableWidgetItem*)), this, SLOT(groupTableClicked())); 01774 connect(deleteButton, SIGNAL(clicked()), this, SLOT(deleteGroupButtonClicked())); 01775 01776 QGroupBox* modeBox = new QGroupBox(this); 01777 modeBox->setTitle("Add groups"); 01778 QVBoxLayout* modeBoxLayout = new QVBoxLayout(modeBox); 01779 QPushButton* add_kinematic_chain_button = new QPushButton(tr("&Add Kinematic Chain Group")); 01780 QPushButton* add_joint_collection_button = new QPushButton(tr("&Add Joint Collection Group")); 01781 modeBoxLayout->addWidget(add_kinematic_chain_button); 01782 modeBoxLayout->addWidget(add_joint_collection_button); 01783 01784 first_group_field_ = new QLineEdit(this); 01785 registerField("first_group*", first_group_field_); 01786 first_group_field_->hide(); 01787 01788 connect(add_kinematic_chain_button, SIGNAL(clicked()), this, SLOT(addKinematicChainGroup())); 01789 connect(add_joint_collection_button, SIGNAL(clicked()), this, SLOT(addJointCollectionGroup())); 01790 01791 modeBox->setLayout(modeBoxLayout); 01792 layout->addWidget(modeBox, 0, 2, 1, 1); 01793 01794 setLayout(layout); 01795 layout->setAlignment(modeBox, Qt::AlignTop); 01796 01797 setButtonText(QWizard::NextButton, "Done with groups"); 01798 } 01799 01800 01801 void SetupGroupsWizardPage::groupTableClicked() 01802 { 01803 QList<QTableWidgetItem*> selected = current_group_table_->selectedItems(); 01804 01805 if(selected.size() == 0) 01806 { 01807 return; 01808 } 01809 else 01810 { 01811 QTableWidgetItem* first = selected[0]; 01812 int row = first->row(); 01813 QTableWidgetItem* groupName = current_group_table_->item(row, 0); 01814 parent_->setCurrentShowGroup(groupName->text().toStdString()); 01815 } 01816 } 01817 01818 01819 void SetupGroupsWizardPage::updateGroupTable() 01820 { 01821 current_group_table_->clear(); 01822 first_group_field_->clear(); 01823 01824 vector<string> modelNames; 01825 parent_->getKinematicModel()->getModelGroupNames(modelNames); 01826 current_group_table_->setRowCount((int)modelNames.size()); 01827 current_group_table_->setColumnCount(1); 01828 current_group_table_->setColumnWidth(0, 300); 01829 current_group_table_->setDragEnabled(false); 01830 current_group_table_->setHorizontalHeaderItem(0, new QTableWidgetItem("Planning Groups")); 01831 if(!modelNames.empty()) { 01832 first_group_field_->setText(modelNames[0].c_str()); 01833 } 01834 for(size_t i = 0; i < modelNames.size(); i++) 01835 { 01836 QTableWidgetItem* item = new QTableWidgetItem(modelNames[i].c_str()); 01837 current_group_table_->setItem((int)i, 0, item); 01838 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 01839 } 01840 } 01841 01842 void SetupGroupsWizardPage::deleteGroupButtonClicked() 01843 { 01844 QList<QTableWidgetItem*> itemList = current_group_table_->selectedItems(); 01845 01846 for(int i = 0; i < itemList.size(); i++) 01847 { 01848 if(parent_->getKinematicModel()->hasModelGroup(itemList[i]->text().toStdString())) 01849 { 01850 parent_->removeGroup(itemList[i]->text().toStdString()); 01851 } 01852 } 01853 updateGroupTable(); 01854 } 01855 01856 int SetupGroupsWizardPage::nextId() const { 01857 if(next_from_groups_id_ == PlanningDescriptionConfigurationWizard::OutputFilesPage) 01858 { 01859 if(parent_->getWizardMode() == PlanningDescriptionConfigurationWizard::Advanced) 01860 { 01861 return PlanningDescriptionConfigurationWizard::SelectDOFPage; 01862 } 01863 else 01864 { 01865 return PlanningDescriptionConfigurationWizard::OutputFilesPage; 01866 } 01867 } 01868 return next_from_groups_id_; 01869 } 01870 01871 void SetupGroupsWizardPage::addKinematicChainGroup() { 01872 next_from_groups_id_ = PlanningDescriptionConfigurationWizard::KinematicChainsPage; 01873 parent_->next(); 01874 next_from_groups_id_ = PlanningDescriptionConfigurationWizard::OutputFilesPage; 01875 } 01876 01877 void SetupGroupsWizardPage::addJointCollectionGroup() { 01878 next_from_groups_id_ = PlanningDescriptionConfigurationWizard::JointCollectionsPage; 01879 parent_->next(); 01880 next_from_groups_id_ = PlanningDescriptionConfigurationWizard::OutputFilesPage; 01881 } 01882 01883 KinematicChainWizardPage::KinematicChainWizardPage(PlanningDescriptionConfigurationWizard *parent) 01884 : QWizardPage(parent), return_to_groups_(false) 01885 { 01886 parent_ = parent; 01887 setTitle("Select Kinematic Chain"); 01888 01889 QGridLayout* layout = new QGridLayout(this); 01890 setSubTitle("Select a planning group based on a kinematic chain." 01891 " Select a base link (the first link in the chain) and a tip link." 01892 " They must be connected by a direct line of joints."); 01893 01894 QImage* image = new QImage(); 01895 if(!image->load("./resources/chains.png")) 01896 { 01897 ROS_ERROR("FAILED TO LOAD ./resources/chains.png"); 01898 } 01899 ROS_INFO("Loaded Image with %d bytes.", image->byteCount()); 01900 01901 QLabel* imageLabel = new QLabel(this); 01902 imageLabel->setPixmap(QPixmap::fromImage(*image)); 01903 imageLabel->setAlignment(Qt::AlignTop); 01904 imageLabel->setMinimumHeight(10); 01905 imageLabel->setMinimumWidth(10); 01906 layout->addWidget(imageLabel, 0, 0, 0, 1); 01907 QGroupBox* treeBox = new QGroupBox(this); 01908 treeBox->setTitle("Links"); 01909 layout->addWidget(treeBox, 0, 1, 1, 1); 01910 01911 QVBoxLayout* treeLayout = new QVBoxLayout(treeBox); 01912 link_tree_ = new QTreeWidget(treeBox); 01913 connect(link_tree_, SIGNAL(itemSelectionChanged()), this, SLOT(showTreeLink())); 01914 treeLayout->addWidget(link_tree_); 01915 QPushButton* baseLinkButton = new QPushButton(treeBox); 01916 baseLinkButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 01917 baseLinkButton->setText("Select Base Link"); 01918 treeLayout->addWidget(baseLinkButton); 01919 QPushButton* tipLinkButton = new QPushButton(treeBox); 01920 tipLinkButton->setText("Select Tip Link"); 01921 tipLinkButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 01922 treeLayout->addWidget(tipLinkButton); 01923 treeBox->setLayout(treeLayout); 01924 createLinkTree(parent->getKinematicModel()); 01925 01926 connect(baseLinkButton, SIGNAL(clicked()), this, SLOT(baseLinkTreeClick())); 01927 connect(tipLinkButton, SIGNAL(clicked()), this, SLOT(tipLinkTreeClick())); 01928 QGroupBox* chainBox = new QGroupBox(this); 01929 chainBox->setTitle("Kinematic Chain"); 01930 QFormLayout* chainLayout = new QFormLayout(chainBox); 01931 chain_name_field_ = new QLineEdit(chainBox); 01932 base_link_field_ = new QLineEdit(chainBox); 01933 tip_link_field_ = new QLineEdit(chainBox); 01934 chainLayout->addRow("Chain Name", chain_name_field_); 01935 chainLayout->addRow("Base Link", base_link_field_); 01936 chainLayout->addRow("Tip Link", tip_link_field_); 01937 layout->addWidget(chainBox, 1, 1, 1, 2); 01938 01939 registerField("chain_name*", chain_name_field_); 01940 registerField("base_link*", base_link_field_); 01941 registerField("tip_link*", tip_link_field_); 01942 01943 setLayout(layout); 01944 01945 good_group_dialog_ = new QDialog(this); 01946 QVBoxLayout* good_group_layout = new QVBoxLayout(good_group_dialog_); 01947 QLabel* good_dialog_text = new QLabel(good_group_dialog_); 01948 good_dialog_text->setText("Your group is valid and has been added to the planning groups.\nIt should be visualized in Rviz"); 01949 good_group_layout->addWidget(good_dialog_text); 01950 QPushButton* return_to_groups_button = new QPushButton(tr("&Return To Groups")); 01951 QPushButton* add_another_kinematic_chain_button = new QPushButton(tr("&Add Another Kinematic Chain")); 01952 QPushButton* done_with_groups_button = new QPushButton(tr("&Done Adding Groups")); 01953 QDialogButtonBox* good_button_box = new QDialogButtonBox(); 01954 good_group_layout->addWidget(good_button_box); 01955 good_button_box->addButton(return_to_groups_button, QDialogButtonBox::RejectRole); 01956 good_button_box->addButton(add_another_kinematic_chain_button, QDialogButtonBox::ResetRole); 01957 good_button_box->addButton(done_with_groups_button, QDialogButtonBox::AcceptRole); 01958 connect(good_button_box, SIGNAL(rejected()), good_group_dialog_, SLOT(reject())); 01959 connect(good_button_box, SIGNAL(rejected()), parent, SLOT(back())); 01960 connect(good_button_box, SIGNAL(accepted()), good_group_dialog_, SLOT(accept())); 01961 connect(add_another_kinematic_chain_button, SIGNAL(clicked()), this, SLOT(resetPage())); 01962 good_group_dialog_->setLayout(good_group_layout); 01963 01964 not_ok_dialog_ = new QDialog(this); 01965 QVBoxLayout* notOkDialogLayout = new QVBoxLayout(not_ok_dialog_); 01966 QLabel* notOkText = new QLabel(not_ok_dialog_); 01967 notOkText->setText("Error! The planning group was invalid!"); 01968 notOkDialogLayout->addWidget(notOkText); 01969 QDialogButtonBox* ok_button_box = new QDialogButtonBox(QDialogButtonBox::Ok); 01970 notOkDialogLayout->addWidget(ok_button_box); 01971 connect(ok_button_box, SIGNAL(accepted()), not_ok_dialog_, SLOT(accept())); 01972 not_ok_dialog_->setLayout(notOkDialogLayout); 01973 01974 setButtonText(QWizard::NextButton, "Add Group"); 01975 } 01976 01977 bool KinematicChainWizardPage::validatePage() { 01978 01979 KinematicModel::GroupConfig gc(getChainNameField(), getBaseLinkField(), getTipLinkField()); 01980 01981 PlanningDescriptionConfigurationWizard::GroupAddStatus stat = 01982 parent_->addGroup(gc); 01983 01984 if(stat == PlanningDescriptionConfigurationWizard::GroupAddSuccess) { 01985 int val = good_group_dialog_->exec(); 01986 parent_->setCurrentShowGroup(""); 01987 parent_->setCurrentShowLink(""); 01988 if(val == QDialog::Accepted) { 01989 return true; 01990 } else if(val == QDialog::Rejected) { 01991 return false; 01992 } else { 01993 return false; 01994 } 01995 } else if(stat == PlanningDescriptionConfigurationWizard::GroupAddFailed) { 01996 not_ok_dialog_->exec(); 01997 return false; 01998 } else { 01999 //cancelled duplicated 02000 return false; 02001 } 02002 } 02003 02004 void KinematicChainWizardPage::showTreeLink() { 02005 QTreeWidgetItem* item = link_tree_->currentItem(); 02006 if(item != NULL) 02007 { 02008 std::string link_name = item->text(0).toStdString(); 02009 if(!link_name.empty()) { 02010 parent_->setCurrentShowGroup(""); 02011 parent_->setCurrentShowLink(link_name); 02012 } 02013 } 02014 } 02015 02016 void KinematicChainWizardPage::baseLinkTreeClick() { 02017 QTreeWidgetItem* item = link_tree_->currentItem(); 02018 if(item != NULL) 02019 { 02020 base_link_field_->setText(item->text(0)); 02021 } 02022 } 02023 02024 void KinematicChainWizardPage::tipLinkTreeClick() 02025 { 02026 QTreeWidgetItem* item = link_tree_->currentItem(); 02027 if(item != NULL) 02028 { 02029 tip_link_field_->setText(item->text(0)); 02030 } 02031 } 02032 02033 void KinematicChainWizardPage::createLinkTree(const planning_models::KinematicModel* kmodel) 02034 { 02035 const KinematicModel::JointModel* rootJoint = kmodel->getRoot(); 02036 addLinktoTreeRecursive(rootJoint->getChildLinkModel(), NULL); 02037 02038 link_tree_->expandToDepth(0); 02039 link_tree_->header()->setResizeMode(0, QHeaderView::ResizeToContents); 02040 link_tree_->header()->setStretchLastSection(false); 02041 } 02042 02043 02044 02045 void KinematicChainWizardPage::addLinktoTreeRecursive(const KinematicModel::LinkModel* link, 02046 const KinematicModel::LinkModel* parent) 02047 { 02048 QTreeWidgetItem* toAdd = new QTreeWidgetItem(link_tree_); 02049 if(parent == NULL) 02050 { 02051 toAdd->setText(0, link->getName().c_str()); 02052 link_tree_->addTopLevelItem(toAdd); 02053 } 02054 else 02055 { 02056 for(int i = 0; i < link_tree_->topLevelItemCount(); i++) 02057 { 02058 if(addLinkChildRecursive(link_tree_->topLevelItem(i), link, parent->getName())) 02059 { 02060 break; 02061 } 02062 } 02063 } 02064 for(size_t i = 0; i < link->getChildJointModels().size(); i++) 02065 { 02066 addLinktoTreeRecursive(link->getChildJointModels()[i]->getChildLinkModel(), link); 02067 } 02068 } 02069 02070 bool KinematicChainWizardPage::addLinkChildRecursive(QTreeWidgetItem* parent, 02071 const KinematicModel::LinkModel* link, 02072 const string& parentName) 02073 { 02074 if(parent->text(0).toStdString() == parentName) 02075 { 02076 QTreeWidgetItem* toAdd = new QTreeWidgetItem(parent); 02077 toAdd->setText(0, link->getName().c_str()); 02078 parent->addChild(toAdd); 02079 return true; 02080 } 02081 else 02082 { 02083 for(int i = 0; i < parent->childCount(); i++) 02084 { 02085 if(addLinkChildRecursive(parent->child(i), link, parentName)) 02086 { 02087 return true; 02088 } 02089 } 02090 } 02091 02092 return false; 02093 } 02094 02095 JointCollectionWizardPage::JointCollectionWizardPage(PlanningDescriptionConfigurationWizard *parent) 02096 : QWizardPage(parent), return_to_groups_(false) 02097 { 02098 parent_ = parent; 02099 setTitle("Select Joint Collections"); 02100 02101 QGridLayout* layout = new QGridLayout(this); 02102 02103 setSubTitle("Select an arbitrary group of joints to form a planning group."); 02104 02105 QImage* image = new QImage(); 02106 if(!image->load("./resources/groups.png")) 02107 { 02108 ROS_ERROR("FAILED TO LOAD ./resources/groups.png"); 02109 } 02110 02111 QLabel* imageLabel = new QLabel(this); 02112 imageLabel->setPixmap(QPixmap::fromImage(*image)); 02113 imageLabel->setAlignment(Qt::AlignTop); 02114 imageLabel->setMinimumHeight(10); 02115 imageLabel->setMinimumWidth(10); 02116 02117 layout->addWidget(imageLabel, 0, 1, 1, 1); 02118 02119 QGroupBox* jointBox = new QGroupBox(this); 02120 jointBox->setTitle("Joints"); 02121 02122 02123 QVBoxLayout* jointLayout = new QVBoxLayout(jointBox); 02124 joint_table_ = new QTableWidget(jointBox); 02125 jointLayout->addWidget(joint_table_); 02126 jointBox->setLayout(jointLayout); 02127 layout->addWidget(jointBox, 0, 0, 3, 1); 02128 02129 QPushButton* selectButton = new QPushButton(jointBox); 02130 selectButton->setText("v Select v"); 02131 jointLayout->addWidget(selectButton); 02132 selectButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 02133 02134 first_joint_field_ = new QLineEdit(this); 02135 registerField("first_joint*", first_joint_field_); 02136 first_joint_field_->hide(); 02137 02138 connect(selectButton, SIGNAL(clicked()), this, SLOT(selectJointButtonClicked())); 02139 02140 QGroupBox* selectedBox = new QGroupBox(this); 02141 selectedBox->setTitle("Joint Group"); 02142 02143 QVBoxLayout* selectedLayout = new QVBoxLayout(selectedBox); 02144 selected_joint_table_ = new QTableWidget(jointBox); 02145 jointLayout->addWidget(selected_joint_table_); 02146 02147 QPushButton* deselectButton = new QPushButton(jointBox); 02148 deselectButton->setText("^ Deselect ^"); 02149 jointLayout->addWidget(deselectButton); 02150 deselectButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 02151 02152 connect(deselectButton, SIGNAL(clicked()), this, SLOT(deselectJointButtonClicked())); 02153 02154 QLabel* jointGroupLabel = new QLabel(selectedBox); 02155 jointGroupLabel->setText(" Joint Group Name: "); 02156 joint_group_name_field_ = new QLineEdit(selectedBox); 02157 selectedLayout->addWidget(jointGroupLabel); 02158 selectedLayout->addWidget(joint_group_name_field_); 02159 selectedBox->setLayout(selectedLayout); 02160 layout->addWidget(selectedBox, 1, 1, 1, 1); 02161 setLayout(layout); 02162 02163 createJointCollectionTables(); 02164 02165 good_group_dialog_ = new QDialog(this); 02166 QVBoxLayout* good_group_layout = new QVBoxLayout(good_group_dialog_); 02167 QLabel* good_dialog_text = new QLabel(good_group_dialog_); 02168 good_dialog_text->setText("Your group is valid and has been added to the planning groups.\nIt should be visualized in Rviz"); 02169 good_group_layout->addWidget(good_dialog_text); 02170 QPushButton* return_to_groups_button = new QPushButton(tr("&Return To Groups")); 02171 QPushButton* add_another_kinematic_chain_button = new QPushButton(tr("&Add Another Joint Collection")); 02172 QPushButton* done_with_groups_button = new QPushButton(tr("&Done Adding Groups")); 02173 QDialogButtonBox* good_button_box = new QDialogButtonBox(); 02174 good_group_layout->addWidget(good_button_box); 02175 good_button_box->addButton(return_to_groups_button, QDialogButtonBox::RejectRole); 02176 good_button_box->addButton(add_another_kinematic_chain_button, QDialogButtonBox::ResetRole); 02177 good_button_box->addButton(done_with_groups_button, QDialogButtonBox::AcceptRole); 02178 connect(good_button_box, SIGNAL(rejected()), good_group_dialog_, SLOT(reject())); 02179 connect(good_button_box, SIGNAL(rejected()), parent, SLOT(back())); 02180 connect(good_button_box, SIGNAL(accepted()), good_group_dialog_, SLOT(accept())); 02181 connect(add_another_kinematic_chain_button, SIGNAL(clicked()), this, SLOT(resetPage())); 02182 good_group_dialog_->setLayout(good_group_layout); 02183 02184 not_ok_dialog_ = new QDialog(this); 02185 QVBoxLayout* notOkDialogLayout = new QVBoxLayout(not_ok_dialog_); 02186 QLabel* notOkText = new QLabel(not_ok_dialog_); 02187 notOkText->setText("Error! The planning group was invalid!"); 02188 notOkDialogLayout->addWidget(notOkText); 02189 QDialogButtonBox* ok_button_box = new QDialogButtonBox(QDialogButtonBox::Ok); 02190 notOkDialogLayout->addWidget(ok_button_box); 02191 connect(ok_button_box, SIGNAL(accepted()), not_ok_dialog_, SLOT(accept())); 02192 not_ok_dialog_->setLayout(notOkDialogLayout); 02193 02194 setButtonText(QWizard::NextButton, "Add Group"); 02195 registerField("collection_name*", joint_group_name_field_); 02196 02197 02198 } 02199 02200 bool JointCollectionWizardPage::validatePage() { 02201 02202 string new_group_name = joint_group_name_field_->text().toStdString(); 02203 vector<string> joints; 02204 for(int i = 0; i < selected_joint_table_->rowCount(); i++) 02205 { 02206 joints.push_back(selected_joint_table_->item(i, 0)->text().toStdString()); 02207 } 02208 02209 vector<string> subgroups; 02210 KinematicModel::GroupConfig gc(new_group_name, joints, subgroups); 02211 02212 PlanningDescriptionConfigurationWizard::GroupAddStatus stat = 02213 parent_->addGroup(gc); 02214 02215 if(stat == PlanningDescriptionConfigurationWizard::GroupAddSuccess) { 02216 int val = good_group_dialog_->exec(); 02217 parent_->setCurrentShowGroup(""); 02218 if(val == QDialog::Accepted) { 02219 return true; 02220 } else if(val == QDialog::Rejected) { 02221 return false; 02222 } else { 02223 return false; 02224 } 02225 } else if(stat == PlanningDescriptionConfigurationWizard::GroupAddFailed) { 02226 not_ok_dialog_->exec(); 02227 return false; 02228 } else { 02229 //cancelled duplicated 02230 return false; 02231 } 02232 } 02233 02234 void JointCollectionWizardPage::selectJointButtonClicked() 02235 { 02236 QList<QTableWidgetItem*> selected = joint_table_->selectedItems(); 02237 02238 for(int i = 0; i < selected.size(); i++) 02239 { 02240 string name = selected[i]->text().toStdString(); 02241 bool alreadyExists = false; 02242 int rowToAdd = 0; 02243 for(int r = 0; r < selected_joint_table_->rowCount(); r++) 02244 { 02245 QTableWidgetItem* item = selected_joint_table_->item(r, 0); 02246 02247 if(item->text().toStdString() == name) 02248 { 02249 alreadyExists = true; 02250 break; 02251 } 02252 rowToAdd = r + 1; 02253 } 02254 02255 if(!alreadyExists) 02256 { 02257 selected_joint_table_->setRowCount(selected_joint_table_->rowCount() + 1); 02258 QTableWidgetItem* newItem = new QTableWidgetItem(name.c_str()); 02259 newItem->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 02260 selected_joint_table_->setItem(rowToAdd, 0, newItem); 02261 } 02262 } 02263 if(selected_joint_table_->rowCount() > 0) { 02264 first_joint_field_->setText("has"); 02265 } 02266 } 02267 02268 void JointCollectionWizardPage::deselectJointButtonClicked() 02269 { 02270 QList<QTableWidgetItem*> deselected = selected_joint_table_->selectedItems(); 02271 02272 for(int i = 0; i < deselected.size(); i++) 02273 { 02274 selected_joint_table_->removeRow(deselected[i]->row()); 02275 } 02276 if(selected_joint_table_->rowCount() == 0) { 02277 first_joint_field_->clear(); 02278 } 02279 } 02280 02281 void JointCollectionWizardPage::createJointCollectionTables() 02282 { 02283 const vector<KinematicModel::JointModel*>& jmv = parent_->getKinematicModel()->getJointModels(); 02284 02285 joint_table_->setRowCount((int)jmv.size()); 02286 joint_table_->setColumnCount(1); 02287 joint_table_->setColumnWidth(0, 300); 02288 selected_joint_table_->setColumnCount(1); 02289 selected_joint_table_->setColumnWidth(0, 300); 02290 QStringList headerLabels; 02291 headerLabels.append("Joint"); 02292 QStringList headerLabels2; 02293 headerLabels2.append("Selected Joints"); 02294 joint_table_->setHorizontalHeaderLabels(headerLabels); 02295 selected_joint_table_->setHorizontalHeaderLabels(headerLabels2); 02296 for(size_t i = 1; i < jmv.size(); i++) 02297 { 02298 QTableWidgetItem* item = new QTableWidgetItem(jmv[i]->getName().c_str()); 02299 item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 02300 joint_table_->setItem((int)i - 1, 0, item); 02301 } 02302 } 02303 02304 CollisionsWizardPage::CollisionsWizardPage(PlanningDescriptionConfigurationWizard *parent, 02305 CollisionOperationsGenerator::DisableType disable_type) 02306 : QWizardPage(parent), disable_type_(disable_type), 02307 allow_enable_(true), show_percentages_(false), is_clickable_(true), coll_default_enabled_(false) 02308 { 02309 parent_ = parent; 02310 std::string title = "Links "; 02311 std::string subtitle; 02312 if(disable_type_ == CollisionOperationsGenerator::ALWAYS) { 02313 title += "Always"; 02314 subtitle = "The following links are always in collision over the sample space.\nClick on a link name to visualize the collision in Rviz"; 02315 allow_enable_ = false; 02316 } else if(disable_type_ == CollisionOperationsGenerator::DEFAULT) { 02317 subtitle = "The following links are in collision in the default state, and will be disabled by default.\nClick on a link name to visualize the collision in Rviz, and check Enable to force self-collision checking for the indicated pair."; 02318 title += "Default"; 02319 } else if(disable_type_ == CollisionOperationsGenerator::OFTEN) { 02320 title += "Often"; 02321 subtitle = "The following links are in collision in the majority of sampled states. Enabling them will substantially slow collision checking.\nClick on a link name to visualize the collision in Rviz, and check Enable to force self-collision checking for the indicated pair."; 02322 show_percentages_ = true; 02323 } else if(disable_type == CollisionOperationsGenerator::ADJACENT) { 02324 is_clickable_ = false; 02325 title += "Adjacent"; 02326 subtitle = "The following links are adjacent in the kinematic tree and will be disabled by default.\nCheck Enable to force self-collision checking for the indicated pair"; 02327 } else { 02328 coll_default_enabled_ = true; 02329 show_percentages_ = true; 02330 subtitle = "The following links are in the indicated percentage of samples. By default, link pairs that were found to be in collision in one or more samples have collision checking enabled.\nLink pairs that were never found to be in collision have been disabled.\nClick on a link name to visualize the collision in Rviz."; 02331 title += "Occasionally and Never"; 02332 } 02333 title += " In Collision"; 02334 setTitle(title.c_str()); 02335 02336 QVBoxLayout* layout = new QVBoxLayout(this); 02337 setSubTitle(subtitle.c_str()); 02338 QPushButton* generateButton = new QPushButton(this); 02339 generateButton->setText("Generate List (May take a minute)"); 02340 layout->addWidget(generateButton); 02341 connect(generateButton, SIGNAL(clicked()), this, SLOT(generateCollisionTable())); 02342 generateButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 02343 02344 collision_table_ = new QTableWidget(this); 02345 layout->addWidget(collision_table_); 02346 02347 if(allow_enable_) { 02348 QPushButton* toggle_selected = new QPushButton(this); 02349 toggle_selected->setText("Toggle Selected"); 02350 layout->addWidget(toggle_selected); 02351 connect(toggle_selected, SIGNAL(clicked()), this, SLOT(toggleTable())); 02352 toggle_selected->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 02353 } 02354 if(is_clickable_) { 02355 connect(collision_table_, SIGNAL(cellClicked(int, int)), this, SLOT(tableClicked())); 02356 } 02357 setLayout(layout); 02358 } 02359 02360 void CollisionsWizardPage::generateCollisionTable() { 02361 vector<CollisionOperationsGenerator::StringPair> not_in_collision; 02362 vector<double> percentages; 02363 if(disable_type_ == CollisionOperationsGenerator::ALWAYS) { 02364 parent_->getOperationsGenerator()->generateAlwaysInCollisionPairs(collision_pairs_, in_collision_joint_values_); 02365 } else if(disable_type_ == CollisionOperationsGenerator::DEFAULT) { 02366 parent_->getOperationsGenerator()->generateDefaultInCollisionPairs(collision_pairs_, in_collision_joint_values_); 02367 } else if(disable_type_ == CollisionOperationsGenerator::OFTEN) { 02368 parent_->getOperationsGenerator()->generateOftenInCollisionPairs(collision_pairs_, percentages, in_collision_joint_values_); 02369 } else if(disable_type_ == CollisionOperationsGenerator::ADJACENT) { 02370 parent_->getOperationsGenerator()->generateAdjacentInCollisionPairs(collision_pairs_); 02371 } else { 02372 parent_->getOperationsGenerator()->generateOccasionallyAndNeverInCollisionPairs(collision_pairs_, not_in_collision, 02373 percentages, in_collision_joint_values_); 02374 } 02375 02376 if(disable_type_ == CollisionOperationsGenerator::NEVER || 02377 disable_type_ == CollisionOperationsGenerator::OCCASIONALLY) { 02378 disable_pairs_ = not_in_collision; 02379 enable_pairs_ = collision_pairs_; 02380 } else { 02381 disable_pairs_ = collision_pairs_; 02382 } 02383 02384 collision_table_->clear(); 02385 collision_table_->setRowCount((int)collision_pairs_.size()+(int)not_in_collision.size()); 02386 collision_table_->setColumnCount(2); 02387 collision_table_->setColumnWidth(0, 500); 02388 collision_table_->setColumnWidth(1, 500); 02389 QStringList titleList; 02390 titleList.append("Link A"); 02391 titleList.append("Link B"); 02392 if(show_percentages_) { 02393 titleList.append("% Colliding"); 02394 } 02395 if(allow_enable_) { 02396 titleList.append("Enable?"); 02397 } 02398 if(show_percentages_ && allow_enable_) { 02399 collision_table_->setColumnCount(4); 02400 02401 collision_table_->setColumnWidth(0, 300); 02402 collision_table_->setColumnWidth(1, 300); 02403 collision_table_->setColumnWidth(2, 200); 02404 collision_table_->setColumnWidth(3, 200); 02405 } else if(allow_enable_) { 02406 collision_table_->setColumnCount(3); 02407 02408 collision_table_->setColumnWidth(0, 300); 02409 collision_table_->setColumnWidth(1, 300); 02410 collision_table_->setColumnWidth(2, 300); 02411 } 02412 //shouldn't ever have percentages without allowed enable 02413 02414 collision_table_->setHorizontalHeaderLabels(titleList); 02415 if(collision_pairs_.size() + not_in_collision.size() == 0) { 02416 collision_table_->setRowCount(1); 02417 QTableWidgetItem* no_collide = new QTableWidgetItem("No Link Pairs Of This Kind"); 02418 collision_table_->setItem(0, 0, no_collide); 02419 } 02420 02421 bool bad_percentages = false; 02422 if(show_percentages_ && collision_pairs_.size() != percentages.size()) { 02423 ROS_WARN_STREAM("Percentages enabled but percentage size " << percentages.size() 02424 << " not equal to collision pairs size " << collision_pairs_.size()); 02425 bad_percentages = true; 02426 } 02427 02428 for(size_t i = 0; i < collision_pairs_.size(); i++) 02429 { 02430 QTableWidgetItem* linkA = new QTableWidgetItem(collision_pairs_[i].first.c_str()); 02431 linkA->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 02432 QTableWidgetItem* linkB = new QTableWidgetItem(collision_pairs_[i].second.c_str()); 02433 linkB->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 02434 02435 collision_table_->setItem((int)i, 0, linkA); 02436 collision_table_->setItem((int)i, 1, linkB); 02437 02438 if(show_percentages_) { 02439 stringstream percentageStream; 02440 if(bad_percentages) { 02441 percentageStream << 1.0; 02442 } else { 02443 percentageStream << percentages[i]; 02444 } 02445 QTableWidgetItem* percentage = new QTableWidgetItem(percentageStream.str().c_str()); 02446 percentage->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 02447 collision_table_->setItem((int)i, 2, percentage); 02448 } 02449 02450 if(allow_enable_) { 02451 QCheckBox* enable_box = new QCheckBox(collision_table_); 02452 if(coll_default_enabled_) { 02453 enable_box->setChecked(true); 02454 } else { 02455 enable_box->setChecked(false); 02456 } 02457 connect(enable_box, SIGNAL(toggled(bool)), this, SLOT(tableChanged())); 02458 if(show_percentages_) { 02459 collision_table_->setCellWidget((int)i, 3, enable_box); 02460 } else { 02461 collision_table_->setCellWidget((int)i, 2, enable_box); 02462 } 02463 } 02464 } 02465 for(size_t i = 0; i < not_in_collision.size(); i++) 02466 { 02467 QTableWidgetItem* linkA = new QTableWidgetItem(not_in_collision[i].first.c_str()); 02468 linkA->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 02469 QTableWidgetItem* linkB = new QTableWidgetItem(not_in_collision[i].second.c_str()); 02470 linkB->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 02471 02472 collision_table_->setItem((int)i+collision_pairs_.size(), 0, linkA); 02473 collision_table_->setItem((int)i+collision_pairs_.size(), 1, linkB); 02474 02475 if(show_percentages_) { 02476 stringstream percentageStream; 02477 percentageStream << 0.0; 02478 QTableWidgetItem* percentage = new QTableWidgetItem(percentageStream.str().c_str()); 02479 percentage->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable); 02480 collision_table_->setItem((int)i+collision_pairs_.size(), 2, percentage); 02481 } 02482 02483 if(allow_enable_) { 02484 QCheckBox* enable_box = new QCheckBox(collision_table_); 02485 enable_box->setChecked(false); 02486 connect(enable_box, SIGNAL(toggled(bool)), this, SLOT(tableChanged())); 02487 if(show_percentages_) { 02488 collision_table_->setCellWidget((int)i+collision_pairs_.size(), 3, enable_box); 02489 } else { 02490 collision_table_->setCellWidget((int)i+collision_pairs_.size(), 2, enable_box); 02491 } 02492 } 02493 } 02494 tableChanged(); 02495 } 02496 02497 void CollisionsWizardPage::toggleTable() 02498 { 02499 unsigned int column = 2; 02500 if(show_percentages_) { 02501 column = 3; 02502 } 02503 vector<int> rows = getSelectedRows(collision_table_); 02504 for(size_t i = 0; i < rows.size(); i++) 02505 { 02506 QCheckBox* box = dynamic_cast<QCheckBox*> (collision_table_->cellWidget(rows[i], column)); 02507 02508 if(box != NULL) 02509 { 02510 if(box->isChecked()) 02511 { 02512 box->setChecked(false); 02513 } 02514 else 02515 { 02516 box->setChecked(true); 02517 } 02518 } 02519 } 02520 tableChanged(); 02521 } 02522 02523 void CollisionsWizardPage::tableClicked() { 02524 QList<QTableWidgetItem*> selected = collision_table_->selectedItems(); 02525 02526 ROS_DEBUG_STREAM("Table clicked"); 02527 02528 if(selected.size() == 0) 02529 { 02530 return; 02531 } 02532 02533 int row = selected[0]->row(); 02534 ROS_DEBUG_STREAM("Showing selection " << row); 02535 02536 std_msgs::ColorRGBA color; 02537 color.r = 1.0; 02538 color.g = 1.0; 02539 color.b = 0.2; 02540 color.a = 1.0; 02541 parent_->visualizeCollision(in_collision_joint_values_, collision_pairs_, row, color); 02542 } 02543 02544 void CollisionsWizardPage::tableChanged() { 02545 unsigned int column = 2; 02546 if(show_percentages_) { 02547 column = 3; 02548 } 02549 for(int i = 0; i < collision_table_->rowCount(); i++) 02550 { 02551 QCheckBox* box = dynamic_cast<QCheckBox*> (collision_table_->cellWidget(i, column)); 02552 if(box != NULL) 02553 { 02554 pair<string, string> link_pair; 02555 link_pair.first = collision_table_->item(i, 0)->text().toStdString(); 02556 link_pair.second = collision_table_->item(i, 1)->text().toStdString(); 02557 bool in_disabled = false; 02558 vector<pair<string, string> >::iterator it = disable_pairs_.begin(); 02559 while(it != disable_pairs_.end()) 02560 { 02561 if((*it) == link_pair) { 02562 in_disabled = true; 02563 if(box->isChecked()) { 02564 disable_pairs_.erase(it); 02565 } 02566 break; 02567 } 02568 it++; 02569 } 02570 if(!in_disabled) { 02571 if(box->isChecked()) { 02572 it = extra_disable_pairs_.begin(); 02573 while(it != extra_disable_pairs_.end()) { 02574 if((*it) == link_pair) { 02575 extra_disable_pairs_.erase(it); 02576 break; 02577 } 02578 it++; 02579 } 02580 } 02581 if(!box->isChecked()) { 02582 bool in_enable = false; 02583 it = enable_pairs_.begin(); 02584 while(it != enable_pairs_.end()) { 02585 if((*it) == link_pair) { 02586 in_enable = true; 02587 break; 02588 } 02589 it++; 02590 } 02591 if(!in_enable) { 02592 disable_pairs_.push_back(link_pair); 02593 } else { 02594 bool found = false; 02595 it = extra_disable_pairs_.begin(); 02596 while(it != extra_disable_pairs_.end()) { 02597 if((*it) == link_pair) { 02598 found = true; 02599 break; 02600 } 02601 it++; 02602 } 02603 if(!found) { 02604 extra_disable_pairs_.push_back(link_pair); 02605 } 02606 } 02607 } 02608 } 02609 } 02610 } 02611 } 02612 02613 bool CollisionsWizardPage::validatePage() { 02614 parent_->getOperationsGenerator()->disablePairCollisionChecking(disable_pairs_); 02615 //for occasionally and never 02616 if(!extra_disable_pairs_.empty()) { 02617 parent_->setDisableMap(CollisionOperationsGenerator::OCCASIONALLY, extra_disable_pairs_); 02618 } 02619 parent_->setDisableMap(disable_type_, disable_pairs_); 02620 return true; 02621 } 02622 02623 OutputWizardPage::OutputWizardPage(PlanningDescriptionConfigurationWizard *parent) 02624 : QWizardPage(parent), successful_generation_(false) 02625 { 02626 setTitle("Output Files"); 02627 QVBoxLayout* layout = new QVBoxLayout(this); 02628 02629 setSubTitle("Done! The wizard will auto-generate a stack called <your_robot_name>_arm_navigation " 02630 "in the selected folder when you click the generate button below."); 02631 02632 package_path_field_ = new QLineEdit(this); 02633 package_path_field_->setText("<absolute directory path>"); 02634 layout->addWidget(package_path_field_); 02635 02636 QPushButton* selectFileButton = new QPushButton(this); 02637 selectFileButton->setText("Select Directory ..."); 02638 selectFileButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 02639 file_selector_ = new QFileDialog(this); 02640 file_selector_->setFileMode(QFileDialog::Directory); 02641 file_selector_->setOption(QFileDialog::ShowDirsOnly, true); 02642 02643 connect(file_selector_, SIGNAL(fileSelected(const QString&)), this, SLOT(fileSelected(const QString&))); 02644 connect(selectFileButton, SIGNAL(clicked()), file_selector_, SLOT(open())); 02645 layout->addWidget(selectFileButton); 02646 02647 QPushButton* generateButton = new QPushButton(this); 02648 generateButton->setText("Generate Config Files..."); 02649 generateButton->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum); 02650 02651 layout->addWidget(generateButton); 02652 02653 progress_bar_ = new QProgressBar(this); 02654 progress_label_ = new QLabel(this); 02655 layout->addWidget(progress_bar_); 02656 layout->addWidget(progress_label_); 02657 02658 really_exit_dialog_ = new QDialog(this); 02659 QVBoxLayout* really_exit_layout = new QVBoxLayout(really_exit_dialog_); 02660 QLabel* really_exit_text = new QLabel(really_exit_dialog_); 02661 really_exit_text->setText("You haven't generated an application - do you really want to exit?"); 02662 really_exit_layout->addWidget(really_exit_text); 02663 QDialogButtonBox* exit_button_box = new QDialogButtonBox(QDialogButtonBox::Yes | QDialogButtonBox::No); 02664 connect(exit_button_box, SIGNAL(accepted()), really_exit_dialog_, SLOT(accept())); 02665 connect(exit_button_box, SIGNAL(rejected()), really_exit_dialog_, SLOT(reject())); 02666 really_exit_layout->addWidget(exit_button_box); 02667 really_exit_dialog_->setLayout(really_exit_layout); 02668 02669 successful_creation_dialog_ = new QDialog(this); 02670 QVBoxLayout* successful_creation_layout = new QVBoxLayout(successful_creation_dialog_); 02671 QLabel* successful_creation_text = new QLabel(successful_creation_dialog_); 02672 successful_creation_text->setText("Your application was successfully created."); 02673 successful_creation_layout->addWidget(successful_creation_text); 02674 QPushButton* exit_now_button = new QPushButton(tr("&Exit Wizard")); 02675 QPushButton* stay_in_application_button = new QPushButton(tr("&Stay In Wizard")); 02676 QDialogButtonBox* success_button_box = new QDialogButtonBox(); 02677 successful_creation_layout->addWidget(success_button_box); 02678 success_button_box->addButton(stay_in_application_button, QDialogButtonBox::RejectRole); 02679 success_button_box->addButton(exit_now_button, QDialogButtonBox::AcceptRole); 02680 connect(success_button_box, SIGNAL(rejected()), successful_creation_dialog_, SLOT(reject())); 02681 connect(success_button_box, SIGNAL(accepted()), successful_creation_dialog_, SLOT(accept())); 02682 connect(success_button_box, SIGNAL(accepted()), parent, SLOT(accept())); 02683 successful_creation_dialog_->setLayout(successful_creation_layout); 02684 02685 connect(generateButton, SIGNAL(clicked()), parent, SLOT(writeFiles())); 02686 //addPage(output_files_page_); 02687 setLayout(layout); 02688 } 02689 02690 PlanningDescriptionConfigurationWizard* pdcw; 02691 02692 bool inited = false; 02693 02694 void spin_function() 02695 { 02696 ros::WallRate r(100.0); 02697 unsigned int counter = 0; 02698 while(ros::ok()) 02699 { 02700 if(inited) 02701 { 02702 pdcw->sendTransforms(); 02703 if(counter % CONTROL_SPEED == 0) 02704 { 02705 counter = 1; 02706 pdcw->sendMarkers(); 02707 } 02708 else 02709 { 02710 counter++; 02711 } 02712 } 02713 r.sleep(); 02714 ros::spinOnce(); 02715 } 02716 } 02717 02718 void quit(int sig) 02719 { 02720 if(pdcw != NULL) 02721 { 02722 delete pdcw; 02723 } 02724 exit(0); 02725 } 02726 02727 int main(int argc, char** argv) 02728 { 02729 02730 QApplication qtApp(argc, argv); 02731 02732 srand(time(NULL)); 02733 ros::init(argc, argv, "planning_description_configuration_wizard", ros::init_options::NoSigintHandler); 02734 02735 if(argc < 3) 02736 { 02737 ROS_INFO_STREAM("Must specify a package and relative urdf file"); 02738 exit(0); 02739 } 02740 02741 string urdf_package = argv[1]; 02742 string urdf_path = argv[2]; 02743 pdcw = new PlanningDescriptionConfigurationWizard(urdf_package, urdf_path, NULL); 02744 pdcw->setUpdatesEnabled(true); 02745 02746 qtApp.setActiveWindow(pdcw); 02747 02748 pdcw->show(); 02749 if(!pdcw->isInited()) 02750 { 02751 ROS_WARN_STREAM("Can't init. Exiting"); 02752 exit(0); 02753 } 02754 02755 inited = true; 02756 02757 boost::thread spin_thread(boost::bind(&spin_function)); 02758 return qtApp.exec(); 02759 } 02760