mirror of
https://github.com/introlab/rtabmap_ros.git
synced 2026-10-04 00:37:46 +08:00
Update version 0.10.11:
-Added parameter "Mem/ReduceGraph" with new link type (NeighborMerged) -DatabaseViewer: add Info panel, fixed empty extracted database when "RGB images" is not checked -ConsoleWidget: added buffer size and refresh rate options -DBDriver: new database info getters -Graph: added reduceGraph() method, added Dijsktra computePath() with links only -Updated default parameters: RGBD/LocalLoopDetectionSpace=true, RGBD/LinearUpdate=0.1 and RGBD/AngularUpdate=0.1 -Goals are saved with label instead of ID if the target node has a label -DataRecorder: fixed saving incrementally the database (instead of only at the end) -MainWindow: When waypoints are used, resend the current goal (1 sec delay) if it has failed setting it
This commit is contained in:
@@ -106,6 +106,79 @@ long DBDriver::getMemoryUsed() const
|
||||
return bytes;
|
||||
}
|
||||
|
||||
long DBDriver::getImagesMemoryUsed() const
|
||||
{
|
||||
long bytes;
|
||||
_dbSafeAccessMutex.lock();
|
||||
bytes = getImagesMemoryUsedQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return bytes;
|
||||
}
|
||||
long DBDriver::getDepthImagesMemoryUsed() const
|
||||
{
|
||||
long bytes;
|
||||
_dbSafeAccessMutex.lock();
|
||||
bytes = getDepthImagesMemoryUsedQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return bytes;
|
||||
}
|
||||
long DBDriver::getLaserScansMemoryUsed() const
|
||||
{
|
||||
long bytes;
|
||||
_dbSafeAccessMutex.lock();
|
||||
bytes = getLaserScansMemoryUsedQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return bytes;
|
||||
}
|
||||
long DBDriver::getUserDataMemoryUsed() const
|
||||
{
|
||||
long bytes;
|
||||
_dbSafeAccessMutex.lock();
|
||||
bytes = getUserDataMemoryUsedQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return bytes;
|
||||
}
|
||||
long DBDriver::getWordsMemoryUsed() const
|
||||
{
|
||||
long bytes;
|
||||
_dbSafeAccessMutex.lock();
|
||||
bytes = getWordsMemoryUsedQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return bytes;
|
||||
}
|
||||
int DBDriver::getLastNodesSize() const
|
||||
{
|
||||
int nodes;
|
||||
_dbSafeAccessMutex.lock();
|
||||
nodes = getLastNodesSizeQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return nodes;
|
||||
}
|
||||
int DBDriver::getLastDictionarySize() const
|
||||
{
|
||||
int words;
|
||||
_dbSafeAccessMutex.lock();
|
||||
words = getLastDictionarySizeQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return words;
|
||||
}
|
||||
int DBDriver::getTotalNodesSize() const
|
||||
{
|
||||
int words;
|
||||
_dbSafeAccessMutex.lock();
|
||||
words = getTotalNodesSizeQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return words;
|
||||
}
|
||||
int DBDriver::getTotalDictionarySize() const
|
||||
{
|
||||
int words;
|
||||
_dbSafeAccessMutex.lock();
|
||||
words = getTotalDictionarySizeQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return words;
|
||||
}
|
||||
|
||||
std::string DBDriver::getDatabaseVersion() const
|
||||
{
|
||||
std::string version = "0.0.0";
|
||||
@@ -473,7 +546,8 @@ void DBDriver::getNodeData(
|
||||
}
|
||||
}
|
||||
|
||||
bool DBDriver::getNodeInfo(int signatureId,
|
||||
bool DBDriver::getNodeInfo(
|
||||
int signatureId,
|
||||
Transform & pose,
|
||||
int & mapId,
|
||||
int & weight,
|
||||
@@ -568,7 +642,8 @@ void DBDriver::getAllNodeIds(std::set<int> & ids, bool ignoreChildren) const
|
||||
nIter!=sIter->second->getLinks().end();
|
||||
++nIter)
|
||||
{
|
||||
if(nIter->second.type() == Link::kNeighbor)
|
||||
if(nIter->second.type() == Link::kNeighbor ||
|
||||
nIter->second.type() == Link::kNeighborMerged)
|
||||
{
|
||||
hasNeighbors = true;
|
||||
break;
|
||||
@@ -778,7 +853,8 @@ void DBDriver::generateGraph(
|
||||
|
||||
const char * colorG = "green";
|
||||
const char * colorP = "pink";
|
||||
; UINFO("Generating map with %d locations", ids.size());
|
||||
const char * colorNM = "blue";
|
||||
UINFO("Generating map with %d locations", ids.size());
|
||||
fprintf(fout, "digraph G {\n");
|
||||
for(std::set<int>::iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
@@ -809,6 +885,16 @@ void DBDriver::generateGraph(
|
||||
iter->first,
|
||||
weightNeighbor);
|
||||
}
|
||||
else if(iter->second.type() == Link::kNeighborMerged)
|
||||
{
|
||||
//merged neighbor
|
||||
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"M\", fontcolor=%s, fontsize=8];\n",
|
||||
id,
|
||||
weight,
|
||||
iter->first,
|
||||
weightNeighbor,
|
||||
colorNM);
|
||||
}
|
||||
else if(iter->first > id)
|
||||
{
|
||||
//loop
|
||||
@@ -860,6 +946,15 @@ void DBDriver::generateGraph(
|
||||
iter->first,
|
||||
weightNeighbor);
|
||||
}
|
||||
else if(iter->second.type() == Link::kNeighborMerged)
|
||||
{
|
||||
fprintf(fout, " \"%d\\n%d\" -> \"%d\\n%d\" [label=\"M\", fontcolor=%s, fontsize=8];\n",
|
||||
id,
|
||||
weight,
|
||||
iter->first,
|
||||
weightNeighbor,
|
||||
colorNM);
|
||||
}
|
||||
else if(iter->first > id)
|
||||
{
|
||||
//loop
|
||||
|
||||
@@ -446,6 +446,259 @@ long DBDriverSqlite3::getMemoryUsedQuery() const
|
||||
}
|
||||
}
|
||||
|
||||
long DBDriverSqlite3::getImagesMemoryUsedQuery() const
|
||||
{
|
||||
UDEBUG("");
|
||||
long size = 0L;
|
||||
if(_ppDb)
|
||||
{
|
||||
std::string query;
|
||||
if(uStrNumCmp(_version, "0.10.1") >= 0)
|
||||
{
|
||||
query = "SELECT sum(length(image)) from Data;";
|
||||
}
|
||||
else
|
||||
{
|
||||
query = "SELECT sum(length(data)) from Image;";
|
||||
}
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
size = sqlite3_column_int64(ppStmt, 0);
|
||||
rc = sqlite3_step(ppStmt);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
long DBDriverSqlite3::getDepthImagesMemoryUsedQuery() const
|
||||
{
|
||||
UDEBUG("");
|
||||
long size = 0L;
|
||||
if(_ppDb)
|
||||
{
|
||||
std::string query;
|
||||
if(uStrNumCmp(_version, "0.10.1") >= 0)
|
||||
{
|
||||
query = "SELECT sum(length(depth)) from Data;";
|
||||
}
|
||||
else
|
||||
{
|
||||
query = "SELECT sum(length(data)) from Depth;";
|
||||
}
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
size = sqlite3_column_int64(ppStmt, 0);
|
||||
rc = sqlite3_step(ppStmt);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
long DBDriverSqlite3::getLaserScansMemoryUsedQuery() const
|
||||
{
|
||||
UDEBUG("");
|
||||
long size = 0L;
|
||||
if(_ppDb)
|
||||
{
|
||||
std::string query;
|
||||
if(uStrNumCmp(_version, "0.10.1") >= 0)
|
||||
{
|
||||
query = "SELECT sum(length(scan)) from Data;";
|
||||
}
|
||||
else
|
||||
{
|
||||
query = "SELECT sum(length(data2d)) from Depth;";
|
||||
}
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
size = sqlite3_column_int64(ppStmt, 0);
|
||||
rc = sqlite3_step(ppStmt);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
long DBDriverSqlite3::getUserDataMemoryUsedQuery() const
|
||||
{
|
||||
UDEBUG("");
|
||||
long size = 0L;
|
||||
if(_ppDb)
|
||||
{
|
||||
std::string query;
|
||||
if(uStrNumCmp(_version, "0.10.1") >= 0)
|
||||
{
|
||||
query = "SELECT sum(length(user_data)) from Data;";
|
||||
}
|
||||
else if(uStrNumCmp(_version, "0.8.8") >= 0)
|
||||
{
|
||||
query = "SELECT sum(length(user_data)) from Node;";
|
||||
}
|
||||
else
|
||||
{
|
||||
return size; // no user_data
|
||||
}
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
size = sqlite3_column_int64(ppStmt, 0);
|
||||
rc = sqlite3_step(ppStmt);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
long DBDriverSqlite3::getWordsMemoryUsedQuery() const
|
||||
{
|
||||
UDEBUG("");
|
||||
long size = 0L;
|
||||
if(_ppDb)
|
||||
{
|
||||
std::string query = "SELECT sum(length(descriptor)) from Word;";
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
size = sqlite3_column_int64(ppStmt, 0);
|
||||
rc = sqlite3_step(ppStmt);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
int DBDriverSqlite3::getLastNodesSizeQuery() const
|
||||
{
|
||||
UDEBUG("");
|
||||
int size = 0;
|
||||
if(_ppDb)
|
||||
{
|
||||
std::string query = "SELECT count(id) from Node WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics);";
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
size = sqlite3_column_int(ppStmt, 0);
|
||||
rc = sqlite3_step(ppStmt);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
int DBDriverSqlite3::getLastDictionarySizeQuery() const
|
||||
{
|
||||
UDEBUG("");
|
||||
int size = 0;
|
||||
if(_ppDb)
|
||||
{
|
||||
std::string query = "SELECT count(id) from Word WHERE time_enter >= (SELECT MAX(time_enter) FROM Statistics);";
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
size = sqlite3_column_int(ppStmt, 0);
|
||||
rc = sqlite3_step(ppStmt);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
int DBDriverSqlite3::getTotalNodesSizeQuery() const
|
||||
{
|
||||
UDEBUG("");
|
||||
int size = 0;
|
||||
if(_ppDb)
|
||||
{
|
||||
std::string query = "SELECT count(id) from Node;";
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
size = sqlite3_column_int(ppStmt, 0);
|
||||
rc = sqlite3_step(ppStmt);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
int DBDriverSqlite3::getTotalDictionarySizeQuery() const
|
||||
{
|
||||
UDEBUG("");
|
||||
int size = 0;
|
||||
if(_ppDb)
|
||||
{
|
||||
std::string query = "SELECT count(id) from Word;";
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
sqlite3_stmt * ppStmt = 0;
|
||||
rc = sqlite3_prepare_v2(_ppDb, query.c_str(), -1, &ppStmt, 0);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_step(ppStmt);
|
||||
if(rc == SQLITE_ROW)
|
||||
{
|
||||
size = sqlite3_column_int(ppStmt, 0);
|
||||
rc = sqlite3_step(ppStmt);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_DONE, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void DBDriverSqlite3::loadNodeDataQuery(std::list<Signature *> & signatures) const
|
||||
{
|
||||
UDEBUG("load data for %d signatures", (int)signatures.size());
|
||||
@@ -830,7 +1083,7 @@ void DBDriverSqlite3::getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildre
|
||||
query << "SELECT id "
|
||||
<< "FROM Node "
|
||||
<< "INNER JOIN Link "
|
||||
<< "ON id = to_id " // use to_id tp ignore all children (which don't have link pointing on them)
|
||||
<< "ON id = to_id " // use to_id to ignore all children (which don't have link pointing on them)
|
||||
<< "ORDER BY id";
|
||||
}
|
||||
|
||||
@@ -2067,7 +2320,10 @@ void DBDriverSqlite3::saveQuery(const std::list<Signature *> & signatures) const
|
||||
|
||||
for(std::list<Signature *>::const_iterator i=signatures.begin(); i!=signatures.end(); ++i)
|
||||
{
|
||||
if(!(*i)->sensorData().imageCompressed().empty())
|
||||
if(!(*i)->sensorData().imageCompressed().empty() ||
|
||||
!(*i)->sensorData().depthOrRightCompressed().empty() ||
|
||||
!(*i)->sensorData().laserScanCompressed().empty() ||
|
||||
!(*i)->sensorData().userDataCompressed().empty())
|
||||
{
|
||||
UASSERT((*i)->id() == (*i)->sensorData().id());
|
||||
stepSensorData(ppStmt, (*i)->sensorData());
|
||||
@@ -2506,7 +2762,7 @@ void DBDriverSqlite3::stepSensorData(sqlite3_stmt * ppStmt,
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = sqlite3_bind_zeroblob(ppStmt, index++, 4);
|
||||
rc = sqlite3_bind_null(ppStmt, index++);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
|
||||
@@ -2517,7 +2773,7 @@ void DBDriverSqlite3::stepSensorData(sqlite3_stmt * ppStmt,
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = sqlite3_bind_zeroblob(ppStmt, index++, 4);
|
||||
rc = sqlite3_bind_null(ppStmt, index++);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
|
||||
@@ -2578,7 +2834,7 @@ void DBDriverSqlite3::stepSensorData(sqlite3_stmt * ppStmt,
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = sqlite3_bind_zeroblob(ppStmt, index++, 4);
|
||||
rc = sqlite3_bind_null(ppStmt, index++);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
|
||||
@@ -2591,7 +2847,7 @@ void DBDriverSqlite3::stepSensorData(sqlite3_stmt * ppStmt,
|
||||
}
|
||||
else
|
||||
{
|
||||
rc = sqlite3_bind_zeroblob(ppStmt, index++, 4);
|
||||
rc = sqlite3_bind_null(ppStmt, index++);
|
||||
}
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error: %s", sqlite3_errmsg(_ppDb)).c_str());
|
||||
}
|
||||
|
||||
@@ -54,6 +54,15 @@ private:
|
||||
virtual bool isConnectedQuery() const;
|
||||
virtual long getMemoryUsedQuery() const; // In bytes
|
||||
virtual bool getDatabaseVersionQuery(std::string & version) const;
|
||||
virtual long getImagesMemoryUsedQuery() const;
|
||||
virtual long getDepthImagesMemoryUsedQuery() const;
|
||||
virtual long getLaserScansMemoryUsedQuery() const;
|
||||
virtual long getUserDataMemoryUsedQuery() const;
|
||||
virtual long getWordsMemoryUsedQuery() const;
|
||||
virtual int getLastNodesSizeQuery() const;
|
||||
virtual int getLastDictionarySizeQuery() const;
|
||||
virtual int getTotalNodesSizeQuery() const;
|
||||
virtual int getTotalDictionarySizeQuery() const;
|
||||
|
||||
virtual void executeNoResultQuery(const std::string & sql) const;
|
||||
|
||||
|
||||
+26
-14
@@ -157,12 +157,13 @@ void DBReader::mainLoop()
|
||||
OdometryEvent odom = this->getNextData();
|
||||
if(odom.data().id())
|
||||
{
|
||||
int goalId = 0;
|
||||
std::string goalId;
|
||||
double previousStamp = odom.data().stamp();
|
||||
if(previousStamp == 0)
|
||||
{
|
||||
odom.data().setStamp(UTimer::now());
|
||||
}
|
||||
|
||||
if(!_goalsIgnored &&
|
||||
odom.data().userDataRaw().type() == CV_8SC1 &&
|
||||
odom.data().userDataRaw().cols >= 7 && // including null str ending
|
||||
@@ -176,7 +177,7 @@ void DBReader::mainLoop()
|
||||
std::list<std::string> strs = uSplit(goalStr, ':');
|
||||
if(strs.size() == 2)
|
||||
{
|
||||
goalId = atoi(strs.rbegin()->c_str());
|
||||
goalId = *strs.rbegin();
|
||||
odom.data().setUserData(cv::Mat());
|
||||
}
|
||||
}
|
||||
@@ -196,8 +197,9 @@ void DBReader::mainLoop()
|
||||
this->post(new CameraEvent(odom.data()));
|
||||
}
|
||||
|
||||
if(goalId > 0)
|
||||
if(!goalId.empty())
|
||||
{
|
||||
double delay = 0.0;
|
||||
if(!_ignoreGoalDelay && _currentId != _ids.end())
|
||||
{
|
||||
// get stamp for the next signature to compute the delay
|
||||
@@ -210,23 +212,33 @@ void DBReader::mainLoop()
|
||||
_dbDriver->getNodeInfo(*_currentId, pose, mapId, weight, label, stamp);
|
||||
if(previousStamp && stamp && stamp > previousStamp)
|
||||
{
|
||||
double delay = stamp - previousStamp;
|
||||
UWARN("Goal %d detected, posting it! Waiting %f seconds before sending next data...",
|
||||
goalId, delay);
|
||||
this->post(new RtabmapEventCmd(RtabmapEventCmd::kCmdGoal, goalId));
|
||||
uSleep(delay*1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Goal %d detected, posting it!", goalId);
|
||||
this->post(new RtabmapEventCmd(RtabmapEventCmd::kCmdGoal, goalId));
|
||||
delay = stamp - previousStamp;
|
||||
}
|
||||
}
|
||||
|
||||
if(delay > 0.0)
|
||||
{
|
||||
UWARN("Goal \"%s\" detected, posting it! Waiting %f seconds before sending next data...",
|
||||
goalId.c_str(), delay);
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Goal \"%s\" detected, posting it!", goalId.c_str());
|
||||
}
|
||||
|
||||
if(uIsInteger(goalId))
|
||||
{
|
||||
this->post(new RtabmapEventCmd(RtabmapEventCmd::kCmdGoal, atoi(goalId.c_str())));
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Goal %d detected, posting it!", goalId);
|
||||
this->post(new RtabmapEventCmd(RtabmapEventCmd::kCmdGoal, goalId));
|
||||
}
|
||||
|
||||
if(delay > 0.0)
|
||||
{
|
||||
uSleep(delay*1000);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ void Feature2D::filterKeypointsByDepth(
|
||||
const cv::Mat & depth,
|
||||
float maxDepth)
|
||||
{
|
||||
if(!depth.empty() && maxDepth > 0.0f && (descriptors.empty() || descriptors.rows == (int)keypoints.size()))
|
||||
if(!depth.empty() && (descriptors.empty() || descriptors.rows == (int)keypoints.size()))
|
||||
{
|
||||
std::vector<cv::KeyPoint> output(keypoints.size());
|
||||
std::vector<int> indexes(keypoints.size(), 0);
|
||||
@@ -85,7 +85,7 @@ void Feature2D::filterKeypointsByDepth(
|
||||
if(u >=0 && u<depth.cols && v >=0 && v<depth.rows)
|
||||
{
|
||||
float d = isInMM?(float)depth.at<uint16_t>(v,u)*0.001f:depth.at<float>(v,u);
|
||||
if(d!=0.0f && uIsFinite(d) && d < maxDepth)
|
||||
if(uIsFinite(d) && d>0.0f && (maxDepth <= 0.0f || d < maxDepth))
|
||||
{
|
||||
output[oi++] = keypoints[i];
|
||||
indexes[i] = 1;
|
||||
|
||||
+363
-39
@@ -240,7 +240,9 @@ void Optimizer::getConnectedGraph(
|
||||
std::multimap<int, int> biLinks;
|
||||
for(std::multimap<int, Link>::const_iterator iter=linksIn.begin(); iter!=linksIn.end(); ++iter)
|
||||
{
|
||||
UASSERT_MSG(findLink(biLinks, iter->second.from(), iter->second.to()) == biLinks.end(), "Input links should be unique between two poses.");
|
||||
UASSERT_MSG(findLink(biLinks, iter->second.from(), iter->second.to()) == biLinks.end(),
|
||||
uFormat("Input links should be unique between two poses (%d->%d).",
|
||||
iter->second.from(), iter->second.to()).c_str());
|
||||
biLinks.insert(std::make_pair(iter->second.from(), iter->second.to()));
|
||||
biLinks.insert(std::make_pair(iter->second.to(), iter->second.from()));
|
||||
}
|
||||
@@ -396,12 +398,14 @@ std::map<int, Transform> TOROOptimizer::optimize(
|
||||
}
|
||||
}
|
||||
}
|
||||
UDEBUG("buildMST...");
|
||||
UDEBUG("buildMST... root=%d", rootId);
|
||||
UASSERT(uContains(poses, rootId));
|
||||
if(isSlam2d())
|
||||
{
|
||||
pg2.buildMST(rootId); // pg.buildSimpleTree();
|
||||
UDEBUG("initializeOnTree()");
|
||||
pg2.initializeOnTree();
|
||||
UDEBUG("initializeTreeParameters()");
|
||||
pg2.initializeTreeParameters();
|
||||
UDEBUG("Building TORO tree... (if a crash happens just after this msg, "
|
||||
"TORO is not able to find the root of the graph!)");
|
||||
@@ -410,7 +414,9 @@ std::map<int, Transform> TOROOptimizer::optimize(
|
||||
else
|
||||
{
|
||||
pg3.buildMST(rootId); // pg.buildSimpleTree();
|
||||
UDEBUG("initializeOnTree()");
|
||||
pg3.initializeOnTree();
|
||||
UDEBUG("initializeTreeParameters()");
|
||||
pg3.initializeTreeParameters();
|
||||
UDEBUG("Building TORO tree... (if a crash happens just after this msg, "
|
||||
"TORO is not able to find the root of the graph!)");
|
||||
@@ -799,7 +805,9 @@ std::map<int, Transform> G2OOptimizer::optimize(
|
||||
g2o::HyperGraph::Edge * edge = 0;
|
||||
|
||||
VertexSwitchLinear * v = 0;
|
||||
if(this->isRobust() && iter->second.type() != Link::kNeighbor)
|
||||
if(this->isRobust() &&
|
||||
iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
// For loop closure links, add switchable edges
|
||||
|
||||
@@ -840,7 +848,9 @@ std::map<int, Transform> G2OOptimizer::optimize(
|
||||
information(2,2) = iter->second.infMatrix().at<double>(5,5); // theta-theta
|
||||
}
|
||||
|
||||
if(this->isRobust() && iter->second.type() != Link::kNeighbor)
|
||||
if(this->isRobust() &&
|
||||
iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
EdgeSE2Switchable * e = new EdgeSE2Switchable();
|
||||
g2o::VertexSE2* v1 = (g2o::VertexSE2*)optimizer.vertex(id1);
|
||||
@@ -881,7 +891,9 @@ std::map<int, Transform> G2OOptimizer::optimize(
|
||||
constraint = a.rotation();
|
||||
constraint.translation() = a.translation();
|
||||
|
||||
if(this->isRobust() && iter->second.type() != Link::kNeighbor)
|
||||
if(this->isRobust() &&
|
||||
iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
EdgeSE3Switchable * e = new EdgeSE3Switchable();
|
||||
g2o::VertexSE3* v1 = (g2o::VertexSE3*)optimizer.vertex(id1);
|
||||
@@ -1079,7 +1091,9 @@ bool G2OOptimizer::saveGraph(
|
||||
std::string prefix = "EDGE_SE3:QUAT";
|
||||
std::string suffix = "";
|
||||
|
||||
if(useRobustConstraints && iter->second.type() != Link::kNeighbor)
|
||||
if(useRobustConstraints &&
|
||||
iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
prefix = "EDGE_SE3_SWITCHABLE";
|
||||
fprintf(file, "VERTEX_SWITCH %d 1\n", virtualVertexId);
|
||||
@@ -1196,7 +1210,9 @@ std::map<int, Transform> GTSAMOptimizer::optimize(
|
||||
|
||||
UASSERT(!iter->second.transform().isNull());
|
||||
|
||||
if(this->isRobust() && iter->second.type()!=Link::kNeighbor)
|
||||
if(this->isRobust() &&
|
||||
iter->second.type()!=Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
// create new switch variable
|
||||
// Sunderhauf IROS 2012:
|
||||
@@ -1233,7 +1249,9 @@ std::map<int, Transform> GTSAMOptimizer::optimize(
|
||||
}
|
||||
gtsam::noiseModel::Gaussian::shared_ptr model = gtsam::noiseModel::Gaussian::Information(information);
|
||||
|
||||
if(this->isRobust() && iter->second.type()!=Link::kNeighbor)
|
||||
if(this->isRobust() &&
|
||||
iter->second.type()!=Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
// create switchable edge factor
|
||||
graph.add(vertigo::BetweenFactorSwitchableLinear<gtsam::Pose2>(id1, id2, gtsam::Symbol('s', switchCounter++), gtsam::Pose2(iter->second.transform().x(), iter->second.transform().y(), iter->second.transform().theta()), model));
|
||||
@@ -1255,7 +1273,9 @@ std::map<int, Transform> GTSAMOptimizer::optimize(
|
||||
|
||||
gtsam::noiseModel::Gaussian::shared_ptr model = gtsam::noiseModel::Gaussian::Information(information);
|
||||
|
||||
if(this->isRobust() && iter->second.type()!=Link::kNeighbor)
|
||||
if(this->isRobust() &&
|
||||
iter->second.type()!=Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
// create switchable edge factor
|
||||
graph.add(vertigo::BetweenFactorSwitchableLinear<gtsam::Pose3>(id1, id2, gtsam::Symbol('s', switchCounter++), gtsam::Pose3(iter->second.transform().toEigen4d()), model));
|
||||
@@ -1683,7 +1703,8 @@ bool exportPoses(
|
||||
std::multimap<int, Link>::iterator findLink(
|
||||
std::multimap<int, Link> & links,
|
||||
int from,
|
||||
int to)
|
||||
int to,
|
||||
bool checkBothWays)
|
||||
{
|
||||
std::multimap<int, Link>::iterator iter = links.find(from);
|
||||
while(iter != links.end() && iter->first == from)
|
||||
@@ -1695,15 +1716,18 @@ std::multimap<int, Link>::iterator findLink(
|
||||
++iter;
|
||||
}
|
||||
|
||||
// let's try to -> from
|
||||
iter = links.find(to);
|
||||
while(iter != links.end() && iter->first == to)
|
||||
if(checkBothWays)
|
||||
{
|
||||
if(iter->second.to() == from)
|
||||
// let's try to -> from
|
||||
iter = links.find(to);
|
||||
while(iter != links.end() && iter->first == to)
|
||||
{
|
||||
return iter;
|
||||
if(iter->second.to() == from)
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return links.end();
|
||||
}
|
||||
@@ -1711,7 +1735,8 @@ std::multimap<int, Link>::iterator findLink(
|
||||
std::multimap<int, int>::iterator findLink(
|
||||
std::multimap<int, int> & links,
|
||||
int from,
|
||||
int to)
|
||||
int to,
|
||||
bool checkBothWays)
|
||||
{
|
||||
std::multimap<int, int>::iterator iter = links.find(from);
|
||||
while(iter != links.end() && iter->first == from)
|
||||
@@ -1723,22 +1748,26 @@ std::multimap<int, int>::iterator findLink(
|
||||
++iter;
|
||||
}
|
||||
|
||||
// let's try to -> from
|
||||
iter = links.find(to);
|
||||
while(iter != links.end() && iter->first == to)
|
||||
if(checkBothWays)
|
||||
{
|
||||
if(iter->second == from)
|
||||
// let's try to -> from
|
||||
iter = links.find(to);
|
||||
while(iter != links.end() && iter->first == to)
|
||||
{
|
||||
return iter;
|
||||
if(iter->second == from)
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return links.end();
|
||||
}
|
||||
std::multimap<int, Link>::const_iterator findLink(
|
||||
const std::multimap<int, Link> & links,
|
||||
int from,
|
||||
int to)
|
||||
int to,
|
||||
bool checkBothWays)
|
||||
{
|
||||
std::multimap<int, Link>::const_iterator iter = links.find(from);
|
||||
while(iter != links.end() && iter->first == from)
|
||||
@@ -1750,15 +1779,18 @@ std::multimap<int, Link>::const_iterator findLink(
|
||||
++iter;
|
||||
}
|
||||
|
||||
// let's try to -> from
|
||||
iter = links.find(to);
|
||||
while(iter != links.end() && iter->first == to)
|
||||
if(checkBothWays)
|
||||
{
|
||||
if(iter->second.to() == from)
|
||||
// let's try to -> from
|
||||
iter = links.find(to);
|
||||
while(iter != links.end() && iter->first == to)
|
||||
{
|
||||
return iter;
|
||||
if(iter->second.to() == from)
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return links.end();
|
||||
}
|
||||
@@ -1766,7 +1798,8 @@ std::multimap<int, Link>::const_iterator findLink(
|
||||
std::multimap<int, int>::const_iterator findLink(
|
||||
const std::multimap<int, int> & links,
|
||||
int from,
|
||||
int to)
|
||||
int to,
|
||||
bool checkBothWays)
|
||||
{
|
||||
std::multimap<int, int>::const_iterator iter = links.find(from);
|
||||
while(iter != links.end() && iter->first == from)
|
||||
@@ -1778,15 +1811,18 @@ std::multimap<int, int>::const_iterator findLink(
|
||||
++iter;
|
||||
}
|
||||
|
||||
// let's try to -> from
|
||||
iter = links.find(to);
|
||||
while(iter != links.end() && iter->first == to)
|
||||
if(checkBothWays)
|
||||
{
|
||||
if(iter->second == from)
|
||||
// let's try to -> from
|
||||
iter = links.find(to);
|
||||
while(iter != links.end() && iter->first == to)
|
||||
{
|
||||
return iter;
|
||||
if(iter->second == from)
|
||||
{
|
||||
return iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return links.end();
|
||||
}
|
||||
@@ -1955,6 +1991,192 @@ std::multimap<int, int> radiusPosesClustering(const std::map<int, Transform> & p
|
||||
return clusters;
|
||||
}
|
||||
|
||||
void reduceGraph(
|
||||
const std::map<int, Transform> & poses,
|
||||
const std::multimap<int, Link> & links,
|
||||
std::multimap<int, int> & hyperNodes, //<parent ID, child ID>
|
||||
std::multimap<int, Link> & hyperLinks)
|
||||
{
|
||||
UINFO("Input: poses=%d links=%d", (int)poses.size(), (int)links.size());
|
||||
UTimer timer;
|
||||
std::map<int, int> posesToHyperNodes;
|
||||
std::map<int, std::multimap<int, Link> > clusterloopClosureLinks;
|
||||
|
||||
{
|
||||
std::multimap<int, Link> bidirectionalLoopClosureLinks;
|
||||
for(std::multimap<int, Link>::const_iterator jter=links.begin(); jter!=links.end(); ++jter)
|
||||
{
|
||||
if(jter->second.type() != Link::kNeighbor &&
|
||||
jter->second.type() != Link::kNeighborMerged &&
|
||||
jter->second.userDataCompressed().empty())
|
||||
{
|
||||
if(uContains(poses, jter->second.from()) &&
|
||||
uContains(poses, jter->second.to()))
|
||||
{
|
||||
UASSERT_MSG(graph::findLink(links, jter->second.to(), jter->second.from(), false) == links.end(), "Input links should be unique!");
|
||||
bidirectionalLoopClosureLinks.insert(std::make_pair(jter->second.from(), jter->second));
|
||||
//bidirectionalLoopClosureLinks.insert(std::make_pair(jter->second.to(), jter->second.inverse()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UINFO("Clustering hyper nodes...");
|
||||
// largest ID to smallest ID
|
||||
for(std::map<int, Transform>::const_reverse_iterator iter=poses.rbegin(); iter!=poses.rend(); ++iter)
|
||||
{
|
||||
if(posesToHyperNodes.find(iter->first) == posesToHyperNodes.end())
|
||||
{
|
||||
int hyperNodeId = iter->first;
|
||||
std::list<int> loopClosures;
|
||||
std::set<int> loopClosuresAdded;
|
||||
loopClosures.push_back(iter->first);
|
||||
std::multimap<int, Link> clusterLinks;
|
||||
while(loopClosures.size())
|
||||
{
|
||||
int id = loopClosures.front();
|
||||
loopClosures.pop_front();
|
||||
|
||||
UASSERT(posesToHyperNodes.find(id) == posesToHyperNodes.end());
|
||||
|
||||
posesToHyperNodes.insert(std::make_pair(id, hyperNodeId));
|
||||
hyperNodes.insert(std::make_pair(hyperNodeId, id));
|
||||
|
||||
for(std::multimap<int, Link>::const_iterator jter=bidirectionalLoopClosureLinks.find(id); jter!=bidirectionalLoopClosureLinks.end() && jter->first==id; ++jter)
|
||||
{
|
||||
if(posesToHyperNodes.find(jter->second.to()) == posesToHyperNodes.end() &&
|
||||
loopClosuresAdded.find(jter->second.to()) == loopClosuresAdded.end())
|
||||
{
|
||||
loopClosures.push_back(jter->second.to());
|
||||
loopClosuresAdded.insert(jter->second.to());
|
||||
clusterLinks.insert(*jter);
|
||||
clusterLinks.insert(std::make_pair(jter->second.to(), jter->second.inverse()));
|
||||
if(jter->second.from() < jter->second.to())
|
||||
{
|
||||
UWARN("Child to Parent link? %d->%d (type=%d)",
|
||||
jter->second.from(),
|
||||
jter->second.to(),
|
||||
jter->second.type());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
UASSERT(clusterloopClosureLinks.find(hyperNodeId) == clusterloopClosureLinks.end());
|
||||
clusterloopClosureLinks.insert(std::make_pair(hyperNodeId, clusterLinks));
|
||||
UDEBUG("Created hyper node %d with %d children (%f%%)",
|
||||
hyperNodeId, (int)loopClosuresAdded.size(), float(posesToHyperNodes.size())/float(poses.size())*100.0f);
|
||||
}
|
||||
}
|
||||
UINFO("Clustering hyper nodes... done! (%f s)", timer.ticks());
|
||||
}
|
||||
|
||||
UINFO("Creating hyper links...");
|
||||
int i=0;
|
||||
for(std::multimap<int, Link>::const_reverse_iterator jter=links.rbegin(); jter!=links.rend(); ++jter)
|
||||
{
|
||||
if((jter->second.type() == Link::kNeighbor ||
|
||||
jter->second.type() == Link::kNeighborMerged ||
|
||||
!jter->second.userDataCompressed().empty()) &&
|
||||
uContains(poses, jter->second.from()) &&
|
||||
uContains(poses, jter->second.to()))
|
||||
{
|
||||
UASSERT_MSG(uContains(posesToHyperNodes, jter->second.from()), uFormat("%d->%d (type=%d)", jter->second.from(), jter->second.to(), jter->second.type()).c_str());
|
||||
UASSERT_MSG(uContains(posesToHyperNodes, jter->second.to()), uFormat("%d->%d (type=%d)", jter->second.from(), jter->second.to(), jter->second.type()).c_str());
|
||||
int hyperNodeIDFrom = posesToHyperNodes.at(jter->second.from());
|
||||
int hyperNodeIDTo = posesToHyperNodes.at(jter->second.to());
|
||||
|
||||
// ignore links inside a hyper node
|
||||
if(hyperNodeIDFrom != hyperNodeIDTo)
|
||||
{
|
||||
std::multimap<int, Link>::iterator tmpIter = graph::findLink(hyperLinks, hyperNodeIDFrom, hyperNodeIDTo);
|
||||
if(tmpIter!=hyperLinks.end() &&
|
||||
hyperNodeIDFrom == jter->second.from() &&
|
||||
hyperNodeIDTo == jter->second.to() &&
|
||||
tmpIter->second.type() > Link::kNeighbor &&
|
||||
jter->second.type() == Link::kNeighbor)
|
||||
{
|
||||
// neighbor links have priority, so remove the previously added link
|
||||
hyperLinks.erase(tmpIter);
|
||||
}
|
||||
|
||||
// only add unique link between two hyper nodes (keeping only the more recent)
|
||||
if(graph::findLink(hyperLinks, hyperNodeIDFrom, hyperNodeIDTo) == hyperLinks.end())
|
||||
{
|
||||
UASSERT(clusterloopClosureLinks.find(hyperNodeIDFrom) != clusterloopClosureLinks.end());
|
||||
UASSERT(clusterloopClosureLinks.find(hyperNodeIDTo) != clusterloopClosureLinks.end());
|
||||
std::multimap<int, Link> tmpLinks = clusterloopClosureLinks.at(hyperNodeIDFrom);
|
||||
tmpLinks.insert(clusterloopClosureLinks.at(hyperNodeIDTo).begin(), clusterloopClosureLinks.at(hyperNodeIDTo).end());
|
||||
tmpLinks.insert(std::make_pair(jter->second.from(), jter->second));
|
||||
|
||||
std::list<int> path = computePath(tmpLinks, hyperNodeIDFrom, hyperNodeIDTo, false, true);
|
||||
UASSERT_MSG(path.size()>1,
|
||||
uFormat("path.size()=%d, hyperNodeIDFrom=%d, hyperNodeIDTo=%d",
|
||||
(int)path.size(),
|
||||
hyperNodeIDFrom,
|
||||
hyperNodeIDTo).c_str());
|
||||
|
||||
if(path.size() > 10)
|
||||
{
|
||||
UWARN("Large path! %d nodes", (int)path.size());
|
||||
std::stringstream stream;
|
||||
for(std::list<int>::const_iterator iter=path.begin(); iter!=path.end();++iter)
|
||||
{
|
||||
if(iter!=path.begin())
|
||||
{
|
||||
stream << ",";
|
||||
}
|
||||
|
||||
stream << *iter;
|
||||
}
|
||||
UWARN("Path = [%s]", stream.str().c_str());
|
||||
}
|
||||
|
||||
// create the hyperlink
|
||||
std::list<int>::iterator iter=path.begin();
|
||||
int from = *iter;
|
||||
++iter;
|
||||
int to = *iter;
|
||||
std::multimap<int, Link>::const_iterator foundIter = graph::findLink(tmpLinks, from, to, false);
|
||||
UASSERT(foundIter != tmpLinks.end());
|
||||
Link hyperLink = foundIter->second;
|
||||
++iter;
|
||||
from = to;
|
||||
for(; iter!=path.end(); ++iter)
|
||||
{
|
||||
to = *iter;
|
||||
std::multimap<int, Link>::const_iterator foundIter = graph::findLink(tmpLinks, from, to, false);
|
||||
UASSERT(foundIter != tmpLinks.end());
|
||||
hyperLink = hyperLink.merge(foundIter->second, jter->second.type());
|
||||
|
||||
from = to;
|
||||
}
|
||||
|
||||
UASSERT(hyperLink.from() == hyperNodeIDFrom);
|
||||
UASSERT(hyperLink.to() == hyperNodeIDTo);
|
||||
hyperLinks.insert(std::make_pair(hyperNodeIDFrom, hyperLink));
|
||||
|
||||
UDEBUG("Created hyper link %d->%d (%f%%)",
|
||||
hyperLink.from(), hyperLink.to(), float(i)/float(links.size())*100.0f);
|
||||
if(hyperLink.transform().getNorm() > jter->second.transform().getNorm()+1)
|
||||
{
|
||||
UWARN("Large hyper link %d->%d (%f m)! original %d->%d (%f m)",
|
||||
hyperLink.from(),
|
||||
hyperLink.to(),
|
||||
hyperLink.transform().getNorm(),
|
||||
jter->second.from(),
|
||||
jter->second.to(),
|
||||
jter->second.transform().getNorm());
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++i;
|
||||
}
|
||||
UINFO("Creating hyper links... done! (%f s)", timer.ticks());
|
||||
|
||||
UINFO("Output: poses=%d links=%d", (int)uUniqueKeys(hyperNodes).size(), (int)links.size());
|
||||
}
|
||||
|
||||
|
||||
class Node
|
||||
{
|
||||
@@ -2005,6 +2227,7 @@ struct Order
|
||||
}
|
||||
};
|
||||
|
||||
// A*
|
||||
std::list<std::pair<int, Transform> > computePath(
|
||||
const std::map<int, rtabmap::Transform> & poses,
|
||||
const std::multimap<int, int> & links,
|
||||
@@ -2014,7 +2237,6 @@ std::list<std::pair<int, Transform> > computePath(
|
||||
{
|
||||
std::list<std::pair<int, Transform> > path;
|
||||
|
||||
//A*
|
||||
int startNode = from;
|
||||
int endNode = to;
|
||||
rtabmap::Transform endPose = poses.at(endNode);
|
||||
@@ -2076,6 +2298,7 @@ std::list<std::pair<int, Transform> > computePath(
|
||||
Node n(iter->second, currentNode->id(), poseIter->second);
|
||||
n.setCostSoFar(currentNode->costSoFar() + currentNode->distFrom(poseIter->second));
|
||||
n.setDistToEnd(n.distFrom(endPose));
|
||||
|
||||
nodes.insert(std::make_pair(iter->second, n));
|
||||
if(updateNewCosts)
|
||||
{
|
||||
@@ -2110,6 +2333,107 @@ std::list<std::pair<int, Transform> > computePath(
|
||||
return path;
|
||||
}
|
||||
|
||||
// Dijksta
|
||||
std::list<int> RTABMAP_EXP computePath(
|
||||
const std::multimap<int, Link> & links,
|
||||
int from,
|
||||
int to,
|
||||
bool updateNewCosts,
|
||||
bool useSameCostForAllLinks)
|
||||
{
|
||||
std::list<int> path;
|
||||
|
||||
int startNode = from;
|
||||
int endNode = to;
|
||||
std::map<int, Node> nodes;
|
||||
nodes.insert(std::make_pair(startNode, Node(startNode, 0, Transform())));
|
||||
std::priority_queue<Pair, std::vector<Pair>, Order> pq;
|
||||
std::multimap<float, int> pqmap;
|
||||
if(updateNewCosts)
|
||||
{
|
||||
pqmap.insert(std::make_pair(0, startNode));
|
||||
}
|
||||
else
|
||||
{
|
||||
pq.push(Pair(startNode, 0));
|
||||
}
|
||||
|
||||
while((updateNewCosts && pqmap.size()) || (!updateNewCosts && pq.size()))
|
||||
{
|
||||
Node * currentNode;
|
||||
if(updateNewCosts)
|
||||
{
|
||||
currentNode = &nodes.find(pqmap.begin()->second)->second;
|
||||
pqmap.erase(pqmap.begin());
|
||||
}
|
||||
else
|
||||
{
|
||||
currentNode = &nodes.find(pq.top().first)->second;
|
||||
pq.pop();
|
||||
}
|
||||
|
||||
currentNode->setClosed(true);
|
||||
|
||||
if(currentNode->id() == endNode)
|
||||
{
|
||||
while(currentNode->id()!=startNode)
|
||||
{
|
||||
path.push_front(currentNode->id());
|
||||
currentNode = &nodes.find(currentNode->fromId())->second;
|
||||
}
|
||||
path.push_front(startNode);
|
||||
break;
|
||||
}
|
||||
|
||||
// lookup neighbors
|
||||
for(std::multimap<int, Link>::const_iterator iter = links.find(currentNode->id());
|
||||
iter!=links.end() && iter->first == currentNode->id();
|
||||
++iter)
|
||||
{
|
||||
std::map<int, Node>::iterator nodeIter = nodes.find(iter->second.to());
|
||||
float cost = 1;
|
||||
if(!useSameCostForAllLinks)
|
||||
{
|
||||
cost = iter->second.transform().getNorm();
|
||||
}
|
||||
if(nodeIter == nodes.end())
|
||||
{
|
||||
Node n(iter->second.to(), currentNode->id(), Transform());
|
||||
|
||||
n.setCostSoFar(currentNode->costSoFar() + cost);
|
||||
nodes.insert(std::make_pair(iter->second.to(), n));
|
||||
if(updateNewCosts)
|
||||
{
|
||||
pqmap.insert(std::make_pair(n.totalCost(), n.id()));
|
||||
}
|
||||
else
|
||||
{
|
||||
pq.push(Pair(n.id(), n.totalCost()));
|
||||
}
|
||||
}
|
||||
else if(!useSameCostForAllLinks && updateNewCosts && nodeIter->second.isOpened())
|
||||
{
|
||||
float newCostSoFar = currentNode->costSoFar() + cost;
|
||||
if(nodeIter->second.costSoFar() > newCostSoFar)
|
||||
{
|
||||
// update the cost in the priority queue
|
||||
for(std::multimap<float, int>::iterator mapIter=pqmap.begin(); mapIter!=pqmap.end(); ++mapIter)
|
||||
{
|
||||
if(mapIter->second == nodeIter->first)
|
||||
{
|
||||
pqmap.erase(mapIter);
|
||||
nodeIter->second.setCostSoFar(newCostSoFar);
|
||||
pqmap.insert(std::make_pair(nodeIter->second.totalCost(), nodeIter->first));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
// return path starting from "fromId" (Identity pose for the first node)
|
||||
std::list<std::pair<int, Transform> > computePath(
|
||||
@@ -2503,7 +2827,7 @@ std::list<std::map<int, Transform> > getPaths(
|
||||
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end();)
|
||||
{
|
||||
std::multimap<int, Link>::const_iterator jter = findLink(links, path.rbegin()->first, iter->first);
|
||||
if(path.size() == 0 || (jter != links.end() && jter->second.type() == Link::kNeighbor))
|
||||
if(path.size() == 0 || (jter != links.end() && (jter->second.type() == Link::kNeighbor || jter->second.type() == Link::kNeighborMerged)))
|
||||
{
|
||||
path.insert(*iter);
|
||||
poses.erase(iter++);
|
||||
|
||||
+268
-125
@@ -71,6 +71,7 @@ Memory::Memory(const ParametersMap & parameters) :
|
||||
_saveDepth16Format(Parameters::defaultMemSaveDepth16Format()),
|
||||
_notLinkedNodesKeptInDb(Parameters::defaultMemNotLinkedNodesKept()),
|
||||
_incrementalMemory(Parameters::defaultMemIncrementalMemory()),
|
||||
_reduceGraph(Parameters::defaultMemReduceGraph()),
|
||||
_maxStMemSize(Parameters::defaultMemSTMSize()),
|
||||
_recentWmRatio(Parameters::defaultMemRecentWmRatio()),
|
||||
_transferSortingByWeightId(Parameters::defaultMemTransferSortingByWeightId()),
|
||||
@@ -402,6 +403,7 @@ void Memory::parseParameters(const ParametersMap & parameters)
|
||||
Parameters::parse(parameters, Parameters::kMemImageKept(), _rawDataKept);
|
||||
Parameters::parse(parameters, Parameters::kMemBinDataKept(), _binDataKept);
|
||||
Parameters::parse(parameters, Parameters::kMemSaveDepth16Format(), _saveDepth16Format);
|
||||
Parameters::parse(parameters, Parameters::kMemReduceGraph(), _reduceGraph);
|
||||
Parameters::parse(parameters, Parameters::kMemNotLinkedNodesKept(), _notLinkedNodesKeptInDb);
|
||||
Parameters::parse(parameters, Parameters::kMemRehearsalIdUpdatedToNewOne(), _idUpdatedToNewOneRehearsal);
|
||||
Parameters::parse(parameters, Parameters::kMemGenerateIds(), _generateIds);
|
||||
@@ -626,49 +628,36 @@ bool Memory::update(
|
||||
//============================================================
|
||||
// Transfer the oldest signature of the short-term memory to the working memory
|
||||
//============================================================
|
||||
int validSignaturesCount = 0;
|
||||
int notIntermediateNodesCount = 0;
|
||||
for(std::set<int>::iterator iter=_stMem.begin(); iter!=_stMem.end(); ++iter)
|
||||
{
|
||||
const Signature * s = this->getSignature(*iter);
|
||||
UASSERT(s != 0);
|
||||
if(!s->isBadSignature())
|
||||
if(s->getWeight() >= 0)
|
||||
{
|
||||
++validSignaturesCount;
|
||||
++notIntermediateNodesCount;
|
||||
}
|
||||
}
|
||||
while(_stMem.size() && _maxStMemSize>0 && validSignaturesCount > _maxStMemSize)
|
||||
std::map<int, int> reducedIds;
|
||||
while(_stMem.size() && _maxStMemSize>0 && notIntermediateNodesCount > _maxStMemSize)
|
||||
{
|
||||
UDEBUG("Inserting node %d from STM in WM...", *_stMem.begin());
|
||||
Signature * s = this->_getSignature(*_stMem.begin());
|
||||
if(!_localSpaceLinksKeptInWM)
|
||||
int id = *_stMem.begin();
|
||||
Signature * s = this->_getSignature(id);
|
||||
UASSERT(s != 0);
|
||||
if(s->getWeight() >= 0)
|
||||
{
|
||||
// remove local space links outside STM
|
||||
UASSERT(s!=0);
|
||||
std::map<int, Link> links = s->getLinks(); // get a copy because we will remove some links in "s"
|
||||
for(std::map<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(iter->second.type() == Link::kLocalSpaceClosure)
|
||||
{
|
||||
Signature * sTo = this->_getSignature(iter->first);
|
||||
if(sTo)
|
||||
{
|
||||
sTo->removeLink(s->id());
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Link %d of %d not in WM/STM?!?", iter->first, s->id());
|
||||
}
|
||||
s->removeLink(iter->first);
|
||||
}
|
||||
}
|
||||
--notIntermediateNodesCount;
|
||||
}
|
||||
if(!s->isBadSignature())
|
||||
|
||||
int reducedTo = 0;
|
||||
moveSignatureToWMFromSTM(id, &reducedTo);
|
||||
|
||||
if(reducedTo > 0)
|
||||
{
|
||||
--validSignaturesCount;
|
||||
reducedIds.insert(std::make_pair(id, reducedTo));
|
||||
}
|
||||
_workingMem.insert(_workingMem.end(), std::make_pair(*_stMem.begin(), UTimer::now()));
|
||||
_stMem.erase(*_stMem.begin());
|
||||
}
|
||||
if(stats) stats->setReducedIds(reducedIds);
|
||||
|
||||
if(!_memoryChanged && _incrementalMemory)
|
||||
{
|
||||
@@ -784,7 +773,7 @@ void Memory::addSignatureToStm(Signature * signature, const cv::Mat & covariance
|
||||
UDEBUG("time = %fs", timer.ticks());
|
||||
}
|
||||
|
||||
void Memory::addSignatureToWm(Signature * signature)
|
||||
void Memory::addSignatureToWmFromLTM(Signature * signature)
|
||||
{
|
||||
if(signature)
|
||||
{
|
||||
@@ -799,6 +788,127 @@ void Memory::addSignatureToWm(Signature * signature)
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::moveSignatureToWMFromSTM(int id, int * reducedTo)
|
||||
{
|
||||
UDEBUG("Inserting node %d from STM in WM...", id);
|
||||
UASSERT(_stMem.find(id) != _stMem.end());
|
||||
Signature * s = this->_getSignature(id);
|
||||
UASSERT(s!=0);
|
||||
if(!_localSpaceLinksKeptInWM)
|
||||
{
|
||||
// remove local space links outside STM
|
||||
std::map<int, Link> links = s->getLinks(); // get a copy because we will remove some links in "s"
|
||||
for(std::map<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(iter->second.type() == Link::kLocalSpaceClosure)
|
||||
{
|
||||
Signature * sTo = this->_getSignature(iter->first);
|
||||
if(sTo)
|
||||
{
|
||||
sTo->removeLink(s->id());
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Link %d of %d not in WM/STM?!?", iter->first, s->id());
|
||||
}
|
||||
s->removeLink(iter->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(_reduceGraph)
|
||||
{
|
||||
bool merge = false;
|
||||
const std::map<int, Link> & links = s->getLinks();
|
||||
std::map<int, Link> neighbors;
|
||||
for(std::map<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(!merge)
|
||||
{
|
||||
merge = iter->second.to() < s->id() && // should be a parent->child link
|
||||
iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged &&
|
||||
iter->second.userDataCompressed().empty() &&
|
||||
iter->second.type() != Link::kUndef &&
|
||||
iter->second.type() != Link::kVirtualClosure;
|
||||
if(merge)
|
||||
{
|
||||
UDEBUG("Reduce %d to %d", s->id(), iter->second.to());
|
||||
if(reducedTo)
|
||||
{
|
||||
*reducedTo = iter->second.to();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if(iter->second.type() == Link::kNeighbor)
|
||||
{
|
||||
neighbors.insert(*iter);
|
||||
}
|
||||
}
|
||||
if(merge)
|
||||
{
|
||||
if(s->getLabel().empty())
|
||||
{
|
||||
for(std::map<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
merge = true;
|
||||
Signature * sTo = this->_getSignature(iter->first);
|
||||
UASSERT(sTo!=0);
|
||||
sTo->removeLink(s->id());
|
||||
if(iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged &&
|
||||
iter->second.type() != Link::kUndef)
|
||||
{
|
||||
// link to all neighbors
|
||||
for(std::map<int, Link>::iterator jter=neighbors.begin(); jter!=neighbors.end(); ++jter)
|
||||
{
|
||||
if(!sTo->hasLink(jter->second.to()))
|
||||
{
|
||||
Link l = iter->second.inverse().merge(
|
||||
jter->second,
|
||||
iter->second.userDataCompressed().empty() && iter->second.type() != Link::kVirtualClosure?Link::kNeighborMerged:iter->second.type());
|
||||
sTo->addLink(l);
|
||||
Signature * sB = this->_getSignature(l.to());
|
||||
UASSERT(sB!=0);
|
||||
UASSERT(!sB->hasLink(l.to()));
|
||||
sB->addLink(l.inverse());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//remove neighbor links
|
||||
std::map<int, Link> linksCopy = links;
|
||||
for(std::map<int, Link>::iterator iter=linksCopy.begin(); iter!=linksCopy.end(); ++iter)
|
||||
{
|
||||
if(iter->second.type() == Link::kNeighbor ||
|
||||
iter->second.type() == Link::kNeighborMerged)
|
||||
{
|
||||
s->removeLink(iter->first);
|
||||
if(iter->second.type() == Link::kNeighbor)
|
||||
{
|
||||
if(_lastGlobalLoopClosureId == s->id())
|
||||
{
|
||||
_lastGlobalLoopClosureId = iter->first;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->moveToTrash(s, _notLinkedNodesKeptInDb);
|
||||
s = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(s != 0)
|
||||
{
|
||||
_workingMem.insert(_workingMem.end(), std::make_pair(*_stMem.begin(), UTimer::now()));
|
||||
_stMem.erase(*_stMem.begin());
|
||||
}
|
||||
// else already removed from STM/WM in moveToTrash()
|
||||
}
|
||||
|
||||
const Signature * Memory::getSignature(int id) const
|
||||
{
|
||||
return _getSignature(id);
|
||||
@@ -825,7 +935,8 @@ std::map<int, Link> Memory::getNeighborLinks(
|
||||
const std::map<int, Link> & allLinks = s->getLinks();
|
||||
for(std::map<int, Link>::const_iterator iter = allLinks.begin(); iter!=allLinks.end(); ++iter)
|
||||
{
|
||||
if(iter->second.type() == Link::kNeighbor)
|
||||
if(iter->second.type() == Link::kNeighbor ||
|
||||
iter->second.type() == Link::kNeighborMerged)
|
||||
{
|
||||
links.insert(*iter);
|
||||
}
|
||||
@@ -834,8 +945,19 @@ std::map<int, Link> Memory::getNeighborLinks(
|
||||
else if(lookInDatabase && _dbDriver)
|
||||
{
|
||||
std::map<int, Link> neighbors;
|
||||
_dbDriver->loadLinks(signatureId, neighbors, Link::kNeighbor);
|
||||
links.insert(neighbors.begin(), neighbors.end());
|
||||
_dbDriver->loadLinks(signatureId, neighbors);
|
||||
for(std::map<int, Link>::iterator iter=neighbors.begin(); iter!=neighbors.end();)
|
||||
{
|
||||
if(iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
neighbors.erase(iter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -855,7 +977,8 @@ std::map<int, Link> Memory::getLoopClosureLinks(
|
||||
const std::map<int, Link> & allLinks = s->getLinks();
|
||||
for(std::map<int, Link>::const_iterator iter = allLinks.begin(); iter!=allLinks.end(); ++iter)
|
||||
{
|
||||
if(iter->second.type() > Link::kNeighbor &&
|
||||
if(iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged &&
|
||||
iter->second.type() != Link::kUndef)
|
||||
{
|
||||
loopClosures.insert(*iter);
|
||||
@@ -867,7 +990,9 @@ std::map<int, Link> Memory::getLoopClosureLinks(
|
||||
_dbDriver->loadLinks(signatureId, loopClosures);
|
||||
for(std::map<int, Link>::iterator iter=loopClosures.begin(); iter!=loopClosures.end();)
|
||||
{
|
||||
if(iter->second.type() == Link::kNeighbor)
|
||||
if(iter->second.type() == Link::kNeighbor ||
|
||||
iter->second.type() == Link::kNeighborMerged ||
|
||||
iter->second.type() == Link::kUndef )
|
||||
{
|
||||
loopClosures.erase(iter++);
|
||||
}
|
||||
@@ -931,7 +1056,8 @@ std::multimap<int, Link> Memory::getAllLinks(bool lookInDatabase, bool ignoreNul
|
||||
// return map<Id,Margin>, including signatureId
|
||||
// maxCheckedInDatabase = -1 means no limit to check in database (default)
|
||||
// maxCheckedInDatabase = 0 means don't check in database
|
||||
std::map<int, int> Memory::getNeighborsId(int signatureId,
|
||||
std::map<int, int> Memory::getNeighborsId(
|
||||
int signatureId,
|
||||
int maxGraphDepth, // 0 means infinite margin
|
||||
int maxCheckedInDatabase, // default -1 (no limit)
|
||||
bool incrementMarginOnLoop, // default false
|
||||
@@ -992,7 +1118,7 @@ std::map<int, int> Memory::getNeighborsId(int signatureId,
|
||||
ids.insert(std::pair<int, int>(*jter, m));
|
||||
|
||||
UTimer timer;
|
||||
_dbDriver->loadLinks(*jter, tmpLinks, ignoreLoopIds?Link::kNeighbor:Link::kUndef);
|
||||
_dbDriver->loadLinks(*jter, tmpLinks);
|
||||
if(dbAccessTime)
|
||||
{
|
||||
*dbAccessTime += timer.getElapsedTime();
|
||||
@@ -1005,7 +1131,8 @@ std::map<int, int> Memory::getNeighborsId(int signatureId,
|
||||
if( !uContains(ids, iter->first) && ignoredIds.find(iter->first) == ignoredIds.end())
|
||||
{
|
||||
UASSERT(iter->second.type() != Link::kUndef);
|
||||
if(iter->second.type() == Link::kNeighbor)
|
||||
if(iter->second.type() == Link::kNeighbor ||
|
||||
iter->second.type() == Link::kNeighborMerged)
|
||||
{
|
||||
if(ignoreIntermediateNodes && s->getWeight()==-1)
|
||||
{
|
||||
@@ -1116,7 +1243,7 @@ int Memory::getNextId()
|
||||
return ++_idCount;
|
||||
}
|
||||
|
||||
int Memory::incrementMapId()
|
||||
int Memory::incrementMapId(std::map<int, int> * reducedIds)
|
||||
{
|
||||
//don't increment if there is no location in the current map
|
||||
const Signature * s = getLastWorkingSignature();
|
||||
@@ -1125,32 +1252,13 @@ int Memory::incrementMapId()
|
||||
// New session! move all signatures from the STM to WM
|
||||
while(_stMem.size())
|
||||
{
|
||||
UDEBUG("Inserting node %d from STM in WM...", *_stMem.begin());
|
||||
if(!_localSpaceLinksKeptInWM)
|
||||
int reducedId = 0;
|
||||
int id = *_stMem.begin();
|
||||
moveSignatureToWMFromSTM(id, &reducedId);
|
||||
if(reducedIds && reducedId > 0)
|
||||
{
|
||||
// remove local space links outside STM
|
||||
Signature * s = this->_getSignature(*_stMem.begin());
|
||||
UASSERT(s!=0);
|
||||
std::map<int, Link> links = s->getLinks(); // get a copy because we will remove some links in "s"
|
||||
for(std::map<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(iter->second.type() == Link::kLocalSpaceClosure)
|
||||
{
|
||||
Signature * sTo = this->_getSignature(iter->first);
|
||||
if(sTo)
|
||||
{
|
||||
sTo->removeLink(s->id());
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Link %d of %d not in WM/STM?!?", iter->first, s->id());
|
||||
}
|
||||
s->removeLink(iter->first);
|
||||
}
|
||||
}
|
||||
reducedIds->insert(std::make_pair(id, reducedId));
|
||||
}
|
||||
_workingMem.insert(_workingMem.end(), std::make_pair(*_stMem.begin(), UTimer::now()));
|
||||
_stMem.erase(*_stMem.begin());
|
||||
}
|
||||
|
||||
return ++_idMapCount;
|
||||
@@ -1210,6 +1318,17 @@ void Memory::clear()
|
||||
{
|
||||
UDEBUG("");
|
||||
|
||||
// empty the STM
|
||||
while(_stMem.size())
|
||||
{
|
||||
moveSignatureToWMFromSTM(*_stMem.begin());
|
||||
}
|
||||
if(_stMem.size() != 0)
|
||||
{
|
||||
ULOGGER_ERROR("_stMem must be empty here, size=%d", _stMem.size());
|
||||
}
|
||||
_stMem.clear();
|
||||
|
||||
this->cleanUnusedWords();
|
||||
|
||||
if(_dbDriver)
|
||||
@@ -1217,6 +1336,12 @@ void Memory::clear()
|
||||
_dbDriver->emptyTrashes();
|
||||
_dbDriver->join();
|
||||
}
|
||||
if(_dbDriver)
|
||||
{
|
||||
// make sure time_enter in database is at least 1 second
|
||||
// after for the next stuf added to database
|
||||
uSleep(1500);
|
||||
}
|
||||
|
||||
// Save some stats to the db, save only when the mem is not empty
|
||||
if(_dbDriver && (_stMem.size() || _workingMem.size()))
|
||||
@@ -1261,11 +1386,6 @@ void Memory::clear()
|
||||
ULOGGER_ERROR("_workingMem must be empty here, size=%d", _workingMem.size());
|
||||
}
|
||||
_workingMem.clear();
|
||||
if(_stMem.size() != 0)
|
||||
{
|
||||
ULOGGER_ERROR("_stMem must be empty here, size=%d", _stMem.size());
|
||||
}
|
||||
_stMem.clear();
|
||||
if(_signatures.size()!=0)
|
||||
{
|
||||
ULOGGER_ERROR("_signatures must be empty here, size=%d", _signatures.size());
|
||||
@@ -1450,8 +1570,15 @@ std::list<int> Memory::forget(const std::set<int> & ignoredIds)
|
||||
{
|
||||
UDEBUG("");
|
||||
std::list<int> signaturesRemoved;
|
||||
if(this->isIncremental() && _vwd->isIncremental() && _vwd->getVisualWords().size())
|
||||
if(this->isIncremental() &&
|
||||
_vwd->isIncremental() &&
|
||||
_vwd->getVisualWords().size() &&
|
||||
!_vwd->isIncrementalFlann())
|
||||
{
|
||||
// Note that when using incremental FLANN, the number of words
|
||||
// is not the biggest issue, so use the number of signatures instead
|
||||
// of the number of words
|
||||
|
||||
int newWords = 0;
|
||||
int wordsRemoved = 0;
|
||||
|
||||
@@ -1719,32 +1846,33 @@ void Memory::moveToTrash(Signature * s, bool keepLinkedToGraph, std::list<int> *
|
||||
if(!keepLinkedToGraph || (!s->isSaved() && s->isBadSignature() && _badSignaturesIgnored))
|
||||
{
|
||||
UASSERT_MSG(this->isInSTM(s->id()),
|
||||
uFormat("Deleting location (%d) outside the STM is not implemented!", s->id()).c_str());
|
||||
uFormat("Deleting location (%d) outside the "
|
||||
"STM is not implemented!", s->id()).c_str());
|
||||
const std::map<int, Link> & links = s->getLinks();
|
||||
for(std::map<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
Signature * sTo = this->_getSignature(iter->first);
|
||||
// neighbor to s
|
||||
if(sTo)
|
||||
{
|
||||
if(iter->first > s->id() && (sTo->getLinks().size() == 1 || !sTo->hasLink(s->id())))
|
||||
{
|
||||
UWARN("Link %d of %d is newer, removing neighbor link may split the map!",
|
||||
iter->first, s->id());
|
||||
}
|
||||
UASSERT_MSG(sTo!=0,
|
||||
uFormat("A neighbor (%d) of the deleted location %d is "
|
||||
"not found in WM/STM! Are you deleting a location "
|
||||
"outside the STM?", iter->first, s->id()).c_str());
|
||||
|
||||
// child
|
||||
if(iter->second.type() == Link::kGlobalClosure && s->id() > sTo->id())
|
||||
{
|
||||
sTo->setWeight(sTo->getWeight() + s->getWeight()); // copy weight
|
||||
}
|
||||
|
||||
sTo->removeLink(s->id());
|
||||
}
|
||||
else
|
||||
if(iter->first > s->id() && links.size()>1 && sTo->hasLink(s->id()))
|
||||
{
|
||||
UERROR("Link %d of %d not in WM/STM?!?", iter->first, s->id());
|
||||
UWARN("Link %d of %d is newer, removing neighbor link "
|
||||
"may split the map!",
|
||||
iter->first, s->id());
|
||||
}
|
||||
|
||||
// child
|
||||
if(iter->second.type() == Link::kGlobalClosure && s->id() > sTo->id())
|
||||
{
|
||||
sTo->setWeight(sTo->getWeight() + s->getWeight()); // copy weight
|
||||
}
|
||||
|
||||
sTo->removeLink(s->id());
|
||||
|
||||
}
|
||||
s->removeLinks(); // remove all links
|
||||
s->setWeight(0);
|
||||
@@ -1801,6 +1929,11 @@ void Memory::moveToTrash(Signature * s, bool keepLinkedToGraph, std::list<int> *
|
||||
}
|
||||
}
|
||||
|
||||
if(_lastGlobalLoopClosureId == s->id())
|
||||
{
|
||||
_lastGlobalLoopClosureId = 0;
|
||||
}
|
||||
|
||||
if( (_notLinkedNodesKeptInDb || keepLinkedToGraph) &&
|
||||
_dbDriver &&
|
||||
s->id()>0 &&
|
||||
@@ -1959,7 +2092,9 @@ void Memory::removeLink(int oldId, int newId)
|
||||
bool noChildrenAnymore = true;
|
||||
for(std::map<int, Link>::const_iterator iter=newS->getLinks().begin(); iter!=newS->getLinks().end(); ++iter)
|
||||
{
|
||||
if(iter->second.type() > Link::kNeighbor && iter->first < newS->id())
|
||||
if(iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged &&
|
||||
iter->first < newS->id())
|
||||
{
|
||||
noChildrenAnymore = false;
|
||||
break;
|
||||
@@ -2554,7 +2689,11 @@ Transform Memory::computeIcpTransform(
|
||||
fabs(ipitch) > _icpMaxRotation ||
|
||||
fabs(iyaw) > _icpMaxRotation)))
|
||||
{
|
||||
msg = uFormat("Cannot compute transform (ICP correction too large)");
|
||||
msg = uFormat("Cannot compute transform (ICP correction too large -> %f m %f rad, limits=%f m, %f rad)",
|
||||
uMax3(fabs(ix), fabs(iy), fabs(iz)),
|
||||
uMax3(fabs(iroll), fabs(ipitch), fabs(iyaw)),
|
||||
_icpMaxTranslation,
|
||||
_icpMaxRotation);
|
||||
UINFO(msg.c_str());
|
||||
}
|
||||
else
|
||||
@@ -2888,23 +3027,28 @@ bool Memory::addLink(const Link & link)
|
||||
if(link.type()!=Link::kVirtualClosure)
|
||||
{
|
||||
_linksChanged = true;
|
||||
}
|
||||
|
||||
if(link.type() == Link::kGlobalClosure)
|
||||
{
|
||||
_lastGlobalLoopClosureId = fromS->id()>toS->id()?fromS->id():toS->id();
|
||||
// update weight
|
||||
// ignore scan matching loop closures
|
||||
if(link.type() != Link::kLocalSpaceClosure ||
|
||||
link.userDataCompressed().empty())
|
||||
{
|
||||
_lastGlobalLoopClosureId = fromS->id()>toS->id()?fromS->id():toS->id();
|
||||
|
||||
// update weights only if the memory is incremental
|
||||
UASSERT(fromS->getWeight() >= 0 && toS->getWeight() >=0);
|
||||
if(fromS->id() > toS->id())
|
||||
{
|
||||
fromS->setWeight(fromS->getWeight() + toS->getWeight());
|
||||
toS->setWeight(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
toS->setWeight(toS->getWeight() + fromS->getWeight());
|
||||
fromS->setWeight(0);
|
||||
// update weights only if the memory is incremental
|
||||
// When reducing the graph, transfer weight to the oldest signature
|
||||
UASSERT(fromS->getWeight() >= 0 && toS->getWeight() >=0);
|
||||
if((_reduceGraph && fromS->id() < toS->id()) ||
|
||||
(!_reduceGraph && fromS->id() > toS->id()))
|
||||
{
|
||||
fromS->setWeight(fromS->getWeight() + toS->getWeight());
|
||||
toS->setWeight(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
toS->setWeight(toS->getWeight() + fromS->getWeight());
|
||||
fromS->setWeight(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3101,7 +3245,8 @@ void Memory::dumpMemoryTree(const char * fileNameTree) const
|
||||
iter!=i->second->getLinks().end();
|
||||
++iter)
|
||||
{
|
||||
if(iter->second.type() > Link::kNeighbor)
|
||||
if(iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
if(iter->first < i->first)
|
||||
{
|
||||
@@ -3199,7 +3344,9 @@ bool Memory::rehearsalMerge(int oldId, int newId)
|
||||
if(oldS && newS && _incrementalMemory)
|
||||
{
|
||||
std::map<int, Link>::const_iterator iter = oldS->getLinks().find(newS->id());
|
||||
if(iter != oldS->getLinks().end() && iter->second.type() > Link::kNeighbor)
|
||||
if(iter != oldS->getLinks().end() &&
|
||||
iter->second.type() != Link::kNeighbor &&
|
||||
iter->second.type() != Link::kNeighborMerged)
|
||||
{
|
||||
// do nothing, already merged
|
||||
UWARN("already merged, old=%d, new=%d", oldId, newId);
|
||||
@@ -3608,8 +3755,7 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
|
||||
data.imageRaw().type() == CV_8UC3);
|
||||
UASSERT_MSG(data.depthOrRightRaw().empty() ||
|
||||
( (data.depthOrRightRaw().type() == CV_16UC1 || data.depthOrRightRaw().type() == CV_32FC1 || data.depthOrRightRaw().type() == CV_8UC1) &&
|
||||
data.depthOrRightRaw().rows == data.imageRaw().rows &&
|
||||
data.depthOrRightRaw().cols == data.imageRaw().cols),
|
||||
((data.imageRaw().empty() && data.depthOrRightRaw().type() != CV_8UC1) || (data.depthOrRightRaw().rows == data.imageRaw().rows && data.depthOrRightRaw().cols == data.imageRaw().cols))),
|
||||
uFormat("image=(%d/%d) depth=(%d/%d, type=%d [accepted=%d,%d,%d])",
|
||||
data.imageRaw().cols,
|
||||
data.imageRaw().rows,
|
||||
@@ -3912,7 +4058,7 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
|
||||
descriptors = data.descriptors().clone();
|
||||
|
||||
// filter by depth
|
||||
if(!data.depthOrRightRaw().empty() && data.stereoCameraModel().isValid())
|
||||
if(!data.depthOrRightRaw().empty() && !data.imageRaw().empty() && data.stereoCameraModel().isValid())
|
||||
{
|
||||
//stereo
|
||||
cv::Mat imageMono;
|
||||
@@ -4104,6 +4250,12 @@ Signature * Memory::createSignature(const SensorData & data, const Transform & p
|
||||
Signature * s;
|
||||
if(this->isBinDataKept())
|
||||
{
|
||||
UDEBUG("Bin data kept: rgb=%d, depth=%d, scan=%d, userData=%d",
|
||||
image.empty()?0:1,
|
||||
depthOrRightImage.empty()?0:1,
|
||||
laserScan.empty()?0:1,
|
||||
data.userDataRaw().empty()?0:1);
|
||||
|
||||
std::vector<unsigned char> imageBytes;
|
||||
std::vector<unsigned char> depthBytes;
|
||||
|
||||
@@ -4398,7 +4550,7 @@ std::set<int> Memory::reactivateSignatures(const std::list<int> & ids, unsigned
|
||||
{
|
||||
idsLoaded.push_back((*i)->id());
|
||||
//append to working memory
|
||||
this->addSignatureToWm(*i);
|
||||
this->addSignatureToWmFromLTM(*i);
|
||||
}
|
||||
this->enableWordsRef(idsLoaded);
|
||||
UDEBUG("time = %fs", timer.ticks());
|
||||
@@ -4427,14 +4579,16 @@ void Memory::getMetricConstraints(
|
||||
{
|
||||
if(uContains(poses, *iter))
|
||||
{
|
||||
std::map<int, Link> neighbors = this->getNeighborLinks(*iter, lookInDatabase); // only direct neighbors
|
||||
for(std::map<int, Link>::iterator jter=neighbors.begin(); jter!=neighbors.end(); ++jter)
|
||||
std::map<int, Link> tmpLinks = getLinks(*iter, lookInDatabase);
|
||||
for(std::map<int, Link>::iterator jter=tmpLinks.begin(); jter!=tmpLinks.end(); ++jter)
|
||||
{
|
||||
if( jter->second.isValid() &&
|
||||
uContains(poses, jter->first) &&
|
||||
graph::findLink(links, *iter, jter->first) == links.end())
|
||||
{
|
||||
if(!lookInDatabase)
|
||||
if(!lookInDatabase &&
|
||||
(jter->second.type() == Link::kNeighbor ||
|
||||
jter->second.type() == Link::kNeighborMerged))
|
||||
{
|
||||
Link link = jter->second;
|
||||
const Signature * s = this->getSignature(jter->first);
|
||||
@@ -4471,17 +4625,6 @@ void Memory::getMetricConstraints(
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::map<int, Link> loops = this->getLoopClosureLinks(*iter, lookInDatabase);
|
||||
for(std::map<int, Link>::iterator jter=loops.begin(); jter!=loops.end(); ++jter)
|
||||
{
|
||||
if( jter->second.isValid() && // null transform means a rehearsed location
|
||||
jter->first < *iter && // Loop parent to child
|
||||
uContains(poses, jter->first))
|
||||
{
|
||||
links.insert(std::make_pair(*iter, jter->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -505,6 +505,7 @@ Transform OdometryOpticalFlow::computeTransform(
|
||||
data.cameraModels()[0].fy(),
|
||||
true);
|
||||
if(pcl::isFinite(pt) &&
|
||||
pt.z > 0 &&
|
||||
(this->getMaxDepth() == 0.0f || pt.z < this->getMaxDepth()))
|
||||
{
|
||||
newCorners3D->at(oi) = util3d::transformPoint(pt, data.cameraModels()[0].localTransform());
|
||||
|
||||
+129
-19
@@ -658,12 +658,27 @@ int Rtabmap::triggerNewMap()
|
||||
int mapId = -1;
|
||||
if(_memory)
|
||||
{
|
||||
mapId = _memory->incrementMapId();
|
||||
std::map<int, int> reducedIds;
|
||||
mapId = _memory->incrementMapId(&reducedIds);
|
||||
UINFO("New map triggered, new map = %d", mapId);
|
||||
_optimizedPoses.clear();
|
||||
_constraints.clear();
|
||||
_lastLocalizationNodeId = 0;
|
||||
_distanceTravelled = 0.0f;
|
||||
|
||||
//Verify if there are nodes that were merged through graph reduction
|
||||
if(reducedIds.size() && _path.size())
|
||||
{
|
||||
for(unsigned int i=0; i<_path.size(); ++i)
|
||||
{
|
||||
std::map<int, int>::const_iterator iter = reducedIds.find(_path[i].first);
|
||||
if(iter!= reducedIds.end())
|
||||
{
|
||||
// change path ID to loop closure ID
|
||||
_path[i].first = iter->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return mapId;
|
||||
}
|
||||
@@ -942,7 +957,6 @@ bool Rtabmap::process(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
signature = _memory->getLastWorkingSignature();
|
||||
if(!signature)
|
||||
{
|
||||
@@ -957,6 +971,7 @@ bool Rtabmap::process(
|
||||
// Metric
|
||||
//============================================================
|
||||
bool smallDisplacement = false;
|
||||
std::list<int> signaturesRemoved;
|
||||
if(_rgbdSlamMode)
|
||||
{
|
||||
//Verify if there was a rehearsal
|
||||
@@ -1080,9 +1095,10 @@ bool Rtabmap::process(
|
||||
{
|
||||
newPose = _mapCorrection * signature->getPose();
|
||||
}
|
||||
|
||||
// Update Poses and Constraints
|
||||
_optimizedPoses.insert(std::make_pair(signature->id(), newPose));
|
||||
_lastLocalizationPose = newPose; // used in localization mode only (path planning)
|
||||
|
||||
if(signature->getLinks().size() == 1)
|
||||
{
|
||||
// link should be old to new
|
||||
@@ -1108,6 +1124,43 @@ bool Rtabmap::process(
|
||||
}
|
||||
_constraints.insert(std::make_pair(tmp.from(), tmp));
|
||||
}
|
||||
//============================================================
|
||||
// Reduced graph
|
||||
//============================================================
|
||||
//Verify if there are nodes that were merged through graph reduction
|
||||
if(statistics_.reducedIds().size())
|
||||
{
|
||||
for(unsigned int i=0; i<_path.size(); ++i)
|
||||
{
|
||||
std::map<int, int>::const_iterator iter = statistics_.reducedIds().find(_path[i].first);
|
||||
if(iter!= statistics_.reducedIds().end())
|
||||
{
|
||||
// change path ID to loop closure ID
|
||||
_path[i].first = iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
for(std::map<int, int>::const_iterator iter=statistics_.reducedIds().begin();
|
||||
iter!=statistics_.reducedIds().end();
|
||||
++iter)
|
||||
{
|
||||
int erased = _optimizedPoses.erase(iter->first);
|
||||
if(erased)
|
||||
{
|
||||
for(std::multimap<int, Link>::iterator jter = _constraints.begin(); jter!=_constraints.end();)
|
||||
{
|
||||
if(jter->second.from() == iter->first || jter->second.to() == iter->first)
|
||||
{
|
||||
_constraints.erase(jter++);
|
||||
}
|
||||
else
|
||||
{
|
||||
++jter;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// Local loop closure in TIME
|
||||
@@ -1132,7 +1185,6 @@ bool Rtabmap::process(
|
||||
if(!transform.isNull() && _globalLoopClosureIcpType > 0)
|
||||
{
|
||||
transform = _memory->computeIcpTransform(*iter, signature->id(), transform, _globalLoopClosureIcpType==1, &rejectedMsg, 0, &variance);
|
||||
variance = 1.0f; // ICP, set variance to 1 // FIXME why? all other links based on visual keep the variance
|
||||
}
|
||||
if(!transform.isNull())
|
||||
{
|
||||
@@ -2097,9 +2149,10 @@ bool Rtabmap::process(
|
||||
if(_rgbdSlamMode &&
|
||||
(_loopClosureHypothesis.first>0 ||
|
||||
lastLocalSpaceClosureId>0 || // can be different map of the current one
|
||||
statistics_.reducedIds().size() ||
|
||||
localLoopClosuresInTimeFound>0 ||
|
||||
((_memory->isIncremental() || signature->getLinks().size()) && // In localization mode, the new node should be linked
|
||||
(localLoopClosuresInTimeFound>0 || // only same map of the current one
|
||||
signaturesRetrieved.size())))) // can be different map of the current one
|
||||
signaturesRetrieved.size()))) // can be different map of the current one
|
||||
{
|
||||
UASSERT(uContains(_optimizedPoses, signature->id()));
|
||||
|
||||
@@ -2345,7 +2398,6 @@ bool Rtabmap::process(
|
||||
}
|
||||
|
||||
// remove last signature if the memory is not incremental or is a bad signature (if bad signatures are ignored)
|
||||
std::list<int> signaturesRemoved;
|
||||
int signatureRemoved = _memory->cleanup();
|
||||
if(signatureRemoved)
|
||||
{
|
||||
@@ -2898,11 +2950,46 @@ std::map<int, Transform> Rtabmap::optimizeGraph(
|
||||
{
|
||||
UTimer timer;
|
||||
std::map<int, Transform> optimizedPoses;
|
||||
std::map<int, Transform> poses;
|
||||
std::multimap<int, Link> edgeConstraints;
|
||||
std::map<int, Transform> poses, posesOut;
|
||||
std::multimap<int, Link> edgeConstraints, linksOut;
|
||||
UDEBUG("ids=%d", (int)ids.size());
|
||||
_memory->getMetricConstraints(ids, poses, edgeConstraints, lookInDatabase);
|
||||
UINFO("get constraints (%d poses, %d edges) time %f s", (int)poses.size(), (int)edgeConstraints.size(), timer.ticks());
|
||||
UINFO("get constraints (ids=%d, %d poses, %d edges) time %f s", (int)ids.size(), (int)poses.size(), (int)edgeConstraints.size(), timer.ticks());
|
||||
|
||||
// The constraints must be all already connected! Only check in debug
|
||||
if(ULogger::level() == ULogger::kDebug)
|
||||
{
|
||||
_graphOptimizer->getConnectedGraph(fromId, poses, edgeConstraints, posesOut, linksOut);
|
||||
if(poses.size() != posesOut.size())
|
||||
{
|
||||
for(std::map<int, Transform>::iterator iter=poses.begin(); iter!=poses.end(); ++iter)
|
||||
{
|
||||
if(posesOut.find(iter->first) == posesOut.end())
|
||||
{
|
||||
UERROR("Not found %d in posesOut", iter->first);
|
||||
for(std::multimap<int, Link>::iterator jter=edgeConstraints.begin(); jter!=edgeConstraints.end(); ++jter)
|
||||
{
|
||||
if(jter->second.from() == iter->first || jter->second.to()==iter->first)
|
||||
{
|
||||
UERROR("Found link %d->%d", jter->second.from(), jter->second.to());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(edgeConstraints.size() != linksOut.size())
|
||||
{
|
||||
for(std::multimap<int, Link>::iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
|
||||
{
|
||||
if(graph::findLink(linksOut, iter->second.from(), iter->second.to()) == linksOut.end())
|
||||
{
|
||||
UERROR("Not found link %d->%d in linksOut", iter->second.from(), iter->second.to());
|
||||
}
|
||||
}
|
||||
}
|
||||
UASSERT_MSG(poses.size() == posesOut.size() && edgeConstraints.size() == linksOut.size(),
|
||||
uFormat("nodes %d->%d, links %d->%d", poses.size(), posesOut.size(), edgeConstraints.size(), linksOut.size()).c_str());
|
||||
}
|
||||
|
||||
if(constraints)
|
||||
{
|
||||
@@ -3285,6 +3372,24 @@ bool Rtabmap::computePath(int targetNode, bool global)
|
||||
{
|
||||
// set goal to latest signature
|
||||
std::string goalStr = uFormat("GOAL:%d", targetNode);
|
||||
|
||||
// use label is exist
|
||||
if(_memory->getSignature(targetNode))
|
||||
{
|
||||
if(!_memory->getSignature(targetNode)->getLabel().empty())
|
||||
{
|
||||
goalStr = std::string("GOAL:")+_memory->getSignature(targetNode)->getLabel();
|
||||
}
|
||||
}
|
||||
else if(global)
|
||||
{
|
||||
std::map<int, std::string> labels = _memory->getAllLabels();
|
||||
std::map<int, std::string>::iterator iter = labels.find(targetNode);
|
||||
if(iter != labels.end() && !iter->second.empty())
|
||||
{
|
||||
goalStr = std::string("GOAL:")+labels.at(targetNode);
|
||||
}
|
||||
}
|
||||
setUserData(0, cv::Mat(1, int(goalStr.size()+1), CV_8SC1, (void *)goalStr.c_str()).clone());
|
||||
}
|
||||
updateGoalIndex();
|
||||
@@ -3474,17 +3579,19 @@ void Rtabmap::updateGoalIndex()
|
||||
// remove all previous virtual links
|
||||
for(unsigned int i=0; i<_pathCurrentIndex && i<_path.size(); ++i)
|
||||
{
|
||||
if(_memory->getSignature(_path[i].first))
|
||||
const Signature * s = _memory->getSignature(_path[i].first);
|
||||
if(s)
|
||||
{
|
||||
_memory->removeVirtualLinks(_path[i].first);
|
||||
_memory->removeVirtualLinks(s->id());
|
||||
}
|
||||
}
|
||||
|
||||
// for the current index, only keep the newest virtual link
|
||||
// This will make sure that the path is still connected even
|
||||
// if the new signature is removed (e.g., because of a small displacement)
|
||||
UASSERT(_pathCurrentIndex < _path.size());
|
||||
const Signature * currentIndexS = _memory->getSignature(_path[_pathCurrentIndex].first);
|
||||
UASSERT(currentIndexS != 0);
|
||||
UASSERT_MSG(currentIndexS != 0, uFormat("_path[%d].first=%d", _pathCurrentIndex, _path[_pathCurrentIndex].first).c_str());
|
||||
std::map<int, Link> links = currentIndexS->getLinks(); // make a copy
|
||||
bool latestVirtualLinkFound = false;
|
||||
for(std::map<int, Link>::reverse_iterator iter=links.rbegin(); iter!=links.rend(); ++iter)
|
||||
@@ -3516,14 +3623,17 @@ void Rtabmap::updateGoalIndex()
|
||||
}
|
||||
if(distanceSoFar <= _localRadius)
|
||||
{
|
||||
const Signature * s = _memory->getSignature(_path[i].first);
|
||||
if(s)
|
||||
if(_path[i].first != _path[i-1].first)
|
||||
{
|
||||
if(!s->hasLink(_path[i-1].first) && _memory->getSignature(_path[i-1].first) != 0)
|
||||
const Signature * s = _memory->getSignature(_path[i].first);
|
||||
if(s)
|
||||
{
|
||||
Transform virtualLoop = _path[i].second.inverse() * _path[i-1].second;
|
||||
_memory->addLink(Link(_path[i].first, _path[i-1].first, Link::kVirtualClosure, virtualLoop, 100, 100)); // on the optimized path
|
||||
UINFO("Added Virtual link between %d and %d", _path[i-1].first, _path[i].first);
|
||||
if(!s->hasLink(_path[i-1].first) && _memory->getSignature(_path[i-1].first) != 0)
|
||||
{
|
||||
Transform virtualLoop = _path[i].second.inverse() * _path[i-1].second;
|
||||
_memory->addLink(Link(_path[i].first, _path[i-1].first, Link::kVirtualClosure, virtualLoop, 100, 100)); // on the optimized path
|
||||
UINFO("Added Virtual link between %d and %d", _path[i-1].first, _path[i].first);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,10 +257,18 @@ void RtabmapThread::mainLoop()
|
||||
if(id == 0 && !parameters.at("label").empty() && _rtabmap->getMemory())
|
||||
{
|
||||
id = _rtabmap->getMemory()->getSignatureIdByLabel(parameters.at("label"));
|
||||
if(id <= 0)
|
||||
{
|
||||
UERROR("Failed to find a node with label \"%s\".", parameters.at("label").c_str());
|
||||
}
|
||||
}
|
||||
if(id <= 0 || !_rtabmap->computePath(id, true))
|
||||
else if(id < 0)
|
||||
{
|
||||
UERROR("Failed to set a goal to location=%d.", id);
|
||||
UERROR("Failed to set a goal. ID (%d) should be positive > 0", id);
|
||||
}
|
||||
if(id > 0 && !_rtabmap->computePath(id, true))
|
||||
{
|
||||
UERROR("Failed to compute a path to goal %d.", id);
|
||||
}
|
||||
this->post(new RtabmapGlobalPathEvent(id, parameters.at("label"), _rtabmap->getPath()));
|
||||
break;
|
||||
|
||||
@@ -97,7 +97,8 @@ void Signature::addLinks(const std::map<int, Link> & links)
|
||||
void Signature::addLink(const Link & link)
|
||||
{
|
||||
UDEBUG("Add link %d to %d (type=%d)", link.to(), this->id(), (int)link.type());
|
||||
UASSERT(link.from() == this->id());
|
||||
UASSERT_MSG(link.from() == this->id(), uFormat("%d->%d for signature %d (type=%d)", link.from(), link.to(), this->id(), link.type()).c_str());
|
||||
UASSERT_MSG(link.to() != this->id(), uFormat("%d->%d for signature %d (type=%d)", link.from(), link.to(), this->id(), link.type()).c_str());
|
||||
std::pair<std::map<int, Link>::iterator, bool> pair = _links.insert(std::make_pair(link.to(), link));
|
||||
UASSERT_MSG(pair.second, uFormat("Link %d (type=%d) already added to signature %d!", link.to(), link.type(), this->id()).c_str());
|
||||
_linksModified = true;
|
||||
@@ -134,6 +135,7 @@ void Signature::removeLink(int idTo)
|
||||
int count = (int)_links.erase(idTo);
|
||||
if(count)
|
||||
{
|
||||
UDEBUG("Removed link %d from %d", idTo, this->id());
|
||||
_linksModified = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user