MapsManager.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
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     * Redistributions of source code must retain the above copyright
00008       notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright
00010       documentation and/or other materials provided with the distribution.
00011     * Neither the name of the Universite de Sherbrooke nor the
00012       names of its contributors may be used to endorse or promote products
00013       derived from this software without specific prior written permission.
00014 
00015 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00016 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00017 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00018 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
00019 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00020 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00021 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00022 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00023 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00024 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00025 */
00026 
00027 #include "rtabmap_ros/MapsManager.h"
00028 
00029 #include <rtabmap/utilite/ULogger.h>
00030 #include <rtabmap/utilite/UTimer.h>
00031 #include <rtabmap/utilite/UStl.h>
00032 #include <rtabmap/utilite/UConversion.h>
00033 #include <rtabmap/core/util3d_mapping.h>
00034 #include <rtabmap/core/util3d_filtering.h>
00035 #include <rtabmap/core/util3d_transforms.h>
00036 #include <rtabmap/core/util2d.h>
00037 #include <rtabmap/core/Memory.h>
00038 #include <rtabmap/core/Graph.h>
00039 #include <rtabmap/core/Version.h>
00040 #include <rtabmap/core/OccupancyGrid.h>
00041 
00042 #include <pcl/search/kdtree.h>
00043 
00044 #include <nav_msgs/OccupancyGrid.h>
00045 #include <ros/ros.h>
00046 
00047 #include <pcl_conversions/pcl_conversions.h>
00048 
00049 #ifdef WITH_OCTOMAP_MSGS
00050 #ifdef RTABMAP_OCTOMAP
00051 #include <octomap_msgs/conversions.h>
00052 #include <octomap/ColorOcTree.h>
00053 #include <rtabmap/core/OctoMap.h>
00054 #endif
00055 #endif
00056 
00057 using namespace rtabmap;
00058 
00059 MapsManager::MapsManager() :
00060                 cloudOutputVoxelized_(true),
00061                 cloudSubtractFiltering_(false),
00062                 cloudSubtractFilteringMinNeighbors_(2),
00063                 mapFilterRadius_(0.0),
00064                 mapFilterAngle_(30.0), // degrees
00065                 mapCacheCleanup_(true),
00066                 negativePosesIgnored_(true),
00067                 negativeScanEmptyRayTracing_(true),
00068                 assembledObstacles_(new pcl::PointCloud<pcl::PointXYZRGB>),
00069                 assembledGround_(new pcl::PointCloud<pcl::PointXYZRGB>),
00070                 occupancyGrid_(new OccupancyGrid),
00071                 octomap_(0),
00072                 octomapTreeDepth_(16)
00073 {
00074 }
00075 
00076 void MapsManager::init(ros::NodeHandle & nh, ros::NodeHandle & pnh, const std::string & name, bool usePublicNamespace)
00077 {
00078         // common map stuff
00079         pnh.param("map_filter_radius", mapFilterRadius_, mapFilterRadius_);
00080         pnh.param("map_filter_angle", mapFilterAngle_, mapFilterAngle_);
00081         pnh.param("map_cleanup", mapCacheCleanup_, mapCacheCleanup_);
00082         pnh.param("map_negative_poses_ignored", negativePosesIgnored_, negativePosesIgnored_);
00083         pnh.param("map_negative_scan_empty_ray_tracing", negativeScanEmptyRayTracing_, negativeScanEmptyRayTracing_);
00084 
00085         if(pnh.hasParam("scan_output_voxelized"))
00086         {
00087                 ROS_WARN("Parameter \"scan_output_voxelized\" has been "
00088                                 "removed. Use \"cloud_output_voxelized\" instead.");
00089                 if(!pnh.hasParam("cloud_output_voxelized"))
00090                 {
00091                         pnh.getParam("scan_output_voxelized", cloudOutputVoxelized_);
00092                 }
00093         }
00094         pnh.param("cloud_output_voxelized", cloudOutputVoxelized_, cloudOutputVoxelized_);
00095         pnh.param("cloud_subtract_filtering", cloudSubtractFiltering_, cloudSubtractFiltering_);
00096         pnh.param("cloud_subtract_filtering_min_neighbors", cloudSubtractFilteringMinNeighbors_, cloudSubtractFilteringMinNeighbors_);
00097 
00098         ROS_INFO("%s(maps): map_filter_radius          = %f", name.c_str(), mapFilterRadius_);
00099         ROS_INFO("%s(maps): map_filter_angle           = %f", name.c_str(), mapFilterAngle_);
00100         ROS_INFO("%s(maps): map_cleanup                = %s", name.c_str(), mapCacheCleanup_?"true":"false");
00101         ROS_INFO("%s(maps): map_negative_poses_ignored = %s", name.c_str(), negativePosesIgnored_?"true":"false");
00102         ROS_INFO("%s(maps): map_negative_scan_ray_tracing = %s", name.c_str(), negativeScanEmptyRayTracing_?"true":"false");
00103         ROS_INFO("%s(maps): cloud_output_voxelized     = %s", name.c_str(), cloudOutputVoxelized_?"true":"false");
00104         ROS_INFO("%s(maps): cloud_subtract_filtering   = %s", name.c_str(), cloudSubtractFiltering_?"true":"false");
00105         ROS_INFO("%s(maps): cloud_subtract_filtering_min_neighbors = %d", name.c_str(), cloudSubtractFilteringMinNeighbors_);
00106 
00107 #ifdef WITH_OCTOMAP_MSGS
00108 #ifdef RTABMAP_OCTOMAP
00109         octomap_ = new OctoMap(occupancyGrid_->getCellSize(), 0.5, occupancyGrid_->isFullUpdate(), occupancyGrid_->getUpdateError());
00110         pnh.param("octomap_tree_depth", octomapTreeDepth_, octomapTreeDepth_);
00111         if(octomapTreeDepth_ > 16)
00112         {
00113                 ROS_WARN("octomap_tree_depth maximum is 16");
00114                 octomapTreeDepth_ = 16;
00115         }
00116         else if(octomapTreeDepth_ < 0)
00117         {
00118                 ROS_WARN("octomap_tree_depth cannot be negative, set to 16 instead");
00119                 octomapTreeDepth_ = 16;
00120         }
00121         ROS_INFO("%s(maps): octomap_tree_depth         = %d", name.c_str(), octomapTreeDepth_);
00122 #endif
00123 #endif
00124 
00125         // If true, the last message published on
00126         // the map topics will be saved and sent to new subscribers when they
00127         // connect
00128         bool latch = true;
00129         pnh.param("latch", latch, latch);
00130 
00131         // mapping topics
00132         ros::NodeHandle * nht;
00133         if(usePublicNamespace)
00134         {
00135                 nht = &nh;
00136         }
00137         else
00138         {
00139                 nht = &pnh;
00140         }
00141         gridMapPub_ = nht->advertise<nav_msgs::OccupancyGrid>("grid_map", 1, latch);
00142         gridProbMapPub_ = nht->advertise<nav_msgs::OccupancyGrid>("grid_prob_map", 1, latch);
00143         cloudMapPub_ = nht->advertise<sensor_msgs::PointCloud2>("cloud_map", 1, latch);
00144         cloudObstaclesPub_ = nht->advertise<sensor_msgs::PointCloud2>("cloud_obstacles", 1, latch);
00145         cloudGroundPub_ = nht->advertise<sensor_msgs::PointCloud2>("cloud_ground", 1, latch);
00146 
00147         // deprecated
00148         projMapPub_ = nht->advertise<nav_msgs::OccupancyGrid>("proj_map", 1, latch);
00149         scanMapPub_ = nht->advertise<sensor_msgs::PointCloud2>("scan_map", 1, latch);
00150 
00151 #ifdef WITH_OCTOMAP_MSGS
00152 #ifdef RTABMAP_OCTOMAP
00153         octoMapPubBin_ = nht->advertise<octomap_msgs::Octomap>("octomap_binary", 1, latch);
00154         octoMapPubFull_ = nht->advertise<octomap_msgs::Octomap>("octomap_full", 1, latch);
00155         octoMapCloud_ = nht->advertise<sensor_msgs::PointCloud2>("octomap_occupied_space", 1, latch);
00156         octoMapObstacleCloud_ = nht->advertise<sensor_msgs::PointCloud2>("octomap_obstacles", 1, latch);
00157         octoMapGroundCloud_ = nht->advertise<sensor_msgs::PointCloud2>("octomap_ground", 1, latch);
00158         octoMapEmptySpace_ = nht->advertise<sensor_msgs::PointCloud2>("octomap_empty_space", 1, latch);
00159         octoMapProj_ = nht->advertise<nav_msgs::OccupancyGrid>("octomap_grid", 1, latch);
00160 #endif
00161 #endif
00162 }
00163 
00164 MapsManager::~MapsManager() {
00165         clear();
00166 
00167         delete occupancyGrid_;
00168 
00169 #ifdef WITH_OCTOMAP_MSGS
00170 #ifdef RTABMAP_OCTOMAP
00171         if(octomap_)
00172         {
00173                 delete octomap_;
00174                 octomap_ = 0;
00175         }
00176 #endif
00177 #endif
00178 }
00179 
00180 void parameterMoved(
00181                 ros::NodeHandle & nh,
00182                 const std::string & rosName,
00183                 const std::string & parameterName,
00184                 ParametersMap & parameters)
00185 {
00186         if(nh.hasParam(rosName))
00187         {
00188                 ParametersMap::const_iterator iter = Parameters::getDefaultParameters().find(parameterName);
00189                 if(iter != Parameters::getDefaultParameters().end())
00190                 {
00191                         ROS_WARN("Parameter \"%s\" has moved from "
00192                                          "rtabmap_ros to rtabmap library. Use "
00193                                          "parameter \"%s\" instead. The value is still "
00194                                          "copied to new parameter name.",
00195                                          rosName.c_str(),
00196                                          parameterName.c_str());
00197                         std::string type = Parameters::getType(parameterName);
00198                         if(type.compare("float") || type.compare("double"))
00199                         {
00200                                 double v = uStr2Double(iter->second);
00201                                 nh.getParam(rosName, v);
00202                                 parameters.insert(ParametersPair(parameterName, uNumber2Str(v)));
00203                         }
00204                         else if(type.compare("int") || type.compare("unsigned int"))
00205                         {
00206                                 int v = uStr2Int(iter->second);
00207                                 nh.getParam(rosName, v);
00208                                 parameters.insert(ParametersPair(parameterName, uNumber2Str(v)));
00209                         }
00210                         else if(type.compare("bool"))
00211                         {
00212                                 bool v = uStr2Bool(iter->second);
00213                                 nh.getParam(rosName, v);
00214                                 if(rosName.compare("grid_incremental") == 0)
00215                                 {
00216                                         v = !v; // new parameter is called kGridGlobalFullUpdate(), which is the inverse
00217                                 }
00218                                 parameters.insert(ParametersPair(parameterName, uNumber2Str(v)));
00219 
00220                         }
00221                         else
00222                         {
00223                                 ROS_ERROR("Not handled type \"%s\" for parameter \"%s\"", type.c_str(), parameterName.c_str());
00224                         }
00225                 }
00226                 else
00227                 {
00228                         ROS_ERROR("Parameter \"%s\" not found in default parameters.", parameterName.c_str());
00229                 }
00230         }
00231 }
00232 
00233 void MapsManager::backwardCompatibilityParameters(ros::NodeHandle & pnh, ParametersMap & parameters) const
00234 {
00235         // removed
00236         if(pnh.hasParam("cloud_frustum_culling"))
00237         {
00238                 ROS_WARN("Parameter \"cloud_frustum_culling\" has been removed. OctoMap topics "
00239                                 "already do it. You can remove it from your launch file.");
00240         }
00241 
00242         // moved
00243         parameterMoved(pnh, "cloud_decimation", Parameters::kGridDepthDecimation(), parameters);
00244         parameterMoved(pnh, "cloud_max_depth", Parameters::kGridRangeMax(), parameters);
00245         parameterMoved(pnh, "cloud_min_depth", Parameters::kGridRangeMin(), parameters);
00246         parameterMoved(pnh, "cloud_voxel_size", Parameters::kGridCellSize(), parameters);
00247         parameterMoved(pnh, "cloud_floor_culling_height", Parameters::kGridMaxGroundHeight(), parameters);
00248         parameterMoved(pnh, "cloud_ceiling_culling_height", Parameters::kGridMaxObstacleHeight(), parameters);
00249         parameterMoved(pnh, "cloud_noise_filtering_radius", Parameters::kGridNoiseFilteringRadius(), parameters);
00250         parameterMoved(pnh, "cloud_noise_filtering_min_neighbors", Parameters::kGridNoiseFilteringMinNeighbors(), parameters);
00251         parameterMoved(pnh, "scan_decimation", Parameters::kGridScanDecimation(), parameters);
00252         parameterMoved(pnh, "scan_voxel_size", Parameters::kGridCellSize(), parameters);
00253         parameterMoved(pnh, "proj_max_ground_angle", Parameters::kGridMaxGroundAngle(), parameters);
00254         parameterMoved(pnh, "proj_min_cluster_size", Parameters::kGridMinClusterSize(), parameters);
00255         parameterMoved(pnh, "proj_max_height", Parameters::kGridMaxObstacleHeight(), parameters);
00256         parameterMoved(pnh, "proj_max_obstacles_height", Parameters::kGridMaxObstacleHeight(), parameters);
00257         parameterMoved(pnh, "proj_max_ground_height", Parameters::kGridMaxGroundHeight(), parameters);
00258 
00259         parameterMoved(pnh, "proj_detect_flat_obstacles", Parameters::kGridFlatObstacleDetected(), parameters);
00260         parameterMoved(pnh, "proj_map_frame", Parameters::kGridMapFrameProjection(), parameters);
00261         parameterMoved(pnh, "grid_unknown_space_filled", Parameters::kGridScan2dUnknownSpaceFilled(), parameters);
00262         parameterMoved(pnh, "grid_cell_size", Parameters::kGridCellSize(), parameters);
00263         parameterMoved(pnh, "grid_incremental", Parameters::kGridGlobalFullUpdate(), parameters);
00264         parameterMoved(pnh, "grid_size", Parameters::kGridGlobalMinSize(), parameters);
00265         parameterMoved(pnh, "grid_eroded", Parameters::kGridGlobalEroded(), parameters);
00266         parameterMoved(pnh, "grid_footprint_radius", Parameters::kGridGlobalFootprintRadius(), parameters);
00267 
00268 #ifdef WITH_OCTOMAP_MSGS
00269 #ifdef RTABMAP_OCTOMAP
00270         parameterMoved(pnh, "octomap_ground_is_obstacle", Parameters::kGridGroundIsObstacle(), parameters);
00271         parameterMoved(pnh, "octomap_occupancy_thr", Parameters::kGridGlobalOccupancyThr(), parameters);
00272 #endif
00273 #endif
00274 }
00275 
00276 void MapsManager::setParameters(const rtabmap::ParametersMap & parameters)
00277 {
00278         parameters_ = parameters;
00279         occupancyGrid_->parseParameters(parameters_);
00280 
00281 #ifdef WITH_OCTOMAP_MSGS
00282 #ifdef RTABMAP_OCTOMAP
00283         if(octomap_)
00284         {
00285                 delete octomap_;
00286                 octomap_ = 0;
00287         }
00288         octomap_ = new OctoMap(parameters_);
00289 #endif
00290 #endif
00291 }
00292 
00293 void MapsManager::set2DMap(
00294                 const cv::Mat & map,
00295                 float xMin,
00296                 float yMin,
00297                 float cellSize,
00298                 const std::map<int, rtabmap::Transform> & poses,
00299                 const rtabmap::Memory * memory)
00300 {
00301         occupancyGrid_->setMap(map, xMin, yMin, cellSize, poses);
00302         //update cache in case the map should be updated
00303         if(memory)
00304         {
00305                 for(std::map<int, rtabmap::Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
00306                 {
00307                         std::map<int, std::pair< std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator jter = gridMaps_.find(iter->first);
00308                         if(!uContains(gridMaps_, iter->first))
00309                         {
00310                                 rtabmap::SensorData data;
00311                                 data = memory->getSignatureDataConst(iter->first, false, false, false, true);
00312                                 if(data.gridCellSize() == 0.0f)
00313                                 {
00314                                         ROS_WARN("Local occupancy grid doesn't exist for node %d", iter->first);
00315                                 }
00316                                 else
00317                                 {
00318                                         cv::Mat ground, obstacles, emptyCells;
00319                                         data.uncompressData(
00320                                                         0,
00321                                                         0,
00322                                                         0,
00323                                                         0,
00324                                                         &ground,
00325                                                         &obstacles,
00326                                                         &emptyCells);
00327 
00328                                         uInsert(gridMaps_, std::make_pair(iter->first, std::make_pair(std::make_pair(ground, obstacles), emptyCells)));
00329                                         uInsert(gridMapsViewpoints_, std::make_pair(iter->first, data.gridViewPoint()));
00330                                         occupancyGrid_->addToCache(iter->first, ground, obstacles, emptyCells);
00331                                 }
00332                         }
00333                         else
00334                         {
00335                                 occupancyGrid_->addToCache(iter->first, jter->second.first.first, jter->second.first.second, jter->second.second);
00336                         }
00337                 }
00338         }
00339 }
00340 
00341 void MapsManager::clear()
00342 {
00343         gridMaps_.clear();
00344         gridMapsViewpoints_.clear();
00345         assembledGround_->clear();
00346         assembledObstacles_->clear();
00347         assembledGroundPoses_.clear();
00348         assembledObstaclePoses_.clear();
00349         assembledGroundIndex_.release();
00350         assembledObstacleIndex_.release();
00351         groundClouds_.clear();
00352         obstacleClouds_.clear();
00353         occupancyGrid_->clear();
00354 #ifdef WITH_OCTOMAP_MSGS
00355 #ifdef RTABMAP_OCTOMAP
00356         octomap_->clear();
00357 #endif
00358 #endif
00359 }
00360 
00361 bool MapsManager::hasSubscribers() const
00362 {
00363         return  cloudMapPub_.getNumSubscribers() != 0 ||
00364                         cloudObstaclesPub_.getNumSubscribers() != 0 ||
00365                         cloudGroundPub_.getNumSubscribers() != 0 ||
00366                         projMapPub_.getNumSubscribers() != 0 ||
00367                         gridMapPub_.getNumSubscribers() != 0 ||
00368                         gridProbMapPub_.getNumSubscribers() != 0 ||
00369                         scanMapPub_.getNumSubscribers() != 0 ||
00370                         octoMapPubBin_.getNumSubscribers() != 0 ||
00371                         octoMapPubFull_.getNumSubscribers() != 0 ||
00372                         octoMapCloud_.getNumSubscribers() != 0 ||
00373                         octoMapObstacleCloud_.getNumSubscribers() != 0 ||
00374                         octoMapGroundCloud_.getNumSubscribers() != 0 ||
00375                         octoMapEmptySpace_.getNumSubscribers() != 0 ||
00376                         octoMapProj_.getNumSubscribers() != 0;
00377 }
00378 
00379 std::map<int, Transform> MapsManager::getFilteredPoses(const std::map<int, Transform> & poses)
00380 {
00381         if(mapFilterRadius_ > 0.0)
00382         {
00383                 // filter nodes
00384                 double angle = mapFilterAngle_ == 0.0?CV_PI+0.1:mapFilterAngle_*CV_PI/180.0;
00385                 return rtabmap::graph::radiusPosesFiltering(poses, mapFilterRadius_, angle);
00386         }
00387         return std::map<int, Transform>();
00388 }
00389 
00390 std::map<int, rtabmap::Transform> MapsManager::updateMapCaches(
00391                 const std::map<int, rtabmap::Transform> & poses,
00392                 const rtabmap::Memory * memory,
00393                 bool updateGrid,
00394                 bool updateOctomap,
00395                 const std::map<int, rtabmap::Signature> & signatures)
00396 {
00397         bool updateGridCache = updateGrid || updateOctomap;
00398         if(!updateGrid && !updateOctomap)
00399         {
00400                 //  all false, update only those where we have subscribers
00401                 updateOctomap =
00402                                 octoMapPubBin_.getNumSubscribers() != 0 ||
00403                                 octoMapPubFull_.getNumSubscribers() != 0 ||
00404                                 octoMapCloud_.getNumSubscribers() != 0 ||
00405                                 octoMapObstacleCloud_.getNumSubscribers() != 0 ||
00406                                 octoMapGroundCloud_.getNumSubscribers() != 0 ||
00407                                 octoMapEmptySpace_.getNumSubscribers() != 0 ||
00408                                 octoMapProj_.getNumSubscribers() != 0;
00409 
00410                 updateGrid = projMapPub_.getNumSubscribers() != 0 ||
00411                                 gridMapPub_.getNumSubscribers() != 0 ||
00412                                 gridProbMapPub_.getNumSubscribers() != 0;
00413 
00414                 updateGridCache = updateOctomap || updateGrid ||
00415                                 cloudMapPub_.getNumSubscribers() != 0 ||
00416                                 cloudObstaclesPub_.getNumSubscribers() != 0 ||
00417                                 cloudGroundPub_.getNumSubscribers() != 0 ||
00418                                 scanMapPub_.getNumSubscribers() != 0;
00419         }
00420 
00421 #ifndef WITH_OCTOMAP_MSGS
00422         updateOctomap = false;
00423 #endif
00424 #ifndef RTABMAP_OCTOMAP
00425         updateOctomap = false;
00426 #endif
00427 
00428 
00429         UDEBUG("Updating map caches...");
00430 
00431         if(!memory && signatures.size() == 0)
00432         {
00433                 ROS_ERROR("Memory and signatures should not be both null!?");
00434                 return std::map<int, rtabmap::Transform>();
00435         }
00436 
00437         std::map<int, rtabmap::Transform> filteredPoses;
00438 
00439         // update cache
00440         if(updateGridCache)
00441         {
00442                 // filter nodes
00443                 if(mapFilterRadius_ > 0.0)
00444                 {
00445                         UDEBUG("Filter nodes...");
00446                         double angle = mapFilterAngle_ == 0.0?CV_PI+0.1:mapFilterAngle_*CV_PI/180.0;
00447                         filteredPoses = rtabmap::graph::radiusPosesFiltering(poses, mapFilterRadius_, angle);
00448                         for(std::map<int, rtabmap::Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
00449                         {
00450                                 if(iter->first <=0)
00451                                 {
00452                                         // make sure to keep latest data
00453                                         filteredPoses.insert(*iter);
00454                                 }
00455                                 else
00456                                 {
00457                                         break;
00458                                 }
00459                         }
00460                 }
00461                 else
00462                 {
00463                         filteredPoses = poses;
00464                 }
00465 
00466                 if(negativePosesIgnored_)
00467                 {
00468                         for(std::map<int, rtabmap::Transform>::iterator iter=filteredPoses.begin(); iter!=filteredPoses.end();)
00469                         {
00470                                 if(iter->first <= 0)
00471                                 {
00472                                         filteredPoses.erase(iter++);
00473                                 }
00474                                 else
00475                                 {
00476                                         ++iter;
00477                                 }
00478                         }
00479                 }
00480 
00481                 bool longUpdate = false;
00482                 UTimer longUpdateTimer;
00483                 if(filteredPoses.size() > 20)
00484                 {
00485                         if(updateGridCache && gridMaps_.size() < 5)
00486                         {
00487                                 ROS_WARN("Many occupancy grids should be loaded (~%d), this may take a while to update the map(s)...", int(filteredPoses.size()-gridMaps_.size()));
00488                                 longUpdate = true;
00489                         }
00490 #ifdef WITH_OCTOMAP_MSGS
00491 #ifdef RTABMAP_OCTOMAP
00492                         if(updateOctomap && octomap_->addedNodes().size() < 5)
00493                         {
00494                                 ROS_WARN("Many clouds should be added to octomap (~%d), this may take a while to update the map(s)...", int(filteredPoses.size()-octomap_->addedNodes().size()));
00495                                 longUpdate = true;
00496                         }
00497 #endif
00498 #endif
00499                 }
00500 
00501                 bool occupancySavedInDB = memory && uStrNumCmp(memory->getDatabaseVersion(), "0.11.10")>=0?true:false;
00502 
00503                 for(std::map<int, rtabmap::Transform>::iterator iter=filteredPoses.begin(); iter!=filteredPoses.end(); ++iter)
00504                 {
00505                         if(!iter->second.isNull())
00506                         {
00507                                 rtabmap::SensorData data;
00508                                 if(updateGridCache && (iter->first < 0 || !uContains(gridMaps_, iter->first)))
00509                                 {
00510                                         UDEBUG("Data required for %d", iter->first);
00511                                         std::map<int, rtabmap::Signature>::const_iterator findIter = signatures.find(iter->first);
00512                                         if(findIter != signatures.end())
00513                                         {
00514                                                 data = findIter->second.sensorData();
00515                                         }
00516                                         else if(memory)
00517                                         {
00518                                                 data = memory->getSignatureDataConst(iter->first, occupancyGrid_->isGridFromDepth() && !occupancySavedInDB, !occupancyGrid_->isGridFromDepth() && !occupancySavedInDB, false, true);
00519                                         }
00520 
00521                                         if(data.id() != 0)
00522                                         {
00523                                                 UDEBUG("Adding grid map %d to cache...", iter->first);
00524                                                 cv::Point3f viewPoint;
00525                                                 cv::Mat ground, obstacles, emptyCells;
00526                                                 if(iter->first > 0)
00527                                                 {
00528                                                         cv::Mat rgb, depth;
00529                                                         LaserScan scan;
00530                                                         bool generateGrid = data.gridCellSize() == 0.0f;
00531                                                         static bool warningShown = false;
00532                                                         if(occupancySavedInDB && generateGrid && !warningShown)
00533                                                         {
00534                                                                 warningShown = true;
00535                                                                 UWARN("Occupancy grid for location %d should be added to global map (e..g, a ROS node is subscribed to "
00536                                                                                 "any occupancy grid output) but it cannot be found "
00537                                                                                 "in memory. For convenience, the occupancy "
00538                                                                                 "grid is regenerated. Make sure parameter \"%s\" is true to "
00539                                                                                 "avoid this warning for the next locations added to map. For older "
00540                                                                                 "locations already in database without an occupancy grid map, you can use the "
00541                                                                                 "\"rtabmap-databaseViewer\" to regenerate the missing occupancy grid maps and "
00542                                                                                 "save them back in the database for next sessions. This warning is only shown once.",
00543                                                                                 data.id(), Parameters::kRGBDCreateOccupancyGrid().c_str());
00544                                                         }
00545                                                         if(memory && occupancySavedInDB && generateGrid)
00546                                                         {
00547                                                                 // if we are here, it is because we loaded a database with old nodes not having occupancy grid set
00548                                                                 // try reload again
00549                                                                 data = memory->getSignatureDataConst(iter->first, occupancyGrid_->isGridFromDepth(), !occupancyGrid_->isGridFromDepth(), false, false);
00550                                                         }
00551                                                         data.uncompressData(
00552                                                                         occupancyGrid_->isGridFromDepth() && generateGrid?&rgb:0,
00553                                                                         occupancyGrid_->isGridFromDepth() && generateGrid?&depth:0,
00554                                                                         !occupancyGrid_->isGridFromDepth() && generateGrid?&scan:0,
00555                                                                         0,
00556                                                                         generateGrid?0:&ground,
00557                                                                         generateGrid?0:&obstacles,
00558                                                                         generateGrid?0:&emptyCells);
00559 
00560                                                         if(generateGrid)
00561                                                         {
00562                                                                 Signature tmp(data);
00563                                                                 tmp.setPose(iter->second);
00564                                                                 occupancyGrid_->createLocalMap(tmp, ground, obstacles, emptyCells, viewPoint);
00565                                                                 uInsert(gridMaps_, std::make_pair(iter->first, std::make_pair(std::make_pair(ground, obstacles), emptyCells)));
00566                                                                 uInsert(gridMapsViewpoints_, std::make_pair(iter->first, viewPoint));
00567                                                         }
00568                                                         else
00569                                                         {
00570                                                                 viewPoint = data.gridViewPoint();
00571                                                                 uInsert(gridMaps_, std::make_pair(iter->first, std::make_pair(std::make_pair(ground, obstacles), emptyCells)));
00572                                                                 uInsert(gridMapsViewpoints_, std::make_pair(iter->first, viewPoint));
00573                                                         }
00574                                                 }
00575                                                 else
00576                                                 {
00577                                                         // generate tmp occupancy grid for negative ids (assuming data is already uncompressed)
00578                                                         // For negative laser scans, fill empty space?
00579                                                         bool unknownSpaceFilled = Parameters::defaultGridScan2dUnknownSpaceFilled();
00580                                                         Parameters::parse(parameters_, Parameters::kGridScan2dUnknownSpaceFilled(), unknownSpaceFilled);
00581 
00582                                                         if(unknownSpaceFilled != negativeScanEmptyRayTracing_ && negativeScanEmptyRayTracing_)
00583                                                         {
00584                                                                 ParametersMap parameters;
00585                                                                 parameters.insert(ParametersPair(Parameters::kGridScan2dUnknownSpaceFilled(), uBool2Str(negativeScanEmptyRayTracing_)));
00586                                                                 occupancyGrid_->parseParameters(parameters);
00587                                                         }
00588 
00589                                                         cv::Mat rgb, depth;
00590                                                         LaserScan scan;
00591                                                         bool generateGrid = data.gridCellSize() == 0.0f || (unknownSpaceFilled != negativeScanEmptyRayTracing_ && negativeScanEmptyRayTracing_);
00592                                                         data.uncompressData(
00593                                                                 occupancyGrid_->isGridFromDepth() && generateGrid?&rgb:0,
00594                                                                 occupancyGrid_->isGridFromDepth() && generateGrid?&depth:0,
00595                                                                 !occupancyGrid_->isGridFromDepth() && generateGrid?&scan:0,
00596                                                                 0,
00597                                                                 generateGrid?0:&ground,
00598                                                                 generateGrid?0:&obstacles,
00599                                                                 generateGrid?0:&emptyCells);
00600 
00601                                                         if(generateGrid)
00602                                                         {
00603                                                                 Signature tmp(data);
00604                                                                 tmp.setPose(iter->second);
00605                                                                 occupancyGrid_->createLocalMap(tmp, ground, obstacles, emptyCells, viewPoint);
00606                                                                 uInsert(gridMaps_,  std::make_pair(iter->first, std::make_pair(std::make_pair(ground, obstacles), emptyCells)));
00607                                                                 uInsert(gridMapsViewpoints_, std::make_pair(iter->first, viewPoint));
00608                                                         }
00609                                                         else
00610                                                         {
00611                                                                 viewPoint = data.gridViewPoint();
00612                                                                 uInsert(gridMaps_,  std::make_pair(iter->first, std::make_pair(std::make_pair(ground, obstacles), emptyCells)));
00613                                                                 uInsert(gridMapsViewpoints_, std::make_pair(iter->first, viewPoint));
00614                                                         }
00615 
00616                                                         // put back
00617                                                         if(unknownSpaceFilled != negativeScanEmptyRayTracing_ && negativeScanEmptyRayTracing_)
00618                                                         {
00619                                                                 ParametersMap parameters;
00620                                                                 parameters.insert(ParametersPair(Parameters::kGridScan2dUnknownSpaceFilled(), uBool2Str(unknownSpaceFilled)));
00621                                                                 occupancyGrid_->parseParameters(parameters);
00622                                                         }
00623                                                 }
00624                                         }
00625                                         else if(memory)
00626                                         {
00627                                                 ROS_ERROR("Data missing for node %d to update the maps", iter->first);
00628                                         }
00629                                 }
00630 
00631                                 if(updateGrid &&
00632                                                 (iter->first < 0 ||
00633                                                   occupancyGrid_->addedNodes().find(iter->first) == occupancyGrid_->addedNodes().end()))
00634                                 {
00635                                         std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator mter = gridMaps_.find(iter->first);
00636                                         if(mter != gridMaps_.end())
00637                                         {
00638                                                 if(!mter->second.first.first.empty() || !mter->second.first.second.empty())
00639                                                 {
00640                                                         occupancyGrid_->addToCache(iter->first, mter->second.first.first, mter->second.first.second, mter->second.second);
00641                                                 }
00642                                         }
00643                                 }
00644 
00645 #ifdef WITH_OCTOMAP_MSGS
00646 #ifdef RTABMAP_OCTOMAP
00647                                 if(updateOctomap &&
00648                                                 (iter->first < 0 ||
00649                                                   octomap_->addedNodes().find(iter->first) == octomap_->addedNodes().end()))
00650                                 {
00651                                         std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator mter = gridMaps_.find(iter->first);
00652                                         std::map<int, cv::Point3f>::iterator pter = gridMapsViewpoints_.find(iter->first);
00653                                         if(mter != gridMaps_.end() && pter!=gridMapsViewpoints_.end())
00654                                         {
00655                                                 if((mter->second.first.first.empty() || mter->second.first.first.channels() > 2) &&
00656                                                    (mter->second.first.second.empty() || mter->second.first.second.channels() > 2))
00657                                                 {
00658                                                         octomap_->addToCache(iter->first, mter->second.first.first, mter->second.first.second, mter->second.second, pter->second);
00659                                                 }
00660                                                 else if(!mter->second.first.first.empty() && !mter->second.first.second.empty())
00661                                                 {
00662                                                         ROS_WARN("Node %d: Cannot update octomap with 2D occupancy grids. "
00663                                                                         "Do \"$ rosrun rtabmap_ros rtabmap --params | grep Grid\" to see "
00664                                                                         "all occupancy grid parameters.",
00665                                                                         iter->first);
00666                                                 }
00667                                         }
00668                                 }
00669 #endif
00670 #endif
00671                         }
00672                         else
00673                         {
00674                                 ROS_ERROR("Pose null for node %d", iter->first);
00675                         }
00676                 }
00677 
00678                 if(updateGrid)
00679                 {
00680                         occupancyGrid_->update(filteredPoses);
00681                 }
00682 
00683 #ifdef WITH_OCTOMAP_MSGS
00684 #ifdef RTABMAP_OCTOMAP
00685                 if(updateOctomap)
00686                 {
00687                         UTimer time;
00688                         octomap_->update(filteredPoses);
00689                         ROS_INFO("Octomap update time = %fs", time.ticks());
00690                 }
00691 #endif
00692 #endif
00693                 for(std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator iter=gridMaps_.begin();
00694                         iter!=gridMaps_.end();)
00695                 {
00696                         if(!uContains(poses, iter->first))
00697                         {
00698                                 UASSERT(gridMapsViewpoints_.erase(iter->first) != 0);
00699                                 gridMaps_.erase(iter++);
00700                         }
00701                         else
00702                         {
00703                                 ++iter;
00704                         }
00705                 }
00706 
00707                 for(std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr >::iterator iter=groundClouds_.begin();
00708                         iter!=groundClouds_.end();)
00709                 {
00710                         if(!uContains(poses, iter->first))
00711                         {
00712                                 groundClouds_.erase(iter++);
00713                         }
00714                         else
00715                         {
00716                                 ++iter;
00717                         }
00718                 }
00719 
00720                 for(std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr >::iterator iter=obstacleClouds_.begin();
00721                         iter!=obstacleClouds_.end();)
00722                 {
00723                         if(!uContains(poses, iter->first))
00724                         {
00725                                 obstacleClouds_.erase(iter++);
00726                         }
00727                         else
00728                         {
00729                                 ++iter;
00730                         }
00731                 }
00732 
00733                 if(longUpdate)
00734                 {
00735                         ROS_WARN("Map(s) updated! (%f s)", longUpdateTimer.ticks());
00736                 }
00737         }
00738 
00739         return filteredPoses;
00740 }
00741 
00742 pcl::PointCloud<pcl::PointXYZRGB>::Ptr subtractFiltering(
00743                 const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
00744                 const rtabmap::FlannIndex & substractCloudIndex,
00745                 float radiusSearch,
00746                 int minNeighborsInRadius)
00747 {
00748         UASSERT(minNeighborsInRadius > 0);
00749         UASSERT(substractCloudIndex.indexedFeatures());
00750 
00751         pcl::PointCloud<pcl::PointXYZRGB>::Ptr output(new pcl::PointCloud<pcl::PointXYZRGB>);
00752         output->resize(cloud->size());
00753         int oi = 0; // output iterator
00754         for(unsigned int i=0; i<cloud->size(); ++i)
00755         {
00756                 std::vector<std::vector<size_t> > kIndices;
00757                 std::vector<std::vector<float> > kDistances;
00758                 cv::Mat pt = (cv::Mat_<float>(1, 3) << cloud->at(i).x, cloud->at(i).y, cloud->at(i).z);
00759                 substractCloudIndex.radiusSearch(pt, kIndices, kDistances, radiusSearch, minNeighborsInRadius, 32, 0, false);
00760                 if(kIndices.size() == 1 && kIndices[0].size() < minNeighborsInRadius)
00761                 {
00762                         output->at(oi++) = cloud->at(i);
00763                 }
00764         }
00765         output->resize(oi);
00766         return output;
00767 }
00768 
00769 void MapsManager::publishMaps(
00770                 const std::map<int, rtabmap::Transform> & poses,
00771                 const ros::Time & stamp,
00772                 const std::string & mapFrameId)
00773 {
00774         UDEBUG("Publishing maps...");
00775 
00776         // publish maps
00777         if(cloudMapPub_.getNumSubscribers() ||
00778            scanMapPub_.getNumSubscribers() ||
00779            cloudObstaclesPub_.getNumSubscribers() ||
00780            cloudGroundPub_.getNumSubscribers())
00781         {
00782                 // generate the assembled cloud!
00783                 UTimer time;
00784 
00785                 if(scanMapPub_.getNumSubscribers())
00786                 {
00787                         if(parameters_.find(Parameters::kGridFromDepth()) != parameters_.end() &&
00788                                 uStr2Bool(parameters_.at(Parameters::kGridFromDepth())))
00789                         {
00790                                 ROS_WARN("/scan_map topic is deprecated! Subscribe to /cloud_map topic "
00791                                                 "instead with <param name=\"%s\" type=\"string\" value=\"false\"/>. "
00792                                                 "Do \"$ rosrun rtabmap_ros rtabmap --params | grep Grid\" to see "
00793                                                 "all occupancy grid parameters.",
00794                                                 Parameters::kGridFromDepth().c_str());
00795                         }
00796                         else
00797                         {
00798                                 ROS_WARN("/scan_map topic is deprecated! Subscribe to /cloud_map topic instead.");
00799                         }
00800                 }
00801 
00802                 // detect if the graph has changed, if so, recreate the clouds
00803                 bool graphGroundOptimized = false;
00804                 bool graphObstacleOptimized = false;
00805                 bool updateGround = cloudMapPub_.getNumSubscribers() ||
00806                                    scanMapPub_.getNumSubscribers() ||
00807                                    cloudGroundPub_.getNumSubscribers();
00808                 bool updateObstacles = cloudMapPub_.getNumSubscribers() ||
00809                                    scanMapPub_.getNumSubscribers() ||
00810                                    cloudObstaclesPub_.getNumSubscribers();
00811                 bool graphGroundChanged = updateGround;
00812                 bool graphObstacleChanged = updateObstacles;
00813                 for(std::map<int, Transform>::const_iterator iter=poses.begin(); iter!=poses.end(); ++iter)
00814                 {
00815                         std::map<int, Transform>::const_iterator jter;
00816                         if(updateGround)
00817                         {
00818                                 jter = assembledGroundPoses_.find(iter->first);
00819                                 if(jter != assembledGroundPoses_.end())
00820                                 {
00821                                         graphGroundChanged = false;
00822                                         UASSERT(!iter->second.isNull() && !jter->second.isNull());
00823                                         if(iter->second.getDistanceSquared(jter->second) > 0.0001)
00824                                         {
00825                                                 graphGroundOptimized = true;
00826                                         }
00827                                 }
00828                         }
00829                         if(updateObstacles)
00830                         {
00831                                 jter = assembledObstaclePoses_.find(iter->first);
00832                                 if(jter != assembledObstaclePoses_.end())
00833                                 {
00834                                         graphObstacleChanged = false;
00835                                         UASSERT(!iter->second.isNull() && !jter->second.isNull());
00836                                         if(iter->second.getDistanceSquared(jter->second) > 0.0001)
00837                                         {
00838                                                 graphObstacleOptimized = true;
00839                                         }
00840                                 }
00841                         }
00842                 }
00843                 int countObstacles = 0;
00844                 int countGrounds = 0;
00845                 int previousIndexedGroundSize = assembledGroundIndex_.indexedFeatures();
00846                 int previousIndexedObstacleSize = assembledObstacleIndex_.indexedFeatures();
00847                 if(graphGroundOptimized || graphGroundChanged)
00848                 {
00849                         int previousSize = assembledGround_->size();
00850                         assembledGround_->clear();
00851                         assembledGround_->reserve(previousSize);
00852                         assembledGroundPoses_.clear();
00853                         assembledGroundIndex_.release();
00854                 }
00855                 if(graphObstacleOptimized || graphObstacleChanged )
00856                 {
00857                         int previousSize = assembledObstacles_->size();
00858                         assembledObstacles_->clear();
00859                         assembledObstacles_->reserve(previousSize);
00860                         assembledObstaclePoses_.clear();
00861                         assembledObstacleIndex_.release();
00862                 }
00863 
00864                 if(graphGroundOptimized || graphObstacleOptimized)
00865                 {
00866                         ROS_INFO("Graph has changed, updating clouds...");
00867                         UTimer t;
00868                         cv::Mat tmpGroundPts;
00869                         cv::Mat tmpObstaclePts;
00870                         for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00871                         {
00872                                 if(iter->first > 0)
00873                                 {
00874                                         if(updateGround  &&
00875                                            (graphGroundOptimized || assembledGroundPoses_.find(iter->first) == assembledGroundPoses_.end()))
00876                                         {
00877                                                 assembledGroundPoses_.insert(*iter);
00878                                                 std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr >::iterator kter=groundClouds_.find(iter->first);
00879                                                 if(kter != groundClouds_.end() && kter->second->size())
00880                                                 {
00881                                                         pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed = util3d::transformPointCloud(kter->second, iter->second);
00882                                                         *assembledGround_+=*transformed;
00883                                                         if(cloudSubtractFiltering_)
00884                                                         {
00885                                                                 for(unsigned int i=0; i<transformed->size(); ++i)
00886                                                                 {
00887                                                                         if(tmpGroundPts.empty())
00888                                                                         {
00889                                                                                 tmpGroundPts = (cv::Mat_<float>(1, 3) << transformed->at(i).x, transformed->at(i).y, transformed->at(i).z);
00890                                                                                 tmpGroundPts.reserve(previousIndexedGroundSize>0?previousIndexedGroundSize:100);
00891                                                                         }
00892                                                                         else
00893                                                                         {
00894                                                                                 cv::Mat pt = (cv::Mat_<float>(1, 3) << transformed->at(i).x, transformed->at(i).y, transformed->at(i).z);
00895                                                                                 tmpGroundPts.push_back(pt);
00896                                                                         }
00897                                                                 }
00898                                                         }
00899                                                         ++countGrounds;
00900                                                 }
00901                                         }
00902                                         if(updateObstacles  &&
00903                                            (graphObstacleOptimized || assembledObstaclePoses_.find(iter->first) == assembledObstaclePoses_.end()))
00904                                         {
00905                                                 assembledObstaclePoses_.insert(*iter);
00906                                                 std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr >::iterator kter=obstacleClouds_.find(iter->first);
00907                                                 if(kter != obstacleClouds_.end() && kter->second->size())
00908                                                 {
00909                                                         pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed = util3d::transformPointCloud(kter->second, iter->second);
00910                                                         *assembledObstacles_+=*transformed;
00911                                                         if(cloudSubtractFiltering_)
00912                                                         {
00913                                                                 for(unsigned int i=0; i<transformed->size(); ++i)
00914                                                                 {
00915                                                                         if(tmpObstaclePts.empty())
00916                                                                         {
00917                                                                                 tmpObstaclePts = (cv::Mat_<float>(1, 3) << transformed->at(i).x, transformed->at(i).y, transformed->at(i).z);
00918                                                                                 tmpObstaclePts.reserve(previousIndexedObstacleSize>0?previousIndexedObstacleSize:100);
00919                                                                         }
00920                                                                         else
00921                                                                         {
00922                                                                                 cv::Mat pt = (cv::Mat_<float>(1, 3) << transformed->at(i).x, transformed->at(i).y, transformed->at(i).z);
00923                                                                                 tmpObstaclePts.push_back(pt);
00924                                                                         }
00925                                                                 }
00926                                                         }
00927                                                         ++countObstacles;
00928                                                 }
00929                                         }
00930                                 }
00931                         }
00932                         double addingPointsTime = t.ticks();
00933 
00934                         if(graphGroundOptimized && !tmpGroundPts.empty())
00935                         {
00936                                 assembledGroundIndex_.buildKDTreeSingleIndex(tmpGroundPts, 15);
00937                         }
00938                         if(graphObstacleOptimized && !tmpObstaclePts.empty())
00939                         {
00940                                 assembledObstacleIndex_.buildKDTreeSingleIndex(tmpObstaclePts, 15);
00941                         }
00942                         double indexingTime = t.ticks();
00943                         UINFO("Graph optimized! Time recreating clouds (%d ground, %d obstacles) = %f s (indexing %fs)", countGrounds, countObstacles, addingPointsTime+indexingTime, indexingTime);
00944                 }
00945                 else if(graphGroundChanged || graphObstacleChanged)
00946                 {
00947                         UWARN("Graph has changed! The whole cloud is regenerated.");
00948                 }
00949 
00950                 for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00951                 {
00952                         std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator jter = gridMaps_.find(iter->first);
00953                         if(updateGround  && assembledGroundPoses_.find(iter->first) == assembledGroundPoses_.end())
00954                         {
00955                                 if(iter->first > 0)
00956                                 {
00957                                         assembledGroundPoses_.insert(*iter);
00958                                 }
00959                                 if(jter!=gridMaps_.end() && jter->second.first.first.cols)
00960                                 {
00961                                         pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed = util3d::laserScanToPointCloudRGB(LaserScan::backwardCompatibility(jter->second.first.first), iter->second, 0, 255, 0);
00962                                         pcl::PointCloud<pcl::PointXYZRGB>::Ptr subtractedCloud = transformed;
00963                                         if(cloudSubtractFiltering_)
00964                                         {
00965                                                 if(assembledGroundIndex_.indexedFeatures())
00966                                                 {
00967                                                         subtractedCloud = subtractFiltering(transformed, assembledGroundIndex_, occupancyGrid_->getCellSize(), cloudSubtractFilteringMinNeighbors_);
00968                                                 }
00969                                                 if(subtractedCloud->size())
00970                                                 {
00971                                                         UDEBUG("Adding ground %d pts=%d/%d (index=%d)", iter->first, subtractedCloud->size(), transformed->size(), assembledGroundIndex_.indexedFeatures());
00972                                                         cv::Mat pts(subtractedCloud->size(), 3, CV_32FC1);
00973                                                         for(unsigned int i=0; i<subtractedCloud->size(); ++i)
00974                                                         {
00975                                                                 pts.at<float>(i, 0) = subtractedCloud->at(i).x;
00976                                                                 pts.at<float>(i, 1) = subtractedCloud->at(i).y;
00977                                                                 pts.at<float>(i, 2) = subtractedCloud->at(i).z;
00978                                                         }
00979                                                         if(!assembledGroundIndex_.isBuilt())
00980                                                         {
00981                                                                 assembledGroundIndex_.buildKDTreeSingleIndex(pts, 15);
00982                                                         }
00983                                                         else
00984                                                         {
00985                                                                 assembledGroundIndex_.addPoints(pts);
00986                                                         }
00987                                                 }
00988                                         }
00989                                         if(iter->first>0)
00990                                         {
00991                                                 groundClouds_.insert(std::make_pair(iter->first, util3d::transformPointCloud(subtractedCloud, iter->second.inverse())));
00992                                         }
00993                                         if(subtractedCloud->size())
00994                                         {
00995                                                 *assembledGround_+=*subtractedCloud;
00996                                         }
00997                                         ++countGrounds;
00998                                 }
00999                         }
01000                         if(updateObstacles  && assembledObstaclePoses_.find(iter->first) == assembledObstaclePoses_.end())
01001                         {
01002                                 if(iter->first > 0)
01003                                 {
01004                                         assembledObstaclePoses_.insert(*iter);
01005                                 }
01006                                 if(jter!=gridMaps_.end() && jter->second.first.second.cols)
01007                                 {
01008                                         pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed = util3d::laserScanToPointCloudRGB(LaserScan::backwardCompatibility(jter->second.first.second), iter->second, 255, 0, 0);
01009                                         pcl::PointCloud<pcl::PointXYZRGB>::Ptr subtractedCloud = transformed;
01010                                         if(cloudSubtractFiltering_)
01011                                         {
01012                                                 if(assembledObstacleIndex_.indexedFeatures())
01013                                                 {
01014                                                         subtractedCloud = subtractFiltering(transformed, assembledObstacleIndex_, occupancyGrid_->getCellSize(), cloudSubtractFilteringMinNeighbors_);
01015                                                 }
01016                                                 if(subtractedCloud->size())
01017                                                 {
01018                                                         UDEBUG("Adding obstacle %d pts=%d/%d (index=%d)", iter->first, subtractedCloud->size(), transformed->size(), assembledObstacleIndex_.indexedFeatures());
01019                                                         cv::Mat pts(subtractedCloud->size(), 3, CV_32FC1);
01020                                                         for(unsigned int i=0; i<subtractedCloud->size(); ++i)
01021                                                         {
01022                                                                 pts.at<float>(i, 0) = subtractedCloud->at(i).x;
01023                                                                 pts.at<float>(i, 1) = subtractedCloud->at(i).y;
01024                                                                 pts.at<float>(i, 2) = subtractedCloud->at(i).z;
01025                                                         }
01026                                                         if(!assembledObstacleIndex_.isBuilt())
01027                                                         {
01028                                                                 assembledObstacleIndex_.buildKDTreeSingleIndex(pts, 15);
01029                                                         }
01030                                                         else
01031                                                         {
01032                                                                 assembledObstacleIndex_.addPoints(pts);
01033                                                         }
01034                                                 }
01035                                         }
01036                                         if(iter->first>0)
01037                                         {
01038                                                 obstacleClouds_.insert(std::make_pair(iter->first, util3d::transformPointCloud(subtractedCloud, iter->second.inverse())));
01039                                         }
01040                                         if(subtractedCloud->size())
01041                                         {
01042                                                 *assembledObstacles_+=*subtractedCloud;
01043                                         }
01044                                         ++countObstacles;
01045                                 }
01046                         }
01047                 }
01048 
01049                 if(cloudOutputVoxelized_)
01050                 {
01051                         UASSERT(occupancyGrid_->getCellSize() > 0.0);
01052                         if(countGrounds && assembledGround_->size())
01053                         {
01054                                 assembledGround_ = util3d::voxelize(assembledGround_, occupancyGrid_->getCellSize());
01055                         }
01056                         if(countObstacles && assembledObstacles_->size())
01057                         {
01058                                 assembledObstacles_ = util3d::voxelize(assembledObstacles_, occupancyGrid_->getCellSize());
01059                         }
01060                 }
01061 
01062                 ROS_INFO("Assembled %d obstacle and %d ground clouds (%d points, %fs)",
01063                                 countObstacles, countGrounds, (int)(assembledGround_->size() + assembledObstacles_->size()), time.ticks());
01064 
01065                 if(cloudGroundPub_.getNumSubscribers())
01066                 {
01067                         sensor_msgs::PointCloud2::Ptr cloudMsg(new sensor_msgs::PointCloud2);
01068                         pcl::toROSMsg(*assembledGround_, *cloudMsg);
01069                         cloudMsg->header.stamp = stamp;
01070                         cloudMsg->header.frame_id = mapFrameId;
01071                         cloudGroundPub_.publish(cloudMsg);
01072                 }
01073                 if(cloudObstaclesPub_.getNumSubscribers())
01074                 {
01075                         sensor_msgs::PointCloud2::Ptr cloudMsg(new sensor_msgs::PointCloud2);
01076                         pcl::toROSMsg(*assembledObstacles_, *cloudMsg);
01077                         cloudMsg->header.stamp = stamp;
01078                         cloudMsg->header.frame_id = mapFrameId;
01079                         cloudObstaclesPub_.publish(cloudMsg);
01080                 }
01081                 if(cloudMapPub_.getNumSubscribers() || scanMapPub_.getNumSubscribers())
01082                 {
01083                         pcl::PointCloud<pcl::PointXYZRGB> cloud = *assembledObstacles_ + *assembledGround_;
01084                         sensor_msgs::PointCloud2::Ptr cloudMsg(new sensor_msgs::PointCloud2);
01085                         pcl::toROSMsg(cloud, *cloudMsg);
01086                         cloudMsg->header.stamp = stamp;
01087                         cloudMsg->header.frame_id = mapFrameId;
01088 
01089                         if(cloudMapPub_.getNumSubscribers())
01090                         {
01091                                 cloudMapPub_.publish(cloudMsg);
01092                         }
01093                         if(scanMapPub_.getNumSubscribers())
01094                         {
01095                                 scanMapPub_.publish(cloudMsg);
01096                         }
01097                 }
01098         }
01099         else if(mapCacheCleanup_)
01100         {
01101                 assembledGround_->clear();
01102                 assembledObstacles_->clear();
01103                 assembledGroundPoses_.clear();
01104                 assembledObstaclePoses_.clear();
01105                 assembledGroundIndex_.release();
01106                 assembledObstacleIndex_.release();
01107                 groundClouds_.clear();
01108                 obstacleClouds_.clear();
01109         }
01110 
01111 #ifdef WITH_OCTOMAP_MSGS
01112 #ifdef RTABMAP_OCTOMAP
01113         if(octoMapPubBin_.getNumSubscribers() ||
01114                         octoMapPubFull_.getNumSubscribers() ||
01115                         octoMapCloud_.getNumSubscribers() ||
01116                         octoMapObstacleCloud_.getNumSubscribers() ||
01117                         octoMapGroundCloud_.getNumSubscribers() ||
01118                         octoMapEmptySpace_.getNumSubscribers() ||
01119                         octoMapProj_.getNumSubscribers())
01120         {
01121                 if(octoMapPubBin_.getNumSubscribers())
01122                 {
01123                         octomap_msgs::Octomap msg;
01124                         octomap_msgs::binaryMapToMsg(*octomap_->octree(), msg);
01125                         msg.header.frame_id = mapFrameId;
01126                         msg.header.stamp = stamp;
01127                         octoMapPubBin_.publish(msg);
01128                 }
01129                 if(octoMapPubFull_.getNumSubscribers())
01130                 {
01131                         octomap_msgs::Octomap msg;
01132                         octomap_msgs::fullMapToMsg(*octomap_->octree(), msg);
01133                         msg.header.frame_id = mapFrameId;
01134                         msg.header.stamp = stamp;
01135                         octoMapPubFull_.publish(msg);
01136                 }
01137                 if(octoMapCloud_.getNumSubscribers() ||
01138                         octoMapObstacleCloud_.getNumSubscribers() ||
01139                         octoMapGroundCloud_.getNumSubscribers() ||
01140                         octoMapEmptySpace_.getNumSubscribers())
01141                 {
01142                         sensor_msgs::PointCloud2 msg;
01143                         pcl::IndicesPtr obstacleIndices(new std::vector<int>);
01144                         pcl::IndicesPtr emptyIndices(new std::vector<int>);
01145                         pcl::IndicesPtr groundIndices(new std::vector<int>);
01146                         pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud = octomap_->createCloud(octomapTreeDepth_, obstacleIndices.get(), emptyIndices.get(), groundIndices.get());
01147 
01148                         if(octoMapCloud_.getNumSubscribers())
01149                         {
01150                                 pcl::PointCloud<pcl::PointXYZRGB> cloudOccupiedSpace;
01151                                 pcl::IndicesPtr indices = util3d::concatenate(obstacleIndices, groundIndices);
01152                                 pcl::copyPointCloud(*cloud, *indices, cloudOccupiedSpace);
01153                                 pcl::toROSMsg(cloudOccupiedSpace, msg);
01154                                 msg.header.frame_id = mapFrameId;
01155                                 msg.header.stamp = stamp;
01156                                 octoMapCloud_.publish(msg);
01157                         }
01158                         if(octoMapObstacleCloud_.getNumSubscribers())
01159                         {
01160                                 pcl::PointCloud<pcl::PointXYZRGB> cloudObstacles;
01161                                 pcl::copyPointCloud(*cloud, *obstacleIndices, cloudObstacles);
01162                                 pcl::toROSMsg(cloudObstacles, msg);
01163                                 msg.header.frame_id = mapFrameId;
01164                                 msg.header.stamp = stamp;
01165                                 octoMapObstacleCloud_.publish(msg);
01166                         }
01167                         if(octoMapGroundCloud_.getNumSubscribers())
01168                         {
01169                                 pcl::PointCloud<pcl::PointXYZRGB> cloudGround;
01170                                 pcl::copyPointCloud(*cloud, *groundIndices, cloudGround);
01171                                 pcl::toROSMsg(cloudGround, msg);
01172                                 msg.header.frame_id = mapFrameId;
01173                                 msg.header.stamp = stamp;
01174                                 octoMapGroundCloud_.publish(msg);
01175                         }
01176                         if(octoMapEmptySpace_.getNumSubscribers())
01177                         {
01178                                 pcl::PointCloud<pcl::PointXYZRGB> cloudEmptySpace;
01179                                 pcl::copyPointCloud(*cloud, *emptyIndices, cloudEmptySpace);
01180                                 pcl::toROSMsg(cloudEmptySpace, msg);
01181                                 msg.header.frame_id = mapFrameId;
01182                                 msg.header.stamp = stamp;
01183                                 octoMapEmptySpace_.publish(msg);
01184                         }
01185                 }
01186                 if(octoMapProj_.getNumSubscribers())
01187                 {
01188                         // create the projection map
01189                         float xMin=0.0f, yMin=0.0f, gridCellSize = 0.05f;
01190                         cv::Mat pixels = octomap_->createProjectionMap(xMin, yMin, gridCellSize, occupancyGrid_->getMinMapSize(), octomapTreeDepth_);
01191 
01192                         if(!pixels.empty())
01193                         {
01194                                 //init
01195                                 nav_msgs::OccupancyGrid map;
01196                                 map.info.resolution = gridCellSize;
01197                                 map.info.origin.position.x = 0.0;
01198                                 map.info.origin.position.y = 0.0;
01199                                 map.info.origin.position.z = 0.0;
01200                                 map.info.origin.orientation.x = 0.0;
01201                                 map.info.origin.orientation.y = 0.0;
01202                                 map.info.origin.orientation.z = 0.0;
01203                                 map.info.origin.orientation.w = 1.0;
01204 
01205                                 map.info.width = pixels.cols;
01206                                 map.info.height = pixels.rows;
01207                                 map.info.origin.position.x = xMin;
01208                                 map.info.origin.position.y = yMin;
01209                                 map.data.resize(map.info.width * map.info.height);
01210 
01211                                 memcpy(map.data.data(), pixels.data, map.info.width * map.info.height);
01212 
01213                                 map.header.frame_id = mapFrameId;
01214                                 map.header.stamp = stamp;
01215 
01216                                 octoMapProj_.publish(map);
01217                         }
01218                         else if(poses.size())
01219                         {
01220                                 ROS_WARN("Octomap projection map is empty! (poses=%d octomap nodes=%d). "
01221                                                 "Make sure you activated \"%s\" and \"%s\" to true. "
01222                                                 "See \"$ rosrun rtabmap_ros rtabmap --params | grep Grid\" for more info.",
01223                                                 (int)poses.size(), (int)octomap_->octree()->size(),
01224                                                 Parameters::kGrid3D().c_str(), Parameters::kGridFromDepth().c_str());
01225                         }
01226                 }
01227         }
01228         else if(mapCacheCleanup_)
01229         {
01230                 octomap_->clear();
01231         }
01232 #endif
01233 #endif
01234 
01235         if(gridMapPub_.getNumSubscribers() || projMapPub_.getNumSubscribers() || gridProbMapPub_.getNumSubscribers())
01236         {
01237                 if(projMapPub_.getNumSubscribers())
01238                 {
01239                         if(parameters_.find(Parameters::kGridFromDepth()) != parameters_.end() &&
01240                                 !uStr2Bool(parameters_.at(Parameters::kGridFromDepth())))
01241                         {
01242                                 ROS_WARN("/proj_map topic is deprecated! Subscribe to /grid_map topic "
01243                                                 "instead with <param name=\"%s\" type=\"string\" value=\"true\"/>. "
01244                                                 "Do \"$ rosrun rtabmap_ros rtabmap --params | grep Grid\" to see "
01245                                                 "all occupancy grid parameters.",
01246                                                 Parameters::kGridFromDepth().c_str());
01247                         }
01248                         else
01249                         {
01250                                 ROS_WARN("/proj_map topic is deprecated! Subscribe to /grid_map topic instead.");
01251                         }
01252                 }
01253 
01254                 if(gridProbMapPub_.getNumSubscribers())
01255                 {
01256                         // create the grid map
01257                         float xMin=0.0f, yMin=0.0f, gridCellSize = 0.05f;
01258                         cv::Mat pixels = this->getGridProbMap(xMin, yMin, gridCellSize);
01259                         if(!pixels.empty())
01260                         {
01261                                 //init
01262                                 nav_msgs::OccupancyGrid map;
01263                                 map.info.resolution = gridCellSize;
01264                                 map.info.origin.position.x = 0.0;
01265                                 map.info.origin.position.y = 0.0;
01266                                 map.info.origin.position.z = 0.0;
01267                                 map.info.origin.orientation.x = 0.0;
01268                                 map.info.origin.orientation.y = 0.0;
01269                                 map.info.origin.orientation.z = 0.0;
01270                                 map.info.origin.orientation.w = 1.0;
01271 
01272                                 map.info.width = pixels.cols;
01273                                 map.info.height = pixels.rows;
01274                                 map.info.origin.position.x = xMin;
01275                                 map.info.origin.position.y = yMin;
01276                                 map.data.resize(map.info.width * map.info.height);
01277 
01278                                 memcpy(map.data.data(), pixels.data, map.info.width * map.info.height);
01279 
01280                                 map.header.frame_id = mapFrameId;
01281                                 map.header.stamp = stamp;
01282 
01283                                 if(gridProbMapPub_.getNumSubscribers())
01284                                 {
01285                                         gridProbMapPub_.publish(map);
01286                                 }
01287                         }
01288                         else if(poses.size())
01289                         {
01290                                 ROS_WARN("Grid map is empty! (local maps=%d)", (int)gridMaps_.size());
01291                         }
01292                 }
01293                 if(gridMapPub_.getNumSubscribers() || projMapPub_.getNumSubscribers())
01294                 {
01295                         // create the grid map
01296                         float xMin=0.0f, yMin=0.0f, gridCellSize = 0.05f;
01297                         cv::Mat pixels = this->getGridMap(xMin, yMin, gridCellSize);
01298 
01299                         if(!pixels.empty())
01300                         {
01301                                 //init
01302                                 nav_msgs::OccupancyGrid map;
01303                                 map.info.resolution = gridCellSize;
01304                                 map.info.origin.position.x = 0.0;
01305                                 map.info.origin.position.y = 0.0;
01306                                 map.info.origin.position.z = 0.0;
01307                                 map.info.origin.orientation.x = 0.0;
01308                                 map.info.origin.orientation.y = 0.0;
01309                                 map.info.origin.orientation.z = 0.0;
01310                                 map.info.origin.orientation.w = 1.0;
01311 
01312                                 map.info.width = pixels.cols;
01313                                 map.info.height = pixels.rows;
01314                                 map.info.origin.position.x = xMin;
01315                                 map.info.origin.position.y = yMin;
01316                                 map.data.resize(map.info.width * map.info.height);
01317 
01318                                 memcpy(map.data.data(), pixels.data, map.info.width * map.info.height);
01319 
01320                                 map.header.frame_id = mapFrameId;
01321                                 map.header.stamp = stamp;
01322 
01323                                 if(gridMapPub_.getNumSubscribers())
01324                                 {
01325                                         gridMapPub_.publish(map);
01326                                 }
01327                                 if(projMapPub_.getNumSubscribers())
01328                                 {
01329                                         projMapPub_.publish(map);
01330                                 }
01331                         }
01332                         else if(poses.size())
01333                         {
01334                                 ROS_WARN("Grid map is empty! (local maps=%d)", (int)gridMaps_.size());
01335                         }
01336                 }
01337         }
01338 
01339         if(!this->hasSubscribers() && mapCacheCleanup_)
01340         {
01341                 gridMaps_.clear();
01342                 gridMapsViewpoints_.clear();
01343         }
01344 }
01345 
01346 cv::Mat MapsManager::getGridMap(
01347                 float & xMin,
01348                 float & yMin,
01349                 float & gridCellSize)
01350 {
01351         gridCellSize = occupancyGrid_->getCellSize();
01352         return occupancyGrid_->getMap(xMin, yMin);
01353 }
01354 
01355 cv::Mat MapsManager::getGridProbMap(
01356                 float & xMin,
01357                 float & yMin,
01358                 float & gridCellSize)
01359 {
01360         gridCellSize = occupancyGrid_->getCellSize();
01361         return occupancyGrid_->getProbMap(xMin, yMin);
01362 }
01363 


rtabmap_ros
Author(s): Mathieu Labbe
autogenerated on Thu Jun 6 2019 21:30:49