Parameters: Changed Grid/FromDepth to Grid/Sensor to add a new choice to use both scan and depth for local grids. Increased version to 0.20.15.

This commit is contained in:
matlabbe
2021-10-29 20:05:12 -04:00
parent 1886f99cbf
commit 7c5acd8970
9 changed files with 418 additions and 332 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
####################### #######################
SET(RTABMAP_MAJOR_VERSION 0) SET(RTABMAP_MAJOR_VERSION 0)
SET(RTABMAP_MINOR_VERSION 20) SET(RTABMAP_MINOR_VERSION 20)
SET(RTABMAP_PATCH_VERSION 14) SET(RTABMAP_PATCH_VERSION 15)
SET(RTABMAP_VERSION SET(RTABMAP_VERSION
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION}) ${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
+3 -3
View File
@@ -58,7 +58,7 @@ public:
float getCellSize() const {return cellSize_;} float getCellSize() const {return cellSize_;}
void setCloudAssembling(bool enabled); void setCloudAssembling(bool enabled);
float getMinMapSize() const {return minMapSize_;} float getMinMapSize() const {return minMapSize_;}
bool isGridFromDepth() const {return occupancyFromDepth_;} bool isGridFromDepth() const {return occupancySensor_;}
bool isFullUpdate() const {return fullUpdate_;} bool isFullUpdate() const {return fullUpdate_;}
float getUpdateError() const {return updateError_;} float getUpdateError() const {return updateError_;}
bool isMapFrameProjection() const {return projMapFrame_;} bool isMapFrameProjection() const {return projMapFrame_;}
@@ -81,7 +81,7 @@ public:
cv::Mat & groundCells, cv::Mat & groundCells,
cv::Mat & obstacleCells, cv::Mat & obstacleCells,
cv::Mat & emptyCells, cv::Mat & emptyCells,
cv::Point3f & viewPoint) const; cv::Point3f & viewPoint);
void createLocalMap( void createLocalMap(
const LaserScan & cloud, const LaserScan & cloud,
@@ -118,7 +118,7 @@ private:
int scanDecimation_; int scanDecimation_;
float cellSize_; float cellSize_;
bool preVoxelFiltering_; bool preVoxelFiltering_;
bool occupancyFromDepth_; int occupancySensor_;
bool projMapFrame_; bool projMapFrame_;
float maxObstacleHeight_; float maxObstacleHeight_;
int normalKSearch_; int normalKSearch_;
+5 -5
View File
@@ -723,15 +723,15 @@ class RTABMAP_EXP Parameters
#endif #endif
// Occupancy Grid // Occupancy Grid
RTABMAP_PARAM(Grid, FromDepth, bool, true, "Create occupancy grid from depth image(s), otherwise it is created from laser scan."); RTABMAP_PARAM(Grid, Sensor, int, 1, "Create occupancy grid from selected sensor: 0=laser scan, 1=depth image(s) or 2=both laser scan and depth image(s).");
RTABMAP_PARAM(Grid, DepthDecimation, unsigned int, 4, uFormat("[%s=true] Decimation of the depth image before creating cloud.", kGridDepthDecimation().c_str())); RTABMAP_PARAM(Grid, DepthDecimation, unsigned int, 4, uFormat("[%s=true] Decimation of the depth image before creating cloud.", kGridDepthDecimation().c_str()));
RTABMAP_PARAM(Grid, RangeMin, float, 0.0, "Minimum range from sensor."); RTABMAP_PARAM(Grid, RangeMin, float, 0.0, "Minimum range from sensor.");
RTABMAP_PARAM(Grid, RangeMax, float, 5.0, "Maximum range from sensor. 0=inf."); RTABMAP_PARAM(Grid, RangeMax, float, 5.0, "Maximum range from sensor. 0=inf.");
RTABMAP_PARAM_STR(Grid, DepthRoiRatios, "0.0 0.0 0.0 0.0", uFormat("[%s=true] Region of interest ratios [left, right, top, bottom].", kGridFromDepth().c_str())); RTABMAP_PARAM_STR(Grid, DepthRoiRatios, "0.0 0.0 0.0 0.0", uFormat("[%s>=1] Region of interest ratios [left, right, top, bottom].", kGridSensor().c_str()));
RTABMAP_PARAM(Grid, FootprintLength, float, 0.0, "Footprint length used to filter points over the footprint of the robot."); RTABMAP_PARAM(Grid, FootprintLength, float, 0.0, "Footprint length used to filter points over the footprint of the robot.");
RTABMAP_PARAM(Grid, FootprintWidth, float, 0.0, "Footprint width used to filter points over the footprint of the robot. Footprint length should be set."); RTABMAP_PARAM(Grid, FootprintWidth, float, 0.0, "Footprint width used to filter points over the footprint of the robot. Footprint length should be set.");
RTABMAP_PARAM(Grid, FootprintHeight, float, 0.0, "Footprint height used to filter points over the footprint of the robot. Footprint length and width should be set."); RTABMAP_PARAM(Grid, FootprintHeight, float, 0.0, "Footprint height used to filter points over the footprint of the robot. Footprint length and width should be set.");
RTABMAP_PARAM(Grid, ScanDecimation, int, 1, uFormat("[%s=false] Decimation of the laser scan before creating cloud.", kGridFromDepth().c_str())); RTABMAP_PARAM(Grid, ScanDecimation, int, 1, uFormat("[%s=0 or 2] Decimation of the laser scan before creating cloud.", kGridSensor().c_str()));
RTABMAP_PARAM(Grid, CellSize, float, 0.05, "Resolution of the occupancy grid."); RTABMAP_PARAM(Grid, CellSize, float, 0.05, "Resolution of the occupancy grid.");
RTABMAP_PARAM(Grid, PreVoxelFiltering, bool, true, uFormat("Input cloud is downsampled by voxel filter (voxel size is \"%s\") before doing segmentation of obstacles and ground.", kGridCellSize().c_str())); RTABMAP_PARAM(Grid, PreVoxelFiltering, bool, true, uFormat("Input cloud is downsampled by voxel filter (voxel size is \"%s\") before doing segmentation of obstacles and ground.", kGridCellSize().c_str()));
RTABMAP_PARAM(Grid, MapFrameProjection, bool, false, "Projection in map frame. On a 3D terrain and a fixed local camera transform (the cloud is created relative to ground), you may want to disable this to do the projection in robot frame instead."); RTABMAP_PARAM(Grid, MapFrameProjection, bool, false, "Projection in map frame. On a 3D terrain and a fixed local camera transform (the cloud is created relative to ground), you may want to disable this to do the projection in robot frame instead.");
@@ -745,9 +745,9 @@ class RTABMAP_EXP Parameters
RTABMAP_PARAM(Grid, MinClusterSize, int, 10, uFormat("[%s=true] Minimum cluster size to project the points.", kGridNormalsSegmentation().c_str())); RTABMAP_PARAM(Grid, MinClusterSize, int, 10, uFormat("[%s=true] Minimum cluster size to project the points.", kGridNormalsSegmentation().c_str()));
RTABMAP_PARAM(Grid, FlatObstacleDetected, bool, true, uFormat("[%s=true] Flat obstacles detected.", kGridNormalsSegmentation().c_str())); RTABMAP_PARAM(Grid, FlatObstacleDetected, bool, true, uFormat("[%s=true] Flat obstacles detected.", kGridNormalsSegmentation().c_str()));
#ifdef RTABMAP_OCTOMAP #ifdef RTABMAP_OCTOMAP
RTABMAP_PARAM(Grid, 3D, bool, true, uFormat("A 3D occupancy grid is required if you want an OctoMap (3D ray tracing). Set to false if you want only a 2D map, the cloud will be projected on xy plane. A 2D map can be still generated if checked, but it requires more memory and time to generate it. Ignored if laser scan is 2D and \"%s\" is false.", kGridFromDepth().c_str())); RTABMAP_PARAM(Grid, 3D, bool, true, uFormat("A 3D occupancy grid is required if you want an OctoMap (3D ray tracing). Set to false if you want only a 2D map, the cloud will be projected on xy plane. A 2D map can be still generated if checked, but it requires more memory and time to generate it. Ignored if laser scan is 2D and \"%s\" is 0.", kGridSensor().c_str()));
#else #else
RTABMAP_PARAM(Grid, 3D, bool, false, uFormat("A 3D occupancy grid is required if you want an OctoMap (3D ray tracing). Set to false if you want only a 2D map, the cloud will be projected on xy plane. A 2D map can be still generated if checked, but it requires more memory and time to generate it. Ignored if laser scan is 2D and \"%s\" is false.", kGridFromDepth().c_str())); RTABMAP_PARAM(Grid, 3D, bool, false, uFormat("A 3D occupancy grid is required if you want an OctoMap (3D ray tracing). Set to false if you want only a 2D map, the cloud will be projected on xy plane. A 2D map can be still generated if checked, but it requires more memory and time to generate it. Ignored if laser scan is 2D and \"%s\" is 0.", kGridSensor().c_str()));
#endif #endif
RTABMAP_PARAM(Grid, GroundIsObstacle, bool, false, uFormat("[%s=true] Ground segmentation (%s) is ignored, all points are obstacles. Use this only if you want an OctoMap with ground identified as an obstacle (e.g., with an UAV).", kGrid3D().c_str(), kGridNormalsSegmentation().c_str())); RTABMAP_PARAM(Grid, GroundIsObstacle, bool, false, uFormat("[%s=true] Ground segmentation (%s) is ignored, all points are obstacles. Use this only if you want an OctoMap with ground identified as an obstacle (e.g., with an UAV).", kGrid3D().c_str(), kGridNormalsSegmentation().c_str()));
RTABMAP_PARAM(Grid, NoiseFilteringRadius, float, 0.0, "Noise filtering radius (0=disabled). Done after segmentation."); RTABMAP_PARAM(Grid, NoiseFilteringRadius, float, 0.0, "Noise filtering radius (0=disabled). Done after segmentation.");
+72 -9
View File
@@ -52,7 +52,7 @@ OccupancyGrid::OccupancyGrid(const ParametersMap & parameters) :
scanDecimation_(Parameters::defaultGridScanDecimation()), scanDecimation_(Parameters::defaultGridScanDecimation()),
cellSize_(Parameters::defaultGridCellSize()), cellSize_(Parameters::defaultGridCellSize()),
preVoxelFiltering_(Parameters::defaultGridPreVoxelFiltering()), preVoxelFiltering_(Parameters::defaultGridPreVoxelFiltering()),
occupancyFromDepth_(Parameters::defaultGridFromDepth()), occupancySensor_(Parameters::defaultGridSensor()),
projMapFrame_(Parameters::defaultGridMapFrameProjection()), projMapFrame_(Parameters::defaultGridMapFrameProjection()),
maxObstacleHeight_(Parameters::defaultGridMaxObstacleHeight()), maxObstacleHeight_(Parameters::defaultGridMaxObstacleHeight()),
normalKSearch_(Parameters::defaultGridNormalK()), normalKSearch_(Parameters::defaultGridNormalK()),
@@ -91,7 +91,7 @@ OccupancyGrid::OccupancyGrid(const ParametersMap & parameters) :
void OccupancyGrid::parseParameters(const ParametersMap & parameters) void OccupancyGrid::parseParameters(const ParametersMap & parameters)
{ {
Parameters::parse(parameters, Parameters::kGridFromDepth(), occupancyFromDepth_); Parameters::parse(parameters, Parameters::kGridSensor(), occupancySensor_);
Parameters::parse(parameters, Parameters::kGridDepthDecimation(), cloudDecimation_); Parameters::parse(parameters, Parameters::kGridDepthDecimation(), cloudDecimation_);
if(cloudDecimation_ == 0) if(cloudDecimation_ == 0)
{ {
@@ -284,12 +284,12 @@ void OccupancyGrid::createLocalMap(
cv::Mat & groundCells, cv::Mat & groundCells,
cv::Mat & obstacleCells, cv::Mat & obstacleCells,
cv::Mat & emptyCells, cv::Mat & emptyCells,
cv::Point3f & viewPoint) const cv::Point3f & viewPoint)
{ {
UDEBUG("scan format=%s, occupancyFromDepth_=%d normalsSegmentation_=%d grid3D_=%d", UDEBUG("scan format=%s, occupancySensor_=%d normalsSegmentation_=%d grid3D_=%d",
node.sensorData().laserScanRaw().isEmpty()?"NA":node.sensorData().laserScanRaw().formatName().c_str(), occupancyFromDepth_?1:0, normalsSegmentation_?1:0, grid3D_?1:0); node.sensorData().laserScanRaw().isEmpty()?"NA":node.sensorData().laserScanRaw().formatName().c_str(), occupancySensor_, normalsSegmentation_?1:0, grid3D_?1:0);
if((node.sensorData().laserScanRaw().is2d()) && !occupancyFromDepth_) if((node.sensorData().laserScanRaw().is2d()) && occupancySensor_ == 0)
{ {
UDEBUG("2D laser scan"); UDEBUG("2D laser scan");
//2D //2D
@@ -328,7 +328,7 @@ void OccupancyGrid::createLocalMap(
else else
{ {
// 3D // 3D
if(!occupancyFromDepth_) if(occupancySensor_ == 0 || occupancySensor_ == 2)
{ {
if(!node.sensorData().laserScanRaw().isEmpty()) if(!node.sensorData().laserScanRaw().isEmpty())
{ {
@@ -350,14 +350,35 @@ void OccupancyGrid::createLocalMap(
viewPoint = cv::Point3f(t.x(), t.y(), t.z()); viewPoint = cv::Point3f(t.x(), t.y(), t.z());
UDEBUG("scan format=%d", scan.format()); UDEBUG("scan format=%d", scan.format());
bool normalSegmentationTmp = normalsSegmentation_;
float minGroundHeightTmp = minGroundHeight_;
float maxGroundHeightTmp = maxGroundHeight_;
if(scan.is2d())
{
// if 2D, assume the whole scan is obstacle
normalsSegmentation_ = false;
minGroundHeight_ = std::numeric_limits<int>::min();
maxGroundHeight_ = std::numeric_limits<int>::min()+100;
}
createLocalMap(scan, node.getPose(), groundCells, obstacleCells, emptyCells, viewPoint); createLocalMap(scan, node.getPose(), groundCells, obstacleCells, emptyCells, viewPoint);
if(scan.is2d())
{
// restore
normalsSegmentation_ = normalSegmentationTmp;
minGroundHeight_ = minGroundHeightTmp;
maxGroundHeight_ = maxGroundHeightTmp;
}
} }
else else
{ {
UWARN("Cannot create local map, scan is empty (node=%d, %s=false).", node.id(), Parameters::kGridFromDepth().c_str()); UWARN("Cannot create local map, scan is empty (node=%d, %s=0).", node.id(), Parameters::kGridSensor().c_str());
} }
} }
else
if(occupancySensor_ >= 1)
{ {
pcl::IndicesPtr indices(new std::vector<int>); pcl::IndicesPtr indices(new std::vector<int>);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud; pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud;
@@ -407,7 +428,49 @@ void OccupancyGrid::createLocalMap(
const Transform & t = node.sensorData().stereoCameraModel().localTransform(); const Transform & t = node.sensorData().stereoCameraModel().localTransform();
viewPoint = cv::Point3f(t.x(), t.y(), t.z()); viewPoint = cv::Point3f(t.x(), t.y(), t.z());
} }
cv::Mat scanGroundCells;
cv::Mat scanObstacleCells;
cv::Mat scanEmptyCells;
if(occupancySensor_ == 2)
{
// backup
scanGroundCells = groundCells.clone();
scanObstacleCells = obstacleCells.clone();
scanEmptyCells = emptyCells.clone();
}
createLocalMap(LaserScan(util3d::laserScanFromPointCloud(*cloud, indices), 0, 0.0f), node.getPose(), groundCells, obstacleCells, emptyCells, viewPoint); createLocalMap(LaserScan(util3d::laserScanFromPointCloud(*cloud, indices), 0, 0.0f), node.getPose(), groundCells, obstacleCells, emptyCells, viewPoint);
if(occupancySensor_ == 2)
{
if(grid3D_)
{
// We should convert scans to 4 channels (XYZRGB) to be compatible
scanGroundCells = util3d::laserScanFromPointCloud(*util3d::laserScanToPointCloudRGB(LaserScan::backwardCompatibility(scanGroundCells), Transform::getIdentity(), 255, 255, 255)).data();
scanObstacleCells = util3d::laserScanFromPointCloud(*util3d::laserScanToPointCloudRGB(LaserScan::backwardCompatibility(scanObstacleCells), Transform::getIdentity(), 255, 255, 255)).data();
scanEmptyCells = util3d::laserScanFromPointCloud(*util3d::laserScanToPointCloudRGB(LaserScan::backwardCompatibility(scanEmptyCells), Transform::getIdentity(), 255, 255, 255)).data();
}
UDEBUG("groundCells, depth: size=%d channels=%d vs scan: size=%d channels=%d", groundCells.cols, groundCells.channels(), scanGroundCells.cols, scanGroundCells.channels());
UDEBUG("obstacleCells, depth: size=%d channels=%d vs scan: size=%d channels=%d", obstacleCells.cols, obstacleCells.channels(), scanObstacleCells.cols, scanObstacleCells.channels());
UDEBUG("emptyCells, depth: size=%d channels=%d vs scan: size=%d channels=%d", emptyCells.cols, emptyCells.channels(), scanEmptyCells.cols, scanEmptyCells.channels());
if(!groundCells.empty() && !scanGroundCells.empty())
cv::hconcat(groundCells, scanGroundCells, groundCells);
else if(!scanGroundCells.empty())
groundCells = scanGroundCells;
if(!obstacleCells.empty() && !scanObstacleCells.empty())
cv::hconcat(obstacleCells, scanObstacleCells, obstacleCells);
else if(!scanObstacleCells.empty())
obstacleCells = scanObstacleCells;
if(!emptyCells.empty() && !scanEmptyCells.empty())
cv::hconcat(emptyCells, scanEmptyCells, emptyCells);
else if(!scanEmptyCells.empty())
emptyCells = scanEmptyCells;
}
} }
} }
} }
+3
View File
@@ -234,6 +234,9 @@ const std::map<std::string, std::pair<bool, std::string> > & Parameters::getRemo
{ {
// removed parameters // removed parameters
// 0.20.15
removedParameters_.insert(std::make_pair("Grid/FromDepth", std::make_pair(true, Parameters::kGridSensor())));
// 0.20.9 // 0.20.9
removedParameters_.insert(std::make_pair("OdomORBSLAM2/VocPath", std::make_pair(true, Parameters::kOdomORBSLAMVocPath()))); removedParameters_.insert(std::make_pair("OdomORBSLAM2/VocPath", std::make_pair(true, Parameters::kOdomORBSLAMVocPath())));
removedParameters_.insert(std::make_pair("OdomORBSLAM2/Bf", std::make_pair(true, Parameters::kOdomORBSLAMBf()))); removedParameters_.insert(std::make_pair("OdomORBSLAM2/Bf", std::make_pair(true, Parameters::kOdomORBSLAMBf())));
@@ -226,7 +226,7 @@ public:
double getSubtractFilteringAngle() const; double getSubtractFilteringAngle() const;
bool getGridMapShown() const; bool getGridMapShown() const;
bool isGridMapFrom3DCloud() const; int getGridMapSensor() const;
bool projMapFrame() const; bool projMapFrame() const;
double projMaxGroundAngle() const; double projMaxGroundAngle() const;
double projMaxGroundHeight() const; double projMaxGroundHeight() const;
+5 -4
View File
@@ -1219,7 +1219,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
_ui->doubleSpinBox_grid_footprintWidth->setObjectName(Parameters::kGridFootprintWidth().c_str()); _ui->doubleSpinBox_grid_footprintWidth->setObjectName(Parameters::kGridFootprintWidth().c_str());
_ui->doubleSpinBox_grid_footprintHeight->setObjectName(Parameters::kGridFootprintHeight().c_str()); _ui->doubleSpinBox_grid_footprintHeight->setObjectName(Parameters::kGridFootprintHeight().c_str());
_ui->checkBox_grid_flatObstaclesDetected->setObjectName(Parameters::kGridFlatObstacleDetected().c_str()); _ui->checkBox_grid_flatObstaclesDetected->setObjectName(Parameters::kGridFlatObstacleDetected().c_str());
_ui->groupBox_grid_fromDepthImage->setObjectName(Parameters::kGridFromDepth().c_str()); _ui->comboBox_grid_sensor->setObjectName(Parameters::kGridSensor().c_str());
_ui->checkBox_grid_projMapFrame->setObjectName(Parameters::kGridMapFrameProjection().c_str()); _ui->checkBox_grid_projMapFrame->setObjectName(Parameters::kGridMapFrameProjection().c_str());
_ui->doubleSpinBox_grid_maxGroundAngle->setObjectName(Parameters::kGridMaxGroundAngle().c_str()); _ui->doubleSpinBox_grid_maxGroundAngle->setObjectName(Parameters::kGridMaxGroundAngle().c_str());
_ui->spinBox_grid_normalK->setObjectName(Parameters::kGridNormalK().c_str()); _ui->spinBox_grid_normalK->setObjectName(Parameters::kGridNormalK().c_str());
@@ -4377,7 +4377,8 @@ void PreferencesDialog::setParameter(const std::string & key, const std::string
{ {
//backward compatibility //backward compatibility
std::string valueCpy = value; std::string valueCpy = value;
if(key.compare(Parameters::kIcpStrategy()) == 0) if( key.compare(Parameters::kIcpStrategy()) == 0 ||
key.compare(Parameters::kGridSensor()) == 0)
{ {
if(value.compare("true") == 0) if(value.compare("true") == 0)
{ {
@@ -5595,9 +5596,9 @@ bool PreferencesDialog::getGridMapShown() const
{ {
return _ui->checkBox_map_shown->isChecked(); return _ui->checkBox_map_shown->isChecked();
} }
bool PreferencesDialog::isGridMapFrom3DCloud() const int PreferencesDialog::getGridMapSensor() const
{ {
return _ui->groupBox_grid_fromDepthImage->isChecked(); return _ui->comboBox_grid_sensor->currentIndex();
} }
bool PreferencesDialog::projMapFrame() const bool PreferencesDialog::projMapFrame() const
{ {
+324 -305
View File
@@ -63,9 +63,9 @@
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
<y>-466</y> <y>0</y>
<width>675</width> <width>686</width>
<height>3499</height> <height>3905</height>
</rect> </rect>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_16"> <layout class="QVBoxLayout" name="verticalLayout_16">
@@ -95,7 +95,7 @@
<enum>QFrame::Raised</enum> <enum>QFrame::Raised</enum>
</property> </property>
<property name="currentIndex"> <property name="currentIndex">
<number>5</number> <number>15</number>
</property> </property>
<widget class="QWidget" name="page_22"> <widget class="QWidget" name="page_22">
<layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1"> <layout class="QVBoxLayout" name="verticalLayout_29" stretch="0,1">
@@ -11863,26 +11863,135 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<layout class="QVBoxLayout" name="verticalLayout_110"> <layout class="QVBoxLayout" name="verticalLayout_110">
<item> <item>
<layout class="QGridLayout" name="gridLayout_75" columnstretch="0,1"> <layout class="QGridLayout" name="gridLayout_75" columnstretch="0,1">
<item row="8" column="0"> <item row="10" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_noiseRadius"> <widget class="QSpinBox" name="spinBox_grid_noiseMinNeighbors">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_333">
<property name="text">
<string>Footprint filtering length (0=disabled).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_footprintLength">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
</property> </property>
<property name="decimals"> <property name="decimals">
<number>3</number> <number>2</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<double>1.000000000000000</double> <double>10.000000000000000</double>
</property> </property>
<property name="singleStep"> <property name="singleStep">
<double>0.050000000000000</double> <double>0.100000000000000</double>
</property> </property>
<property name="value"> <property name="value">
<double>0.000000000000000</double> <double>0.000000000000000</double>
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_minDepth">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_325">
<property name="text">
<string>Noise filtering radius (0=disabled). Done after segmentation.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="8" column="1">
<widget class="QLabel" name="label_309">
<property name="text">
<string>Maximum obstacles height (0=disabled).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="5" column="0"> <item row="5" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_maxDepth">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>4.000000000000000</double>
</property>
</widget>
</item>
<item row="12" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_footprintWidth">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_minGroundHeight"> <widget class="QDoubleSpinBox" name="doubleSpinBox_grid_minGroundHeight">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -11904,117 +12013,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="1"> <item row="14" column="1">
<widget class="QLabel" name="label_335">
<property name="text">
<string>Footprint filtering height (0=disabled). Footprint length and width should be set.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_maxObstacleHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>9999.000000000000000</double>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_maxGroundHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="9" column="1">
<widget class="QLabel" name="label_321">
<property name="text">
<string>Noise filtering min neighbors.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_310">
<property name="text">
<string>Maximum ground height (0=disabled). Should be set if Normals Segmentation Approach is checked below.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QLabel" name="label_309">
<property name="text">
<string>Maximum obstacles height (0=disabled).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QSpinBox" name="spinBox_grid_noiseMinNeighbors">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>1000</number>
</property>
<property name="value">
<number>5</number>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_resolution">
<property name="suffix">
<string> m</string>
</property>
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.050000000000000</double>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="label_331"> <widget class="QLabel" name="label_331">
<property name="text"> <property name="text">
<string>Laser scan decimation.</string> <string>Laser scan decimation.</string>
@@ -12027,47 +12026,8 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="13" column="0"> <item row="8" column="0">
<widget class="QSpinBox" name="spinBox_grid_scanDecimation"> <widget class="QDoubleSpinBox" name="doubleSpinBox_grid_maxObstacleHeight">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_333">
<property name="text">
<string>Footprint filtering length (0=disabled).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="1">
<widget class="QLabel" name="label_334">
<property name="text">
<string>Footprint filtering width (0=disabled). Footprint length should be set.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="11" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_footprintWidth">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
</property> </property>
@@ -12075,17 +12035,11 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<number>2</number> <number>2</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<double>10.000000000000000</double> <double>9999.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property> </property>
</widget> </widget>
</item> </item>
<item row="12" column="0"> <item row="13" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_footprintHeight"> <widget class="QDoubleSpinBox" name="doubleSpinBox_grid_footprintHeight">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
@@ -12104,7 +12058,20 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="5" column="1"> <item row="0" column="1">
<widget class="QLabel" name="label_365">
<property name="text">
<string>Create local occupancy grid maps. This should be enabled to generate a global occupancy grid map. A cloud will be created from the depth image (see option below) or the 3D laser scan. This cloud will be segmented into ground and obstacle cells. For 2D laser scan, the occupancy grid is created using 2D ray casting (only Resolution and 2D Laser Scan related parameters are used).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QLabel" name="label_327"> <widget class="QLabel" name="label_327">
<property name="text"> <property name="text">
<string>Minimum ground height (0=disabled).</string> <string>Minimum ground height (0=disabled).</string>
@@ -12117,10 +12084,114 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="1"> <item row="15" column="1">
<widget class="QLabel" name="label_326"> <widget class="QLabel" name="label_456">
<property name="text"> <property name="text">
<string>Resolution (cell size).</string> <string>Input cloud is downsampled by voxel filter (voxel size is cell size) before doing segmentation of obstacles and ground.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="13" column="1">
<widget class="QLabel" name="label_335">
<property name="text">
<string>Footprint filtering height (0=disabled). Footprint length and width should be set.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_maxGroundHeight">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>99999.000000000000000</double>
</property>
<property name="singleStep">
<double>0.010000000000000</double>
</property>
</widget>
</item>
<item row="10" column="1">
<widget class="QLabel" name="label_321">
<property name="text">
<string>Noise filtering min neighbors.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="15" column="0">
<widget class="QCheckBox" name="checkBox_grid_preVoxelFiltering">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="checkBox_grid_projMapFrame">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_323">
<property name="text">
<string>Minimum range from the sensor.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_642">
<property name="text">
<string>Sensor from which the local grid is created.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="12" column="1">
<widget class="QLabel" name="label_334">
<property name="text">
<string>Footprint filtering width (0=disabled). Footprint length should be set.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property> </property>
<property name="textInteractionFlags"> <property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
@@ -12137,62 +12208,26 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="1">
<widget class="QLabel" name="label_325">
<property name="text">
<string>Noise filtering radius (0=disabled). Done after segmentation.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="10" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_footprintLength">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>2</number>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="checkBox_grid_projMapFrame"> <widget class="QComboBox" name="comboBox_grid_sensor">
<item>
<property name="text"> <property name="text">
<string/> <string>LiDAR</string>
</property> </property>
<property name="checked"> </item>
<bool>false</bool> <item>
<property name="text">
<string>Camera(s)</string>
</property> </property>
</item>
<item>
<property name="text">
<string>LiDAR and Camera(s)</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item row="0" column="1"> <item row="2" column="1">
<widget class="QLabel" name="label_365">
<property name="text">
<string>Create local occupancy grid maps. This should be enabled to generate a global occupancy grid map. A cloud will be created from the depth image (see option below) or the 3D laser scan. This cloud will be segmented into ground and obstacle cells. For 2D laser scan, the occupancy grid is created using 2D ray casting (only Resolution and 2D Laser Scan related parameters are used).</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLabel" name="label_311"> <widget class="QLabel" name="label_311">
<property name="text"> <property name="text">
<string>Projection in map frame. On a 3D terrain and a fixed local camera transform (the cloud is created relative to ground), you may want to disable this to do the projection in robot frame instead.</string> <string>Projection in map frame. On a 3D terrain and a fixed local camera transform (the cloud is created relative to ground), you may want to disable this to do the projection in robot frame instead.</string>
@@ -12205,10 +12240,10 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="1"> <item row="7" column="1">
<widget class="QLabel" name="label_323"> <widget class="QLabel" name="label_310">
<property name="text"> <property name="text">
<string>Minimum range from the sensor.</string> <string>Maximum ground height (0=disabled). Should be set if Normals Segmentation Approach is checked below.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -12218,26 +12253,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0"> <item row="5" column="1">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_minDepth">
<property name="suffix">
<string> m</string>
</property>
<property name="decimals">
<number>1</number>
</property>
<property name="maximum">
<double>100.000000000000000</double>
</property>
<property name="singleStep">
<double>0.100000000000000</double>
</property>
<property name="value">
<double>0.000000000000000</double>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QLabel" name="label_320"> <widget class="QLabel" name="label_320">
<property name="text"> <property name="text">
<string>Maximum range from the sensor (0 means no limit).</string> <string>Maximum range from the sensor (0 means no limit).</string>
@@ -12250,45 +12266,61 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="0"> <item row="9" column="0">
<widget class="QDoubleSpinBox" name="doubleSpinBox_grid_maxDepth"> <widget class="QDoubleSpinBox" name="doubleSpinBox_grid_noiseRadius">
<property name="suffix"> <property name="suffix">
<string> m</string> <string> m</string>
</property> </property>
<property name="decimals"> <property name="decimals">
<number>1</number> <number>3</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<double>100.000000000000000</double>
</property>
<property name="singleStep">
<double>1.000000000000000</double> <double>1.000000000000000</double>
</property> </property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value"> <property name="value">
<double>4.000000000000000</double> <double>0.000000000000000</double>
</property> </property>
</widget> </widget>
</item> </item>
<item row="14" column="1"> <item row="14" column="0">
<widget class="QLabel" name="label_456"> <widget class="QSpinBox" name="spinBox_grid_scanDecimation">
<property name="text"> <property name="minimum">
<string>Input cloud is downsampled by voxel filter (voxel size is cell size) before doing segmentation of obstacles and ground.</string> <number>1</number>
</property> </property>
<property name="wordWrap"> <property name="maximum">
<bool>true</bool> <number>100</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLabel" name="label_326">
<property name="text">
<string>Resolution (cell size).</string>
</property> </property>
<property name="textInteractionFlags"> <property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set> <set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property> </property>
</widget> </widget>
</item> </item>
<item row="14" column="0"> <item row="3" column="0">
<widget class="QCheckBox" name="checkBox_grid_preVoxelFiltering"> <widget class="QDoubleSpinBox" name="doubleSpinBox_grid_resolution">
<property name="text"> <property name="suffix">
<string/> <string> m</string>
</property> </property>
<property name="checked"> <property name="minimum">
<bool>false</bool> <double>0.010000000000000</double>
</property>
<property name="maximum">
<double>1.000000000000000</double>
</property>
<property name="value">
<double>0.050000000000000</double>
</property> </property>
</widget> </widget>
</item> </item>
@@ -12297,25 +12329,12 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<item> <item>
<widget class="QGroupBox" name="groupBox_grid_fromDepthImage"> <widget class="QGroupBox" name="groupBox_grid_fromDepthImage">
<property name="title"> <property name="title">
<string>From Depth Image</string> <string>Camera Sensor</string>
</property> </property>
<property name="checkable"> <property name="checkable">
<bool>true</bool> <bool>false</bool>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_108"> <layout class="QVBoxLayout" name="verticalLayout_108">
<item>
<widget class="QLabel" name="label_octomap_groundObstacle_2">
<property name="text">
<string>Use depth image for cloud projection instead of laser scan.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item> <item>
<layout class="QGridLayout" name="gridLayout_76" columnstretch="0,1"> <layout class="QGridLayout" name="gridLayout_76" columnstretch="0,1">
<item row="0" column="0"> <item row="0" column="0">
@@ -12364,29 +12383,6 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="4" column="1">
<widget class="QLabel" name="label_363">
<property name="text">
<string>Ray tracing is done for each obstacle, filling unknown space between the sensor and obstacles. If RTAB-Map is not built with OctoMap and 3D is checked below, 3D ray tracing cannot be done.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="checkBox_grid_projRayTracing">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@@ -12575,7 +12571,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<item> <item>
<widget class="QLabel" name="label_octomap_groundObstacle_3"> <widget class="QLabel" name="label_octomap_groundObstacle_3">
<property name="text"> <property name="text">
<string>A 3D occupancy grid is required if you want an Octomap. Set to false if you want only a 2D map, the cloud will be projected on xy plane. A 2D map can be still generated if checked, but it requires more memory and time to generate it.</string> <string>A 3D occupancy grid is required if you want an OctoMap. Set to false if you want only a 2D map, the cloud will be projected on xy plane. A 2D map can be still generated if checked, but it requires more memory and time to generate it.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
@@ -12610,6 +12606,29 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1">
<widget class="QLabel" name="label_363">
<property name="text">
<string>Ray tracing is done for each obstacle, filling unknown space between the sensor and obstacles. If RTAB-Map is not built with OctoMap, 3D ray tracing cannot be done.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="checkBox_grid_projRayTracing">
<property name="text">
<string/>
</property>
<property name="checked">
<bool>false</bool>
</property>
</widget>
</item>
</layout> </layout>
</item> </item>
</layout> </layout>
@@ -12624,7 +12643,7 @@ If set to false, classic RTAB-Map loop closure detection is done using only imag
<item> <item>
<widget class="QLabel" name="label_octomap_groundObstacle_5"> <widget class="QLabel" name="label_octomap_groundObstacle_5">
<property name="text"> <property name="text">
<string>These parameters only affect 2D occupancy grid created from 2D laser scan (when &quot;From Depth image&quot; is not checked and laser scan is 2D).</string> <string>These parameters only affect 2D occupancy grid created from 2D laser scan.</string>
</property> </property>
<property name="wordWrap"> <property name="wordWrap">
<bool>true</bool> <bool>true</bool>
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<package> <package>
<name>rtabmap</name> <name>rtabmap</name>
<version>0.20.14</version> <version>0.20.15</version>
<description>RTAB-Map's standalone library. RTAB-Map is a RGB-D SLAM approach with real-time constraints.</description> <description>RTAB-Map's standalone library. RTAB-Map is a RGB-D SLAM approach with real-time constraints.</description>
<maintainer email="[email protected]">Mathieu Labbe</maintainer> <maintainer email="[email protected]">Mathieu Labbe</maintainer>
<author>Mathieu Labbe</author> <author>Mathieu Labbe</author>