00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include <moveit/motion_planning_rviz_plugin/motion_planning_frame.h>
00033 #include <moveit/motion_planning_rviz_plugin/motion_planning_display.h>
00034
00035 #include <geometric_shapes/shape_operations.h>
00036
00037 #include <rviz/display_context.h>
00038 #include <rviz/frame_manager.h>
00039
00040 #include <QMessageBox>
00041 #include <QInputDialog>
00042 #include <QShortcut>
00043
00044 #include "ui_motion_planning_rviz_plugin_frame.h"
00045
00046 namespace moveit_rviz_plugin
00047 {
00048
00049 MotionPlanningFrame::MotionPlanningFrame(MotionPlanningDisplay *pdisplay, rviz::DisplayContext *context, QWidget *parent) :
00050 QWidget(parent),
00051 planning_display_(pdisplay),
00052 context_(context),
00053 ui_(new Ui::MotionPlanningUI()),
00054 first_time_(true)
00055 {
00056
00057 ui_->setupUi(this);
00058
00059
00060
00061 connect( ui_->plan_button, SIGNAL( clicked() ), this, SLOT( planButtonClicked() ));
00062 connect( ui_->execute_button, SIGNAL( clicked() ), this, SLOT( executeButtonClicked() ));
00063 connect( ui_->plan_and_execute_button, SIGNAL( clicked() ), this, SLOT( planAndExecuteButtonClicked() ));
00064 connect( ui_->use_start_state_button, SIGNAL( clicked() ), this, SLOT( useStartStateButtonClicked() ));
00065 connect( ui_->use_goal_state_button, SIGNAL( clicked() ), this, SLOT( useGoalStateButtonClicked() ));
00066 connect( ui_->database_connect_button, SIGNAL( clicked() ), this, SLOT( databaseConnectButtonClicked() ));
00067 connect( ui_->save_scene_button, SIGNAL( clicked() ), this, SLOT( saveSceneButtonClicked() ));
00068 connect( ui_->save_query_button, SIGNAL( clicked() ), this, SLOT( saveQueryButtonClicked() ));
00069 connect( ui_->delete_scene_button, SIGNAL( clicked() ), this, SLOT( deleteSceneButtonClicked() ));
00070 connect( ui_->delete_query_button, SIGNAL( clicked() ), this, SLOT( deleteQueryButtonClicked() ));
00071 connect( ui_->planning_scene_tree, SIGNAL( itemSelectionChanged() ), this, SLOT( planningSceneItemClicked() ));
00072 connect( ui_->load_scene_button, SIGNAL( clicked() ), this, SLOT( loadSceneButtonClicked() ));
00073 connect( ui_->load_query_button, SIGNAL( clicked() ), this, SLOT( loadQueryButtonClicked() ));
00074 connect( ui_->allow_looking, SIGNAL( toggled(bool) ), this, SLOT( allowLookingToggled(bool) ));
00075 connect( ui_->allow_replanning, SIGNAL( toggled(bool) ), this, SLOT( allowReplanningToggled(bool) ));
00076 connect( ui_->planning_algorithm_combo_box, SIGNAL( currentIndexChanged ( int ) ), this, SLOT( planningAlgorithmIndexChanged( int ) ));
00077 connect( ui_->import_file_button, SIGNAL( clicked() ), this, SLOT( importFileButtonClicked() ));
00078 connect( ui_->import_url_button, SIGNAL( clicked() ), this, SLOT( importUrlButtonClicked() ));
00079 connect( ui_->clear_scene_button, SIGNAL( clicked() ), this, SLOT( clearSceneButtonClicked() ));
00080 connect( ui_->scene_scale, SIGNAL( valueChanged(int) ), this, SLOT( sceneScaleChanged(int) ));
00081 connect( ui_->scene_scale, SIGNAL( sliderPressed() ), this, SLOT( sceneScaleStartChange() ));
00082 connect( ui_->scene_scale, SIGNAL( sliderReleased() ), this, SLOT( sceneScaleEndChange() ));
00083 connect( ui_->remove_object_button, SIGNAL( clicked() ), this, SLOT( removeObjectButtonClicked() ));
00084 connect( ui_->object_x, SIGNAL( valueChanged(double) ), this, SLOT( objectPoseValueChanged(double) ));
00085 connect( ui_->object_y, SIGNAL( valueChanged(double) ), this, SLOT( objectPoseValueChanged(double) ));
00086 connect( ui_->object_z, SIGNAL( valueChanged(double) ), this, SLOT( objectPoseValueChanged(double) ));
00087 connect( ui_->object_rx, SIGNAL( valueChanged(double) ), this, SLOT( objectPoseValueChanged(double) ));
00088 connect( ui_->object_ry, SIGNAL( valueChanged(double) ), this, SLOT( objectPoseValueChanged(double) ));
00089 connect( ui_->object_rz, SIGNAL( valueChanged(double) ), this, SLOT( objectPoseValueChanged(double) ));
00090 connect( ui_->publish_current_scene_button, SIGNAL( clicked() ), this, SLOT( publishSceneButtonClicked() ));
00091 connect( ui_->collision_objects_list, SIGNAL( itemSelectionChanged() ), this, SLOT( selectedCollisionObjectChanged() ));
00092 connect( ui_->collision_objects_list, SIGNAL( itemChanged( QListWidgetItem * ) ), this, SLOT( collisionObjectChanged( QListWidgetItem * ) ));
00093 connect( ui_->path_constraints_combo_box, SIGNAL( currentIndexChanged ( int ) ), this, SLOT( pathConstraintsIndexChanged( int ) ));
00094 connect( ui_->planning_scene_tree, SIGNAL( itemChanged( QTreeWidgetItem *, int ) ), this, SLOT( warehouseItemNameChanged( QTreeWidgetItem *, int ) ));
00095 connect( ui_->reset_db_button, SIGNAL( clicked() ), this, SLOT( resetDbButtonClicked() ));
00096 connect( ui_->export_scene_text_button, SIGNAL( clicked() ), this, SLOT( exportAsTextButtonClicked() ));
00097 connect( ui_->import_scene_text_button, SIGNAL( clicked() ), this, SLOT( importFromTextButtonClicked() ));
00098 connect( ui_->load_state_button, SIGNAL( clicked() ), this, SLOT( loadStateButtonClicked() ));
00099 connect( ui_->save_start_state_button, SIGNAL( clicked() ), this, SLOT( saveStartStateButtonClicked() ));
00100 connect( ui_->save_goal_state_button, SIGNAL( clicked() ), this, SLOT( saveGoalStateButtonClicked() ));
00101 connect( ui_->set_as_start_state_button, SIGNAL( clicked() ), this, SLOT( setAsStartStateButtonClicked() ));
00102 connect( ui_->set_as_goal_state_button, SIGNAL( clicked() ), this, SLOT( setAsGoalStateButtonClicked() ));
00103 connect( ui_->remove_state_button, SIGNAL( clicked() ), this, SLOT( removeStateButtonClicked() ));
00104 connect( ui_->clear_states_button, SIGNAL( clicked() ), this, SLOT( clearStatesButtonClicked() ));
00105 connect( ui_->approximate_ik, SIGNAL( stateChanged(int) ), this, SLOT( approximateIKChanged(int) ));
00106
00107 connect( ui_->tabWidget, SIGNAL( currentChanged ( int ) ), this, SLOT( tabChanged( int ) ));
00108
00109 QShortcut *copy_object_shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_C), ui_->collision_objects_list);
00110 connect(copy_object_shortcut, SIGNAL( activated() ), this, SLOT( copySelectedCollisionObject() ) );
00111
00112 ui_->reset_db_button->hide();
00113 ui_->background_job_progress->hide();
00114 ui_->background_job_progress->setMaximum(0);
00115
00116 ui_->tabWidget->setCurrentIndex(0);
00117
00118 known_collision_objects_version_ = 0;
00119
00120 planning_scene_publisher_ = nh_.advertise<moveit_msgs::PlanningScene>("planning_scene", 1);
00121 planning_scene_world_publisher_ = nh_.advertise<moveit_msgs::PlanningSceneWorld>("planning_scene_world", 1);
00122 }
00123
00124 MotionPlanningFrame::~MotionPlanningFrame()
00125 {
00126 }
00127
00128 void MotionPlanningFrame::approximateIKChanged(int state)
00129 {
00130 planning_display_->useApproximateIK(state == Qt::Checked);
00131 }
00132
00133 void MotionPlanningFrame::setItemSelectionInList(const std::string &item_name, bool selection, QListWidget *list)
00134 {
00135 QList<QListWidgetItem*> found_items = list->findItems(QString(item_name.c_str()), Qt::MatchExactly);
00136 for (std::size_t i = 0 ; i < found_items.size(); ++i)
00137 found_items[i]->setSelected(selection);
00138 }
00139
00140 void MotionPlanningFrame::fillStateSelectionOptions()
00141 {
00142 ui_->start_state_selection->clear();
00143 ui_->goal_state_selection->clear();
00144
00145 if (!planning_display_->getPlanningSceneMonitor())
00146 return;
00147
00148 const robot_model::RobotModelConstPtr &kmodel = planning_display_->getRobotModel();
00149 std::string group = planning_display_->getCurrentPlanningGroup();
00150 if (group.empty())
00151 return;
00152 const robot_model::JointModelGroup *jmg = kmodel->getJointModelGroup(group);
00153 if (jmg)
00154 {
00155 ui_->start_state_selection->addItem(QString("<random>"));
00156 ui_->start_state_selection->addItem(QString("<current>"));
00157 ui_->start_state_selection->addItem(QString("<same as goal>"));
00158
00159 ui_->goal_state_selection->addItem(QString("<random>"));
00160 ui_->goal_state_selection->addItem(QString("<current>"));
00161 ui_->goal_state_selection->addItem(QString("<same as start>"));
00162
00163 std::vector<std::string> known_states;
00164 jmg->getKnownDefaultStates(known_states);
00165 if (!known_states.empty())
00166 {
00167 ui_->start_state_selection->insertSeparator(ui_->start_state_selection->count());
00168 ui_->goal_state_selection->insertSeparator(ui_->goal_state_selection->count());
00169 for (std::size_t i = 0 ; i < known_states.size() ; ++i)
00170 {
00171 ui_->start_state_selection->addItem(QString::fromStdString(known_states[i]));
00172 ui_->goal_state_selection->addItem(QString::fromStdString(known_states[i]));
00173 }
00174 }
00175 ui_->start_state_selection->setCurrentIndex(1);
00176 ui_->goal_state_selection->setCurrentIndex(0);
00177 }
00178 }
00179
00180 void MotionPlanningFrame::changePlanningGroupHelper()
00181 {
00182 if (!planning_display_->getPlanningSceneMonitor())
00183 return;
00184
00185 planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::fillStateSelectionOptions, this));
00186 planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populateConstraintsList, this, std::vector<std::string>()));
00187
00188 const robot_model::RobotModelConstPtr &kmodel = planning_display_->getRobotModel();
00189 std::string group = planning_display_->getCurrentPlanningGroup();
00190
00191 if (!group.empty() && kmodel)
00192 {
00193 if (move_group_ && move_group_->getName() == group)
00194 return;
00195 ROS_INFO("Constructing new MoveGroup connection for group '%s'", group.c_str());
00196 moveit::planning_interface::MoveGroup::Options opt(group);
00197 opt.robot_model_ = kmodel;
00198 opt.robot_description_.clear();
00199 try
00200 {
00201 move_group_.reset(new moveit::planning_interface::MoveGroup(opt, context_->getFrameManager()->getTFClientPtr(), ros::Duration(30, 0)));
00202 if (planning_scene_storage_)
00203 move_group_->setConstraintsDatabase(ui_->database_host->text().toStdString(), ui_->database_port->value());
00204 }
00205 catch(std::runtime_error &ex)
00206 {
00207 ROS_ERROR("%s", ex.what());
00208 }
00209 if (move_group_)
00210 {
00211 move_group_->allowLooking(ui_->allow_looking->isChecked());
00212 move_group_->allowReplanning(ui_->allow_replanning->isChecked());
00213 moveit_msgs::PlannerInterfaceDescription desc;
00214 if (move_group_->getInterfaceDescription(desc))
00215 planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populatePlannersList, this, desc));
00216 planning_display_->addBackgroundJob(boost::bind(&MotionPlanningFrame::populateConstraintsList, this), "populateConstraintsList");
00217
00218 if (first_time_)
00219 {
00220 first_time_ = false;
00221 const planning_scene_monitor::LockedPlanningSceneRO &ps = planning_display_->getPlanningSceneRO();
00222 if (ps)
00223 {
00224 planning_display_->setQueryStartState(ps->getCurrentState());
00225 planning_display_->setQueryGoalState(ps->getCurrentState());
00226 }
00227 }
00228 }
00229 }
00230 }
00231
00232 void MotionPlanningFrame::changePlanningGroup()
00233 {
00234 planning_display_->addBackgroundJob(boost::bind(&MotionPlanningFrame::changePlanningGroupHelper, this), "Frame::changePlanningGroup");
00235 }
00236
00237 void MotionPlanningFrame::sceneUpdate(planning_scene_monitor::PlanningSceneMonitor::SceneUpdateType update_type)
00238 {
00239 if (update_type & planning_scene_monitor::PlanningSceneMonitor::UPDATE_GEOMETRY)
00240 planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populateCollisionObjectsList, this));
00241 }
00242
00243 void MotionPlanningFrame::importResource(const std::string &path)
00244 {
00245 if (planning_display_->getPlanningSceneMonitor())
00246 {
00247 shapes::Mesh *mesh = shapes::createMeshFromResource(path);
00248 if (mesh)
00249 {
00250 std::size_t slash = path.find_last_of("/\\");
00251 std::string name = path.substr(slash + 1);
00252 shapes::ShapeConstPtr shape(mesh);
00253 Eigen::Affine3d pose;
00254 pose.setIdentity();
00255
00256 if (planning_display_->getPlanningSceneRO()->getCurrentState().hasAttachedBody(name))
00257 {
00258 QMessageBox::warning(this, QString("Duplicate names"),
00259 QString("An attached object named '").append(name.c_str()).append("' already exists. Please rename the attached object before importing."));
00260 return;
00261 }
00262
00263
00264 if (planning_display_->getPlanningSceneRO()->getWorld()->hasObject(name))
00265 {
00266 QMessageBox msgBox;
00267 msgBox.setText("There exists another object with the same name.");
00268 msgBox.setInformativeText("Would you like to overwrite it?");
00269 msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
00270 msgBox.setDefaultButton(QMessageBox::No);
00271 int ret = msgBox.exec();
00272
00273 switch (ret)
00274 {
00275 case QMessageBox::Yes:
00276
00277 {
00278 planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00279 if (ps)
00280 {
00281 ps->getWorldNonConst()->removeObject(name);
00282 addObject(ps->getWorldNonConst(), name, shape, pose);
00283 }
00284 }
00285 break;
00286 case QMessageBox::No:
00287 {
00288
00289 bool ok = false;
00290 QString text = QInputDialog::getText(this, tr("Choose a new name"),
00291 tr("Import the new object under the name:"), QLineEdit::Normal,
00292 QString::fromStdString(name + "-" + boost::lexical_cast<std::string>
00293 (planning_display_->getPlanningSceneRO()->getWorld()->size())), &ok);
00294 if (ok)
00295 {
00296 if (!text.isEmpty())
00297 {
00298 name = text.toStdString();
00299 planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00300 if (ps)
00301 {
00302 if (ps->getWorld()->hasObject(name))
00303 QMessageBox::warning(this, "Name already exists", QString("The name '").append(name.c_str()).
00304 append("' already exists. Not importing object."));
00305 else
00306 addObject(ps->getWorldNonConst(), name, shape, pose);
00307 }
00308 }
00309 else
00310 QMessageBox::warning(this, "Object not imported", "Cannot use an empty name for an imported object");
00311 }
00312 break;
00313 }
00314 default:
00315
00316 break;
00317 }
00318 }
00319 else
00320 {
00321 planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00322 if (ps)
00323 addObject(ps->getWorldNonConst(), name, shape, pose);
00324 }
00325 }
00326 else
00327 {
00328 QMessageBox::warning(this, QString("Import error"), QString("Unable to import scene"));
00329 return;
00330 }
00331 }
00332 }
00333
00334 void MotionPlanningFrame::enable()
00335 {
00336 ui_->planning_algorithm_combo_box->clear();
00337 ui_->library_label->setText("NO PLANNING LIBRARY LOADED");
00338 ui_->library_label->setStyleSheet("QLabel { color : red; font: bold }");
00339 ui_->object_status->setText("");
00340
00341
00342 show();
00343 }
00344
00345 void MotionPlanningFrame::disable()
00346 {
00347 move_group_.reset();
00348 hide();
00349 }
00350
00351 void MotionPlanningFrame::tabChanged(int index)
00352 {
00353 if (scene_marker_ && ui_->tabWidget->tabText(index) != "Scene Objects")
00354 scene_marker_.reset();
00355 else
00356 if (ui_->tabWidget->tabText(index) == "Scene Objects")
00357 selectedCollisionObjectChanged();
00358 }
00359
00360 void MotionPlanningFrame::updateSceneMarkers(float wall_dt, float ros_dt)
00361 {
00362 if (scene_marker_)
00363 scene_marker_->update(wall_dt);
00364 }
00365
00366 }