mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-02 09:30:25 +08:00
Integrated GPS into likelihood computation
This commit is contained in:
@@ -70,6 +70,10 @@ public:
|
||||
void fromENU_WGS84(const cv::Point3d & enu, const GeodeticCoords & origin);
|
||||
|
||||
static cv::Point3d ENU_WGS84ToGeocentric_WGS84(const cv::Point3d & enu, const GeodeticCoords & origin);
|
||||
static cv::Point3d Geocentric_WGS84ToENU_WGS84(
|
||||
const cv::Point3d & geocentric_WGS84,
|
||||
const cv::Point3d & origin_geocentric_WGS84,
|
||||
const GeodeticCoords & origin);
|
||||
|
||||
private:
|
||||
double latitude_; // deg
|
||||
|
||||
@@ -161,6 +161,7 @@ public:
|
||||
int getSignatureIdByLabel(const std::string & label, bool lookInDatabase = true) const;
|
||||
bool labelSignature(int id, const std::string & label);
|
||||
std::map<int, std::string> getAllLabels() const;
|
||||
|
||||
/**
|
||||
* Set user data. Detect automatically if raw or compressed. If raw, the data is
|
||||
* compressed too. A matrix of type CV_8UC1 with 1 row is considered as compressed.
|
||||
@@ -175,6 +176,7 @@ public:
|
||||
double getDbSavingTime() const;
|
||||
Transform getOdomPose(int signatureId, bool lookInDatabase = false) const;
|
||||
Transform getGroundTruthPose(int signatureId, bool lookInDatabase = false) const;
|
||||
void getGPS(int id, GPS & gps, Transform & offsetENU, bool lookInDatabase, int maxGraphDepth = 0) const;
|
||||
bool getNodeInfo(int signatureId,
|
||||
Transform & odomPose,
|
||||
int & mapId,
|
||||
|
||||
@@ -292,6 +292,8 @@ private:
|
||||
Transform _mapCorrectionBackup; // used in localization mode when odom is lost
|
||||
Transform _lastLocalizationPose; // Corrected odometry pose. In mapping mode, this corresponds to last pose return by getLocalOptimizedPoses().
|
||||
int _lastLocalizationNodeId; // for localization mode
|
||||
std::map<int, std::pair<cv::Point3d, Transform> > _gpsGeocentricCache;
|
||||
bool _currentSessionHasGPS;
|
||||
|
||||
// Planning stuff
|
||||
int _pathStatus;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user