motion_planning_frame_objects.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2012, 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 Willow Garage, Inc. 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: Ioan Sucan, Mario Prats */
00031 
00032 #include <moveit/warehouse/planning_scene_storage.h>
00033 
00034 #include <moveit/motion_planning_rviz_plugin/motion_planning_frame.h>
00035 #include <moveit/motion_planning_rviz_plugin/motion_planning_display.h>
00036 #include <moveit/robot_state/conversions.h>
00037 #include <moveit/robot_interaction/interactive_marker_helpers.h>
00038 
00039 #include <interactive_markers/tools.h>
00040 
00041 #include <rviz/display_context.h>
00042 #include <rviz/frame_manager.h>
00043 #include <rviz/window_manager_interface.h>
00044 
00045 #include <eigen_conversions/eigen_msg.h>
00046 #include <geometric_shapes/shape_operations.h>
00047 
00048 #include <QMessageBox>
00049 #include <QInputDialog>
00050 #include <QFileDialog>
00051 
00052 #include "ui_motion_planning_rviz_plugin_frame.h"
00053 
00054 namespace moveit_rviz_plugin
00055 {
00056 
00057 void MotionPlanningFrame::importFileButtonClicked()
00058 {
00059   QString path = QFileDialog::getOpenFileName(this, tr("Import Object"));
00060   if (!path.isEmpty())
00061     importResource("file://" + path.toStdString());
00062 }
00063 
00064 void MotionPlanningFrame::importUrlButtonClicked()
00065 {
00066   bool ok = false;
00067   QString url = QInputDialog::getText(this, tr("Import Object"),
00068                                       tr("URL for file to import:"), QLineEdit::Normal,
00069                                       QString("http://"), &ok);
00070   if (ok && !url.isEmpty())
00071     importResource(url.toStdString());
00072 }
00073 
00074 void MotionPlanningFrame::clearSceneButtonClicked()
00075 {
00076   planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00077   if (ps)
00078   {
00079     ps->getWorldNonConst()->clearObjects();
00080     ps->getCurrentStateNonConst().clearAttachedBodies();
00081     moveit_msgs::PlanningScene msg;
00082     ps->getPlanningSceneMsg(msg);
00083     planning_scene_publisher_.publish(msg);
00084     planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populateCollisionObjectsList, this));
00085     planning_display_->queueRenderSceneGeometry();
00086   }
00087 }
00088 
00089 void MotionPlanningFrame::sceneScaleChanged(int value)
00090 {
00091   if (scaled_object_)
00092   {
00093     planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00094     if (ps)
00095     {
00096       if (ps->getWorld()->hasObject(scaled_object_->id_))
00097       {
00098         ps->getWorldNonConst()->removeObject(scaled_object_->id_);
00099         for (std::size_t i = 0 ; i < scaled_object_->shapes_.size() ; ++i)
00100         {
00101           shapes::Shape *s = scaled_object_->shapes_[i]->clone();
00102           s->scale((double)value / 100.0);
00103           ps->getWorldNonConst()->addToObject(scaled_object_->id_, shapes::ShapeConstPtr(s), scaled_object_->shape_poses_[i]);
00104         }
00105         planning_display_->queueRenderSceneGeometry();
00106       }
00107       else
00108         scaled_object_.reset();
00109     }
00110     else
00111       scaled_object_.reset();
00112   }
00113 }
00114 
00115 void MotionPlanningFrame::sceneScaleStartChange()
00116 {
00117   QList<QListWidgetItem *> sel = ui_->collision_objects_list->selectedItems();
00118   if (sel.empty())
00119     return;
00120   if (planning_display_->getPlanningSceneMonitor() && sel[0]->checkState() == Qt::Unchecked)
00121   {
00122     planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00123     if (ps)
00124     {
00125       scaled_object_ = ps->getWorld()->getObject(sel[0]->text().toStdString());
00126     }
00127   }
00128 }
00129 
00130 void MotionPlanningFrame::sceneScaleEndChange()
00131 {
00132   scaled_object_.reset();
00133   ui_->scene_scale->setSliderPosition(100);
00134 }
00135 
00136 void MotionPlanningFrame::removeObjectButtonClicked()
00137 {
00138   QList<QListWidgetItem *> sel = ui_->collision_objects_list->selectedItems();
00139   if (sel.empty())
00140     return;
00141   planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00142   if (ps)
00143   {
00144     for (int i = 0 ; i < sel.count() ; ++i)
00145       if (sel[i]->checkState() == Qt::Unchecked)
00146         ps->getWorldNonConst()->removeObject(sel[i]->text().toStdString());
00147       else
00148         ps->getCurrentStateNonConst().clearAttachedBody(sel[i]->text().toStdString());
00149     scene_marker_.reset();
00150     planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populateCollisionObjectsList, this));
00151     planning_display_->queueRenderSceneGeometry();
00152   }
00153 }
00154 
00155 static QString decideStatusText(const collision_detection::CollisionWorld::ObjectConstPtr &obj)
00156 {
00157   QString status_text = "'" + QString::fromStdString(obj->id_) + "' is a collision object with ";
00158   if (obj->shapes_.empty())
00159     status_text += "no geometry";
00160   else
00161   {
00162     std::vector<QString> shape_names;
00163     for (std::size_t i = 0 ; i < obj->shapes_.size() ; ++i)
00164       shape_names.push_back(QString::fromStdString(shapes::shapeStringName(obj->shapes_[i].get())));
00165     if (shape_names.size() == 1)
00166       status_text += "one " + shape_names[0];
00167     else
00168     {
00169       status_text += QString::fromStdString(boost::lexical_cast<std::string>(shape_names.size())) + " shapes:";
00170       for (std::size_t i = 0 ; i < shape_names.size() ; ++i)
00171         status_text += " " + shape_names[i];
00172     }
00173   }
00174   return status_text;
00175 }
00176 
00177 static QString decideStatusText(const robot_state::AttachedBody *attached_body)
00178 {
00179   QString status_text = "'" + QString::fromStdString(attached_body->getName()) + "' is attached to '" +
00180       QString::fromStdString(attached_body->getAttachedLinkName()) + "'";
00181   return status_text;
00182 }
00183 
00184 void MotionPlanningFrame::selectedCollisionObjectChanged()
00185 {
00186   QList<QListWidgetItem *> sel = ui_->collision_objects_list->selectedItems();
00187   if (sel.empty())
00188   {
00189     bool oldState = ui_->object_x->blockSignals(true);
00190     ui_->object_x->setValue(0.0);
00191     ui_->object_x->blockSignals(oldState);
00192 
00193     oldState = ui_->object_y->blockSignals(true);
00194     ui_->object_y->setValue(0.0);
00195     ui_->object_y->blockSignals(oldState);
00196 
00197     oldState = ui_->object_z->blockSignals(true);
00198     ui_->object_z->setValue(0.0);
00199     ui_->object_z->blockSignals(oldState);
00200 
00201     oldState = ui_->object_rx->blockSignals(true);
00202     ui_->object_rx->setValue(0.0);
00203     ui_->object_rx->blockSignals(oldState);
00204 
00205     oldState = ui_->object_ry->blockSignals(true);
00206     ui_->object_ry->setValue(0.0);
00207     ui_->object_ry->blockSignals(oldState);
00208 
00209     oldState = ui_->object_rz->blockSignals(true);
00210     ui_->object_rz->setValue(0.0);
00211     ui_->object_rz->blockSignals(oldState);
00212 
00213     ui_->object_status->setText("");
00214     scene_marker_.reset();
00215     ui_->scene_scale->setEnabled(false);
00216   }
00217   else
00218     if (planning_display_->getPlanningSceneMonitor())
00219     {
00220       // if this is a CollisionWorld element
00221       if (sel[0]->checkState() == Qt::Unchecked)
00222       {
00223         ui_->scene_scale->setEnabled(true);
00224         bool update_scene_marker = false;
00225         Eigen::Affine3d obj_pose;
00226         {
00227           const planning_scene_monitor::LockedPlanningSceneRO &ps = planning_display_->getPlanningSceneRO();
00228           const collision_detection::CollisionWorld::ObjectConstPtr &obj = ps->getWorld()->getObject(sel[0]->text().toStdString());
00229           if (obj)
00230           {
00231             ui_->object_status->setText(decideStatusText(obj));
00232 
00233             if (obj->shapes_.size() == 1)
00234             {
00235               obj_pose = obj->shape_poses_[0];
00236               Eigen::Vector3d xyz = obj_pose.rotation().eulerAngles(0, 1, 2);
00237               update_scene_marker = true; // do the marker update outside locked scope to avoid deadlock
00238 
00239               bool oldState = ui_->object_x->blockSignals(true);
00240               ui_->object_x->setValue(obj_pose.translation()[0]);
00241               ui_->object_x->blockSignals(oldState);
00242 
00243               oldState = ui_->object_y->blockSignals(true);
00244               ui_->object_y->setValue(obj_pose.translation()[1]);
00245               ui_->object_y->blockSignals(oldState);
00246 
00247               oldState = ui_->object_z->blockSignals(true);
00248               ui_->object_z->setValue(obj_pose.translation()[2]);
00249               ui_->object_z->blockSignals(oldState);
00250 
00251               oldState = ui_->object_rx->blockSignals(true);
00252               ui_->object_rx->setValue(xyz[0]);
00253               ui_->object_rx->blockSignals(oldState);
00254 
00255               oldState = ui_->object_ry->blockSignals(true);
00256               ui_->object_ry->setValue(xyz[1]);
00257               ui_->object_ry->blockSignals(oldState);
00258 
00259               oldState = ui_->object_rz->blockSignals(true);
00260               ui_->object_rz->setValue(xyz[2]);
00261               ui_->object_rz->blockSignals(oldState);
00262             }
00263           }
00264           else
00265             ui_->object_status->setText("ERROR: '" + sel[0]->text() + "' should be a collision object but it is not");
00266         }
00267         if (update_scene_marker)
00268         {
00269           if (!scene_marker_)
00270             createSceneInteractiveMarker();
00271           if (scene_marker_)
00272           {
00273             Eigen::Quaterniond eq(obj_pose.rotation());
00274             // Update the IM pose to match the current selected object
00275             scene_marker_->setPose(Ogre::Vector3(obj_pose.translation()[0], obj_pose.translation()[1], obj_pose.translation()[2]),
00276                                    Ogre::Quaternion(eq.w(), eq.x(), eq.y(), eq.z()), "");
00277           }
00278         }
00279       }
00280       else
00281       {
00282         ui_->scene_scale->setEnabled(false);
00283         // if it is an attached object
00284         scene_marker_.reset();
00285         const planning_scene_monitor::LockedPlanningSceneRO &ps = planning_display_->getPlanningSceneRO();
00286         const robot_state::AttachedBody *attached_body = ps->getCurrentState().getAttachedBody(sel[0]->text().toStdString());
00287         if (attached_body)
00288           ui_->object_status->setText(decideStatusText(attached_body));
00289         else
00290           ui_->object_status->setText("ERROR: '" + sel[0]->text() + "' should be an attached object but it is not");
00291       }
00292     }
00293 }
00294 
00295 void MotionPlanningFrame::objectPoseValueChanged(double /* value */)
00296 {
00297   updateCollisionObjectPose(true);
00298 }
00299 
00300 void MotionPlanningFrame::updateCollisionObjectPose(bool update_marker_position)
00301 {
00302   QList<QListWidgetItem *> sel = ui_->collision_objects_list->selectedItems();
00303   if (sel.empty())
00304     return;
00305   planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00306   if (ps)
00307   {
00308     collision_detection::CollisionWorld::ObjectConstPtr obj = ps->getWorld()->getObject(sel[0]->text().toStdString());
00309     if (obj && obj->shapes_.size() == 1)
00310     {
00311       Eigen::Affine3d p;
00312       p.translation()[0] = ui_->object_x->value();
00313       p.translation()[1] = ui_->object_y->value();
00314       p.translation()[2] = ui_->object_z->value();
00315 
00316       p = Eigen::Translation3d(p.translation()) *
00317         (Eigen::AngleAxisd(ui_->object_rx->value(), Eigen::Vector3d::UnitX()) *
00318          Eigen::AngleAxisd(ui_->object_ry->value(), Eigen::Vector3d::UnitY()) *
00319          Eigen::AngleAxisd(ui_->object_rz->value(), Eigen::Vector3d::UnitZ()));
00320 
00321       ps->getWorldNonConst()->moveShapeInObject(obj->id_, obj->shapes_[0], p);
00322       planning_display_->queueRenderSceneGeometry();
00323 
00324       // Update the interactive marker pose to match the manually introduced one
00325       if (update_marker_position && scene_marker_)
00326       {
00327         Eigen::Quaterniond eq(p.rotation());
00328         scene_marker_->setPose(Ogre::Vector3(ui_->object_x->value(), ui_->object_y->value(), ui_->object_z->value()),
00329                                Ogre::Quaternion(eq.w(), eq.x(), eq.y(), eq.z()), "");
00330       }
00331     }
00332   }
00333 }
00334 
00335 void MotionPlanningFrame::collisionObjectChanged(QListWidgetItem *item)
00336 {
00337   if (item->type() < (int)known_collision_objects_.size() &&
00338       planning_display_->getPlanningSceneMonitor())
00339   {
00340     // if we have a name change
00341     if (known_collision_objects_[item->type()].first != item->text().toStdString())
00342       renameCollisionObject(item);
00343     else
00344     {
00345       bool checked = item->checkState() == Qt::Checked;
00346       if (known_collision_objects_[item->type()].second != checked)
00347         attachDetachCollisionObject(item);
00348     }
00349   }
00350 }
00351 
00352 /* Receives feedback from the interactive marker and updates the shape pose in the world accordingly */
00353 void  MotionPlanningFrame::imProcessFeedback(visualization_msgs::InteractiveMarkerFeedback &feedback)
00354 {
00355   bool oldState = ui_->object_x->blockSignals(true);
00356   ui_->object_x->setValue(feedback.pose.position.x);
00357   ui_->object_x->blockSignals(oldState);
00358 
00359   oldState = ui_->object_y->blockSignals(true);
00360   ui_->object_y->setValue(feedback.pose.position.y);
00361   ui_->object_y->blockSignals(oldState);
00362 
00363   oldState = ui_->object_z->blockSignals(true);
00364   ui_->object_z->setValue(feedback.pose.position.z);
00365   ui_->object_z->blockSignals(oldState);
00366 
00367   Eigen::Quaterniond q;
00368   tf::quaternionMsgToEigen(feedback.pose.orientation, q);
00369   Eigen::Vector3d xyz = q.matrix().eulerAngles(0, 1, 2);
00370 
00371   oldState = ui_->object_rx->blockSignals(true);
00372   ui_->object_rx->setValue(xyz[0]);
00373   ui_->object_rx->blockSignals(oldState);
00374 
00375   oldState = ui_->object_ry->blockSignals(true);
00376   ui_->object_ry->setValue(xyz[1]);
00377   ui_->object_ry->blockSignals(oldState);
00378 
00379   oldState = ui_->object_rz->blockSignals(true);
00380   ui_->object_rz->setValue(xyz[2]);
00381   ui_->object_rz->blockSignals(oldState);
00382 
00383   updateCollisionObjectPose(false);
00384 }
00385 
00386 void MotionPlanningFrame::copySelectedCollisionObject()
00387 {
00388   QList<QListWidgetItem *> sel = ui_->collision_objects_list->selectedItems();
00389   if (sel.empty())
00390     return;
00391 
00392   planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00393   if (!ps)
00394     return;
00395 
00396   for (int i = 0 ; i < sel.size() ; ++i)
00397   {
00398     std::string name = sel[i]->text().toStdString();
00399     collision_detection::CollisionWorld::ObjectConstPtr obj = ps->getWorld()->getObject(name);
00400     if (!obj)
00401       continue;
00402 
00403     // find a name for the copy
00404     name = "Copy of " + name;
00405     if (ps->getWorld()->hasObject(name))
00406     {
00407       name += " ";
00408       unsigned int n = 1;
00409       while (ps->getWorld()->hasObject(name + boost::lexical_cast<std::string>(n)))
00410         n++;
00411       name += boost::lexical_cast<std::string>(n);
00412     }
00413     ps->getWorldNonConst()->addToObject(name, obj->shapes_, obj->shape_poses_);
00414     ROS_DEBUG("Copied collision object to '%s'", name.c_str());
00415   }
00416   planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populateCollisionObjectsList, this));
00417 }
00418 
00419 void MotionPlanningFrame::computeSaveSceneButtonClicked()
00420 {
00421   if (planning_scene_storage_)
00422   {
00423     moveit_msgs::PlanningScene msg;
00424     planning_display_->getPlanningSceneRO()->getPlanningSceneMsg(msg);
00425     try
00426     {
00427       planning_scene_storage_->removePlanningScene(msg.name);
00428       planning_scene_storage_->addPlanningScene(msg);
00429     }
00430     catch (std::runtime_error &ex)
00431     {
00432       ROS_ERROR("%s", ex.what());
00433     }
00434 
00435     planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populatePlanningSceneTreeView, this));
00436   }
00437 }
00438 
00439 void MotionPlanningFrame::computeSaveQueryButtonClicked(const std::string &scene, const std::string &query_name)
00440 {
00441   moveit_msgs::MotionPlanRequest mreq;
00442   constructPlanningRequest(mreq);
00443   if (planning_scene_storage_)
00444   {
00445     try
00446     {
00447       if (!query_name.empty())
00448         planning_scene_storage_->removePlanningQuery(scene, query_name);
00449       planning_scene_storage_->addPlanningQuery(mreq, scene, query_name);
00450     }
00451     catch (std::runtime_error &ex)
00452     {
00453       ROS_ERROR("%s", ex.what());
00454     }
00455 
00456     planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populatePlanningSceneTreeView, this));
00457   }
00458 }
00459 
00460 void MotionPlanningFrame::computeDeleteSceneButtonClicked()
00461 {
00462   if (planning_scene_storage_)
00463   {
00464     QList<QTreeWidgetItem *> sel = ui_->planning_scene_tree->selectedItems();
00465     if (!sel.empty())
00466     {
00467       QTreeWidgetItem *s = sel.front();
00468       if (s->type() == ITEM_TYPE_SCENE)
00469       {
00470         std::string scene = s->text(0).toStdString();
00471         try
00472         {
00473           planning_scene_storage_->removePlanningScene(scene);
00474         }
00475         catch (std::runtime_error &ex)
00476         {
00477           ROS_ERROR("%s", ex.what());
00478         }
00479       }
00480       else
00481       {
00482         // if we selected a query name, then we overwrite that query
00483         std::string scene = s->parent()->text(0).toStdString();
00484         try
00485         {
00486           planning_scene_storage_->removePlanningScene(scene);
00487         }
00488         catch (std::runtime_error &ex)
00489         {
00490           ROS_ERROR("%s", ex.what());
00491         }
00492       }
00493       planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populatePlanningSceneTreeView, this));
00494     }
00495   }
00496 }
00497 
00498 void MotionPlanningFrame::computeDeleteQueryButtonClicked()
00499 {
00500   if (planning_scene_storage_)
00501   {
00502     QList<QTreeWidgetItem *> sel = ui_->planning_scene_tree->selectedItems();
00503     if (!sel.empty())
00504     {
00505       QTreeWidgetItem *s = sel.front();
00506       if (s->type() == ITEM_TYPE_QUERY)
00507       {
00508         std::string scene = s->parent()->text(0).toStdString();
00509         std::string query_name = s->text(0).toStdString();
00510         try
00511         {
00512           planning_scene_storage_->removePlanningQuery(scene, query_name);
00513         }
00514         catch (std::runtime_error &ex)
00515         {
00516           ROS_ERROR("%s", ex.what());
00517         }
00518         planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::computeDeleteQueryButtonClickedHelper, this, s));
00519       }
00520     }
00521   }
00522 }
00523 
00524 void MotionPlanningFrame::computeDeleteQueryButtonClickedHelper(QTreeWidgetItem *s)
00525 {
00526   ui_->planning_scene_tree->setUpdatesEnabled(false);
00527   s->parent()->removeChild(s);
00528   ui_->planning_scene_tree->setUpdatesEnabled(true);
00529 }
00530 
00531 void MotionPlanningFrame::checkPlanningSceneTreeEnabledButtons()
00532 {
00533   QList<QTreeWidgetItem *> sel = ui_->planning_scene_tree->selectedItems();
00534   if (sel.empty())
00535   {
00536     ui_->load_scene_button->setEnabled(false);
00537     ui_->load_query_button->setEnabled(false);
00538     ui_->save_query_button->setEnabled(false);
00539     ui_->delete_scene_button->setEnabled(false);
00540   }
00541   else
00542   {
00543     ui_->save_query_button->setEnabled(true);
00544 
00545     QTreeWidgetItem *s = sel.front();
00546 
00547     // if the item is a PlanningScene
00548     if (s->type() == ITEM_TYPE_SCENE)
00549     {
00550       ui_->load_scene_button->setEnabled(true);
00551       ui_->load_query_button->setEnabled(false);
00552       ui_->delete_scene_button->setEnabled(true);
00553       ui_->delete_query_button->setEnabled(false);
00554       ui_->save_query_button->setEnabled(true);
00555     }
00556     else
00557     {
00558       // if the item is a query
00559       ui_->load_scene_button->setEnabled(false);
00560       ui_->load_query_button->setEnabled(true);
00561       ui_->delete_scene_button->setEnabled(false);
00562       ui_->delete_query_button->setEnabled(true);
00563     }
00564   }
00565 }
00566 
00567 void MotionPlanningFrame::computeLoadSceneButtonClicked()
00568 {
00569   if (planning_scene_storage_)
00570   {
00571     QList<QTreeWidgetItem *> sel = ui_->planning_scene_tree->selectedItems();
00572     if (!sel.empty())
00573     {
00574       QTreeWidgetItem *s = sel.front();
00575       if (s->type() == ITEM_TYPE_SCENE)
00576       {
00577         std::string scene = s->text(0).toStdString();
00578         ROS_DEBUG("Attempting to load scene '%s'", scene.c_str());
00579         moveit_warehouse::PlanningSceneWithMetadata scene_m;
00580         bool got_ps = false;
00581         try
00582         {
00583           got_ps = planning_scene_storage_->getPlanningScene(scene_m, scene);
00584         }
00585         catch (std::runtime_error &ex)
00586         {
00587           ROS_ERROR("%s", ex.what());
00588         }
00589 
00590         if (got_ps)
00591         {
00592           ROS_INFO("Loaded scene '%s'", scene.c_str());
00593           if (planning_display_->getPlanningSceneMonitor())
00594           {
00595             if (scene_m->robot_model_name != planning_display_->getRobotModel()->getName())
00596             {
00597               ROS_INFO("Scene '%s' was saved for robot '%s' but we are using robot '%s'. Using scene geometry only",
00598                        scene.c_str(), scene_m->robot_model_name.c_str(),
00599                        planning_display_->getRobotModel()->getName().c_str());
00600               planning_scene_world_publisher_.publish(scene_m->world);
00601               // publish the parts that are not in the world
00602               moveit_msgs::PlanningScene diff;
00603               diff.is_diff = true;
00604               diff.name = scene_m->name;
00605               planning_scene_publisher_.publish(diff);
00606             }
00607             else
00608               planning_scene_publisher_.publish(static_cast<const moveit_msgs::PlanningScene&>(*scene_m));
00609           }
00610           else
00611             planning_scene_publisher_.publish(static_cast<const moveit_msgs::PlanningScene&>(*scene_m));
00612         }
00613         else
00614           ROS_WARN("Failed to load scene '%s'. Has the message format changed since the scene was saved?", scene.c_str());
00615       }
00616     }
00617   }
00618 }
00619 
00620 void MotionPlanningFrame::computeLoadQueryButtonClicked()
00621 {
00622   if (planning_scene_storage_)
00623   {
00624     QList<QTreeWidgetItem *> sel = ui_->planning_scene_tree->selectedItems();
00625     if (!sel.empty())
00626     {
00627       QTreeWidgetItem *s = sel.front();
00628       if (s->type() == ITEM_TYPE_QUERY)
00629       {
00630         std::string scene = s->parent()->text(0).toStdString();
00631         std::string query_name = s->text(0).toStdString();
00632         moveit_warehouse::MotionPlanRequestWithMetadata mp;
00633         bool got_q = false;
00634         try
00635         {
00636           got_q = planning_scene_storage_->getPlanningQuery(mp, scene, query_name);
00637         }
00638         catch (std::runtime_error &ex)
00639         {
00640           ROS_ERROR("%s", ex.what());
00641         }
00642 
00643         if (got_q)
00644         {
00645           robot_state::RobotStatePtr start_state(new robot_state::RobotState(*planning_display_->getQueryStartState()));
00646           robot_state::robotStateMsgToRobotState(planning_display_->getPlanningSceneRO()->getTransforms(), mp->start_state, *start_state);
00647           planning_display_->setQueryStartState(*start_state);
00648 
00649           robot_state::RobotStatePtr goal_state(new robot_state::RobotState(*planning_display_->getQueryGoalState()));
00650           for (std::size_t i = 0 ; i < mp->goal_constraints.size() ; ++i)
00651             if (mp->goal_constraints[i].joint_constraints.size() > 0)
00652             {
00653               std::map<std::string, double> vals;
00654               for (std::size_t j = 0 ; j < mp->goal_constraints[i].joint_constraints.size() ; ++j)
00655                 vals[mp->goal_constraints[i].joint_constraints[j].joint_name] = mp->goal_constraints[i].joint_constraints[j].position;
00656               goal_state->setStateValues(vals);
00657               break;
00658             }
00659           planning_display_->setQueryGoalState(*goal_state);
00660         }
00661         else
00662           ROS_ERROR("Failed to load planning query '%s'. Has the message format changed since the query was saved?", query_name.c_str());
00663       }
00664     }
00665   }
00666 }
00667 
00668 void MotionPlanningFrame::addObject(const collision_detection::WorldPtr &world, const std::string &id,
00669                                     const shapes::ShapeConstPtr &shape, const Eigen::Affine3d &pose)
00670 {
00671   world->addToObject(id, shape, pose);
00672 
00673   planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populateCollisionObjectsList, this));
00674 
00675   // Automatically select the inserted object so that its IM is displayed
00676   planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::setItemSelectionInList, this, id, true, ui_->collision_objects_list));
00677 
00678   planning_display_->queueRenderSceneGeometry();
00679 }
00680 
00681 void MotionPlanningFrame::createSceneInteractiveMarker()
00682 {
00683   QList<QListWidgetItem *> sel = ui_->collision_objects_list->selectedItems();
00684   if (sel.empty() || planning_display_->getRobotInteraction()->getActiveEndEffectors().empty())
00685     return;
00686 
00687   const planning_scene_monitor::LockedPlanningSceneRO &ps = planning_display_->getPlanningSceneRO();
00688   if (!ps)
00689     return;
00690 
00691   const collision_detection::CollisionWorld::ObjectConstPtr &obj = ps->getWorld()->getObject(sel[0]->text().toStdString());
00692   if (!scene_marker_ && obj && obj->shapes_.size() == 1)
00693   {
00694     Eigen::Quaterniond eq(obj->shape_poses_[0].rotation());
00695     geometry_msgs::PoseStamped shape_pose;
00696     shape_pose.pose.position.x = obj->shape_poses_[0].translation()[0];
00697     shape_pose.pose.position.y = obj->shape_poses_[0].translation()[1];
00698     shape_pose.pose.position.z = obj->shape_poses_[0].translation()[2];
00699     shape_pose.pose.orientation.x = eq.x();
00700     shape_pose.pose.orientation.y = eq.y();
00701     shape_pose.pose.orientation.z = eq.z();
00702     shape_pose.pose.orientation.w = eq.w();
00703 
00704     // create an interactive marker for moving the shape in the world
00705     visualization_msgs::InteractiveMarker int_marker = robot_interaction::make6DOFMarker(std::string("marker_") + sel[0]->text().toStdString(), shape_pose, 1.0);
00706     int_marker.header.frame_id = context_->getFrameManager()->getFixedFrame();
00707     int_marker.description = sel[0]->text().toStdString();
00708 
00709     rviz::InteractiveMarker* imarker = new rviz::InteractiveMarker(planning_display_->getSceneNode(), context_ );
00710     interactive_markers::autoComplete(int_marker);
00711     imarker->processMessage(int_marker);
00712     imarker->setShowAxes(false);
00713     scene_marker_.reset(imarker);
00714 
00715     // Connect signals
00716     connect( imarker, SIGNAL( userFeedback(visualization_msgs::InteractiveMarkerFeedback &)), this,
00717              SLOT( imProcessFeedback(visualization_msgs::InteractiveMarkerFeedback &) ));
00718   }
00719 }
00720 
00721 void MotionPlanningFrame::renameCollisionObject(QListWidgetItem *item)
00722 {
00723   long unsigned int version = known_collision_objects_version_;
00724   if (item->text().isEmpty())
00725   {
00726     QMessageBox::warning(this, "Invalid object name", "Cannot set an empty object name.");
00727     if (version == known_collision_objects_version_)
00728       item->setText(QString::fromStdString(known_collision_objects_[item->type()].first));
00729     return;
00730   }
00731 
00732   std::string item_text = item->text().toStdString();
00733   bool already_exists = planning_display_->getPlanningSceneRO()->getWorld()->hasObject(item_text);
00734   if (!already_exists)
00735     already_exists = planning_display_->getPlanningSceneRO()->getCurrentState().hasAttachedBody(item_text);
00736   if (already_exists)
00737   {
00738     QMessageBox::warning(this, "Duplicate object name", QString("The name '").append(item->text()).
00739                          append("' already exists. Not renaming object ").append((known_collision_objects_[item->type()].first.c_str())));
00740     if (version == known_collision_objects_version_)
00741       item->setText(QString::fromStdString(known_collision_objects_[item->type()].first));
00742     return;
00743   }
00744 
00745   if (item->checkState() == Qt::Unchecked)
00746   {
00747     planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00748     collision_detection::CollisionWorld::ObjectConstPtr obj = ps->getWorld()->getObject(known_collision_objects_[item->type()].first);
00749     if (obj)
00750     {
00751       known_collision_objects_[item->type()].first = item_text;
00752       ps->getWorldNonConst()->removeObject(obj->id_);
00753       ps->getWorldNonConst()->addToObject(known_collision_objects_[item->type()].first, obj->shapes_, obj->shape_poses_);
00754       if (scene_marker_)
00755       {
00756         scene_marker_.reset();
00757         planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::createSceneInteractiveMarker, this));
00758       }
00759     }
00760   }
00761   else
00762   {
00763     // rename attached body
00764     planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00765     robot_state::RobotState &cs = ps->getCurrentStateNonConst();
00766     const robot_state::AttachedBody *ab = cs.getAttachedBody(known_collision_objects_[item->type()].first);
00767     if (ab)
00768     {
00769       known_collision_objects_[item->type()].first = item_text;
00770       robot_state::AttachedBody *new_ab = new robot_state::AttachedBody(ab->getAttachedLink(),
00771                                                                         known_collision_objects_[item->type()].first,
00772                                                                         ab->getShapes(), ab->getFixedTransforms(),
00773                                                                         ab->getTouchLinks(),
00774                                                                         ab->getDetachPosture());
00775       cs.clearAttachedBody(ab->getName());
00776       cs.attachBody(new_ab);
00777     }
00778   }
00779 }
00780 
00781 void MotionPlanningFrame::attachDetachCollisionObject(QListWidgetItem *item)
00782 {
00783   long unsigned int version = known_collision_objects_version_;
00784   bool checked = item->checkState() == Qt::Checked;
00785   std::pair<std::string, bool> data = known_collision_objects_[item->type()];
00786   moveit_msgs::AttachedCollisionObject aco;
00787 
00788   if (checked) // we need to attach a known collision object
00789   {
00790     QStringList links;
00791     const std::vector<std::string> &links_std = planning_display_->getRobotModel()->getLinkModelNames();
00792     for (std::size_t i = 0 ; i < links_std.size() ; ++i)
00793       links.append(QString::fromStdString(links_std[i]));
00794     bool ok = false;
00795     QString response = QInputDialog::getItem(this, tr("Select Link Name"), tr("Choose the link to attach to:"),
00796                                              links, 0, false, &ok);
00797     if (!ok)
00798     {
00799       if (version == known_collision_objects_version_)
00800         item->setCheckState(Qt::Unchecked);
00801       return;
00802     }
00803     aco.link_name = response.toStdString();
00804     aco.object.id = data.first;
00805     aco.object.operation = moveit_msgs::CollisionObject::ADD;
00806   }
00807   else // we need to detach an attached object
00808   {
00809     const planning_scene_monitor::LockedPlanningSceneRO &ps = planning_display_->getPlanningSceneRO();
00810     const robot_state::AttachedBody *attached_body = ps->getCurrentState().getAttachedBody(data.first);
00811     if (attached_body)
00812     {
00813       aco.link_name = attached_body->getAttachedLinkName();
00814       aco.object.id = attached_body->getName();
00815       aco.object.operation = moveit_msgs::CollisionObject::REMOVE;
00816     }
00817   }
00818   {
00819     planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00820     // we loop through the list in case updates were received since the start of the function
00821     for (std::size_t i = 0 ; i < known_collision_objects_.size() ; ++i)
00822       if (known_collision_objects_[i].first == data.first)
00823       {
00824         known_collision_objects_[i].second = checked;
00825         break;
00826       }
00827     ps->processAttachedCollisionObjectMsg(aco);
00828   }
00829 
00830   selectedCollisionObjectChanged();
00831   planning_display_->queueRenderSceneGeometry();
00832 }
00833 
00834 void MotionPlanningFrame::populateCollisionObjectsList()
00835 {
00836   ui_->collision_objects_list->setUpdatesEnabled(false);
00837   bool oldState = ui_->collision_objects_list->blockSignals(true);
00838 
00839   {
00840     QList<QListWidgetItem *> sel = ui_->collision_objects_list->selectedItems();
00841     std::set<std::string> to_select;
00842     for (int i = 0 ; i < sel.size() ; ++i)
00843       to_select.insert(sel[i]->text().toStdString());
00844     ui_->collision_objects_list->clear();
00845     known_collision_objects_.clear();
00846     known_collision_objects_version_++;
00847 
00848     planning_scene_monitor::LockedPlanningSceneRO ps = planning_display_->getPlanningSceneRO();
00849     if (ps)
00850     {
00851       const std::vector<std::string> &collision_object_names = ps->getWorld()->getObjectIds();
00852       for (std::size_t i = 0 ; i < collision_object_names.size() ; ++i)
00853       {
00854         if (collision_object_names[i] == planning_scene::PlanningScene::OCTOMAP_NS ||
00855             collision_object_names[i] == planning_scene::PlanningScene::COLLISION_MAP_NS)
00856           continue;
00857 
00858         QListWidgetItem *item = new QListWidgetItem(QString::fromStdString(collision_object_names[i]),
00859                                                     ui_->collision_objects_list, (int)i);
00860         item->setFlags(item->flags() | Qt::ItemIsEditable);
00861         item->setToolTip(item->text());
00862         item->setCheckState(Qt::Unchecked);
00863         if (to_select.find(collision_object_names[i]) != to_select.end())
00864           item->setSelected(true);
00865         ui_->collision_objects_list->addItem(item);
00866         known_collision_objects_.push_back(std::make_pair(collision_object_names[i], false));
00867       }
00868 
00869       const robot_state::RobotState &cs = ps->getCurrentState();
00870       std::vector<const robot_state::AttachedBody*> attached_bodies;
00871       cs.getAttachedBodies(attached_bodies);
00872       for (std::size_t i = 0 ; i < attached_bodies.size() ; ++i)
00873       {
00874         QListWidgetItem *item = new QListWidgetItem(QString::fromStdString(attached_bodies[i]->getName()),
00875                                                     ui_->collision_objects_list, (int)(i + collision_object_names.size()));
00876         item->setFlags(item->flags() | Qt::ItemIsEditable);
00877         item->setToolTip(item->text());
00878         item->setCheckState(Qt::Checked);
00879         if (to_select.find(attached_bodies[i]->getName()) != to_select.end())
00880           item->setSelected(true);
00881         ui_->collision_objects_list->addItem(item);
00882         known_collision_objects_.push_back(std::make_pair(attached_bodies[i]->getName(), true));
00883       }
00884     }
00885   }
00886 
00887   ui_->collision_objects_list->blockSignals(oldState);
00888   ui_->collision_objects_list->setUpdatesEnabled(true);
00889   selectedCollisionObjectChanged();
00890 }
00891 
00892 void MotionPlanningFrame::exportAsTextButtonClicked()
00893 {
00894   QString path = QFileDialog::getSaveFileName(this, tr("Export Scene Geometry"), tr(""), tr("Scene Geometry (*.scene)"));
00895   if (!path.isEmpty())
00896     planning_display_->addBackgroundJob(boost::bind(&MotionPlanningFrame::computeExportAsText, this, path.toStdString()), "export as text");
00897 }
00898 
00899 void MotionPlanningFrame::computeExportAsText(const std::string &path)
00900 {
00901   planning_scene_monitor::LockedPlanningSceneRO ps = planning_display_->getPlanningSceneRO();
00902   if (ps)
00903   {
00904     std::string p = (path.length() < 7 || path.substr(path.length() - 6) != ".scene") ? path + ".scene" : path;
00905     std::ofstream fout(p.c_str());
00906     if (fout.good())
00907     {
00908       ps->saveGeometryToStream(fout);
00909       fout.close();
00910       ROS_INFO("Saved current scene geometry to '%s'", p.c_str());
00911     }
00912     else
00913       ROS_WARN("Unable to save current scene geometry to '%s'", p.c_str());
00914   }
00915 }
00916 
00917 void MotionPlanningFrame::computeImportFromText(const std::string &path)
00918 {
00919   planning_scene_monitor::LockedPlanningSceneRW ps = planning_display_->getPlanningSceneRW();
00920   if (ps)
00921   {
00922     std::ifstream fin(path.c_str());
00923     if (fin.good())
00924     {
00925       ps->loadGeometryFromStream(fin);
00926       fin.close();
00927       ROS_INFO("Loaded scene geometry from '%s'", path.c_str());
00928       planning_display_->addMainLoopJob(boost::bind(&MotionPlanningFrame::populateCollisionObjectsList, this));
00929       planning_display_->queueRenderSceneGeometry();
00930     }
00931     else
00932       ROS_WARN("Unable to load scene geometry from '%s'", path.c_str());
00933   }
00934 }
00935 
00936 void MotionPlanningFrame::importFromTextButtonClicked()
00937 {
00938   QString path = QFileDialog::getOpenFileName(this, tr("Import Scene Geometry"), tr(""), tr("Scene Geometry (*.scene)"));
00939   if (!path.isEmpty())
00940     planning_display_->addBackgroundJob(boost::bind(&MotionPlanningFrame::computeImportFromText, this, path.toStdString()), "import from text");
00941 }
00942 
00943 
00944 }


visualization
Author(s): Ioan Sucan , Dave Coleman
autogenerated on Mon Oct 6 2014 02:34:03