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/planning_scene_rviz_plugin/planning_scene_display.h>
00033 #include <moveit/rviz_plugin_render_tools/robot_state_visualization.h>
00034 #include <moveit/rviz_plugin_render_tools/octomap_render.h>
00035
00036 #include <rviz/visualization_manager.h>
00037 #include <rviz/robot/robot.h>
00038 #include <rviz/robot/robot_link.h>
00039
00040 #include <rviz/properties/property.h>
00041 #include <rviz/properties/string_property.h>
00042 #include <rviz/properties/bool_property.h>
00043 #include <rviz/properties/float_property.h>
00044 #include <rviz/properties/ros_topic_property.h>
00045 #include <rviz/properties/color_property.h>
00046 #include <rviz/properties/enum_property.h>
00047 #include <rviz/display_context.h>
00048 #include <rviz/frame_manager.h>
00049 #include <tf/transform_listener.h>
00050
00051 #include <OGRE/OgreSceneManager.h>
00052
00053 namespace moveit_rviz_plugin
00054 {
00055
00056
00057
00058
00059 PlanningSceneDisplay::PlanningSceneDisplay(bool listen_to_planning_scene, bool show_scene_robot) :
00060 Display(),
00061 model_is_loading_(false),
00062 current_scene_time_(0.0f),
00063 planning_scene_needs_render_(true)
00064 {
00065 robot_description_property_ =
00066 new rviz::StringProperty( "Robot Description", "robot_description", "The name of the ROS parameter where the URDF for the robot is loaded",
00067 this,
00068 SLOT( changedRobotDescription() ), this );
00069
00070 if (listen_to_planning_scene)
00071 planning_scene_topic_property_ =
00072 new rviz::RosTopicProperty( "Planning Scene Topic", "planning_scene",
00073 ros::message_traits::datatype<moveit_msgs::PlanningScene>(),
00074 "The topic on which the moveit_msgs::PlanningScene messages are received",
00075 this,
00076 SLOT( changedPlanningSceneTopic() ), this );
00077 else
00078 planning_scene_topic_property_ = NULL;
00079
00080
00081 scene_category_ = new rviz::Property( "Scene Geometry", QVariant(), "", this );
00082
00083 scene_name_property_ =
00084 new rviz::StringProperty( "Scene Name", "(noname)", "Shows the name of the planning scene",
00085 scene_category_,
00086 SLOT( changedSceneName() ), this );
00087 scene_name_property_->setShouldBeSaved(false);
00088 scene_enabled_property_ =
00089 new rviz::BoolProperty( "Show Scene Geometry", true, "Indicates whether planning scenes should be displayed",
00090 scene_category_,
00091 SLOT( changedSceneEnabled() ), this );
00092
00093 scene_alpha_property_ =
00094 new rviz::FloatProperty( "Scene Alpha", 0.9f, "Specifies the alpha for the scene geometry",
00095 scene_category_,
00096 SLOT( changedSceneAlpha() ), this );
00097 scene_alpha_property_->setMin( 0.0 );
00098 scene_alpha_property_->setMax( 1.0 );
00099
00100 scene_color_property_ = new rviz::ColorProperty( "Scene Color", QColor(50, 230, 50), "The color for the planning scene obstacles (if a color is not defined)",
00101 scene_category_,
00102 SLOT( changedSceneColor() ), this );
00103
00104 octree_render_property_ = new rviz::EnumProperty( "Voxel Rendering", "Occupied Voxels",
00105 "Select voxel type.",
00106 scene_category_, SLOT( changedOctreeRenderMode() ), this );
00107
00108 octree_render_property_->addOption( "Occupied Voxels", OCTOMAP_OCCUPIED_VOXELS );
00109 octree_render_property_->addOption( "Free Voxels", OCTOMAP_FREE_VOXELS );
00110 octree_render_property_->addOption( "All Voxels", OCTOMAP_FREE_VOXELS | OCTOMAP_OCCUPIED_VOXELS);
00111
00112 octree_coloring_property_ = new rviz::EnumProperty( "Voxel Coloring", "Z-Axis",
00113 "Select voxel coloring mode",
00114 scene_category_, SLOT( changedOctreeColorMode() ), this );
00115
00116 octree_coloring_property_->addOption( "Z-Axis", OCTOMAP_Z_AXIS_COLOR );
00117 octree_coloring_property_->addOption( "Cell Probability", OCTOMAP_PROBABLILTY_COLOR );
00118
00119 scene_display_time_property_ =
00120 new rviz::FloatProperty( "Scene Display Time", 0.2f, "The amount of wall-time to wait in between rendering updates to the planning scene (if any)",
00121 scene_category_,
00122 SLOT( changedSceneDisplayTime() ), this );
00123 scene_display_time_property_->setMin(0.0001);
00124
00125 if (show_scene_robot)
00126 {
00127 robot_category_ = new rviz::Property( "Scene Robot", QVariant(), "", this );
00128
00129 scene_robot_enabled_property_ =
00130 new rviz::BoolProperty( "Show Scene Robot", true, "Indicates whether the robot state specified by the planning scene should be displayed",
00131 robot_category_,
00132 SLOT( changedSceneRobotEnabled() ), this );
00133
00134 robot_alpha_property_ =
00135 new rviz::FloatProperty( "Robot Alpha", 0.5f, "Specifies the alpha for the robot links",
00136 robot_category_,
00137 SLOT( changedRobotSceneAlpha() ), this );
00138 robot_alpha_property_->setMin( 0.0 );
00139 robot_alpha_property_->setMax( 1.0 );
00140
00141 attached_body_color_property_ = new rviz::ColorProperty( "Attached Body Color", QColor(150, 50, 150), "The color for the attached bodies",
00142 robot_category_,
00143 SLOT( changedAttachedBodyColor() ), this );
00144 }
00145 else
00146 {
00147 robot_category_ = NULL;
00148 scene_robot_enabled_property_ = NULL;
00149 robot_alpha_property_ = NULL;
00150 attached_body_color_property_ = NULL;
00151 }
00152 }
00153
00154
00155
00156
00157 PlanningSceneDisplay::~PlanningSceneDisplay()
00158 {
00159 clearJobs();
00160
00161 planning_scene_render_.reset();
00162 context_->getSceneManager()->destroySceneNode(planning_scene_node_->getName());
00163 if (planning_scene_robot_)
00164 planning_scene_robot_.reset();
00165 planning_scene_monitor_.reset();
00166 }
00167
00168 void PlanningSceneDisplay::clearJobs()
00169 {
00170 background_process_.clear();
00171 {
00172 boost::unique_lock<boost::mutex> ulock(main_loop_jobs_lock_);
00173 main_loop_jobs_.clear();
00174 }
00175 }
00176
00177 void PlanningSceneDisplay::onInitialize()
00178 {
00179 Display::onInitialize();
00180
00181
00182 planning_scene_node_ = scene_node_->createChildSceneNode();
00183
00184 if (robot_category_)
00185 {
00186 planning_scene_robot_.reset(new RobotStateVisualization(planning_scene_node_, context_, "Planning Scene", robot_category_));
00187 planning_scene_robot_->setVisible(scene_robot_enabled_property_->getBool());
00188 }
00189 }
00190
00191 void PlanningSceneDisplay::reset()
00192 {
00193 planning_scene_render_.reset();
00194 if (planning_scene_robot_)
00195 planning_scene_robot_->clear();
00196
00197 addBackgroundJob(boost::bind(&PlanningSceneDisplay::loadRobotModel, this), "loadRobotModel");
00198 Display::reset();
00199
00200 if (planning_scene_robot_)
00201 planning_scene_robot_->setVisible(scene_robot_enabled_property_->getBool());
00202 }
00203
00204 void PlanningSceneDisplay::addBackgroundJob(const boost::function<void()> &job, const std::string &name)
00205 {
00206 background_process_.addJob(job, name);
00207 }
00208
00209 void PlanningSceneDisplay::addMainLoopJob(const boost::function<void()> &job)
00210 {
00211 boost::unique_lock<boost::mutex> ulock(main_loop_jobs_lock_);
00212 main_loop_jobs_.push_back(job);
00213 }
00214
00215 void PlanningSceneDisplay::waitForAllMainLoopJobs()
00216 {
00217 boost::unique_lock<boost::mutex> ulock(main_loop_jobs_lock_);
00218 while (!main_loop_jobs_.empty())
00219 main_loop_jobs_empty_condition_.wait(ulock);
00220 }
00221
00222 void PlanningSceneDisplay::executeMainLoopJobs()
00223 {
00224 main_loop_jobs_lock_.lock();
00225 while (!main_loop_jobs_.empty())
00226 {
00227 boost::function<void()> fn = main_loop_jobs_.front();
00228 main_loop_jobs_.pop_front();
00229 main_loop_jobs_lock_.unlock();
00230 try
00231 {
00232 fn();
00233 }
00234 catch(std::runtime_error &ex)
00235 {
00236 ROS_ERROR("Exception caught executing main loop job: %s", ex.what());
00237 }
00238 catch(...)
00239 {
00240 ROS_ERROR("Exception caught executing main loop job");
00241 }
00242 main_loop_jobs_lock_.lock();
00243 }
00244 main_loop_jobs_empty_condition_.notify_all();
00245 main_loop_jobs_lock_.unlock();
00246 }
00247
00248 const planning_scene_monitor::PlanningSceneMonitorPtr& PlanningSceneDisplay::getPlanningSceneMonitor()
00249 {
00250 return planning_scene_monitor_;
00251 }
00252
00253 const robot_model::RobotModelConstPtr& PlanningSceneDisplay::getRobotModel() const
00254 {
00255 if (planning_scene_monitor_)
00256 return planning_scene_monitor_->getRobotModel();
00257 else
00258 {
00259 static robot_model::RobotModelConstPtr empty;
00260 return empty;
00261 }
00262 }
00263
00264 planning_scene_monitor::LockedPlanningSceneRO PlanningSceneDisplay::getPlanningSceneRO() const
00265 {
00266 return planning_scene_monitor::LockedPlanningSceneRO(planning_scene_monitor_);
00267 }
00268
00269 planning_scene_monitor::LockedPlanningSceneRW PlanningSceneDisplay::getPlanningSceneRW()
00270 {
00271 return planning_scene_monitor::LockedPlanningSceneRW(planning_scene_monitor_);
00272 }
00273
00274 void PlanningSceneDisplay::changedAttachedBodyColor()
00275 {
00276 queueRenderSceneGeometry();
00277 }
00278
00279 void PlanningSceneDisplay::changedSceneColor()
00280 {
00281 queueRenderSceneGeometry();
00282 }
00283
00284 void PlanningSceneDisplay::changedRobotDescription()
00285 {
00286 if (isEnabled())
00287 reset();
00288 }
00289
00290 void PlanningSceneDisplay::changedSceneName()
00291 {
00292 planning_scene_monitor::LockedPlanningSceneRW ps = getPlanningSceneRW();
00293 if (ps)
00294 ps->setName(scene_name_property_->getStdString());
00295 }
00296
00297 void PlanningSceneDisplay::renderPlanningScene()
00298 {
00299 if (planning_scene_render_ && planning_scene_needs_render_)
00300 {
00301 QColor color = scene_color_property_->getColor();
00302 rviz::Color env_color(color.redF(), color.greenF(), color.blueF());
00303 if (attached_body_color_property_)
00304 color = attached_body_color_property_->getColor();
00305 rviz::Color attached_color(color.redF(), color.greenF(), color.blueF());
00306
00307 try
00308 {
00309 const planning_scene_monitor::LockedPlanningSceneRO &ps = getPlanningSceneRO();
00310 planning_scene_render_->renderPlanningScene(ps, env_color,
00311 attached_color,
00312 static_cast<OctreeVoxelRenderMode>(octree_render_property_->getOptionInt()),
00313 static_cast<OctreeVoxelColorMode>(octree_coloring_property_->getOptionInt()),
00314 scene_alpha_property_->getFloat());
00315 }
00316 catch(...)
00317 {
00318 ROS_ERROR("Exception thrown while rendering planning scene");
00319 }
00320 planning_scene_needs_render_ = false;
00321 planning_scene_render_->getGeometryNode()->setVisible(scene_enabled_property_->getBool());
00322 }
00323 }
00324
00325 void PlanningSceneDisplay::changedSceneAlpha()
00326 {
00327 queueRenderSceneGeometry();
00328 }
00329
00330 void PlanningSceneDisplay::changedRobotSceneAlpha()
00331 {
00332 if (planning_scene_robot_)
00333 {
00334 planning_scene_robot_->setAlpha(robot_alpha_property_->getFloat());
00335 queueRenderSceneGeometry();
00336 }
00337 }
00338
00339 void PlanningSceneDisplay::changedPlanningSceneTopic()
00340 {
00341 if (planning_scene_monitor_ && planning_scene_topic_property_)
00342 planning_scene_monitor_->startSceneMonitor(planning_scene_topic_property_->getStdString());
00343 }
00344
00345 void PlanningSceneDisplay::changedSceneDisplayTime()
00346 {
00347 }
00348
00349 void PlanningSceneDisplay::changedOctreeRenderMode()
00350 {
00351 }
00352
00353 void PlanningSceneDisplay::changedOctreeColorMode()
00354 {
00355 }
00356
00357 void PlanningSceneDisplay::changedSceneRobotEnabled()
00358 {
00359 if (isEnabled() && planning_scene_robot_)
00360 planning_scene_robot_->setVisible(scene_robot_enabled_property_->getBool());
00361 }
00362
00363 void PlanningSceneDisplay::changedSceneEnabled()
00364 {
00365 if (planning_scene_render_)
00366 planning_scene_render_->getGeometryNode()->setVisible(scene_enabled_property_->getBool());
00367 }
00368
00369 void PlanningSceneDisplay::setGroupColor(rviz::Robot* robot, const std::string& group_name, const QColor &color)
00370 {
00371 if (getRobotModel())
00372 {
00373 const robot_model::JointModelGroup *jmg = getRobotModel()->getJointModelGroup(group_name);
00374 if (jmg)
00375 {
00376 const std::vector<std::string> &links = jmg->getLinkModelNamesWithCollisionGeometry();
00377 for (std::size_t i = 0 ; i < links.size() ; ++i)
00378 setLinkColor(robot, links[i], color);
00379 }
00380 }
00381 }
00382
00383 void PlanningSceneDisplay::unsetAllColors(rviz::Robot* robot)
00384 {
00385 if (getRobotModel())
00386 {
00387 const std::vector<std::string> &links = getRobotModel()->getLinkModelNamesWithCollisionGeometry();
00388 for (std::size_t i = 0 ; i < links.size() ; ++i)
00389 unsetLinkColor(robot, links[i]);
00390 }
00391 }
00392
00393 void PlanningSceneDisplay::unsetGroupColor(rviz::Robot* robot, const std::string& group_name )
00394 {
00395 if (getRobotModel())
00396 {
00397 const robot_model::JointModelGroup *jmg = getRobotModel()->getJointModelGroup(group_name);
00398 if (jmg)
00399 {
00400 const std::vector<std::string> &links = jmg->getLinkModelNamesWithCollisionGeometry();
00401 for (std::size_t i = 0 ; i < links.size() ; ++i)
00402 unsetLinkColor(robot, links[i]);
00403 }
00404 }
00405 }
00406
00407 void PlanningSceneDisplay::setLinkColor(const std::string& link_name, const QColor &color)
00408 {
00409 if (planning_scene_robot_)
00410 setLinkColor(&planning_scene_robot_->getRobot(), link_name, color );
00411 }
00412
00413 void PlanningSceneDisplay::unsetLinkColor(const std::string& link_name)
00414 {
00415 if (planning_scene_robot_)
00416 unsetLinkColor(&planning_scene_robot_->getRobot(), link_name);
00417 }
00418
00419 void PlanningSceneDisplay::setLinkColor(rviz::Robot* robot, const std::string& link_name, const QColor &color )
00420 {
00421 rviz::RobotLink *link = robot->getLink(link_name);
00422
00423
00424 if (link)
00425 link->setColor( color.redF(), color.greenF(), color.blueF() );
00426 }
00427
00428 void PlanningSceneDisplay::unsetLinkColor(rviz::Robot* robot, const std::string& link_name )
00429 {
00430 rviz::RobotLink *link = robot->getLink(link_name);
00431
00432
00433 if (link)
00434 link->unsetColor();
00435 }
00436
00437
00438
00439
00440 planning_scene_monitor::PlanningSceneMonitorPtr PlanningSceneDisplay::createPlanningSceneMonitor()
00441 {
00442 return planning_scene_monitor::PlanningSceneMonitorPtr
00443 (new planning_scene_monitor::PlanningSceneMonitor(robot_description_property_->getStdString(),
00444 context_->getFrameManager()->getTFClientPtr(),
00445 getNameStd() + "_planning_scene_monitor"));
00446 }
00447
00448 void PlanningSceneDisplay::clearRobotModel()
00449 {
00450 planning_scene_render_.reset();
00451 planning_scene_monitor_.reset();
00452 }
00453
00454 void PlanningSceneDisplay::loadRobotModel()
00455 {
00456
00457 boost::mutex::scoped_lock _(robot_model_loading_lock_);
00458 model_is_loading_ = true;
00459
00460
00461
00462
00463 addMainLoopJob(boost::bind(&PlanningSceneDisplay::clearRobotModel, this));
00464
00465 waitForAllMainLoopJobs();
00466
00467 planning_scene_monitor::PlanningSceneMonitorPtr psm = createPlanningSceneMonitor();
00468 if (psm->getPlanningScene())
00469 {
00470 planning_scene_monitor_.swap(psm);
00471 addMainLoopJob(boost::bind(&PlanningSceneDisplay::onRobotModelLoaded, this));
00472 setStatus(rviz::StatusProperty::Ok, "PlanningScene", "Planning Scene Loaded Successfully");
00473 waitForAllMainLoopJobs();
00474 }
00475 else
00476 {
00477 setStatus(rviz::StatusProperty::Error, "PlanningScene", "No Planning Scene Loaded");
00478 }
00479
00480 if (planning_scene_monitor_)
00481 planning_scene_monitor_->addUpdateCallback(boost::bind(&PlanningSceneDisplay::sceneMonitorReceivedUpdate, this, _1));
00482
00483 model_is_loading_ = false;
00484 }
00485
00486 void PlanningSceneDisplay::onRobotModelLoaded()
00487 {
00488 if (planning_scene_topic_property_)
00489 planning_scene_monitor_->startSceneMonitor(planning_scene_topic_property_->getStdString());
00490 planning_scene_render_.reset(new PlanningSceneRender(planning_scene_node_, context_, planning_scene_robot_));
00491 planning_scene_render_->getGeometryNode()->setVisible(scene_enabled_property_->getBool());
00492
00493 const planning_scene_monitor::LockedPlanningSceneRO &ps = getPlanningSceneRO();
00494 if (planning_scene_robot_)
00495 {
00496 planning_scene_robot_->load(*getRobotModel()->getURDF());
00497 planning_scene_robot_->update(robot_state::RobotStatePtr(new robot_state::RobotState(ps->getCurrentState())));
00498 }
00499
00500 bool oldState = scene_name_property_->blockSignals(true);
00501 scene_name_property_->setStdString(ps->getName());
00502 scene_name_property_->blockSignals(oldState);
00503 }
00504
00505 void PlanningSceneDisplay::sceneMonitorReceivedUpdate(planning_scene_monitor::PlanningSceneMonitor::SceneUpdateType update_type)
00506 {
00507 onSceneMonitorReceivedUpdate(update_type);
00508 }
00509
00510 void PlanningSceneDisplay::onSceneMonitorReceivedUpdate(planning_scene_monitor::PlanningSceneMonitor::SceneUpdateType update_type)
00511 {
00512 bool oldState = scene_name_property_->blockSignals(true);
00513 scene_name_property_->setStdString(getPlanningSceneRO()->getName());
00514 scene_name_property_->blockSignals(oldState);
00515
00516 planning_scene_needs_render_ = true;
00517 }
00518
00519 void PlanningSceneDisplay::onEnable()
00520 {
00521 Display::onEnable();
00522
00523 addBackgroundJob(boost::bind(&PlanningSceneDisplay::loadRobotModel, this), "loadRobotModel");
00524
00525 if (planning_scene_robot_)
00526 planning_scene_robot_->setVisible(scene_robot_enabled_property_->getBool());
00527 if (planning_scene_render_)
00528 planning_scene_render_->getGeometryNode()->setVisible(scene_enabled_property_->getBool());
00529
00530 calculateOffsetPosition();
00531 }
00532
00533
00534
00535
00536 void PlanningSceneDisplay::onDisable()
00537 {
00538 if (planning_scene_monitor_)
00539 {
00540 planning_scene_monitor_->stopSceneMonitor();
00541 if (planning_scene_render_)
00542 planning_scene_render_->getGeometryNode()->setVisible(false);
00543 }
00544 if (planning_scene_robot_)
00545 planning_scene_robot_->setVisible(false);
00546 Display::onDisable();
00547 }
00548
00549 void PlanningSceneDisplay::queueRenderSceneGeometry()
00550 {
00551 planning_scene_needs_render_ = true;
00552 }
00553
00554 void PlanningSceneDisplay::update(float wall_dt, float ros_dt)
00555 {
00556 Display::update(wall_dt, ros_dt);
00557
00558 executeMainLoopJobs();
00559
00560 if (planning_scene_monitor_)
00561 updateInternal(wall_dt, ros_dt);
00562 }
00563
00564 void PlanningSceneDisplay::updateInternal(float wall_dt, float ros_dt)
00565 {
00566 current_scene_time_ += wall_dt;
00567 if (current_scene_time_ > scene_display_time_property_->getFloat())
00568 {
00569 renderPlanningScene();
00570 current_scene_time_ = 0.0f;
00571 }
00572 }
00573
00574 void PlanningSceneDisplay::load( const rviz::Config& config )
00575 {
00576 Display::load(config);
00577 }
00578
00579 void PlanningSceneDisplay::save( rviz::Config config ) const
00580 {
00581 Display::save(config);
00582 }
00583
00584
00585
00586
00587 void PlanningSceneDisplay::calculateOffsetPosition()
00588 {
00589 if (!getRobotModel())
00590 return;
00591
00592 tf::Stamped<tf::Pose> pose(tf::Pose::getIdentity(), ros::Time(0), getRobotModel()->getModelFrame());
00593 static const unsigned int max_attempts = 10;
00594 unsigned int attempts = 0;
00595 while (!context_->getTFClient()->canTransform(fixed_frame_.toStdString(), getRobotModel()->getModelFrame(), ros::Time(0)) && attempts < max_attempts)
00596 {
00597 ros::Duration(0.1).sleep();
00598 attempts++;
00599 }
00600
00601 if (attempts < max_attempts)
00602 {
00603 try
00604 {
00605 context_->getTFClient()->transformPose(fixed_frame_.toStdString(), pose, pose);
00606 }
00607 catch (tf::TransformException& e)
00608 {
00609 ROS_ERROR( "Error transforming from frame '%s' to frame '%s'", pose.frame_id_.c_str(), fixed_frame_.toStdString().c_str() );
00610 }
00611 }
00612
00613 Ogre::Vector3 position(pose.getOrigin().x(), pose.getOrigin().y(), pose.getOrigin().z());
00614 const tf::Quaternion &q = pose.getRotation();
00615 Ogre::Quaternion orientation( q.getW(), q.getX(), q.getY(), q.getZ() );
00616 planning_scene_node_->setPosition(position);
00617 planning_scene_node_->setOrientation(orientation);
00618 }
00619
00620 void PlanningSceneDisplay::fixedFrameChanged()
00621 {
00622 Display::fixedFrameChanged();
00623 calculateOffsetPosition();
00624 }
00625
00626
00627 }