Integrated GPS into likelihood computation

This commit is contained in:
matlabbe
2018-10-22 12:31:07 -04:00
parent 93a3a667c8
commit 3bc8fc4c11
10 changed files with 215 additions and 13 deletions

View File

@@ -106,6 +106,20 @@ cv::Point3d GeodeticCoords::toGeocentric_WGS84() const
geodeticToENU_WGS84
---------------------------------------------------------------*/
cv::Point3d GeodeticCoords::toENU_WGS84(const GeodeticCoords &origin) const
{
// Generate 3D point:
cv::Point3d P_geocentric = this->toGeocentric_WGS84();
// Generate reference 3D point:
cv::Point3d P_geocentric_ref = origin.toGeocentric_WGS84();
return Geocentric_WGS84ToENU_WGS84(P_geocentric, P_geocentric_ref, origin);
}
cv::Point3d GeodeticCoords::Geocentric_WGS84ToENU_WGS84(
const cv::Point3d & geocentric_WGS84,
const cv::Point3d & origin_geocentric_WGS84,
const GeodeticCoords & origin)
{
// --------------------------------------------------------------------
// Explanation: We compute the earth-centric coordinates first,
@@ -116,25 +130,20 @@ cv::Point3d GeodeticCoords::toENU_WGS84(const GeodeticCoords &origin) const
// (JLBC 21/DEC/2006) (Fixed: JLBC 9/JUL/2008)
// - Oct/2013, Emilio Sanjurjo: Fixed UP vector pointing exactly normal to ellipsoid surface.
// --------------------------------------------------------------------
// Generate 3D point:
cv::Point3d P_geocentric = this->toGeocentric_WGS84();
// Generate reference 3D point:
cv::Point3d P_geocentric_ref = origin.toGeocentric_WGS84();
const double clat = cos(DEG2RAD(origin.latitude())), slat = sin(DEG2RAD(origin.latitude()));
const double clon = cos(DEG2RAD(origin.longitude())), slon = sin(DEG2RAD(origin.longitude()));
// Compute the resulting relative coordinates:
// For using smaller numbers:
P_geocentric -= P_geocentric_ref;
cv::Point3d geocentric_WGS84_rel = geocentric_WGS84-origin_geocentric_WGS84;
// Optimized calculation: Local transformed coordinates of P_geo(x,y,z)
// after rotation given by the transposed rotation matrix from ENU -> ECEF.
cv::Point3d out;
out.x = -slon*P_geocentric.x + clon*P_geocentric.y;
out.y = -clon*slat*P_geocentric.x -slon*slat*P_geocentric.y + clat*P_geocentric.z;
out.z = clon*clat*P_geocentric.x + slon*clat*P_geocentric.y +slat*P_geocentric.z;
out.x = -slon*geocentric_WGS84_rel.x + clon*geocentric_WGS84_rel.y;
out.y = -clon*slat*geocentric_WGS84_rel.x -slon*slat*geocentric_WGS84_rel.y + clat*geocentric_WGS84_rel.z;
out.z = clon*clat*geocentric_WGS84_rel.x + slon*clat*geocentric_WGS84_rel.y +slat*geocentric_WGS84_rel.z;
return out;
}

View File

@@ -3446,6 +3446,53 @@ Transform Memory::getGroundTruthPose(int signatureId, bool lookInDatabase) const
return groundTruth;
}
void Memory::getGPS(int id, GPS & gps, Transform & offsetENU, bool lookInDatabase, int maxGraphDepth) const
{
gps = GPS();
offsetENU=Transform::getIdentity();
Transform odomPose, groundTruth;
int mapId, weight;
std::string label;
double stamp;
std::vector<float> velocity;
getNodeInfo(id, odomPose, mapId, weight, label, stamp, groundTruth, velocity, gps, lookInDatabase);
if(gps.stamp() == 0.0)
{
// Search for the nearest node with GPS, and compute its relative transform in ENU coordinates
std::map<int, int> nearestIds;
nearestIds = getNeighborsId(id, maxGraphDepth, lookInDatabase?-1:0, true, false, true);
std::multimap<int, int> nearestIdsSorted;
for(std::map<int, int>::iterator iter=nearestIds.begin(); iter!=nearestIds.end(); ++iter)
{
nearestIdsSorted.insert(std::make_pair(iter->second, iter->first));
}
for(std::map<int, int>::iterator iter=nearestIdsSorted.begin(); iter!=nearestIdsSorted.end(); ++iter)
{
const Signature * s = getSignature(iter->second);
UASSERT(s!=0);
if(s->sensorData().gps().stamp() > 0.0)
{
std::list<std::pair<int, Transform> > path = graph::computePath(s->id(), id, this, lookInDatabase);
if(path.size() >= 2)
{
gps = s->sensorData().gps();
Transform localToENU(0,0,(float)((-(gps.bearing()-90))*M_PI/180.0) - s->getPose().theta());
offsetENU = localToENU*(s->getPose().rotation()*path.rbegin()->second);
break;
}
else
{
UWARN("Failed to find path %d -> %d", s->id(), id);
}
}
}
}
}
bool Memory::getNodeInfo(int signatureId,
Transform & odomPose,
int & mapId,

View File

@@ -138,6 +138,7 @@ Rtabmap::Rtabmap() :
_wDir(""),
_mapCorrection(Transform::getIdentity()),
_lastLocalizationNodeId(0),
_currentSessionHasGPS(false),
_pathStatus(0),
_pathCurrentIndex(0),
_pathGoalIndex(0),
@@ -360,6 +361,8 @@ void Rtabmap::close(bool databaseSaved, const std::string & ouputDatabasePath)
_lastLocalizationNodeId = 0;
_distanceTravelled = 0.0f;
this->clearPath(0);
_gpsGeocentricCache.clear();
_currentSessionHasGPS = false;
flushStatisticLogs();
if(_foutFloat)
@@ -1068,6 +1071,7 @@ bool Rtabmap::process(
}
signature = _memory->getLastWorkingSignature();
_currentSessionHasGPS = _currentSessionHasGPS || signature->sensorData().gps().stamp() > 0.0;
if(!signature)
{
UFATAL("Not supposed to be here...last signature is null?!?");
@@ -1395,6 +1399,39 @@ bool Rtabmap::process(
ULOGGER_INFO("computing likelihood...");
std::list<int> signaturesToCompare;
GPS originGPS = signature->sensorData().gps();
Transform originOffsetENU = Transform::getIdentity();
if(originGPS.stamp() == 0.0 && _currentSessionHasGPS)
{
UTimer tmpT;
if(_optimizedPoses.size() && _memory->isIncremental())
{
//Search for latest node having GPS linked to current signature not too far.
std::map<int, float> nearestIds = graph::getNodesInRadius(signature->id(), _optimizedPoses, _localRadius);
for(std::map<int, float>::reverse_iterator iter=nearestIds.rbegin(); iter!=nearestIds.rend(); ++iter)
{
const Signature * s = _memory->getSignature(iter->first);
UASSERT(s!=0);
if(s->sensorData().gps().stamp() > 0.0)
{
originGPS = s->sensorData().gps();
const Transform & sPose = _optimizedPoses.at(s->id());
Transform localToENU(0,0,(float)((-(originGPS.bearing()-90))*M_PI/180.0) - sPose.theta());
originOffsetENU = localToENU * (sPose.rotation()*(sPose.inverse()*_optimizedPoses.at(signature->id())));
break;
}
}
}
//else if(!_memory->isIncremental()) // TODO, how can we estimate current GPS position in localization?
//{
//}
}
if(originGPS.stamp() > 0.0)
{
// no need to save it if it is in localization mode
_gpsGeocentricCache.insert(std::make_pair(signature->id(), std::make_pair(originGPS.toGeodeticCoords().toGeocentric_WGS84(), originOffsetENU)));
}
for(std::map<int, double>::const_iterator iter=_memory->getWorkingMem().begin();
iter!=_memory->getWorkingMem().end();
++iter)
@@ -1405,7 +1442,58 @@ bool Rtabmap::process(
UASSERT(s!=0);
if(s->getWeight() != -1) // ignore intermediate nodes
{
signaturesToCompare.push_back(iter->first);
bool accept = true;
if(originGPS.stamp()>0.0)
{
std::map<int, std::pair<cv::Point3d, Transform> >::iterator cacheIter = _gpsGeocentricCache.find(s->id());
if(cacheIter == _gpsGeocentricCache.end())
{
GPS gps = s->sensorData().gps();
Transform offsetENU = Transform::getIdentity();
if(gps.stamp()==0.0)
{
_memory->getGPS(s->id(), gps, offsetENU, false);
}
if(gps.stamp() > 0.0)
{
cacheIter = _gpsGeocentricCache.insert(
std::make_pair(s->id(),
std::make_pair(gps.toGeodeticCoords().toGeocentric_WGS84(), offsetENU))).first;
}
}
if(cacheIter != _gpsGeocentricCache.end())
{
std::map<int, std::pair<cv::Point3d, Transform> >::iterator originIter = _gpsGeocentricCache.find(signature->id());
UASSERT(originIter != _gpsGeocentricCache.end());
cv::Point3d relativePose = GeodeticCoords::Geocentric_WGS84ToENU_WGS84(cacheIter->second.first, originIter->second.first, originGPS.toGeodeticCoords());
const double & error = originGPS.error();
const Transform & offsetENU = cacheIter->second.second;
relativePose.x += offsetENU.x() - originOffsetENU.x();
relativePose.y += offsetENU.y() - originOffsetENU.y();
relativePose.z += offsetENU.z() - originOffsetENU.z();
// ignore altitude if difference is under GPS error
if(relativePose.z>error)
{
relativePose.z -= error;
}
else if(relativePose.z < -error)
{
relativePose.z += error;
}
else
{
relativePose.z = 0;
}
accept = uNormSquared(relativePose.x, relativePose.y, relativePose.z) < _localRadius*_localRadius;
}
}
if(accept)
{
signaturesToCompare.push_back(iter->first);
}
}
}
else
@@ -2684,6 +2772,12 @@ bool Rtabmap::process(
}
_lastProcessTime = totalTime;
// cleanup cached gps values
for(std::list<int>::iterator iter=signaturesRemoved.begin(); iter!=signaturesRemoved.end() && _gpsGeocentricCache.size(); ++iter)
{
_gpsGeocentricCache.erase(*iter);
}
//Remove optimized poses from signatures transferred
if(signaturesRemoved.size() && (_optimizedPoses.size() || _constraints.size()))
{