Removed grid_map_assembler, map_assembler is now using MapsManager (now use same published topics and mapping parameters than rtabmap), added all optimization parameters to map_optimizer (g2o and GTSAM can be selected)

This commit is contained in:
matlabbe
2015-10-31 15:20:57 -04:00
parent cb0ebecd5f
commit 1dfa4e7f95
7 changed files with 212 additions and 491 deletions
+2 -6
View File
@@ -145,6 +145,7 @@ SET(rtabmap_ros_lib_src
src/rviz/MapGraphDisplay.cpp src/rviz/MapGraphDisplay.cpp
src/rviz/InfoDisplay.cpp src/rviz/InfoDisplay.cpp
src/rviz/OrbitOrientedViewController.cpp src/rviz/OrbitOrientedViewController.cpp
src/MapsManager.cpp
${MOC_FILES} ${MOC_FILES}
) )
@@ -186,7 +187,7 @@ SET(Libraries
add_definitions(-DWITH_OCTOMAP) add_definitions(-DWITH_OCTOMAP)
ENDIF(octomap_ros_FOUND) ENDIF(octomap_ros_FOUND)
add_executable(rtabmap src/CoreNode.cpp src/CoreWrapper.cpp src/MapsManager.cpp) add_executable(rtabmap src/CoreNode.cpp src/CoreWrapper.cpp)
target_link_libraries(rtabmap rtabmap_ros ${Libraries}) target_link_libraries(rtabmap rtabmap_ros ${Libraries})
add_executable(rgbd_odometry src/RGBDOdometryNode.cpp) add_executable(rgbd_odometry src/RGBDOdometryNode.cpp)
@@ -201,9 +202,6 @@ target_link_libraries(map_optimizer rtabmap_ros ${Libraries})
add_executable(map_assembler src/MapAssemblerNode.cpp) add_executable(map_assembler src/MapAssemblerNode.cpp)
target_link_libraries(map_assembler rtabmap_ros ${Libraries}) target_link_libraries(map_assembler rtabmap_ros ${Libraries})
add_executable(grid_map_assembler src/GridMapAssemblerNode.cpp)
target_link_libraries(grid_map_assembler rtabmap_ros ${Libraries})
add_executable(camera src/CameraNode.cpp) add_executable(camera src/CameraNode.cpp)
add_dependencies(camera ${${PROJECT_NAME}_EXPORTED_TARGETS}) add_dependencies(camera ${${PROJECT_NAME}_EXPORTED_TARGETS})
target_link_libraries(camera ${Libraries}) target_link_libraries(camera ${Libraries})
@@ -244,7 +242,6 @@ install(TARGETS
rgbd_odometry rgbd_odometry
stereo_odometry stereo_odometry
map_assembler map_assembler
grid_map_assembler
map_optimizer map_optimizer
data_player data_player
camera camera
@@ -259,7 +256,6 @@ install(TARGETS
rgbd_odometry rgbd_odometry
stereo_odometry stereo_odometry
map_assembler map_assembler
grid_map_assembler
map_optimizer map_optimizer
data_player data_player
camera camera
+8 -3
View File
@@ -89,6 +89,7 @@ CoreWrapper::CoreWrapper(bool deleteDbOnStart) :
genScan_(false), genScan_(false),
genScanMaxDepth_(4.0), genScanMaxDepth_(4.0),
mapToOdom_(rtabmap::Transform::getIdentity()), mapToOdom_(rtabmap::Transform::getIdentity()),
mapsManager_(true),
depthSync_(0), depthSync_(0),
depthScanSync_(0), depthScanSync_(0),
stereoScanSync_(0), stereoScanSync_(0),
@@ -1244,6 +1245,7 @@ void CoreWrapper::process(
false, false,
false, false,
false, false,
false,
tmpSignature); tmpSignature);
mapsManager_.publishMaps(filteredPoses, stamp, mapFrameId_); mapsManager_.publishMaps(filteredPoses, stamp, mapFrameId_);
@@ -1663,6 +1665,7 @@ bool CoreWrapper::getProjMapCallback(nav_msgs::GetMap::Request &req, nav_msgs::
rtabmap_.getMemory(), rtabmap_.getMemory(),
false, false,
true, true,
false,
false); false);
if(filteredPoses.size()) if(filteredPoses.size())
{ {
@@ -1706,7 +1709,8 @@ bool CoreWrapper::getGridMapCallback(nav_msgs::GetMap::Request &req, nav_msgs::
rtabmap_.getMemory(), rtabmap_.getMemory(),
false, false,
false, false,
true); true,
false);
if(filteredPoses.size()) if(filteredPoses.size())
{ {
// create the grid map // create the grid map
@@ -1818,6 +1822,7 @@ bool CoreWrapper::publishMapCallback(rtabmap_ros::PublishMap::Request& req, rtab
false, false,
false, false,
false, false,
false,
signatures); signatures);
} }
else else
@@ -2282,7 +2287,7 @@ bool CoreWrapper::octomapBinaryCallback(
res.map.header.stamp = ros::Time::now(); res.map.header.stamp = ros::Time::now();
std::map<int, Transform> poses = rtabmap_.getLocalOptimizedPoses(); std::map<int, Transform> poses = rtabmap_.getLocalOptimizedPoses();
poses = mapsManager_.updateMapCaches(poses, rtabmap_.getMemory(), true, false, false); poses = mapsManager_.updateMapCaches(poses, rtabmap_.getMemory(), true, false, false, false);
octomap::OcTree * octree = mapsManager_.createOctomap(poses); octomap::OcTree * octree = mapsManager_.createOctomap(poses);
bool success = octree != 0 && octree->size() && octomap_msgs::binaryMapToMsg(*octree, res.map); bool success = octree != 0 && octree->size() && octomap_msgs::binaryMapToMsg(*octree, res.map);
@@ -2302,7 +2307,7 @@ bool CoreWrapper::octomapFullCallback(
res.map.header.stamp = ros::Time::now(); res.map.header.stamp = ros::Time::now();
std::map<int, Transform> poses = rtabmap_.getLocalOptimizedPoses(); std::map<int, Transform> poses = rtabmap_.getLocalOptimizedPoses();
poses = mapsManager_.updateMapCaches(poses, rtabmap_.getMemory(), true, false, false); poses = mapsManager_.updateMapCaches(poses, rtabmap_.getMemory(), true, false, false, false);
octomap::OcTree * octree = mapsManager_.createOctomap(poses); octomap::OcTree * octree = mapsManager_.createOctomap(poses);
bool success = octree != 0 && octree->size() && octomap_msgs::fullMapToMsg(*octree, res.map); bool success = octree != 0 && octree->size() && octomap_msgs::fullMapToMsg(*octree, res.map);
-199
View File
@@ -1,199 +0,0 @@
/*
Copyright (c) 2010-2014, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <ros/ros.h>
#include "rtabmap_ros/MapData.h"
#include "rtabmap_ros/MsgConversion.h"
#include <rtabmap/core/util3d_mapping.h>
#include <rtabmap/core/Graph.h>
#include <rtabmap/core/Compression.h>
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UTimer.h>
#include <nav_msgs/OccupancyGrid.h>
#include <nav_msgs/GetMap.h>
#include <std_srvs/Empty.h>
#include <pcl_ros/transforms.h>
#include <pcl_conversions/pcl_conversions.h>
using namespace rtabmap;
class GridMapAssembler
{
public:
GridMapAssembler() :
gridCellSize_(0.05), // meters
mapSize_(0), // meters
eroded_(false),
filterRadius_(0.5),
filterAngle_(30.0) // degrees
{
ros::NodeHandle pnh("~");
pnh.param("cell_size", gridCellSize_, gridCellSize_); // m
pnh.param("map_size", mapSize_, mapSize_); // m
pnh.param("filter_radius", filterRadius_, filterRadius_);
pnh.param("filter_angle", filterAngle_, filterAngle_);
pnh.param("eroded", eroded_, eroded_);
UASSERT(gridCellSize_ > 0.0);
UASSERT(mapSize_ >= 0.0);
ros::NodeHandle nh;
mapDataTopic_ = nh.subscribe("mapData", 1, &GridMapAssembler::mapDataReceivedCallback, this);
gridMap_ = nh.advertise<nav_msgs::OccupancyGrid>("grid_map", 1);
//private service
getMapService_ = pnh.advertiseService("get_map", &GridMapAssembler::getGridMapCallback, this);
resetService_ = pnh.advertiseService("reset", &GridMapAssembler::reset, this);
}
~GridMapAssembler()
{
}
void mapDataReceivedCallback(const rtabmap_ros::MapDataConstPtr & msg)
{
UTimer timer;
for(unsigned int i=0; i<msg->nodes.size(); ++i)
{
if(!uContains(gridMaps_, msg->nodes[i].id) && msg->nodes[i].laserScan.size())
{
cv::Mat laserScan = rtabmap::uncompressData(msg->nodes[i].laserScan);
if(!laserScan.empty())
{
cv::Mat ground, obstacles;
util3d::occupancy2DFromLaserScan(laserScan, ground, obstacles, gridCellSize_);
if(!ground.empty() || !obstacles.empty())
{
gridMaps_.insert(std::make_pair(msg->nodes[i].id, std::make_pair(ground, obstacles)));
}
}
}
}
std::map<int, Transform> poses;
UASSERT(msg->graph.posesId.size() == msg->graph.poses.size());
for(unsigned int i=0; i<msg->graph.posesId.size(); ++i)
{
poses.insert(std::make_pair(msg->graph.posesId[i], rtabmap_ros::transformFromPoseMsg(msg->graph.poses[i])));
}
if(filterRadius_ > 0.0 && filterAngle_ > 0.0)
{
poses = rtabmap::graph::radiusPosesFiltering(poses, filterRadius_, filterAngle_*CV_PI/180.0);
}
if(gridMap_.getNumSubscribers())
{
// create the map
float xMin=0.0f, yMin=0.0f;
//cv::Mat pixels = util3d::create2DMap(poses, scans_, gridCellSize_, gridUnknownSpaceFilled_, xMin, yMin, mapSize_);
cv::Mat pixels = util3d::create2DMapFromOccupancyLocalMaps(
poses,
gridMaps_,
gridCellSize_,
xMin, yMin,
mapSize_,
eroded_);
if(!pixels.empty())
{
//init
map_.info.resolution = gridCellSize_;
map_.info.origin.position.x = 0.0;
map_.info.origin.position.y = 0.0;
map_.info.origin.position.z = 0.0;
map_.info.origin.orientation.x = 0.0;
map_.info.origin.orientation.y = 0.0;
map_.info.origin.orientation.z = 0.0;
map_.info.origin.orientation.w = 1.0;
map_.info.width = pixels.cols;
map_.info.height = pixels.rows;
map_.info.origin.position.x = xMin;
map_.info.origin.position.y = yMin;
map_.data.resize(map_.info.width * map_.info.height);
memcpy(map_.data.data(), pixels.data, map_.info.width * map_.info.height);
map_.header.frame_id = msg->header.frame_id;
map_.header.stamp = ros::Time::now();
gridMap_.publish(map_);
ROS_INFO("Grid Map published [%d,%d] (%fs)", pixels.cols, pixels.rows, timer.ticks());
}
}
}
bool getGridMapCallback(nav_msgs::GetMap::Request &req, nav_msgs::GetMap::Response &res)
{
if(map_.data.size())
{
res.map = map_;
return true;
}
return false;
}
bool reset(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{
ROS_INFO("grid_map_assembler: reset!");
gridMaps_.clear();
map_ = nav_msgs::OccupancyGrid();
return true;
}
private:
double gridCellSize_;
double mapSize_;
bool eroded_;
double filterRadius_;
double filterAngle_;
ros::Subscriber mapDataTopic_;
ros::Publisher gridMap_;
ros::ServiceServer getMapService_;
ros::ServiceServer resetService_;
std::map<int, std::pair<cv::Mat, cv::Mat> > gridMaps_; //<ground,obstacles>
nav_msgs::OccupancyGrid map_;
};
int main(int argc, char** argv)
{
ros::init(argc, argv, "grid_map_assembler");
GridMapAssembler assembler;
ros::spin();
return 0;
}
+32 -251
View File
@@ -28,6 +28,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <ros/ros.h> #include <ros/ros.h>
#include "rtabmap_ros/MapData.h" #include "rtabmap_ros/MapData.h"
#include "rtabmap_ros/MsgConversion.h" #include "rtabmap_ros/MsgConversion.h"
#include "MapsManager.h"
#include <rtabmap/core/util3d_transforms.h> #include <rtabmap/core/util3d_transforms.h>
#include <rtabmap/core/util3d.h> #include <rtabmap/core/util3d.h>
#include <rtabmap/core/util3d_filtering.h> #include <rtabmap/core/util3d_filtering.h>
@@ -49,54 +50,13 @@ class MapAssembler
public: public:
MapAssembler() : MapAssembler() :
cloudDecimation_(4), mapsManager_(false)
cloudMaxDepth_(4.0),
cloudVoxelSize_(0.02),
scanVoxelSize_(0.01),
nodeFilteringAngle_(30), // degrees
nodeFilteringRadius_(0.5),
noiseFilterRadius_(0.0),
noiseFilterMinNeighbors_(5),
computeOccupancyGrid_(false),
gridCellSize_(0.05),
groundMaxAngle_(M_PI_4),
clusterMinSize_(20),
maxHeight_(0),
occupancyMapSize_(0.0)
{ {
ros::NodeHandle pnh("~"); ros::NodeHandle pnh("~");
pnh.param("cloud_decimation", cloudDecimation_, cloudDecimation_);
pnh.param("cloud_max_depth", cloudMaxDepth_, cloudMaxDepth_);
pnh.param("cloud_voxel_size", cloudVoxelSize_, cloudVoxelSize_);
pnh.param("scan_voxel_size", scanVoxelSize_, scanVoxelSize_);
pnh.param("filter_radius", nodeFilteringRadius_, nodeFilteringRadius_);
pnh.param("filter_angle", nodeFilteringAngle_, nodeFilteringAngle_);
pnh.param("noise_filter_radius", noiseFilterRadius_, noiseFilterRadius_);
pnh.param("noise_filter_min_neighbors", noiseFilterMinNeighbors_, noiseFilterMinNeighbors_);
pnh.param("occupancy_grid", computeOccupancyGrid_, computeOccupancyGrid_);
pnh.param("occupancy_cell_size", gridCellSize_, gridCellSize_);
pnh.param("occupancy_ground_max_angle", groundMaxAngle_, groundMaxAngle_);
pnh.param("occupancy_cluster_min_size", clusterMinSize_, clusterMinSize_);
pnh.param("occupancy_max_height", maxHeight_, maxHeight_);
pnh.param("occupancy_map_size", occupancyMapSize_, occupancyMapSize_);
UASSERT(gridCellSize_ > 0);
UASSERT(maxHeight_ >= 0);
UASSERT(occupancyMapSize_ >=0.0);
ros::NodeHandle nh; ros::NodeHandle nh;
mapDataTopic_ = nh.subscribe("mapData", 1, &MapAssembler::mapDataReceivedCallback, this); mapDataTopic_ = nh.subscribe("mapData", 1, &MapAssembler::mapDataReceivedCallback, this);
assembledMapClouds_ = nh.advertise<sensor_msgs::PointCloud2>("assembled_clouds", 1);
assembledMapScans_ = nh.advertise<sensor_msgs::PointCloud2>("assembled_scans", 1);
if(computeOccupancyGrid_)
{
occupancyMapPub_ = nh.advertise<nav_msgs::OccupancyGrid>("grid_projection_map", 1);
}
// private service // private service
resetService_ = pnh.advertiseService("reset", &MapAssembler::reset, this); resetService_ = pnh.advertiseService("reset", &MapAssembler::reset, this);
} }
@@ -108,239 +68,60 @@ public:
void mapDataReceivedCallback(const rtabmap_ros::MapDataConstPtr & msg) void mapDataReceivedCallback(const rtabmap_ros::MapDataConstPtr & msg)
{ {
UTimer timer; UTimer timer;
std::map<int, Transform> poses;
std::multimap<int, Link> constraints;
Transform mapOdom;
rtabmap_ros::mapGraphFromROS(msg->graph, poses, constraints, mapOdom);
for(unsigned int i=0; i<msg->nodes.size(); ++i) for(unsigned int i=0; i<msg->nodes.size(); ++i)
{ {
int id = msg->nodes[i].id; if(msg->nodes[i].image.size() ||
if(!uContains(rgbClouds_, id)) msg->nodes[i].depth.size() ||
msg->nodes[i].laserScan.size())
{ {
rtabmap::Signature s = rtabmap_ros::nodeDataFromROS(msg->nodes[i]); uInsert(nodes_, std::make_pair(msg->nodes[i].id, rtabmap_ros::nodeDataFromROS(msg->nodes[i])));
if(!s.sensorData().imageCompressed().empty() &&
!s.sensorData().depthOrRightCompressed().empty() &&
(s.sensorData().cameraModels().size() || s.sensorData().stereoCameraModel().isValid()))
{
cv::Mat image, depth;
s.sensorData().uncompressData(&image, &depth, 0);
if(!s.sensorData().imageRaw().empty() && !s.sensorData().depthOrRightRaw().empty())
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
cloud = rtabmap::util3d::cloudRGBFromSensorData(
s.sensorData(),
cloudDecimation_,
cloudMaxDepth_);
if(cloud->size() && noiseFilterRadius_ > 0.0 && noiseFilterMinNeighbors_ > 0)
{
pcl::IndicesPtr indices = rtabmap::util3d::radiusFiltering(cloud, noiseFilterRadius_, noiseFilterMinNeighbors_);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::copyPointCloud(*cloud, *indices, *tmp);
cloud = tmp;
}
if(cloud->size() && cloudVoxelSize_ > 0)
{
cloud = util3d::voxelize(cloud, cloudVoxelSize_);
}
if(cloud->size())
{
rgbClouds_.insert(std::make_pair(id, cloud));
if(computeOccupancyGrid_)
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudClipped = cloud;
if(cloudClipped->size() && maxHeight_ > 0)
{
cloudClipped = util3d::passThrough(cloudClipped, "z", std::numeric_limits<int>::min(), maxHeight_);
}
if(cloudClipped->size())
{
cloudClipped = util3d::voxelize(cloudClipped, gridCellSize_);
cv::Mat ground, obstacles;
util3d::occupancy2DFromCloud3D<pcl::PointXYZRGB>(cloudClipped, ground, obstacles, gridCellSize_, groundMaxAngle_, clusterMinSize_);
if(!ground.empty() || !obstacles.empty())
{
occupancyLocalMaps_.insert(std::make_pair(id, std::make_pair(ground, obstacles)));
} }
} }
} // create a tmp signature with latest sensory data
} if(poses.size() && nodes_.find(poses.rbegin()->first) != nodes_.end())
} {
} Signature tmpS = nodes_.at(poses.rbegin()->first);
SensorData tmpData = tmpS.sensorData();
tmpData.setId(-1);
uInsert(nodes_, std::make_pair(-1, Signature(-1, -1, 0, tmpS.getStamp(), "", tmpS.getPose(), tmpData)));
poses.insert(std::make_pair(-1, poses.rbegin()->second));
} }
if(!uContains(scans_, id) && msg->nodes[i].laserScan.size()) // Update maps
{ poses = mapsManager_.updateMapCaches(
cv::Mat laserScan = rtabmap::uncompressData(msg->nodes[i].laserScan);
if(!laserScan.empty())
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = util3d::laserScanToPointCloud(laserScan);
if(cloud->size() && scanVoxelSize_ > 0)
{
cloud = util3d::voxelize(cloud, scanVoxelSize_);
}
if(cloud->size())
{
scans_.insert(std::make_pair(id, cloud));
}
}
}
}
// filter poses
std::map<int, Transform> poses;
UASSERT(msg->graph.posesId.size() == msg->graph.poses.size());
for(unsigned int i=0; i<msg->graph.posesId.size(); ++i)
{
poses.insert(std::make_pair(msg->graph.posesId[i], rtabmap_ros::transformFromPoseMsg(msg->graph.poses[i])));
}
if(nodeFilteringAngle_ > 0.0 && nodeFilteringRadius_ > 0.0)
{
poses = rtabmap::graph::radiusPosesFiltering(poses, nodeFilteringRadius_, nodeFilteringAngle_*CV_PI/180.0);
}
if(assembledMapClouds_.getNumSubscribers())
{
// generate the assembled cloud!
pcl::PointCloud<pcl::PointXYZRGB>::Ptr assembledCloud(new pcl::PointCloud<pcl::PointXYZRGB>);
for(std::map<int, Transform>::iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{
std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr >::iterator jter = rgbClouds_.find(iter->first);
if(jter != rgbClouds_.end())
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed = util3d::transformPointCloud(jter->second, iter->second);
*assembledCloud+=*transformed;
}
}
if(assembledCloud->size())
{
if(cloudVoxelSize_ > 0)
{
assembledCloud = util3d::voxelize(assembledCloud,cloudVoxelSize_);
}
sensor_msgs::PointCloud2::Ptr cloudMsg(new sensor_msgs::PointCloud2);
pcl::toROSMsg(*assembledCloud, *cloudMsg);
cloudMsg->header.stamp = ros::Time::now();
cloudMsg->header.frame_id = msg->header.frame_id;
assembledMapClouds_.publish(cloudMsg);
}
}
if(assembledMapScans_.getNumSubscribers())
{
// generate the assembled scan!
pcl::PointCloud<pcl::PointXYZ>::Ptr assembledCloud(new pcl::PointCloud<pcl::PointXYZ>);
for(std::map<int, Transform>::iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{
std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr >::iterator jter = scans_.find(iter->first);
if(jter != scans_.end())
{
pcl::PointCloud<pcl::PointXYZ>::Ptr transformed = util3d::transformPointCloud(jter->second, iter->second);
*assembledCloud+=*transformed;
}
}
if(assembledCloud->size())
{
if(scanVoxelSize_ > 0)
{
assembledCloud = util3d::voxelize(assembledCloud, scanVoxelSize_);
}
sensor_msgs::PointCloud2::Ptr cloudMsg(new sensor_msgs::PointCloud2);
pcl::toROSMsg(*assembledCloud, *cloudMsg);
cloudMsg->header.stamp = ros::Time::now();
cloudMsg->header.frame_id = msg->header.frame_id;
assembledMapScans_.publish(cloudMsg);
}
}
if(occupancyMapPub_.getNumSubscribers())
{
// create the map
float xMin=0.0f, yMin=0.0f;
cv::Mat pixels = util3d::create2DMapFromOccupancyLocalMaps(
poses, poses,
occupancyLocalMaps_, 0,
gridCellSize_, xMin, yMin, false,
occupancyMapSize_); false,
false,
false,
nodes_);
if(!pixels.empty()) mapsManager_.publishMaps(poses, msg->header.stamp, msg->header.frame_id);
{
//init
nav_msgs::OccupancyGrid map;
map.info.resolution = gridCellSize_;
map.info.origin.position.x = 0.0;
map.info.origin.position.y = 0.0;
map.info.origin.position.z = 0.0;
map.info.origin.orientation.x = 0.0;
map.info.origin.orientation.y = 0.0;
map.info.origin.orientation.z = 0.0;
map.info.origin.orientation.w = 1.0;
map.info.width = pixels.cols; ROS_INFO("map_assembler: Publishing data = %fs", timer.ticks());
map.info.height = pixels.rows;
map.info.origin.position.x = xMin;
map.info.origin.position.y = yMin;
map.data.resize(map.info.width * map.info.height);
memcpy(map.data.data(), pixels.data, map.info.width * map.info.height);
map.header.frame_id = msg->header.frame_id;
map.header.stamp = ros::Time::now();
occupancyMapPub_.publish(map);
}
}
ROS_INFO("Processing data %fs", timer.ticks());
} }
bool reset(std_srvs::Empty::Request&, std_srvs::Empty::Response&) bool reset(std_srvs::Empty::Request&, std_srvs::Empty::Response&)
{ {
ROS_INFO("map_assembler: reset!"); ROS_INFO("map_assembler: reset!");
occupancyLocalMaps_.clear(); mapsManager_.clear();
rgbClouds_.clear();
scans_.clear();
return true; return true;
} }
private: private:
int cloudDecimation_; MapsManager mapsManager_;
double cloudMaxDepth_; std::map<int, Signature> nodes_;
double cloudVoxelSize_;
double scanVoxelSize_;
double nodeFilteringAngle_;
double nodeFilteringRadius_;
double noiseFilterRadius_;
double noiseFilterMinNeighbors_;
bool computeOccupancyGrid_;
double gridCellSize_;
double groundMaxAngle_;
int clusterMinSize_;
double maxHeight_;
double occupancyMapSize_;
std::map<int, std::pair<cv::Mat, cv::Mat> > occupancyLocalMaps_; // <ground, obstacles>
ros::Subscriber mapDataTopic_; ros::Subscriber mapDataTopic_;
ros::Publisher assembledMapClouds_;
ros::Publisher assembledMapScans_;
ros::Publisher occupancyMapPub_;
ros::ServiceServer resetService_; ros::ServiceServer resetService_;
std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr > rgbClouds_;
std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr > scans_;
}; };
+28 -10
View File
@@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/core/Parameters.h> #include <rtabmap/core/Parameters.h>
#include <rtabmap/utilite/ULogger.h> #include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UTimer.h> #include <rtabmap/utilite/UTimer.h>
#include <rtabmap/utilite/UConversion.h>
#include <ros/subscriber.h> #include <ros/subscriber.h>
#include <ros/publisher.h> #include <ros/publisher.h>
#include <tf2_ros/transform_broadcaster.h> #include <tf2_ros/transform_broadcaster.h>
@@ -48,8 +49,6 @@ public:
MapOptimizer() : MapOptimizer() :
mapFrameId_("map"), mapFrameId_("map"),
odomFrameId_("odom"), odomFrameId_("odom"),
iterations_(100),
ignoreVariance_(false),
globalOptimization_(true), globalOptimization_(true),
optimizeFromLastNode_(false), optimizeFromLastNode_(false),
mapToOdom_(rtabmap::Transform::getIdentity()), mapToOdom_(rtabmap::Transform::getIdentity()),
@@ -58,14 +57,35 @@ public:
ros::NodeHandle nh; ros::NodeHandle nh;
ros::NodeHandle pnh("~"); ros::NodeHandle pnh("~");
double epsilon = 0.0;
bool robust = true;
bool slam2d =false;
int strategy = 0; // 0=TORO, 1=g2o, 2=GTSAM
int iterations = 100;
bool ignoreVariance = false;
pnh.param("map_frame_id", mapFrameId_, mapFrameId_); pnh.param("map_frame_id", mapFrameId_, mapFrameId_);
pnh.param("odom_frame_id", odomFrameId_, odomFrameId_); pnh.param("odom_frame_id", odomFrameId_, odomFrameId_);
pnh.param("iterations", iterations_, iterations_); pnh.param("iterations", iterations, iterations);
pnh.param("ignore_variance", ignoreVariance_, ignoreVariance_); pnh.param("ignore_variance", ignoreVariance, ignoreVariance);
pnh.param("global_optimization", globalOptimization_, globalOptimization_); pnh.param("global_optimization", globalOptimization_, globalOptimization_);
pnh.param("optimize_from_last_node", optimizeFromLastNode_, optimizeFromLastNode_); pnh.param("optimize_from_last_node", optimizeFromLastNode_, optimizeFromLastNode_);
pnh.param("epsilon", epsilon, epsilon);
pnh.param("robust", robust, robust);
pnh.param("slam_2d", slam2d, slam2d);
pnh.param("strategy", strategy, strategy);
UASSERT(iterations_ > 0);
UASSERT(iterations > 0);
ParametersMap parameters;
parameters.insert(ParametersPair(Parameters::kRGBDOptimizeStrategy(), uNumber2Str(strategy)));
parameters.insert(ParametersPair(Parameters::kRGBDOptimizeEpsilon(), uNumber2Str(epsilon)));
parameters.insert(ParametersPair(Parameters::kRGBDOptimizeIterations(), uNumber2Str(iterations)));
parameters.insert(ParametersPair(Parameters::kRGBDOptimizeRobust(), uBool2Str(robust)));
parameters.insert(ParametersPair(Parameters::kRGBDOptimizeSlam2D(), uBool2Str(slam2d)));
parameters.insert(ParametersPair(Parameters::kRGBDOptimizeVarianceIgnored(), uBool2Str(ignoreVariance)));
optimizer_ = graph::Optimizer::create(parameters);
double tfDelay = 0.05; // 20 Hz double tfDelay = 0.05; // 20 Hz
bool publishTf = true; bool publishTf = true;
@@ -216,15 +236,14 @@ public:
std::multimap<int, rtabmap::Link> linksOut; std::multimap<int, rtabmap::Link> linksOut;
if(poses.size() > 1 && constraints.size() > 0) if(poses.size() > 1 && constraints.size() > 0)
{ {
graph::TOROOptimizer optimizer(iterations_, false, ignoreVariance_);
int fromId = optimizeFromLastNode_?poses.rbegin()->first:poses.begin()->first; int fromId = optimizeFromLastNode_?poses.rbegin()->first:poses.begin()->first;
optimizer.getConnectedGraph( optimizer_->getConnectedGraph(
fromId, fromId,
poses, poses,
constraints, constraints,
posesOut, posesOut,
linksOut); linksOut);
optimizedPoses = optimizer.optimize(fromId, posesOut, linksOut); optimizedPoses = optimizer_->optimize(fromId, posesOut, linksOut);
mapToOdomMutex_.lock(); mapToOdomMutex_.lock();
mapCorrection = optimizedPoses.at(posesOut.rbegin()->first) * posesOut.rbegin()->second.inverse(); mapCorrection = optimizedPoses.at(posesOut.rbegin()->first) * posesOut.rbegin()->second.inverse();
mapToOdom_ = mapCorrection; mapToOdom_ = mapCorrection;
@@ -296,10 +315,9 @@ public:
private: private:
std::string mapFrameId_; std::string mapFrameId_;
std::string odomFrameId_; std::string odomFrameId_;
int iterations_;
bool ignoreVariance_;
bool globalOptimization_; bool globalOptimization_;
bool optimizeFromLastNode_; bool optimizeFromLastNode_;
graph::Optimizer * optimizer_;
rtabmap::Transform mapToOdom_; rtabmap::Transform mapToOdom_;
boost::mutex mapToOdomMutex_; boost::mutex mapToOdomMutex_;
+128 -15
View File
@@ -29,13 +29,15 @@
using namespace rtabmap; using namespace rtabmap;
MapsManager::MapsManager() : MapsManager::MapsManager(bool usePublicNamespace) :
cloudDecimation_(4), cloudDecimation_(4),
cloudMaxDepth_(4.0), // meters cloudMaxDepth_(4.0), // meters
cloudVoxelSize_(0.05), // meters cloudVoxelSize_(0.05), // meters
cloudFloorCullingHeight_(0.0), cloudFloorCullingHeight_(0.0),
cloudOutputVoxelized_(false), cloudOutputVoxelized_(false),
cloudFrustumCulling_(false), cloudFrustumCulling_(false),
scanVoxelSize_(0.0),
scanOutputVoxelized_(false),
projMaxGroundAngle_(45.0), // degrees projMaxGroundAngle_(45.0), // degrees
projMinClusterSize_(20), projMinClusterSize_(20),
projMaxHeight_(2.0), // meters projMaxHeight_(2.0), // meters
@@ -58,6 +60,12 @@ MapsManager::MapsManager() :
pnh.param("cloud_floor_culling_height", cloudFloorCullingHeight_, cloudFloorCullingHeight_); pnh.param("cloud_floor_culling_height", cloudFloorCullingHeight_, cloudFloorCullingHeight_);
pnh.param("cloud_output_voxelized", cloudOutputVoxelized_, cloudOutputVoxelized_); pnh.param("cloud_output_voxelized", cloudOutputVoxelized_, cloudOutputVoxelized_);
pnh.param("cloud_frustum_culling", cloudFrustumCulling_, cloudFrustumCulling_); pnh.param("cloud_frustum_culling", cloudFrustumCulling_, cloudFrustumCulling_);
pnh.param("cloud_noise_filtering_radius", cloudNoiseFilteringRadius_, cloudNoiseFilteringRadius_);
pnh.param("cloud_noise_filtering_min_neighbors", cloudNoiseFilteringMinNeighbors_, cloudNoiseFilteringMinNeighbors_);
// scan map stuff
pnh.param("scan_voxel_size", scanVoxelSize_, scanVoxelSize_);
pnh.param("scan_output_voxelized", scanOutputVoxelized_, scanOutputVoxelized_);
//projection map stuff //projection map stuff
pnh.param("proj_max_ground_angle", projMaxGroundAngle_, projMaxGroundAngle_); pnh.param("proj_max_ground_angle", projMaxGroundAngle_, projMaxGroundAngle_);
@@ -75,10 +83,27 @@ MapsManager::MapsManager() :
pnh.param("map_filter_angle", mapFilterAngle_, mapFilterAngle_); pnh.param("map_filter_angle", mapFilterAngle_, mapFilterAngle_);
pnh.param("map_cleanup", mapCacheCleanup_, mapCacheCleanup_); pnh.param("map_cleanup", mapCacheCleanup_, mapCacheCleanup_);
// If true, the last message published on
// the map topics will be saved and sent to new subscribers when they
// connect
bool latch = true;
pnh.param("latch", latch, latch);
// mapping topics // mapping topics
cloudMapPub_ = nh.advertise<sensor_msgs::PointCloud2>("cloud_map", 1); if(usePublicNamespace)
projMapPub_ = nh.advertise<nav_msgs::OccupancyGrid>("proj_map", 1); {
gridMapPub_ = nh.advertise<nav_msgs::OccupancyGrid>("grid_map", 1); cloudMapPub_ = nh.advertise<sensor_msgs::PointCloud2>("cloud_map", 1, latch);
projMapPub_ = nh.advertise<nav_msgs::OccupancyGrid>("proj_map", 1, latch);
gridMapPub_ = nh.advertise<nav_msgs::OccupancyGrid>("grid_map", 1, latch);
scanMapPub_ = nh.advertise<sensor_msgs::PointCloud2>("scan_map", 1, latch);
}
else
{
cloudMapPub_ = pnh.advertise<sensor_msgs::PointCloud2>("cloud_map", 1, latch);
projMapPub_ = pnh.advertise<nav_msgs::OccupancyGrid>("proj_map", 1, latch);
gridMapPub_ = pnh.advertise<nav_msgs::OccupancyGrid>("grid_map", 1, latch);
scanMapPub_ = pnh.advertise<sensor_msgs::PointCloud2>("scan_map", 1, latch);
}
} }
MapsManager::~MapsManager() { MapsManager::~MapsManager() {
@@ -97,7 +122,8 @@ bool MapsManager::hasSubscribers() const
{ {
return cloudMapPub_.getNumSubscribers() != 0 || return cloudMapPub_.getNumSubscribers() != 0 ||
projMapPub_.getNumSubscribers() != 0 || projMapPub_.getNumSubscribers() != 0 ||
gridMapPub_.getNumSubscribers() != 0; gridMapPub_.getNumSubscribers() != 0 ||
scanMapPub_.getNumSubscribers() != 0;
} }
std::map<int, Transform> MapsManager::getFilteredPoses(const std::map<int, Transform> & poses) std::map<int, Transform> MapsManager::getFilteredPoses(const std::map<int, Transform> & poses)
@@ -117,28 +143,30 @@ std::map<int, rtabmap::Transform> MapsManager::updateMapCaches(
bool updateCloud, bool updateCloud,
bool updateProj, bool updateProj,
bool updateGrid, bool updateGrid,
bool updateScan,
const std::map<int, rtabmap::Signature> & signatures) const std::map<int, rtabmap::Signature> & signatures)
{ {
if(!updateCloud && !updateProj && !updateGrid) if(!updateCloud && !updateProj && !updateGrid && !updateScan)
{ {
// all false, udpate only those where we have subscribers // all false, udpate only those where we have subscribers
updateCloud = cloudMapPub_.getNumSubscribers() != 0; updateCloud = cloudMapPub_.getNumSubscribers() != 0;
updateProj = projMapPub_.getNumSubscribers() != 0; updateProj = projMapPub_.getNumSubscribers() != 0;
updateGrid = gridMapPub_.getNumSubscribers() != 0; updateGrid = gridMapPub_.getNumSubscribers() != 0;
updateScan = scanMapPub_.getNumSubscribers() != 0;
} }
UDEBUG("Updating map caches..."); UDEBUG("Updating map caches...");
if(!memory && signatures.size() == 0) if(!memory && signatures.size() == 0)
{ {
ROS_FATAL("Memory should not be null!?"); ROS_ERROR("Memory and signatures should not be both null!?");
return std::map<int, rtabmap::Transform>(); return std::map<int, rtabmap::Transform>();
} }
std::map<int, rtabmap::Transform> filteredPoses; std::map<int, rtabmap::Transform> filteredPoses;
// update cache // update cache
if(updateCloud || updateProj || updateGrid) if(updateCloud || updateProj || updateGrid || updateScan)
{ {
// filter nodes // filter nodes
if(mapFilterRadius_ > 0.0) if(mapFilterRadius_ > 0.0)
@@ -170,11 +198,13 @@ std::map<int, rtabmap::Transform> MapsManager::updateMapCaches(
rtabmap::SensorData data; rtabmap::SensorData data;
bool rgbDepthRequired = updateCloud && (iter->first < 0 || !uContains(clouds_, iter->first)); bool rgbDepthRequired = updateCloud && (iter->first < 0 || !uContains(clouds_, iter->first));
bool depthRequired = updateProj && (iter->first < 0 || !uContains(projMaps_, iter->first)); bool depthRequired = updateProj && (iter->first < 0 || !uContains(projMaps_, iter->first));
bool scanRequired = updateGrid && (iter->first < 0 || !uContains(gridMaps_, iter->first)); bool gridRequired = updateGrid && (iter->first < 0 || !uContains(gridMaps_, iter->first));
bool scanRequired = updateScan && (iter->first < 0 || !uContains(scans_, iter->first));
if(rgbDepthRequired || if(rgbDepthRequired ||
depthRequired || depthRequired ||
scanRequired) scanRequired ||
gridRequired)
{ {
std::map<int, rtabmap::Signature>::const_iterator findIter = signatures.find(iter->first); std::map<int, rtabmap::Signature>::const_iterator findIter = signatures.find(iter->first);
if(findIter != signatures.end()) if(findIter != signatures.end())
@@ -198,7 +228,7 @@ std::map<int, rtabmap::Transform> MapsManager::updateMapCaches(
data.uncompressData( data.uncompressData(
(rgbDepthRequired||data.stereoCameraModel().isValid()) ? &image:0, (rgbDepthRequired||data.stereoCameraModel().isValid()) ? &image:0,
(rgbDepthRequired||depthRequired) ? &depth:0, (rgbDepthRequired||depthRequired) ? &depth:0,
scanRequired?&scan:0); scanRequired||gridRequired?&scan:0);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudRGB; pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloudRGB;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloudXYZ; pcl::PointCloud<pcl::PointXYZ>::Ptr cloudXYZ;
@@ -211,6 +241,13 @@ std::map<int, rtabmap::Transform> MapsManager::updateMapCaches(
cloudDecimation_, cloudDecimation_,
cloudMaxDepth_, cloudMaxDepth_,
cloudVoxelSize_); cloudVoxelSize_);
if(cloudRGB->size() && cloudNoiseFilteringRadius_ > 0.0 && cloudNoiseFilteringMinNeighbors_ > 0)
{
pcl::IndicesPtr indices = rtabmap::util3d::radiusFiltering(cloudRGB, cloudNoiseFilteringRadius_, cloudNoiseFilteringMinNeighbors_);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr tmp(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::copyPointCloud(*cloudRGB, *indices, *tmp);
cloudRGB = tmp;
}
} }
else else
{ {
@@ -226,6 +263,13 @@ std::map<int, rtabmap::Transform> MapsManager::updateMapCaches(
cloudDecimation_, cloudDecimation_,
cloudMaxDepth_, cloudMaxDepth_,
gridCellSize_); // use gridCellSize since this cloud is only for the projection map gridCellSize_); // use gridCellSize since this cloud is only for the projection map
if(cloudXYZ->size() && cloudNoiseFilteringRadius_ > 0.0 && cloudNoiseFilteringMinNeighbors_ > 0)
{
pcl::IndicesPtr indices = rtabmap::util3d::radiusFiltering(cloudXYZ, cloudNoiseFilteringRadius_, cloudNoiseFilteringMinNeighbors_);
pcl::PointCloud<pcl::PointXYZ>::Ptr tmp(new pcl::PointCloud<pcl::PointXYZ>);
pcl::copyPointCloud(*cloudXYZ, *indices, *tmp);
cloudXYZ = tmp;
}
} }
else else
{ {
@@ -273,7 +317,7 @@ std::map<int, rtabmap::Transform> MapsManager::updateMapCaches(
{ {
cloudClipped = util3d::passThrough(cloudClipped, "z", std::numeric_limits<int>::min(), projMaxHeight_); cloudClipped = util3d::passThrough(cloudClipped, "z", std::numeric_limits<int>::min(), projMaxHeight_);
} }
if(cloudClipped->size()) if(cloudClipped->size() && gridCellSize_ > cloudVoxelSize_)
{ {
cloudClipped = util3d::voxelize(cloudClipped, gridCellSize_); cloudClipped = util3d::voxelize(cloudClipped, gridCellSize_);
util3d::occupancy2DFromCloud3D<pcl::PointXYZRGB>(cloudClipped, ground, obstacles, gridCellSize_, projMaxGroundAngle_*M_PI/180.0, projMinClusterSize_); util3d::occupancy2DFromCloud3D<pcl::PointXYZRGB>(cloudClipped, ground, obstacles, gridCellSize_, projMaxGroundAngle_*M_PI/180.0, projMinClusterSize_);
@@ -294,13 +338,32 @@ std::map<int, rtabmap::Transform> MapsManager::updateMapCaches(
uInsert(projMaps_, std::make_pair(iter->first, std::make_pair(ground, obstacles))); uInsert(projMaps_, std::make_pair(iter->first, std::make_pair(ground, obstacles)));
} }
if(scanRequired || gridRequired)
{
if(scan.cols && (gridRequired || scanVoxelSize_ > 0.0))
{
pcl::PointCloud<pcl::PointXYZ>::Ptr scanCloud = util3d::laserScanToPointCloud(scan);
if(scanVoxelSize_ > 0.0)
{
scanCloud = util3d::voxelize(scanCloud, scanVoxelSize_);
if(gridRequired)
{
scan = util3d::laserScanFromPointCloud(*scanCloud);
}
}
if(scanRequired) if(scanRequired)
{
uInsert(scans_, std::make_pair(iter->first, scanCloud));
}
}
if(gridRequired)
{ {
cv::Mat ground, obstacles; cv::Mat ground, obstacles;
util3d::occupancy2DFromLaserScan(scan, ground, obstacles, gridCellSize_, data.id() < 0 || gridUnknownSpaceFilled_, data.laserScanMaxRange()); util3d::occupancy2DFromLaserScan(scan, ground, obstacles, gridCellSize_, data.id() < 0 || gridUnknownSpaceFilled_, data.laserScanMaxRange());
uInsert(gridMaps_, std::make_pair(iter->first, std::make_pair(ground, obstacles))); uInsert(gridMaps_, std::make_pair(iter->first, std::make_pair(ground, obstacles)));
} }
} }
}
else else
{ {
ROS_ERROR("Some data missing for node %d to update the maps (image=%d, depth=%d, camera=%d)", ROS_ERROR("Some data missing for node %d to update the maps (image=%d, depth=%d, camera=%d)",
@@ -428,6 +491,8 @@ void MapsManager::publishMaps(
cloudMaxDepth_>0.0?cloudMaxDepth_:999999., cloudMaxDepth_>0.0?cloudMaxDepth_:999999.,
true); true);
//ROS_INFO("Frustum culling %d ->%d", size, (int)assembledCloud->size()); //ROS_INFO("Frustum culling %d ->%d", size, (int)assembledCloud->size());
if(jter->second->size())
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed = util3d::transformPointCloud(jter->second, iter->second); pcl::PointCloud<pcl::PointXYZRGB>::Ptr transformed = util3d::transformPointCloud(jter->second, iter->second);
*assembledCloud+=*transformed; *assembledCloud+=*transformed;
} }
@@ -435,13 +500,14 @@ void MapsManager::publishMaps(
} }
} }
} }
}
if(cloudFloorCullingHeight_ > 0.0) if(assembledCloud->size() && cloudFloorCullingHeight_ > 0.0)
{ {
assembledCloud = util3d::passThrough(assembledCloud, "z", cloudFloorCullingHeight_, 99999.0f); assembledCloud = util3d::passThrough(assembledCloud, "z", cloudFloorCullingHeight_, 99999.0f);
} }
if(cloudVoxelSize_ > 0 && cloudOutputVoxelized_) if(assembledCloud->size() && cloudVoxelSize_ > 0 && cloudOutputVoxelized_)
{ {
assembledCloud = util3d::voxelize(assembledCloud, cloudVoxelSize_); assembledCloud = util3d::voxelize(assembledCloud, cloudVoxelSize_);
} }
@@ -456,7 +522,7 @@ void MapsManager::publishMaps(
} }
else if(poses.size()) else if(poses.size())
{ {
ROS_WARN("Cloud map is empty! (clouds=%d)", (int)clouds_.size()); ROS_WARN("Cloud map is empty! (poses=%d clouds=%d)", (int)poses.size(), (int)clouds_.size());
} }
} }
else if(mapCacheCleanup_) else if(mapCacheCleanup_)
@@ -465,6 +531,53 @@ void MapsManager::publishMaps(
cameraModels_.clear(); cameraModels_.clear();
} }
if(scanMapPub_.getNumSubscribers())
{
// generate the assembled scan cloud!
UTimer time;
pcl::PointCloud<pcl::PointXYZ>::Ptr assembledCloud(new pcl::PointCloud<pcl::PointXYZ>);
int count = 0;
std::list<std::pair<int, Transform> > negativePoses;
for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
{
if(iter->first > 0)
{
std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr >::iterator jter = scans_.find(iter->first);
if(jter != scans_.end() && jter->second->size())
{
pcl::PointCloud<pcl::PointXYZ>::Ptr transformed = util3d::transformPointCloud(jter->second, iter->second);
*assembledCloud+=*transformed;
++count;
}
}
// negative poses are not used
}
if(assembledCloud->size())
{
if(assembledCloud->size() && scanVoxelSize_ > 0 && scanOutputVoxelized_)
{
assembledCloud = util3d::voxelize(assembledCloud, scanVoxelSize_);
}
ROS_INFO("Assembled %d scans (%fs)", count, time.ticks());
sensor_msgs::PointCloud2::Ptr cloudMsg(new sensor_msgs::PointCloud2);
pcl::toROSMsg(*assembledCloud, *cloudMsg);
cloudMsg->header.stamp = stamp;
cloudMsg->header.frame_id = mapFrameId;
scanMapPub_.publish(cloudMsg);
}
else if(poses.size())
{
ROS_WARN("Scan map is empty! (poses=%d, scans=%d)", (int)poses.size(), (int)scans_.size());
}
}
else if(mapCacheCleanup_)
{
scans_.clear();
}
if(projMapPub_.getNumSubscribers()) if(projMapPub_.getNumSubscribers())
{ {
// create the projection map // create the projection map
+8 -1
View File
@@ -26,7 +26,7 @@ class Memory;
class MapsManager { class MapsManager {
public: public:
MapsManager(); MapsManager(bool usePublicNamespace);
virtual ~MapsManager(); virtual ~MapsManager();
void clear(); void clear();
bool hasSubscribers() const; bool hasSubscribers() const;
@@ -40,6 +40,7 @@ public:
bool updateCloud, bool updateCloud,
bool updateProj, bool updateProj,
bool updateGrid, bool updateGrid,
bool updateScan,
const std::map<int, rtabmap::Signature> & signatures = std::map<int, rtabmap::Signature>()); const std::map<int, rtabmap::Signature> & signatures = std::map<int, rtabmap::Signature>());
void publishMaps( void publishMaps(
@@ -71,6 +72,10 @@ private:
double cloudFloorCullingHeight_; double cloudFloorCullingHeight_;
bool cloudOutputVoxelized_; bool cloudOutputVoxelized_;
bool cloudFrustumCulling_; bool cloudFrustumCulling_;
double cloudNoiseFilteringRadius_;
int cloudNoiseFilteringMinNeighbors_;
double scanVoxelSize_;
bool scanOutputVoxelized_;
double projMaxGroundAngle_; double projMaxGroundAngle_;
int projMinClusterSize_; int projMinClusterSize_;
double projMaxHeight_; double projMaxHeight_;
@@ -85,8 +90,10 @@ private:
ros::Publisher cloudMapPub_; ros::Publisher cloudMapPub_;
ros::Publisher projMapPub_; ros::Publisher projMapPub_;
ros::Publisher gridMapPub_; ros::Publisher gridMapPub_;
ros::Publisher scanMapPub_;
std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr > clouds_; std::map<int, pcl::PointCloud<pcl::PointXYZRGB>::Ptr > clouds_;
std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr > scans_;
std::map<int, std::vector<rtabmap::CameraModel> > cameraModels_; std::map<int, std::vector<rtabmap::CameraModel> > cameraModels_;
std::map<int, std::pair<cv::Mat, cv::Mat> > projMaps_; // <ground, obstacles> std::map<int, std::pair<cv::Mat, cv::Mat> > projMaps_; // <ground, obstacles>
std::map<int, std::pair<cv::Mat, cv::Mat> > gridMaps_; // <ground, obstacles> std::map<int, std::pair<cv::Mat, cv::Mat> > gridMaps_; // <ground, obstacles>