occupancy_grid_display.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2013, 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  * Author: Julius Kammerl (jkammerl@willowgarage.com)
00030  *
00031  */
00032 #include <QObject>
00033 
00034 #include "octomap_rviz_plugins/occupancy_grid_display.h"
00035 
00036 #include <boost/bind.hpp>
00037 #include <boost/shared_ptr.hpp>
00038 
00039 #include <OGRE/OgreSceneNode.h>
00040 #include <OGRE/OgreSceneManager.h>
00041 
00042 #include "rviz/visualization_manager.h"
00043 #include "rviz/frame_manager.h"
00044 #include "rviz/properties/int_property.h"
00045 #include "rviz/properties/ros_topic_property.h"
00046 #include "rviz/properties/enum_property.h"
00047 
00048 #include <octomap/octomap.h>
00049 #include <octomap_msgs/Octomap.h>
00050 #include <octomap_msgs/conversions.h>
00051 
00052 #include <sstream>
00053 
00054 using namespace rviz;
00055 
00056 namespace octomap_rviz_plugin
00057 {
00058 
00059 static const std::size_t max_octree_depth_ = sizeof(unsigned short) * 8;
00060 
00061 enum OctreeVoxelRenderMode
00062 {
00063   OCTOMAP_FREE_VOXELS = 1,
00064   OCTOMAP_OCCUPIED_VOXELS = 2
00065 };
00066 
00067 enum OctreeVoxelColorMode
00068 {
00069   OCTOMAP_Z_AXIS_COLOR,
00070   OCTOMAP_PROBABLILTY_COLOR,
00071 };
00072 
00073 OccupancyGridDisplay::OccupancyGridDisplay() :
00074     rviz::Display(),
00075     new_points_received_(false),
00076     messages_received_(0),
00077     queue_size_(5),
00078     color_factor_(0.8),
00079     octree_depth_(0)
00080 {
00081 
00082   octomap_topic_property_ = new RosTopicProperty( "Octomap Topic",
00083                                                   "",
00084                                                   QString::fromStdString(ros::message_traits::datatype<octomap_msgs::Octomap>()),
00085                                                   "octomap_msgs::Octomap topic to subscribe to (binary or full probability map)",
00086                                                   this,
00087                                                   SLOT( updateTopic() ));
00088 
00089   queue_size_property_ = new IntProperty( "Queue Size",
00090                                           queue_size_,
00091                                           "Advanced: set the size of the incoming message queue.  Increasing this "
00092                                           "is useful if your incoming TF data is delayed significantly from your"
00093                                           " image data, but it can greatly increase memory usage if the messages are big.",
00094                                           this,
00095                                           SLOT( updateQueueSize() ));
00096   queue_size_property_->setMin(1);
00097 
00098   octree_render_property_ = new rviz::EnumProperty( "Voxel Rendering", "Occupied Voxels",
00099                                                     "Select voxel type.",
00100                                                      this,
00101                                                      SLOT( updateOctreeRenderMode() ) );
00102 
00103   octree_render_property_->addOption( "Occupied Voxels",  OCTOMAP_OCCUPIED_VOXELS );
00104   octree_render_property_->addOption( "Free Voxels",  OCTOMAP_FREE_VOXELS );
00105   octree_render_property_->addOption( "All Voxels",  OCTOMAP_FREE_VOXELS | OCTOMAP_OCCUPIED_VOXELS);
00106 
00107   octree_coloring_property_ = new rviz::EnumProperty( "Voxel Coloring", "Z-Axis",
00108                                                 "Select voxel coloring mode",
00109                                                 this,
00110                                                 SLOT( updateOctreeColorMode() ) );
00111 
00112   octree_coloring_property_->addOption( "Z-Axis",  OCTOMAP_Z_AXIS_COLOR );
00113   octree_coloring_property_->addOption( "Cell Probability",  OCTOMAP_PROBABLILTY_COLOR );
00114 
00115   tree_depth_property_ = new IntProperty("Max. Octree Depth",
00116                                          max_octree_depth_,
00117                                          "Defines the maximum tree depth",
00118                                          this,
00119                                          SLOT (updateTreeDepth() ));
00120   tree_depth_property_->setMin(0);
00121 }
00122 
00123 void OccupancyGridDisplay::onInitialize()
00124 {
00125   boost::mutex::scoped_lock lock(mutex_);
00126 
00127   box_size_.resize(max_octree_depth_);
00128   cloud_.resize(max_octree_depth_);
00129   point_buf_.resize(max_octree_depth_);
00130   new_points_.resize(max_octree_depth_);
00131 
00132   for (std::size_t i = 0; i < max_octree_depth_; ++i)
00133   {
00134     std::stringstream sname;
00135     sname << "PointCloud Nr." << i;
00136     cloud_[i] = new rviz::PointCloud();
00137     cloud_[i]->setName(sname.str());
00138     cloud_[i]->setRenderMode(rviz::PointCloud::RM_BOXES);
00139     scene_node_->attachObject(cloud_[i]);
00140   }
00141 }
00142 
00143 OccupancyGridDisplay::~OccupancyGridDisplay()
00144 {
00145   std::size_t i;
00146 
00147   unsubscribe();
00148 
00149   for (std::vector<rviz::PointCloud*>::iterator it = cloud_.begin(); it != cloud_.end(); ++it) {
00150     delete *(it);
00151   }
00152 
00153   if (scene_node_)
00154     scene_node_->detachAllObjects();
00155 }
00156 
00157 void OccupancyGridDisplay::updateQueueSize()
00158 {
00159   queue_size_ = queue_size_property_->getInt();
00160 
00161   subscribe();
00162 }
00163 
00164 void OccupancyGridDisplay::onEnable()
00165 {
00166   scene_node_->setVisible(true);
00167   subscribe();
00168 }
00169 
00170 void OccupancyGridDisplay::onDisable()
00171 {
00172   scene_node_->setVisible(false);
00173   unsubscribe();
00174 
00175   clear();
00176 }
00177 
00178 void OccupancyGridDisplay::subscribe()
00179 {
00180   if (!isEnabled())
00181   {
00182     return;
00183   }
00184 
00185   try
00186   {
00187     unsubscribe();
00188 
00189     const std::string& topicStr = octomap_topic_property_->getStdString();
00190 
00191     if (!topicStr.empty())
00192     {
00193 
00194       sub_.reset(new message_filters::Subscriber<octomap_msgs::Octomap>());
00195 
00196       sub_->subscribe(threaded_nh_, topicStr, queue_size_);
00197       sub_->registerCallback(boost::bind(&OccupancyGridDisplay::incomingMessageCallback, this, _1));
00198 
00199     }
00200   }
00201   catch (ros::Exception& e)
00202   {
00203     setStatus(StatusProperty::Error, "Topic", (std::string("Error subscribing: ") + e.what()).c_str());
00204   }
00205 
00206 }
00207 
00208 void OccupancyGridDisplay::unsubscribe()
00209 {
00210   clear();
00211 
00212   try
00213   {
00214     // reset filters
00215     sub_.reset();
00216   }
00217   catch (ros::Exception& e)
00218   {
00219     setStatus(StatusProperty::Error, "Topic", (std::string("Error unsubscribing: ") + e.what()).c_str());
00220   }
00221 
00222 }
00223 
00224 // method taken from octomap_server package
00225 void OccupancyGridDisplay::setColor(double z_pos, double min_z, double max_z, double color_factor,
00226                                     rviz::PointCloud::Point& point)
00227 {
00228   int i;
00229   double m, n, f;
00230 
00231   double s = 1.0;
00232   double v = 1.0;
00233 
00234   double h = (1.0 - std::min(std::max((z_pos - min_z) / (max_z - min_z), 0.0), 1.0)) * color_factor;
00235 
00236   h -= floor(h);
00237   h *= 6;
00238   i = floor(h);
00239   f = h - i;
00240   if (!(i & 1))
00241     f = 1 - f; // if i is even
00242   m = v * (1 - s);
00243   n = v * (1 - s * f);
00244 
00245   switch (i)
00246   {
00247     case 6:
00248     case 0:
00249       point.setColor(v, n, m);
00250       break;
00251     case 1:
00252       point.setColor(n, v, m);
00253       break;
00254     case 2:
00255       point.setColor(m, v, n);
00256       break;
00257     case 3:
00258       point.setColor(m, n, v);
00259       break;
00260     case 4:
00261       point.setColor(n, m, v);
00262       break;
00263     case 5:
00264       point.setColor(v, m, n);
00265       break;
00266     default:
00267       point.setColor(1, 0.5, 0.5);
00268       break;
00269   }
00270 }
00271 
00272 void OccupancyGridDisplay::incomingMessageCallback(const octomap_msgs::OctomapConstPtr& msg)
00273 {
00274   ++messages_received_;
00275   setStatus(StatusProperty::Ok, "Messages", QString::number(messages_received_) + " octomap messages received");
00276 
00277   ROS_DEBUG("Received OctomapBinary message (size: %d bytes)", (int)msg->data.size());
00278 
00279   // get tf transform
00280   Ogre::Vector3 pos;
00281   Ogre::Quaternion orient;
00282   if (!context_->getFrameManager()->getTransform(msg->header, pos, orient))
00283   {
00284     std::stringstream ss;
00285     ss << "Failed to transform from frame [" << msg->header.frame_id << "] to frame ["
00286         << context_->getFrameManager()->getFixedFrame() << "]";
00287     this->setStatusStd(StatusProperty::Error, "Message", ss.str());
00288     return;
00289   }
00290 
00291   scene_node_->setOrientation(orient);
00292   scene_node_->setPosition(pos);
00293 
00294   // creating octree
00295   octomap::OcTree* octomap = NULL;
00296   octomap::AbstractOcTree* tree = octomap_msgs::msgToMap(*msg);
00297   if (tree){
00298     octomap = dynamic_cast<octomap::OcTree*>(tree);
00299   }
00300 
00301   if (!octomap)
00302   {
00303     this->setStatusStd(StatusProperty::Error, "Message", "Failed to create octree structure");
00304     return;
00305   }
00306 
00307   std::size_t octree_depth = octomap->getTreeDepth();
00308   tree_depth_property_->setMax(octomap->getTreeDepth());
00309   
00310 
00311   // get dimensions of octree
00312   double minX, minY, minZ, maxX, maxY, maxZ;
00313   octomap->getMetricMin(minX, minY, minZ);
00314   octomap->getMetricMax(maxX, maxY, maxZ);
00315 
00316   // reset rviz pointcloud classes
00317   for (std::size_t i = 0; i < max_octree_depth_; ++i)
00318   {
00319     point_buf_[i].clear();
00320     box_size_[i] = octomap->getNodeSize(i + 1);
00321   }
00322 
00323   size_t pointCount = 0;
00324   {
00325     // traverse all leafs in the tree:
00326     unsigned int treeDepth = std::min<unsigned int>(tree_depth_property_->getInt(), octomap->getTreeDepth());
00327     for (octomap::OcTree::iterator it = octomap->begin(treeDepth), end = octomap->end(); it != end; ++it)
00328     {
00329 
00330       if (octomap->isNodeOccupied(*it))
00331       {
00332 
00333         int render_mode_mask = octree_render_property_->getOptionInt();
00334 
00335         bool display_voxel = false;
00336 
00337         // the left part evaluates to 1 for free voxels and 2 for occupied voxels
00338         if (((int)octomap->isNodeOccupied(*it) + 1) & render_mode_mask)
00339         {
00340           // check if current voxel has neighbors on all sides -> no need to be displayed
00341           bool allNeighborsFound = true;
00342 
00343           octomap::OcTreeKey key;
00344           octomap::OcTreeKey nKey = it.getKey();
00345 
00346           for (key[2] = nKey[2] - 1; allNeighborsFound && key[2] <= nKey[2] + 1; ++key[2])
00347           {
00348             for (key[1] = nKey[1] - 1; allNeighborsFound && key[1] <= nKey[1] + 1; ++key[1])
00349             {
00350               for (key[0] = nKey[0] - 1; allNeighborsFound && key[0] <= nKey[0] + 1; ++key[0])
00351               {
00352                 if (key != nKey)
00353                 {
00354                   octomap::OcTreeNode* node = octomap->search(key);
00355 
00356                   // the left part evaluates to 1 for free voxels and 2 for occupied voxels
00357                   if (!(node && (((int)octomap->isNodeOccupied(node)) + 1) & render_mode_mask))
00358                   {
00359                     // we do not have a neighbor => break!
00360                     allNeighborsFound = false;
00361                   }
00362                 }
00363               }
00364             }
00365           }
00366 
00367           display_voxel |= !allNeighborsFound;
00368         }
00369 
00370 
00371         if (display_voxel)
00372         {
00373           PointCloud::Point newPoint;
00374 
00375           newPoint.position.x = it.getX();
00376           newPoint.position.y = it.getY();
00377           newPoint.position.z = it.getZ();
00378 
00379           float cell_probability;
00380 
00381           OctreeVoxelColorMode octree_color_mode = static_cast<OctreeVoxelColorMode>(octree_coloring_property_->getOptionInt());
00382 
00383           switch (octree_color_mode)
00384           {
00385             case OCTOMAP_Z_AXIS_COLOR:
00386               setColor(newPoint.position.z, minZ, maxZ, color_factor_, newPoint);
00387               break;
00388             case OCTOMAP_PROBABLILTY_COLOR:
00389               cell_probability = it->getOccupancy();
00390               newPoint.setColor((1.0f-cell_probability), cell_probability, 0.0);
00391               break;
00392             default:
00393               break;
00394           }
00395 
00396           // push to point vectors
00397           unsigned int depth = it.getDepth();
00398           point_buf_[depth - 1].push_back(newPoint);
00399 
00400           ++pointCount;
00401         }
00402       }
00403     }
00404   }
00405 
00406   if (pointCount)
00407   {
00408     boost::mutex::scoped_lock lock(mutex_);
00409 
00410     new_points_received_ = true;
00411 
00412     for (size_t i = 0; i < max_octree_depth_; ++i)
00413       new_points_[i].swap(point_buf_[i]);
00414 
00415   }
00416   delete octomap;
00417 }
00418 
00419 void OccupancyGridDisplay::updateTreeDepth()
00420 {
00421 }
00422 
00423 void OccupancyGridDisplay::updateOctreeRenderMode()
00424 {
00425 }
00426 
00427 void OccupancyGridDisplay::updateOctreeColorMode()
00428 {
00429 }
00430 
00431 void OccupancyGridDisplay::clear()
00432 {
00433 
00434   boost::mutex::scoped_lock lock(mutex_);
00435 
00436   // reset rviz pointcloud boxes
00437   for (size_t i = 0; i < cloud_.size(); ++i)
00438   {
00439     cloud_[i]->clear();
00440   }
00441 }
00442 
00443 void OccupancyGridDisplay::update(float wall_dt, float ros_dt)
00444 {
00445   if (new_points_received_)
00446   {
00447     boost::mutex::scoped_lock lock(mutex_);
00448 
00449     for (size_t i = 0; i < max_octree_depth_; ++i)
00450     {
00451       double size = box_size_[i];
00452 
00453       cloud_[i]->clear();
00454       cloud_[i]->setDimensions(size, size, size);
00455 
00456       cloud_[i]->addPoints(&new_points_[i].front(), new_points_[i].size());
00457       new_points_[i].clear();
00458 
00459     }
00460     new_points_received_ = false;
00461   }
00462 }
00463 
00464 void OccupancyGridDisplay::reset()
00465 {
00466   clear();
00467   messages_received_ = 0;
00468   setStatus(StatusProperty::Ok, "Messages", QString("0 binary octomap messages received"));
00469 }
00470 
00471 void OccupancyGridDisplay::updateTopic()
00472 {
00473   unsubscribe();
00474   reset();
00475   subscribe();
00476   context_->queueRender();
00477 }
00478 
00479 
00480 } // namespace octomap_rviz_plugin
00481 
00482 #include <pluginlib/class_list_macros.h>
00483 
00484 PLUGINLIB_EXPORT_CLASS( octomap_rviz_plugin::OccupancyGridDisplay, rviz::Display)
00485 


octomap_rviz_plugins
Author(s): Julius Kammerl
autogenerated on Wed Aug 26 2015 15:00:45