|
|
|
@@ -729,11 +729,17 @@ int Rtabmap::triggerNewMap()
|
|
|
|
int mapId = -1;
|
|
|
|
int mapId = -1;
|
|
|
|
if(_memory)
|
|
|
|
if(_memory)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
_lastLocalizationNodeId = 0;
|
|
|
|
|
|
|
|
_odomCachePoses.clear();
|
|
|
|
|
|
|
|
_odomCacheConstraints.clear();
|
|
|
|
|
|
|
|
|
|
|
|
if(!_memory->isIncremental())
|
|
|
|
if(!_memory->isIncremental())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
UWARN("Memory is not incremental (%s=false), ignoring creating a new map as we "
|
|
|
|
if(_savedLocalizationIgnored)
|
|
|
|
"should be already processing new nodes in a new session.",
|
|
|
|
{
|
|
|
|
Parameters::kMemIncrementalMemory().c_str());
|
|
|
|
_mapCorrection.setIdentity();
|
|
|
|
|
|
|
|
_lastLocalizationPose.setIdentity();
|
|
|
|
|
|
|
|
}
|
|
|
|
return mapId;
|
|
|
|
return mapId;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
std::map<int, int> reducedIds;
|
|
|
|
std::map<int, int> reducedIds;
|
|
|
|
@@ -741,9 +747,6 @@ int Rtabmap::triggerNewMap()
|
|
|
|
UINFO("New map triggered, new map = %d", mapId);
|
|
|
|
UINFO("New map triggered, new map = %d", mapId);
|
|
|
|
_optimizedPoses.clear();
|
|
|
|
_optimizedPoses.clear();
|
|
|
|
_constraints.clear();
|
|
|
|
_constraints.clear();
|
|
|
|
_lastLocalizationNodeId = 0;
|
|
|
|
|
|
|
|
_odomCachePoses.clear();
|
|
|
|
|
|
|
|
_odomCacheConstraints.clear();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(_bayesFilter)
|
|
|
|
if(_bayesFilter)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -1053,36 +1056,34 @@ bool Rtabmap::process(
|
|
|
|
bool fakeOdom = false;
|
|
|
|
bool fakeOdom = false;
|
|
|
|
if(_rgbdSlamMode)
|
|
|
|
if(_rgbdSlamMode)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(!_memory->isIncremental() && !odomPose.isNull())
|
|
|
|
if(!_memory->isIncremental() &&
|
|
|
|
|
|
|
|
!odomPose.isNull() &&
|
|
|
|
|
|
|
|
_optimizedPoses.size() &&
|
|
|
|
|
|
|
|
_mapCorrection.isIdentity() &&
|
|
|
|
|
|
|
|
!_lastLocalizationPose.isNull() &&
|
|
|
|
|
|
|
|
!_lastLocalizationPose.isIdentity() &&
|
|
|
|
|
|
|
|
_lastLocalizationNodeId == 0)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if(!_mapCorrectionBackup.isNull())
|
|
|
|
// Localization mode
|
|
|
|
|
|
|
|
if(!_optimizeFromGraphEnd)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
_mapCorrection = _mapCorrectionBackup;
|
|
|
|
//set map->odom so that odom is moved back to last saved localization
|
|
|
|
_mapCorrectionBackup.setNull();
|
|
|
|
_mapCorrection = _lastLocalizationPose * odomPose.inverse();
|
|
|
|
|
|
|
|
std::map<int, Transform> nodesOnly(_optimizedPoses.lower_bound(1), _optimizedPoses.end());
|
|
|
|
|
|
|
|
_lastLocalizationNodeId = graph::findNearestNode(nodesOnly, _lastLocalizationPose);
|
|
|
|
|
|
|
|
UWARN("Update map correction based on last localization saved in database! correction = %s, nearest id = %d of last pose = %s, odom = %s",
|
|
|
|
|
|
|
|
_mapCorrection.prettyPrint().c_str(),
|
|
|
|
|
|
|
|
_lastLocalizationNodeId,
|
|
|
|
|
|
|
|
_lastLocalizationPose.prettyPrint().c_str(),
|
|
|
|
|
|
|
|
odomPose.prettyPrint().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(_optimizedPoses.size() && _mapCorrection.isIdentity() && !_lastLocalizationPose.isNull() && _lastLocalizationNodeId == 0)
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// Localization mode
|
|
|
|
//move optimized poses accordingly to last saved localization
|
|
|
|
if(!_optimizeFromGraphEnd)
|
|
|
|
Transform mapCorrectionInv = odomPose * _lastLocalizationPose.inverse();
|
|
|
|
|
|
|
|
for(std::map<int, Transform>::iterator iter=_optimizedPoses.begin(); iter!=_optimizedPoses.end(); ++iter)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
//set map->odom so that odom is moved back to last saved localization
|
|
|
|
iter->second = mapCorrectionInv * iter->second;
|
|
|
|
_mapCorrection = _lastLocalizationPose * odomPose.inverse();
|
|
|
|
|
|
|
|
std::map<int, Transform> nodesOnly(_optimizedPoses.lower_bound(1), _optimizedPoses.end());
|
|
|
|
|
|
|
|
_lastLocalizationNodeId = graph::findNearestNode(nodesOnly, _lastLocalizationPose);
|
|
|
|
|
|
|
|
UWARN("Update map correction based on last localization saved in database! correction = %s, nearest id = %d of last pose = %s, odom = %s",
|
|
|
|
|
|
|
|
_mapCorrection.prettyPrint().c_str(),
|
|
|
|
|
|
|
|
_lastLocalizationNodeId,
|
|
|
|
|
|
|
|
_lastLocalizationPose.prettyPrint().c_str(),
|
|
|
|
|
|
|
|
odomPose.prettyPrint().c_str());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
//move optimized poses accordingly to last saved localization
|
|
|
|
|
|
|
|
Transform mapCorrectionInv = odomPose * _lastLocalizationPose.inverse();
|
|
|
|
|
|
|
|
for(std::map<int, Transform>::iterator iter=_optimizedPoses.begin(); iter!=_optimizedPoses.end(); ++iter)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
iter->second = mapCorrectionInv * iter->second;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -1097,12 +1098,20 @@ bool Rtabmap::process(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // fake localization
|
|
|
|
else // fake localization
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
if(!_mapCorrectionBackup.isNull())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
_mapCorrection = _mapCorrectionBackup;
|
|
|
|
|
|
|
|
_mapCorrectionBackup.setNull();
|
|
|
|
|
|
|
|
}
|
|
|
|
if(_lastLocalizationPose.isNull())
|
|
|
|
if(_lastLocalizationPose.isNull())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
_lastLocalizationPose = Transform::getIdentity();
|
|
|
|
_lastLocalizationPose = Transform::getIdentity();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fakeOdom = true;
|
|
|
|
fakeOdom = true;
|
|
|
|
odomPose = _mapCorrection.inverse() * _lastLocalizationPose;
|
|
|
|
odomPose = _mapCorrection.inverse() * _lastLocalizationPose;
|
|
|
|
|
|
|
|
UDEBUG("Map correction = %s", _mapCorrection.prettyPrint().c_str());
|
|
|
|
|
|
|
|
UDEBUG("Last localization pose: %s", _lastLocalizationPose.prettyPrint().c_str());
|
|
|
|
|
|
|
|
UDEBUG("Fake odom: %s", odomPose.prettyPrint().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(_memory->isIncremental()) // only in mapping mode
|
|
|
|
else if(_memory->isIncremental()) // only in mapping mode
|
|
|
|
@@ -1351,6 +1360,7 @@ bool Rtabmap::process(
|
|
|
|
_constraints.insert(std::make_pair(iter->first, iter->second.inverse()));
|
|
|
|
_constraints.insert(std::make_pair(iter->first, iter->second.inverse()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// only in mapping mode we add a neighbor link
|
|
|
|
if(signature->getLinks().size() &&
|
|
|
|
if(signature->getLinks().size() &&
|
|
|
|
signature->getLinks().begin()->second.type() == Link::kNeighbor)
|
|
|
|
signature->getLinks().begin()->second.type() == Link::kNeighbor)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -1381,6 +1391,11 @@ bool Rtabmap::process(
|
|
|
|
_lastLocalizationPose = newPose; // keep in cache the latest corrected pose
|
|
|
|
_lastLocalizationPose = newPose; // keep in cache the latest corrected pose
|
|
|
|
if(!_memory->isIncremental())
|
|
|
|
if(!_memory->isIncremental())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
if(!_odomCacheAddLink.empty())
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
float odomDistance = (_odomCacheAddLink.rbegin()->second.inverse() * signature->getPose()).getNorm();
|
|
|
|
|
|
|
|
_distanceTravelled += odomDistance;
|
|
|
|
|
|
|
|
}
|
|
|
|
_odomCacheAddLink.insert(std::make_pair(signature->id(), signature->getPose()));
|
|
|
|
_odomCacheAddLink.insert(std::make_pair(signature->id(), signature->getPose()));
|
|
|
|
while(!_odomCacheAddLink.empty() && (int)_odomCacheAddLink.size() > _maxOdomCacheSize+1)
|
|
|
|
while(!_odomCacheAddLink.empty() && (int)_odomCacheAddLink.size() > _maxOdomCacheSize+1)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -1415,7 +1430,6 @@ bool Rtabmap::process(
|
|
|
|
odomCovariance.inv())));
|
|
|
|
odomCovariance.inv())));
|
|
|
|
_odomCachePoses.insert(std::make_pair(signature->id(), signature->getPose())); // keep odometry poses
|
|
|
|
_odomCachePoses.insert(std::make_pair(signature->id(), signature->getPose())); // keep odometry poses
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2815,10 +2829,12 @@ bool Rtabmap::process(
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Transform newPose = _optimizedPoses.at(localizationLinks.begin()->first) * localizationLinks.begin()->second.transform().inverse();
|
|
|
|
Transform newPose = _optimizedPoses.at(localizationLinks.begin()->first) * localizationLinks.begin()->second.transform().inverse();
|
|
|
|
|
|
|
|
UDEBUG("newPose=%s", newPose.prettyPrint().c_str());
|
|
|
|
if(_graphOptimizer->isSlam2d())
|
|
|
|
if(_graphOptimizer->isSlam2d())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
// in case of 3d landmarks, transform constraint to 2D
|
|
|
|
// in case of 3d landmarks, transform constraint to 2D
|
|
|
|
newPose = newPose.to3DoF();
|
|
|
|
newPose = newPose.to3DoF();
|
|
|
|
|
|
|
|
UDEBUG("newPose 2D=%s", newPose.prettyPrint().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if(_graphOptimizer->gravitySigma() > 0)
|
|
|
|
else if(_graphOptimizer->gravitySigma() > 0)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -2851,6 +2867,7 @@ bool Rtabmap::process(
|
|
|
|
transform *= error;
|
|
|
|
transform *= error;
|
|
|
|
|
|
|
|
|
|
|
|
newPose = _optimizedPoses.at(loopId) * transform.inverse();
|
|
|
|
newPose = _optimizedPoses.at(loopId) * transform.inverse();
|
|
|
|
|
|
|
|
UDEBUG("newPose gravity=%s", newPose.prettyPrint().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
else
|
|
|
|
{
|
|
|
|
{
|
|
|
|
@@ -3132,6 +3149,7 @@ bool Rtabmap::process(
|
|
|
|
UINFO("Set loop closure transform = %s", loopIter->second.transform().prettyPrint().c_str());
|
|
|
|
UINFO("Set loop closure transform = %s", loopIter->second.transform().prettyPrint().c_str());
|
|
|
|
statistics_.setLoopClosureTransform(loopIter->second.transform());
|
|
|
|
statistics_.setLoopClosureTransform(loopIter->second.transform());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMap_id(), sLoop->mapId());
|
|
|
|
statistics_.addStatistic(Statistics::kLoopVisual_words(), sLoop->getWords().size());
|
|
|
|
statistics_.addStatistic(Statistics::kLoopVisual_words(), sLoop->getWords().size());
|
|
|
|
|
|
|
|
|
|
|
|
// if ground truth exists, compute localization error
|
|
|
|
// if ground truth exists, compute localization error
|
|
|
|
@@ -3153,8 +3171,8 @@ bool Rtabmap::process(
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToOdom_pitch(), pitch*180.0f/M_PI);
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToOdom_pitch(), pitch*180.0f/M_PI);
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToOdom_yaw(), yaw*180.0f/M_PI);
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToOdom_yaw(), yaw*180.0f/M_PI);
|
|
|
|
|
|
|
|
|
|
|
|
// Odom correction (actual odometry pose change)
|
|
|
|
// Odom correction (actual odometry pose change), ignore correction from first localization
|
|
|
|
if(!odomPose.isNull() && !previousMapCorrection.isNull())
|
|
|
|
if(!odomPose.isNull() && !previousMapCorrection.isNull() && !previousMapCorrection.isIdentity())
|
|
|
|
{
|
|
|
|
{
|
|
|
|
Transform odomCorrection = (previousMapCorrection*odomPose).inverse()*_mapCorrection*odomPose;
|
|
|
|
Transform odomCorrection = (previousMapCorrection*odomPose).inverse()*_mapCorrection*odomPose;
|
|
|
|
statistics_.addStatistic(Statistics::kLoopOdom_correction_norm(), odomCorrection.getNorm());
|
|
|
|
statistics_.addStatistic(Statistics::kLoopOdom_correction_norm(), odomCorrection.getNorm());
|
|
|
|
@@ -3177,6 +3195,7 @@ bool Rtabmap::process(
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToBase_roll(), roll*180.0f/M_PI);
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToBase_roll(), roll*180.0f/M_PI);
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToBase_pitch(), pitch*180.0f/M_PI);
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToBase_pitch(), pitch*180.0f/M_PI);
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToBase_yaw(), yaw*180.0f/M_PI);
|
|
|
|
statistics_.addStatistic(Statistics::kLoopMapToBase_yaw(), yaw*180.0f/M_PI);
|
|
|
|
|
|
|
|
UINFO("Localization pose = %s", _lastLocalizationPose.prettyPrint().c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
statistics_.setMapCorrection(_mapCorrection);
|
|
|
|
statistics_.setMapCorrection(_mapCorrection);
|
|
|
|
|