00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #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),
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
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
00126
00127
00128 bool latch = true;
00129 pnh.param("latch", latch, latch);
00130
00131
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
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;
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
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
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
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
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
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
00440 if(updateGridCache)
00441 {
00442
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
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
00548
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
00578
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
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;
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
00777 if(cloudMapPub_.getNumSubscribers() ||
00778 scanMapPub_.getNumSubscribers() ||
00779 cloudObstaclesPub_.getNumSubscribers() ||
00780 cloudGroundPub_.getNumSubscribers())
00781 {
00782
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
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
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
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
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
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
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
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