mirror of
https://github.com/introlab/rtabmap.git
synced 2026-10-04 00:57:46 +08:00
Added doc for Rtabmap and Memory classes
This commit is contained in:
@@ -61,47 +61,203 @@ class LocalGridMaker;
|
||||
class MarkerDetector;
|
||||
class GlobalDescriptorExtractor;
|
||||
|
||||
/**
|
||||
* @class Memory
|
||||
* @brief Three-tiered memory management (STM, WM, LTM) for RTAB-Map.
|
||||
*
|
||||
* Memory is the core map data structure used by @ref Rtabmap. It stores observations
|
||||
* as @ref Signature nodes connected by @ref Link edges and orchestrates their lifecycle
|
||||
* across three tiers:
|
||||
*
|
||||
* - **Short-Term Memory (STM)**: most recently added signatures, kept at a fixed size
|
||||
* (see @ref Parameters::kMemSTMSize()). Used to delay recently observed places before
|
||||
* they become candidates for loop closure.
|
||||
* - **Working Memory (WM)**: signatures available for loop-closure likelihood
|
||||
* computation in the current iteration. Older signatures are transferred from WM
|
||||
* to LTM by @ref forget() to bound iteration time.
|
||||
* - **Long-Term Memory (LTM)**: persisted in the database via @ref DBDriver. Signatures
|
||||
* can be brought back to WM with @ref reactivateSignatures() when their neighbors still
|
||||
* in WM are good loop-closure candidates.
|
||||
*
|
||||
* The class also owns a visual word dictionary (@ref VWDictionary), feature extractor
|
||||
* (@ref Feature2D) and registration pipelines (@ref Registration, @ref RegistrationVis,
|
||||
* @ref RegistrationIcp) used to compute relative transforms between signatures.
|
||||
*
|
||||
* Typical iteration: @ref update() adds a new @ref SensorData as a @ref Signature in
|
||||
* STM; @ref computeLikelihood() scores it against WM; the @ref Rtabmap caller decides
|
||||
* on loop closures with @ref BayesFilter; @ref cleanup() drops bad signatures;
|
||||
* @ref forget() transfers oldest WM signatures to LTM and @ref reactivateSignatures()
|
||||
* pulls relevant ones back.
|
||||
*
|
||||
* @see Signature
|
||||
* @see DBDriver
|
||||
* @see VWDictionary
|
||||
* @see Rtabmap
|
||||
*/
|
||||
class RTABMAP_CORE_EXPORT Memory
|
||||
{
|
||||
public:
|
||||
/** @brief First valid signature id assigned by @ref getNextId() (positive integer). */
|
||||
static const int kIdStart;
|
||||
/** @brief Reserved id for the "virtual place" used by the Bayes filter (negative). */
|
||||
static const int kIdVirtual;
|
||||
/** @brief Sentinel value indicating an invalid signature id (zero). */
|
||||
static const int kIdInvalid;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructs a Memory instance with the given parameters.
|
||||
*
|
||||
* The database is not opened here; call @ref init() to open or create a database
|
||||
* and load persisted state. @p parameters may include any key from @ref Parameters
|
||||
* (memory, keypoint, registration, etc.); missing keys fall back to defaults.
|
||||
*/
|
||||
Memory(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~Memory();
|
||||
|
||||
/**
|
||||
* @brief Re-parses parameters and propagates them to owned sub-objects.
|
||||
*
|
||||
* Forwards the relevant subset to @ref VWDictionary, @ref Feature2D, the registration
|
||||
* pipelines and the database driver. Safe to call at runtime to change settings.
|
||||
*/
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
/** @return The most recent parameter map applied via the constructor or @ref parseParameters(). */
|
||||
virtual const ParametersMap & getParameters() const {return parameters_;}
|
||||
/**
|
||||
* @brief Adds a sensor observation to the map (overload without odometry pose).
|
||||
*
|
||||
* Equivalent to calling the full @ref update() with an identity pose and empty covariance.
|
||||
* The new signature is added to STM; oldest STM entries are promoted to WM as needed.
|
||||
*
|
||||
* @param data Sensor data (images, scan, user data, odometry features) for this frame.
|
||||
* @param stats Optional output statistics receiver for timing/diagnostic values.
|
||||
* @return True if a signature was successfully created and added, false otherwise.
|
||||
*/
|
||||
bool update(const SensorData & data,
|
||||
Statistics * stats = 0);
|
||||
/**
|
||||
* @brief Adds a sensor observation with odometry pose and velocity to the map.
|
||||
*
|
||||
* Creates a new @ref Signature, extracts visual words, links it to the previous
|
||||
* STM signature with a neighbor link, runs rehearsal against STM and promotes
|
||||
* the oldest STM signature to WM if STM is full.
|
||||
*
|
||||
* @param data Sensor data (images, scan, user data, odometry features).
|
||||
* @param pose Odometry pose at this frame (null if odometry not used).
|
||||
* @param covariance 6x6 odometry covariance (or empty if null odometry is provided).
|
||||
* @param velocity Optional 6-vector (vx, vy, vz, vroll, vpitch, vyaw).
|
||||
* @param stats Optional output statistics receiver.
|
||||
* @return True on success, false if signature creation failed.
|
||||
*/
|
||||
bool update(const SensorData & data,
|
||||
const Transform & pose,
|
||||
const cv::Mat & covariance,
|
||||
const std::vector<float> & velocity = std::vector<float>(), // vx,vy,vz,vroll,vpitch,vyaw
|
||||
Statistics * stats = 0);
|
||||
/**
|
||||
* @brief Opens or creates a database and loads existing state into WM.
|
||||
*
|
||||
* @param dbUrl Path to the database file (empty for in-memory).
|
||||
* @param dbOverwritten If true, deletes the existing file before opening.
|
||||
* @param parameters Optional parameter override applied before loading.
|
||||
* @param postInitClosingEvents If true, posts @ref RtabmapEventInit events for
|
||||
* progress reporting (used by GUI).
|
||||
* @return True on success, false if the database could not be opened.
|
||||
*/
|
||||
bool init(const std::string & dbUrl,
|
||||
bool dbOverwritten = false,
|
||||
const ParametersMap & parameters = ParametersMap(),
|
||||
bool postInitClosingEvents = false);
|
||||
/**
|
||||
* @brief Flushes pending data and closes the database connection.
|
||||
*
|
||||
* @param databaseSaved If true, persists STM/WM signatures and statistics before closing.
|
||||
* If false, in-memory state is discarded.
|
||||
* @param postInitClosingEvents If true, posts progress events while closing.
|
||||
* @param ouputDatabasePath If non-empty, the database is copied to this path on close. If a
|
||||
* database on disk was initially created/loaded on a different path, it will be updated with latest
|
||||
* changes and renamed to the output path.
|
||||
*/
|
||||
void close(bool databaseSaved = true, bool postInitClosingEvents = false, const std::string & ouputDatabasePath = "");
|
||||
/**
|
||||
* @brief Computes loop-closure likelihood of @p signature against a set of WM ids.
|
||||
*
|
||||
* Compares visual words (tf-idf if enabled) between @p signature and each id in
|
||||
* @p ids and returns a normalized likelihood per id.
|
||||
*
|
||||
* @param signature Query signature (typically the last added one).
|
||||
* @param ids Candidate signature ids in working memory.
|
||||
* @return Map from id to likelihood score.
|
||||
*/
|
||||
std::map<int, float> computeLikelihood(const Signature * signature,
|
||||
const std::list<int> & ids);
|
||||
/**
|
||||
* @brief Starts a new map id, breaking session continuity (e.g. after localization loss).
|
||||
*
|
||||
* @param reducedIds If non-null, populated with id remappings produced by graph reduction
|
||||
* triggered by the new map.
|
||||
* @return The new map id (auto-incremented).
|
||||
*/
|
||||
int incrementMapId(std::map<int, int> * reducedIds = 0);
|
||||
/**
|
||||
* @brief Refreshes the age of @p signatureId in working memory, marking it as recent.
|
||||
*
|
||||
* Used to keep loop-closure hypotheses active so they are not transferred to LTM
|
||||
* during the next @ref forget() call.
|
||||
*/
|
||||
void updateAge(int signatureId);
|
||||
|
||||
/**
|
||||
* @brief Transfers oldest signatures from WM to LTM to respect memory and/or time limits.
|
||||
*
|
||||
* The number of signatures removed depends on the visual word dictionary growth
|
||||
* since the previous iteration (including retrieved signatures). We remove signatures
|
||||
* until the number of visual words transferred is greater than the number of retrieved
|
||||
* ones on the last iteration. In the case that signatures don't have visual words (e.g., lidar-only mapping),
|
||||
* we remove at least one more signature than the total of signatures added/retrieved in the
|
||||
* previous iteration.
|
||||
*
|
||||
* @param ignoredIds Signatures that must not be transferred (e.g. STM, retrieved ids, on the planned path).
|
||||
* @return Ids of signatures moved to LTM, in transfer order.
|
||||
*/
|
||||
std::list<int> forget(const std::set<int> & ignoredIds = std::set<int>());
|
||||
/**
|
||||
* @brief Reloads signatures from LTM into WM.
|
||||
*
|
||||
* @param ids Candidate ids; those already in WM/STM are ignored.
|
||||
* @param maxLoaded Hard cap on number of ids actually loaded (0 = unlimited).
|
||||
* @param timeDbAccess Output: time spent in the database driver (seconds).
|
||||
* @return Ids effectively brought back to WM.
|
||||
*/
|
||||
std::set<int> reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, double & timeDbAccess);
|
||||
|
||||
/**
|
||||
* @brief Drops the last signature if flagged as bad, or any signature in localization mode.
|
||||
* @return Id of the removed signature, or 0 if none was removed.
|
||||
*/
|
||||
int cleanup();
|
||||
/** @brief Persists @p statistics to the database; @p saveWMState records the WM id list. */
|
||||
void saveStatistics(const Statistics & statistics, bool saveWMState);
|
||||
/** @brief Stores a preview image (typically a thumbnail of the last frame) in the database. */
|
||||
void savePreviewImage(const cv::Mat & image) const;
|
||||
/** @brief Loads the preview image previously written by @ref savePreviewImage(). */
|
||||
cv::Mat loadPreviewImage() const;
|
||||
/** @brief Persists an optimized pose graph and the last localization pose for next session. */
|
||||
void saveOptimizedPoses(const std::map<int, Transform> & optimizedPoses, const Transform & lastlocalizationPose) const;
|
||||
/** @brief Loads optimized poses previously written by @ref saveOptimizedPoses(). */
|
||||
std::map<int, Transform> loadOptimizedPoses(Transform * lastlocalizationPose) const;
|
||||
/** @brief Persists a 2D occupancy grid (origin @p xMin, @p yMin and resolution @p cellSize). */
|
||||
void save2DMap(const cv::Mat & map, float xMin, float yMin, float cellSize) const;
|
||||
/** @brief Loads the 2D occupancy grid previously written by @ref save2DMap(). */
|
||||
cv::Mat load2DMap(float & xMin, float & yMin, float & cellSize) const;
|
||||
/**
|
||||
* @brief Persists an optimized textured/colored mesh to the database.
|
||||
* @param cloud Point cloud (XYZRGB) of vertices.
|
||||
* @param polygons Per-texture list of polygons; each polygon is a list of vertex indices.
|
||||
* @param texCoords Per-texture list of UV coords matching @p polygons.
|
||||
* @param textures Concatenated texture images (square, equal-sized).
|
||||
*/
|
||||
void saveOptimizedMesh(
|
||||
const cv::Mat & cloud,
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons = std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > >(), // Textures -> polygons -> vertices
|
||||
@@ -111,6 +267,7 @@ public:
|
||||
const std::vector<std::vector<Eigen::Vector2f> > & texCoords = std::vector<std::vector<Eigen::Vector2f> >(), // Textures -> uv coords for each vertex of the polygons
|
||||
#endif
|
||||
const cv::Mat & textures = cv::Mat()) const; // concatenated textures (assuming square textures with all same size)
|
||||
/** @brief Loads the optimized mesh previously written by @ref saveOptimizedMesh(). */
|
||||
cv::Mat loadOptimizedMesh(
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons = 0,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
@@ -119,12 +276,39 @@ public:
|
||||
std::vector<std::vector<Eigen::Vector2f> > * texCoords = 0,
|
||||
#endif
|
||||
cv::Mat * textures = 0) const;
|
||||
/** @brief Forces the database driver to flush any queued signature/word saves. */
|
||||
void emptyTrash();
|
||||
/** @brief Blocks until the asynchronous database write thread has finished pending work. */
|
||||
void joinTrashThread();
|
||||
/**
|
||||
* @brief Adds a graph link between two signatures.
|
||||
* @param link Link to add (type, transform, covariance).
|
||||
* @param addInDatabase If true, the link is also added when one of the ids is only in LTM.
|
||||
* @return True if the link was added, false on conflict or missing nodes.
|
||||
*/
|
||||
bool addLink(const Link & link, bool addInDatabase = false);
|
||||
/** @brief Replaces an existing link with @p link (same endpoints and type). */
|
||||
void updateLink(const Link & link, bool updateInDatabase = false);
|
||||
/** @brief Removes every virtual link in WM. */
|
||||
void removeAllVirtualLinks();
|
||||
/** @brief Removes virtual links attached to @p signatureId. */
|
||||
void removeVirtualLinks(int signatureId);
|
||||
/**
|
||||
* @brief Breadth-first walk of the pose graph from @p signatureId.
|
||||
*
|
||||
* Visits neighbor and (optionally) loop-closure neighbors up to @p maxGraphDepth.
|
||||
*
|
||||
* @param signatureId Starting node.
|
||||
* @param maxGraphDepth Maximum graph distance (0 = infinite graph depth).
|
||||
* @param maxCheckedInDatabase Cap on LTM look-ups (-1 = unlimited, 0 = WM only).
|
||||
* @param incrementMarginOnLoop If true, loop-closure links count toward depth.
|
||||
* @param ignoreLoopIds If true, loop-closure neighbors are not traversed.
|
||||
* @param ignoreIntermediateNodes If true, weight==-1 intermediate nodes are skipped.
|
||||
* @param ignoreLocalSpaceLoopIds If true, only global loop closures are traversed.
|
||||
* @param nodesSet If non-empty, traversal is constrained to these ids.
|
||||
* @param dbAccessTime Output: time spent in database access (seconds).
|
||||
* @return Map from visited node id to graph depth, including @p signatureId (with graph depth of 0)
|
||||
*/
|
||||
std::map<int, int> getNeighborsId(
|
||||
int signatureId,
|
||||
int maxGraphDepth,
|
||||
@@ -135,59 +319,171 @@ public:
|
||||
bool ignoreLocalSpaceLoopIds = false,
|
||||
const std::set<int> & nodesSet = std::set<int>(),
|
||||
double * dbAccessTime = 0) const;
|
||||
/**
|
||||
* @brief Returns neighbor ids within a Euclidean radius using optimized poses.
|
||||
* @param signatureId Query node id.
|
||||
* @param radius Maximum distance from @p signatureId (meters).
|
||||
* @param optimizedPoses Pose graph after optimization (used for distances).
|
||||
* @param maxGraphDepth Maximum graph distance (in terms of nodes) to bound the search.
|
||||
* @return Map from node id to squared distance from @p signatureId.
|
||||
*/
|
||||
std::map<int, float> getNeighborsIdRadius(
|
||||
int signatureId,
|
||||
float radius,
|
||||
const std::map<int, Transform> & optimizedPoses,
|
||||
int maxGraphDepth) const;
|
||||
/** @brief Marks @p locationId as intermediate (weight = -1); excludes it from loop closure. */
|
||||
void convertToIntermediate(int locationId);
|
||||
/**
|
||||
* @brief Removes @p locationId from WM/STM and the database.
|
||||
* @param locationId Id of the signature to delete.
|
||||
* @param deletedWords Optional output: words whose reference count dropped to zero.
|
||||
*/
|
||||
void deleteLocation(int locationId, std::list<int> * deletedWords = 0);
|
||||
/** @brief Forces @p locationId to be flushed to the database. */
|
||||
void saveLocationData(int locationId);
|
||||
/** @brief Removes any link between @p idA and @p idB (both directions). */
|
||||
void removeLink(int idA, int idB);
|
||||
/** @brief Strips raw images, scan, user data and/or occupancy grid from @p id to save memory (RAM). This doesn't clear any compressed data.*/
|
||||
void removeRawData(int id, bool image = true, bool scan = true, bool userData = true, bool occupancyGrid = true);
|
||||
/**
|
||||
* @brief Merges @p id with a close neighbor (graph reduction).
|
||||
* @param id Node to reduce.
|
||||
* @param maxDistance Maximum distance to a neighbor to allow the merge (meters).
|
||||
* @param keepLinkedInDb If true, the merged node is kept in the database (history only).
|
||||
* @param direction Restrict merge target: 0=any, 1=previous neighbor, 2=next neighbor.
|
||||
* @return Id of the node @p id was merged into, or 0 if no reduction was performed.
|
||||
*/
|
||||
int reduceNode(int id, float maxDistance = 0.0f, bool keepLinkedInDb = false, int direction = 0);
|
||||
|
||||
//getters
|
||||
/** @return Working memory as { signature id, age } (does not include STM). */
|
||||
const std::map<int, double> & getWorkingMem() const {return _workingMem;}
|
||||
/** @return Set of signature ids currently in short-term memory. */
|
||||
const std::set<int> & getStMem() const {return _stMem;}
|
||||
/** @return Configured maximum STM size (@ref Parameters::kMemSTMSize()). */
|
||||
int getMaxStMemSize() const {return _maxStMemSize;}
|
||||
/** @brief Returns neighbor (sequential) links of @p signatureId; @p lookInDatabase also checks LTM. */
|
||||
std::multimap<int, Link> getNeighborLinks(int signatureId,
|
||||
bool lookInDatabase = false) const;
|
||||
/** @brief Returns loop-closure links of @p signatureId; @p lookInDatabase also checks LTM. */
|
||||
std::multimap<int, Link> getLoopClosureLinks(int signatureId,
|
||||
bool lookInDatabase = false) const;
|
||||
std::multimap<int, Link> getLinks(int signatureId, // can be also used to get links from landmarks
|
||||
/**
|
||||
* @brief Returns all links of @p signatureId (neighbor, loop, prior, gravity, ...).
|
||||
* @param signatureId Source node id (can also be a landmark id).
|
||||
* @param lookInDatabase Also query LTM for links.
|
||||
* @param withLandmarks Include landmark links in the result.
|
||||
*/
|
||||
std::multimap<int, Link> getLinks(int signatureId,
|
||||
bool lookInDatabase = false,
|
||||
bool withLandmarks = false) const;
|
||||
/** @brief Returns links of every signature; @p ignoreNullLinks drops empty placeholders. */
|
||||
std::multimap<int, Link> getAllLinks(bool lookInDatabase, bool ignoreNullLinks = true, bool withLandmarks = false) const;
|
||||
/** @return True if raw binary data (images, scans) is kept in memory after compression. */
|
||||
bool isBinDataKept() const {return _binDataKept;}
|
||||
/** @return Similarity threshold used by rehearsal (@ref Parameters::kMemRehearsalSimilarity()). */
|
||||
float getSimilarityThreshold() const {return _similarityThreshold;}
|
||||
/** @return Map from signature id to weight (rehearsal accumulation count) for WM and STM. */
|
||||
std::map<int, int> getWeights() const;
|
||||
/** @return Id of the most recently added signature, or 0 if none. */
|
||||
int getLastSignatureId() const;
|
||||
/**
|
||||
* @brief Returns the most recent WM signature.
|
||||
* @param ignoreIntermediateNodes If true, skips weight==-1 placeholder nodes.
|
||||
*/
|
||||
const Signature * getLastWorkingSignature(bool ignoreIntermediateNodes) const;
|
||||
/** @brief Returns all nodes observing landmark @p landmarkId, mapped to the observation link. */
|
||||
std::map<int, Link> getNodesObservingLandmark(int landmarkId, bool lookInDatabase) const;
|
||||
/** @return Signature id labeled @p label, or 0 if not found. */
|
||||
int getSignatureIdByLabel(const std::string & label, bool lookInDatabase = true) const;
|
||||
/**
|
||||
* @brief Assigns or removes a label on @p id.
|
||||
* @param id Signature id; pass 0 to remove an existing label by name.
|
||||
* @param label Label text; empty to remove.
|
||||
* @return True if the label was applied.
|
||||
*/
|
||||
bool labelSignature(int id, const std::string & label);
|
||||
/** @return Map from signature id to non-empty label (including STM+WM+LTM). */
|
||||
const std::map<int, std::string> & getAllLabels() const {return _labels;}
|
||||
/** @return Reverse landmark index: { landmark id (negative), nodes observing it }. */
|
||||
const std::map<int, std::set<int> > & getLandmarksIndex() const {return _landmarksIndex;}
|
||||
/** @return True if every persisted node (in LTM) is currently loaded in WM/STM. */
|
||||
bool allNodesInWM() const {return _allNodesInWM;}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* If you have one dimension unsigned 8 bits raw data, make sure to transpose it
|
||||
* (to have multiple rows instead of multiple columns) in order to be detected as
|
||||
* not compressed.
|
||||
* @brief Attaches user data to signature @p id, compressing it on the fly if needed.
|
||||
*
|
||||
* The format is detected automatically: a single-row @c CV_8UC1 matrix is treated
|
||||
* as already-compressed data and stored as-is; anything else is considered raw and
|
||||
* compressed before being stored.
|
||||
*
|
||||
* @note If you pass one-dimensional unsigned 8-bit raw data, transpose it so it has
|
||||
* multiple rows (not multiple columns), otherwise it will be misdetected as
|
||||
* already compressed.
|
||||
*
|
||||
* @param id Target signature id (must be in WM/STM or LTM).
|
||||
* @param data Raw or pre-compressed user data.
|
||||
* @return True if the data was attached, false if @p id was not found.
|
||||
*/
|
||||
bool setUserData(int id, const cv::Mat & data);
|
||||
int getDatabaseMemoryUsed() const; // in bytes
|
||||
/** @return On-disk database size in bytes. */
|
||||
int getDatabaseMemoryUsed() const;
|
||||
/** @return Schema version of the open database (e.g. "0.20.0"). */
|
||||
std::string getDatabaseVersion() const;
|
||||
/** @return File path of the open database (empty if in-memory). */
|
||||
std::string getDatabaseUrl() const;
|
||||
/** @return Last @ref emptyTrash() flush time in seconds. */
|
||||
double getDbSavingTime() const;
|
||||
/** @return Map id of signature @p id; @p lookInDatabase also queries LTM. */
|
||||
int getMapId(int id, bool lookInDatabase = false) const;
|
||||
/** @return Odometry pose stored with @p signatureId (null if unknown). */
|
||||
Transform getOdomPose(int signatureId, bool lookInDatabase = false) const;
|
||||
/** @return Ground-truth pose stored with @p signatureId (null if unknown). */
|
||||
Transform getGroundTruthPose(int signatureId, bool lookInDatabase = false) const;
|
||||
const std::map<int, Transform> & getGroundTruths() const {return _groundTruths;} // only those in working+STM memory
|
||||
/** @return Ground-truth poses for nodes currently in WM/STM. */
|
||||
const std::map<int, Transform> & getGroundTruths() const {return _groundTruths;}
|
||||
/**
|
||||
* @brief Returns a GPS fix for @p id, falling back to the nearest GPS-tagged neighbor.
|
||||
*
|
||||
* Two cases:
|
||||
* - If @p id has a GPS fix attached, @p gps is set to that fix and @p offsetENU
|
||||
* is left at identity.
|
||||
* - Otherwise, the graph is searched (via @ref getNeighborsId() with depth
|
||||
* @p maxGraphDepth, ignoring loop closures) for the closest neighbor that has a
|
||||
* GPS fix. When one is found, @p gps is set to that neighbor's fix and
|
||||
* @p offsetENU is the rigid transform from that neighbor's pose to @p id,
|
||||
* expressed in ENU coordinates (derived from the neighbor's heading/bearing).
|
||||
* Applying @p offsetENU on top of the GPS-derived pose of the neighbor yields
|
||||
* the ENU pose of @p id.
|
||||
*
|
||||
* If no GPS fix is found on @p id or any reachable neighbor, @p gps is returned
|
||||
* empty (@c gps.stamp()==0) and @p offsetENU is identity.
|
||||
*
|
||||
* @param id Query signature id.
|
||||
* @param gps Output GPS fix (empty if none found).
|
||||
* @param offsetENU Output ENU-frame offset from the GPS-tagged node to @p id
|
||||
* (identity when @p id itself carries the GPS fix or when none is found).
|
||||
* @param lookInDatabase If true, also fetch missing nodes from LTM during the search.
|
||||
* @param maxGraphDepth Maximum graph depth used to look for a GPS-tagged neighbor
|
||||
* when @p id has none (0 = no depth limit, i.e. search the whole reachable graph).
|
||||
*/
|
||||
void getGPS(int id, GPS & gps, Transform & offsetENU, bool lookInDatabase, int maxGraphDepth = 0) const;
|
||||
/**
|
||||
* @brief Reads metadata of @p signatureId (no images/scan/words).
|
||||
*
|
||||
* @param signatureId Node id.
|
||||
* @param odomPose Output odometry pose (null if not set).
|
||||
* @param mapId Output map id.
|
||||
* @param weight Output rehearsal weight.
|
||||
* @param label Output label (empty if none).
|
||||
* @param stamp Output timestamp (seconds, epoch).
|
||||
* @param groundTruth Output ground-truth pose (null if not set).
|
||||
* @param velocity Output 6-vector velocity (empty if not set).
|
||||
* @param gps Output GPS fix (invalid if not set).
|
||||
* @param sensors Output environmental sensor readings.
|
||||
* @param lookInDatabase Also query LTM.
|
||||
* @return True if @p signatureId was found.
|
||||
*/
|
||||
bool getNodeInfo(int signatureId,
|
||||
Transform & odomPose,
|
||||
int & mapId,
|
||||
@@ -199,40 +495,183 @@ public:
|
||||
GPS & gps,
|
||||
EnvSensors & sensors,
|
||||
bool lookInDatabase = false) const;
|
||||
/** @return Compressed image blob for @p signatureId (empty if not stored). */
|
||||
cv::Mat getImageCompressed(int signatureId) const;
|
||||
/**
|
||||
* @brief Loads sensor data of @p locationId from WM or LTM.
|
||||
* @param images Include compressed RGB/depth images.
|
||||
* @param scan Include laser scan blob.
|
||||
* @param userData Include user data blob.
|
||||
* @param occupancyGrid Include occupancy grid cells.
|
||||
*/
|
||||
SensorData getNodeData(int locationId, bool images, bool scan, bool userData, bool occupancyGrid) const;
|
||||
/** @brief Loads the visual words, 3D points and global descriptors stored with @p nodeId. */
|
||||
void getNodeWordsAndGlobalDescriptors(int nodeId,
|
||||
std::multimap<int, int> & words,
|
||||
std::vector<cv::KeyPoint> & wordsKpts,
|
||||
std::vector<cv::Point3f> & words3,
|
||||
cv::Mat & wordsDescriptors,
|
||||
std::vector<GlobalDescriptor> & globalDescriptors) const;
|
||||
/** @brief Loads mono and/or stereo camera calibration stored with @p nodeId. */
|
||||
void getNodeCalibration(int nodeId,
|
||||
std::vector<CameraModel> & models,
|
||||
std::vector<StereoCameraModel> & stereoModels) const;
|
||||
/**
|
||||
* @brief Returns all signature ids in WM, STM and LTM.
|
||||
* @param ignoreChildren If true, nodes not linked to graph anymore are excluded
|
||||
*/
|
||||
std::set<int> getAllSignatureIds(bool ignoreChildren = true) const;
|
||||
/**
|
||||
* @brief Reports whether the in-memory map has been modified since the database was last
|
||||
* loaded or reset. @ref close() uses this flag to decide whether the database
|
||||
* needs to be rewritten.
|
||||
*
|
||||
* The flag is cleared to @c false on construction and by @ref close() / @ref clear(),
|
||||
* and is raised to @c true on any of the following events:
|
||||
*
|
||||
* - **@ref update() in mapping mode** (@ref Parameters::kMemIncrementalMemory() == @c true,
|
||||
* see @ref isIncremental()): every successful call sets the flag, since a new
|
||||
* @ref Signature is added to the graph and the visual word dictionary may grow.
|
||||
* - **@ref update() in localization mode** (@ref isIncremental() == @c false): the flag
|
||||
* is set only when @ref Parameters::kMemLocalizationDataSaved() is enabled
|
||||
* (see @ref isLocalizationDataSaved()), i.e. when the new node must be persisted
|
||||
* back to the database. Pure localization (the default,
|
||||
* @ref Parameters::kMemLocalizationDataSaved() == @c false) leaves the flag at
|
||||
* @c false even after many @ref update() calls, because nothing needs to be saved.
|
||||
* - **@ref reduceNode()**: merging a node into a neighbor mutates the graph and
|
||||
* marks the memory as changed (and also raises the link-changed flag).
|
||||
* - **@ref init() dictionary repair**: when @ref init() rebuilds the visual word
|
||||
* dictionary because words are missing from the database, the flag is forced to
|
||||
* @c true so the regenerated dictionary is saved back on @ref close(), even if no
|
||||
* new data was processed.
|
||||
*
|
||||
* Note that link-only modifications (e.g. @ref addLink(), @ref updateLink(),
|
||||
* @ref removeLink()) update an independent @c _linksChanged flag, not this one.
|
||||
*
|
||||
* @return True if the memory has changed and would need to be persisted.
|
||||
*/
|
||||
bool memoryChanged() const {return _memoryChanged;}
|
||||
/**
|
||||
* @return True if the memory grows on @ref update() (mapping mode), false in localization mode.
|
||||
* @see Parameters::kMemIncrementalMemory()
|
||||
*/
|
||||
bool isIncremental() const {return _incrementalMemory;}
|
||||
/**
|
||||
* @return True in localization mode when database writes are disabled
|
||||
* (i.e. @ref isIncremental() is false and @ref Parameters::kMemLocalizationReadOnly() is enabled).
|
||||
* @see Parameters::kMemIncrementalMemory()
|
||||
* @see Parameters::kMemLocalizationReadOnly()
|
||||
*/
|
||||
bool isReadOnly() const {return !_incrementalMemory && _localizationReadOnly;}
|
||||
/**
|
||||
* @return True if data added during localization is persisted to the database.
|
||||
* @see Parameters::kMemLocalizationDataSaved()
|
||||
*/
|
||||
bool isLocalizationDataSaved() const {return _localizationDataSaved;}
|
||||
/** @return Signature with @p id in WM/STM, or null if not loaded. */
|
||||
const Signature * getSignature(int id) const;
|
||||
/** @return True if @p signatureId is in short-term memory. */
|
||||
bool isInSTM(int signatureId) const {return _stMem.find(signatureId) != _stMem.end();}
|
||||
/** @return True if @p signatureId is in working memory. */
|
||||
bool isInWM(int signatureId) const {return _workingMem.find(signatureId) != _workingMem.end();}
|
||||
/** @return True if @p signatureId is not in STM/WM, so when it is in LTM or non-existing. */
|
||||
bool isInLTM(int signatureId) const {return !this->isInSTM(signatureId) && !this->isInWM(signatureId);}
|
||||
/** @return True if signature ids are auto-generated, false if taken from sensor data id. */
|
||||
bool isIDsGenerated() const {return _generateIds;}
|
||||
/** @return Id of the last accepted global loop-closure node, or 0 if none. */
|
||||
int getLastGlobalLoopClosureId() const {return _lastGlobalLoopClosureId;}
|
||||
/** @return Feature extractor used to compute visual words. */
|
||||
const Feature2D * getFeature2D() const {return _feature2D;}
|
||||
/** @return True if graph reduction is enabled (@ref Parameters::kMemReduceGraph()). */
|
||||
bool isGraphReduced() const {return _reduceGraph;}
|
||||
/**
|
||||
* @return Running per-axis maximum of the diagonal of every neighbor (odometry) link's
|
||||
* information matrix observed so far, as a 6-vector
|
||||
* (x, y, z, roll, pitch, yaw). Empty until at least one 6x6 neighbor link
|
||||
* information matrix has been seen.
|
||||
*
|
||||
* This is a runtime statistic, not a configurable parameter: it is updated on
|
||||
* @ref init() (over all loaded neighbor links) and on every @ref update() that
|
||||
* adds a new neighbor link.
|
||||
*
|
||||
* It is consumed by @ref Rtabmap::getInformation() when
|
||||
* @ref Parameters::kRGBDLoopCovLimited() is enabled, to clip loop-closure
|
||||
* information matrices so a loop never claims higher confidence than odometry
|
||||
* itself ever provided.
|
||||
*
|
||||
* @see Parameters::kRGBDLoopCovLimited()
|
||||
*/
|
||||
const std::vector<double> & getOdomMaxInf() const {return _odomMaxInf;}
|
||||
/**
|
||||
* @return True if the odometry pose orientation is used (instead of the IMU
|
||||
* orientation) as the source of each new node's gravity link.
|
||||
*
|
||||
* When enabled, every new node gets a self-loop @ref Link::kGravity holding the
|
||||
* rotation of the odometry pose passed to @ref update(). This assumes odometry is
|
||||
* already gravity-aligned (e.g. a VIO front-end). When disabled, the gravity link
|
||||
* is built from the IMU orientation in @ref SensorData::imu() if available.
|
||||
*
|
||||
* Gravity links are consumed by graph optimization only when
|
||||
* @ref Parameters::kOptimizerGravitySigma() is non-zero.
|
||||
*
|
||||
* @see Parameters::kMemUseOdomGravity()
|
||||
* @see Parameters::kOptimizerGravitySigma()
|
||||
*/
|
||||
bool isOdomGravityUsed() const {return _useOdometryGravity;}
|
||||
|
||||
/** @brief Writes a human-readable dump of WM/STM, links and weights to @p fileNameTree. */
|
||||
void dumpMemoryTree(const char * fileNameTree) const;
|
||||
/** @brief Dumps every internal map (signatures, words, dictionary) to text files in @p directory. */
|
||||
virtual void dumpMemory(std::string directory) const;
|
||||
/** @brief Dumps signatures' word ids (and 3D positions if @p words3D) to @p fileNameSign. */
|
||||
virtual void dumpSignatures(const char * fileNameSign, bool words3D) const;
|
||||
/** @brief Dumps the visual word dictionary: references to @p fileNameRef, descriptors to @p fileNameDesc. */
|
||||
void dumpDictionary(const char * fileNameRef, const char * fileNameDesc) const;
|
||||
/** @return Approximate RAM usage of the in-memory state, in bytes. */
|
||||
unsigned long getMemoryUsed() const; //Bytes
|
||||
|
||||
/**
|
||||
* @brief Writes a Graphviz DOT file of the pose graph.
|
||||
* @param fileName Output path.
|
||||
* @param ids If non-empty, restrict the graph to these node ids.
|
||||
*/
|
||||
void generateGraph(const std::string & fileName, const std::set<int> & ids = std::set<int>());
|
||||
/**
|
||||
* @brief Removes spurious obstacle points from each node's local grid using a reference 2D map.
|
||||
*
|
||||
* For every node in @p poses, the node's local **obstacle** grid is loaded, each
|
||||
* obstacle point is projected with @p poses into the reference @p map, and the
|
||||
* point is kept only if either:
|
||||
* - the reference @p map cell at its projection is not free space
|
||||
* (i.e. the cell is an obstacle or unknown, value != 0), or
|
||||
* - the reference @p map contains an obstacle cell (value == 100) within
|
||||
* @p cropRadius cells of the projection.
|
||||
*
|
||||
* Points that fall on a free cell and have no obstacle neighbor within
|
||||
* @p cropRadius are dropped. The filtered obstacle grid replaces the node's grid
|
||||
* in WM/STM and (if the node is already persisted) in the database via
|
||||
* @ref DBDriver::updateOccupancyGrid().
|
||||
*
|
||||
* **Ground and empty cells are not touched**: they are read and written back as-is.
|
||||
*
|
||||
* When @p filterScans is true, the same projection/filtering rule is also applied
|
||||
* to each node's raw laser scan, and the rewritten scan is saved back to the
|
||||
* database. This is useful to remove dynamic objects from the stored scans before
|
||||
* re-meshing or re-exporting.
|
||||
*
|
||||
* @param poses Optimized poses used to project the local grids/scans into @p map.
|
||||
* @param map Reference 2D occupancy grid (cell values: 0 free, 100 occupied,
|
||||
* anything else unknown).
|
||||
* @param xMin Reference map origin x in world coordinates (meters).
|
||||
* @param yMin Reference map origin y in world coordinates (meters).
|
||||
* @param cellSize Reference map resolution (meters/cell); must match the nodes' grid cell size.
|
||||
* @param cropRadius Search radius (in cells) around each projected point used to
|
||||
* accept points near an obstacle in @p map.
|
||||
* @param filterScans If true, also filter and rewrite the raw laser scan attached
|
||||
* to each node, using the same rule as for obstacle cells.
|
||||
* @return Number of (node, grid or scan) modifications performed, or -1 on error
|
||||
* (no database loaded, empty @p poses or empty @p map).
|
||||
*/
|
||||
int cleanupLocalGrids(
|
||||
const std::map<int, Transform> & poses,
|
||||
const cv::Mat & map,
|
||||
@@ -242,10 +681,20 @@ public:
|
||||
int cropRadius = 1,
|
||||
bool filterScans = false);
|
||||
|
||||
//keypoint stuff
|
||||
/** @return Visual word dictionary used for tf-idf likelihood and feature matching. */
|
||||
const VWDictionary * getVWDictionary() const;
|
||||
|
||||
// RGB-D stuff
|
||||
/**
|
||||
* @brief Extracts a sub-graph (poses + links) for a set of node ids.
|
||||
*
|
||||
* Used by graph optimization callers to retrieve constraints for a region of interest.
|
||||
*
|
||||
* @param ids Ids to include.
|
||||
* @param poses Output: odometry poses for @p ids.
|
||||
* @param links Output: links between the nodes (and to landmarks if @p landmarksAdded).
|
||||
* @param lookInDatabase If true, fetch missing data from LTM.
|
||||
* @param landmarksAdded If true, also include landmark constraints.
|
||||
*/
|
||||
void getMetricConstraints(
|
||||
const std::set<int> & ids,
|
||||
std::map<int, Transform> & poses,
|
||||
@@ -253,9 +702,31 @@ public:
|
||||
bool lookInDatabase = false,
|
||||
bool landmarksAdded = false);
|
||||
|
||||
/**
|
||||
* @brief Computes the relative transform from @p fromS to @p toS using the registration pipeline.
|
||||
* @param fromS Source signature (will be modified to cache extracted data).
|
||||
* @param toS Target signature.
|
||||
* @param guess Initial transform estimate (null if unknown).
|
||||
* @param info Optional output with inlier counts, variance and diagnostics.
|
||||
* @param useKnownCorrespondencesIfPossible If true, reuses existing word-id correspondences.
|
||||
* @return The estimated transform, or a null @ref Transform on failure.
|
||||
*/
|
||||
Transform computeTransform(Signature & fromS, Signature & toS, Transform guess, RegistrationInfo * info = 0, bool useKnownCorrespondencesIfPossible = false) const;
|
||||
/** @brief Convenience overload: loads signatures by id and forwards to the @ref Signature variant. */
|
||||
Transform computeTransform(int fromId, int toId, Transform guess, RegistrationInfo * info = 0, bool useKnownCorrespondencesIfPossible = false);
|
||||
/**
|
||||
* @brief Refines a transform using ICP alignment of laser scans only.
|
||||
* @return The refined transform, or a null @ref Transform on failure.
|
||||
*/
|
||||
Transform computeIcpTransform(const Signature & fromS, const Signature & toS, Transform guess, RegistrationInfo * info = 0) const;
|
||||
/**
|
||||
* @brief ICP registration of one node against an assembled cloud from multiple neighbors.
|
||||
* @param newId New (query) node id.
|
||||
* @param oldId Reference node id.
|
||||
* @param poses Neighbor poses used to assemble the reference cloud.
|
||||
* @param info Optional output with inlier counts and diagnostics.
|
||||
* @return The estimated transform, or a null @ref Transform on failure.
|
||||
*/
|
||||
Transform computeIcpTransformMulti(
|
||||
int newId,
|
||||
int oldId,
|
||||
@@ -296,6 +767,7 @@ private:
|
||||
int getNi(int signatureId) const;
|
||||
|
||||
protected:
|
||||
/** @brief Database driver owning the persistent storage (created by @ref init()). */
|
||||
DBDriver * _dbDriver;
|
||||
|
||||
private:
|
||||
|
||||
@@ -52,22 +52,174 @@ class Signature;
|
||||
class Optimizer;
|
||||
class PythonInterface;
|
||||
|
||||
/**
|
||||
* @class Rtabmap
|
||||
* @brief Top-level RTAB-Map SLAM pipeline (mapping, localization and loop closure).
|
||||
*
|
||||
* Rtabmap orchestrates the full SLAM iteration. Each new sensor observation passed to
|
||||
* @ref process() goes through the steps described below.
|
||||
*
|
||||
*
|
||||
* @par 1. Memory update
|
||||
*
|
||||
* Done via @ref Memory::update(): a new @ref Signature is added to STM, the oldest
|
||||
* STM entry is promoted to WM if STM is full, and rehearsal compares the new
|
||||
* signature to the previous STM signature.
|
||||
*
|
||||
* When the robot barely moved since the previous frame (odometry displacement below
|
||||
* @ref Parameters::kRGBDLinearUpdate() and @ref Parameters::kRGBDAngularUpdate()), the
|
||||
* iteration is flagged as a "small displacement":
|
||||
* - If a loop closure or localization was already accepted on a recent iteration,
|
||||
* appearance-based global loop-closure detection and proximity detection by space
|
||||
* are both skipped to avoid wasting work while the robot is stationary at an
|
||||
* already-known location (only retrieval runs).
|
||||
* - Otherwise (no recent loop closure / localization), both still run normally so
|
||||
* a first-time loop closure can still be detected from a standstill.
|
||||
*
|
||||
* In either case, at the end of the iteration, if no loop closure, proximity
|
||||
* detection or landmark observation latched onto the new node, it is deleted from
|
||||
* @ref Memory so the map does not grow while the robot is idle.
|
||||
*
|
||||
* Rehearsal still runs first, so visually similar consecutive idle frames may also be
|
||||
* merged into the previous STM signature (its weight is incremented and the new
|
||||
* signature is discarded) when the similarity exceeds
|
||||
* @ref Parameters::kMemRehearsalSimilarity().
|
||||
*
|
||||
*
|
||||
* @par 2. Loop-closure hypothesis
|
||||
*
|
||||
* Scored via @ref Memory::computeLikelihood() and the recursive @ref BayesFilter
|
||||
* (prior + observation update).
|
||||
*
|
||||
*
|
||||
* @par 3. Hypothesis selection
|
||||
*
|
||||
* The highest posterior is compared against the loop-closure threshold
|
||||
* (@ref Parameters::kRtabmapLoopThr()); if accepted, the loop-closure link is added
|
||||
* and the pose graph is re-optimized by @ref Optimizer.
|
||||
*
|
||||
* In **RGB-D mode**, two extra checks must pass before the link is committed:
|
||||
* - a valid geometric transform must be computed between the two candidate nodes by
|
||||
* the registration pipeline (visual + optional ICP, see
|
||||
* @ref Memory::computeTransform());
|
||||
* - the resulting transform must not be rejected by the graph-optimization
|
||||
* consistency check (see @ref Parameters::kRGBDOptimizeMaxError()).
|
||||
*
|
||||
* The optimization used by the consistency check depends on the operating mode:
|
||||
* - In **mapping mode**, @ref optimizeCurrentMap() re-optimizes the local map
|
||||
* around the current signature including the new link, then
|
||||
* @ref graph::computeMaxGraphErrors() measures the worst per-link residual / its
|
||||
* standard deviation. If the ratio exceeds @ref Parameters::kRGBDOptimizeMaxError(),
|
||||
* the loop closure(s) added this iteration are removed from @ref Memory.
|
||||
* - In **localization mode**, optimization is run on a sub-graph composed of the
|
||||
* odometry cache (@ref Parameters::kRGBDMaxOdomCacheSize()), the newly added
|
||||
* localization link and pose priors fixing the map nodes (weighted by
|
||||
* @ref Parameters::kRGBDLocalizationPriorInf()). The same error-ratio check is
|
||||
* applied; on failure the localization is rejected for this iteration but the
|
||||
* persisted map and its links are left untouched.
|
||||
*
|
||||
* In both modes, if the same link is rejected twice in a row, @ref repairGraph() may
|
||||
* also be attempted (within @ref Parameters::kRGBDOptimizeMaxErrorRepairRadius()) to
|
||||
* drop the offending link instead of the new candidate.
|
||||
*
|
||||
* If either RGB-D check fails, the candidate is discarded and no link is added.
|
||||
*
|
||||
*
|
||||
* @par 4. Retrieval
|
||||
*
|
||||
* Once a loop-closure hypothesis is selected, neighbors of the matched node are
|
||||
* brought back from LTM into WM via @ref Memory::reactivateSignatures(), so the next
|
||||
* iteration can compare against them too. Up to @ref Parameters::kRtabmapMaxRetrieved()
|
||||
* nodes are pulled per iteration; nodes around the current path or local pose may
|
||||
* also be retrieved (capped by @ref Parameters::kRtabmapMaxLocalRetrieved()).
|
||||
*
|
||||
* Retrieval (and the related node immunization) is only active when memory management
|
||||
* is enabled, i.e. when @ref Parameters::kRtabmapTimeThr() or
|
||||
* @ref Parameters::kRtabmapMemoryThr() is non-zero.
|
||||
*
|
||||
*
|
||||
* @par 5. Proximity detection (RGB-D mode)
|
||||
*
|
||||
* Visual and scan-based local matches to nearby nodes, used in addition to the
|
||||
* appearance-based loop closure.
|
||||
*
|
||||
* Candidate proximity links go through the same two RGB-D gates as loop closures
|
||||
* above: a valid geometric transform must be computed by the registration pipeline,
|
||||
* and the transform must not be rejected by the graph-optimization consistency check.
|
||||
*
|
||||
*
|
||||
* @par 6. Transfer (WM to LTM)
|
||||
*
|
||||
* At the end of the iteration, if the iteration exceeded the configured time budget
|
||||
* (@ref Parameters::kRtabmapTimeThr()) or WM exceeded its size budget
|
||||
* (@ref Parameters::kRtabmapMemoryThr()), @ref Memory::forget() moves the oldest
|
||||
* low-frequency signatures from WM to LTM (immunized nodes -- retrieved neighbors,
|
||||
* the last localization node, etc. -- are kept in WM).
|
||||
*
|
||||
* Transfer is skipped when both thresholds are 0 (memory management disabled).
|
||||
*
|
||||
*
|
||||
* @par 7. Map / localization output
|
||||
*
|
||||
* Optimized poses, current map correction and statistics are made available to
|
||||
* callers via the getters below.
|
||||
*
|
||||
*
|
||||
* @par Operating modes
|
||||
*
|
||||
* Selected by @ref Parameters::kMemIncrementalMemory() (see @ref Memory::isIncremental()):
|
||||
* - **Mapping**: STM and WM grow; loop closures update the optimized graph.
|
||||
* - **Localization**: STM/WM are frozen; the current node is matched against the
|
||||
* persisted map and only @ref getLastLocalizationPose() is updated.
|
||||
*
|
||||
*
|
||||
* @par Path planning
|
||||
*
|
||||
* Rtabmap also exposes basic graph-based path planning in RGB-D mode
|
||||
* (@ref computePath(), @ref getPath(), @ref getPathStatus()), used by the GUI to
|
||||
* navigate between mapped locations.
|
||||
*
|
||||
* When memory management is enabled (see step 4 Retrieval and step 6 Transfer), the
|
||||
* retrieval step also pulls nodes along the currently planned path back from LTM into
|
||||
* WM (capped by @ref Parameters::kRtabmapMaxLocalRetrieved()) so the robot is able to
|
||||
* re-localize against upcoming waypoints as it follows the path, even when those
|
||||
* nodes had been transferred out of WM earlier.
|
||||
*
|
||||
*
|
||||
* @see Memory
|
||||
* @see BayesFilter
|
||||
* @see Optimizer
|
||||
* @see Parameters
|
||||
*/
|
||||
class RTABMAP_CORE_EXPORT Rtabmap
|
||||
{
|
||||
public:
|
||||
enum VhStrategy {kVhNone, kVhEpipolar, kVhUndef};
|
||||
/** @brief Loop-closure verification strategy. */
|
||||
enum VhStrategy {
|
||||
kVhNone, ///< No verification: the highest hypothesis above threshold is accepted.
|
||||
kVhEpipolar, ///< Epipolar geometry verification (mostly historical, RGB-only mode).
|
||||
kVhUndef ///< Sentinel -- undefined.
|
||||
};
|
||||
|
||||
public:
|
||||
Rtabmap();
|
||||
virtual ~Rtabmap();
|
||||
|
||||
/**
|
||||
* @brief Main loop of rtabmap.
|
||||
* @param data Sensor data to process.
|
||||
* @param odomPose Odometry pose, should be non-null for RGB-D SLAM mode.
|
||||
* @param covariance Odometry covariance.
|
||||
* @param externalStats External statistics to be saved in the database for convenience
|
||||
* @return true if data has been added to map.
|
||||
* @brief Main RTAB-Map iteration: ingests one sensor frame and updates the map.
|
||||
*
|
||||
* Adds @p data to @ref Memory, runs the Bayes filter on the current likelihood,
|
||||
* selects a loop-closure hypothesis if any, performs proximity detection,
|
||||
* re-optimizes the graph as needed, and refreshes @ref getStatistics() and
|
||||
* @ref getLastLocalizationPose().
|
||||
*
|
||||
* @param data Sensor data for this frame (images, scan, user data, ...).
|
||||
* @param odomPose Odometry pose; must be non-null in RGB-D SLAM mode.
|
||||
* Pass a null @ref Transform to fall back to appearance-only mode.
|
||||
* @param odomCovariance 6x6 odometry covariance (default: identity).
|
||||
* @param odomVelocity Optional 6-vector (vx, vy, vz, vroll, vpitch, vyaw).
|
||||
* @param externalStats Extra named statistics to record in the database for this iteration.
|
||||
* @return True if @p data was added to the map (i.e. an @ref update() succeeded).
|
||||
*/
|
||||
bool process(
|
||||
const SensorData & data,
|
||||
@@ -75,7 +227,13 @@ public:
|
||||
const cv::Mat & odomCovariance = cv::Mat::eye(6,6,CV_64FC1),
|
||||
const std::vector<float> & odomVelocity = std::vector<float>(),
|
||||
const std::map<std::string, float> & externalStats = std::map<std::string, float>());
|
||||
// for convenience
|
||||
/**
|
||||
* @brief Convenience overload: builds a diagonal covariance from scalar variances.
|
||||
*
|
||||
* The 6x6 odometry covariance is constructed as
|
||||
* @c diag(odomLinearVariance, odomLinearVariance, odomLinearVariance,
|
||||
* odomAngularVariance, odomAngularVariance, odomAngularVariance).
|
||||
*/
|
||||
bool process(
|
||||
const SensorData & data,
|
||||
Transform odomPose,
|
||||
@@ -83,113 +241,366 @@ public:
|
||||
float odomAngularVariance,
|
||||
const std::vector<float> & odomVelocity = std::vector<float>(),
|
||||
const std::map<std::string, float> & externalStats = std::map<std::string, float>());
|
||||
// for convenience, loop closure detection only
|
||||
/**
|
||||
* @brief Appearance-only convenience overload (loop-closure detection without odometry).
|
||||
*
|
||||
* Equivalent to processing @p image alone, with no odometry pose. Useful for offline
|
||||
* loop-closure benchmarking on image sequences.
|
||||
*
|
||||
* @param image RGB or grayscale frame.
|
||||
* @param id Optional frame id (0 = auto-generated).
|
||||
* @param externalStats Extra named statistics to record in the database for this iteration.
|
||||
*/
|
||||
bool process(
|
||||
const cv::Mat & image,
|
||||
int id=0, const std::map<std::string, float> & externalStats = std::map<std::string, float>());
|
||||
|
||||
/**
|
||||
* Initialize Rtabmap with parameters and a database
|
||||
* @brief Initializes Rtabmap with parameters and a database.
|
||||
*
|
||||
* @param parameters Parameters overriding default parameters and database parameters
|
||||
* (@see loadDatabaseParameters)
|
||||
* @param databasePath The database input/output path. If not set, an
|
||||
* empty database is used in RAM. If set and the file doesn't exist,
|
||||
* it will be created empty. If the database exists, nodes and
|
||||
* vocabulary will be loaded in working memory.
|
||||
* @param loadDatabaseParameters If an existing database is used (@see databasePath),
|
||||
* the parameters inside are loaded and set to current
|
||||
* Rtabmap instance.
|
||||
* (see @p loadDatabaseParameters).
|
||||
* @param databasePath Database input/output path. If empty, an in-memory database is
|
||||
* used. If set and the file does not exist, it is created empty;
|
||||
* if it exists, nodes and the visual word vocabulary are loaded
|
||||
* into working memory.
|
||||
* @param loadDatabaseParameters If true and an existing database is opened, the
|
||||
* parameters stored inside the database are loaded and
|
||||
* applied to this Rtabmap instance (then overridden by
|
||||
* @p parameters).
|
||||
*/
|
||||
void init(const ParametersMap & parameters, const std::string & databasePath = "", bool loadDatabaseParameters = false);
|
||||
/**
|
||||
* Initialize Rtabmap with parameters from a configuration file and a database
|
||||
* @param configFile Configuration file (*.ini) overriding default parameters and database parameters
|
||||
* (@see loadDatabaseParameters)
|
||||
* @param databasePath The database input/output path. If not set, an
|
||||
* empty database is used in RAM. If set and the file doesn't exist,
|
||||
* it will be created empty. If the database exists, nodes and
|
||||
* vocabulary will be loaded in working memory.
|
||||
* @param loadDatabaseParameters If an existing database is used (@see databasePath),
|
||||
* the parameters inside are loaded and set to current
|
||||
* Rtabmap instance.
|
||||
* @brief Initializes Rtabmap from a configuration file and a database.
|
||||
*
|
||||
* @param configFile Configuration file (*.ini) overriding default parameters and
|
||||
* database parameters (see @p loadDatabaseParameters).
|
||||
* @param databasePath Database input/output path; same semantics as the other @ref init().
|
||||
* @param loadDatabaseParameters If true and an existing database is opened, the
|
||||
* parameters stored inside the database are loaded and
|
||||
* applied first, then overridden by values from @p configFile.
|
||||
*/
|
||||
void init(const std::string & configFile = "", const std::string & databasePath = "", bool loadDatabaseParameters = false);
|
||||
|
||||
/**
|
||||
* Close rtabmap. This will delete rtabmap object if set.
|
||||
* @param databaseSaved true=database saved, false=database discarded.
|
||||
* @param databasePath output database file name, ignored if
|
||||
* Db/Sqlite3InMemory=false (opened database is
|
||||
* then overwritten).
|
||||
* @brief Closes Rtabmap and releases the underlying @ref Memory.
|
||||
*
|
||||
* @param databaseSaved If true, the in-memory state is flushed to the database;
|
||||
* if false, in-memory changes are discarded.
|
||||
* @param ouputDatabasePath If non-empty, the database is copied to this path on
|
||||
* close. If a database on disk was initially created/loaded on
|
||||
* a different path, it will be updated with the latest changes
|
||||
* and renamed to the output path.
|
||||
*/
|
||||
void close(bool databaseSaved = true, const std::string & ouputDatabasePath = "");
|
||||
|
||||
/** @return Working directory used for dumps, log files and temporary outputs. */
|
||||
const std::string & getWorkingDir() const {return _wDir;}
|
||||
/** @return True if RGB-D SLAM mode is enabled (@ref Parameters::kRGBDEnabled()). */
|
||||
bool isRGBDMode() const { return _rgbdSlamMode; }
|
||||
/** @return Id of the loop-closure hypothesis accepted at the last @ref process() iteration, or 0 if none. */
|
||||
int getLoopClosureId() const {return _loopClosureHypothesis.first;}
|
||||
/** @return Posterior probability of the accepted loop-closure hypothesis, or 0 if none. */
|
||||
float getLoopClosureValue() const {return _loopClosureHypothesis.second;}
|
||||
/** @return Id of the highest-posterior hypothesis at the last iteration (whether or not it was accepted). */
|
||||
int getHighestHypothesisId() const {return _highestHypothesis.first;}
|
||||
/** @return Posterior of the highest-posterior hypothesis at the last iteration. */
|
||||
float getHighestHypothesisValue() const {return _highestHypothesis.second;}
|
||||
/** @return Id of the last non-intermediate signature added to the map (0 if none). */
|
||||
int getLastLocationId() const;
|
||||
std::list<int> getWM() const; // working memory
|
||||
std::set<int> getSTM() const; // short-term memory
|
||||
int getWMSize() const; // working memory size
|
||||
int getSTMSize() const; // short-term memory size
|
||||
/** @return Working memory ids ordered as in @ref Memory::getWorkingMem(). */
|
||||
std::list<int> getWM() const;
|
||||
/** @return Short-term memory ids. */
|
||||
std::set<int> getSTM() const;
|
||||
/** @return Working memory size (number of WM signatures). */
|
||||
int getWMSize() const;
|
||||
/** @return Short-term memory size (number of STM signatures). */
|
||||
int getSTMSize() const;
|
||||
/** @return Per-signature weights (rehearsal counts) for WM and STM. */
|
||||
std::map<int, int> getWeights() const;
|
||||
/** @return Total number of signatures across WM, STM and LTM. */
|
||||
int getTotalMemSize() const;
|
||||
/** @return Wall-clock duration of the last @ref process() call, in seconds. */
|
||||
double getLastProcessTime() const {return _lastProcessTime;};
|
||||
/** @return True if @p locationId is currently in short-term memory. */
|
||||
bool isInSTM(int locationId) const;
|
||||
/** @return True if signature ids are auto-generated (vs. taken from @ref SensorData::id()). */
|
||||
bool isIDsGenerated() const;
|
||||
/** @return Statistics produced by the last @ref process() iteration. */
|
||||
const Statistics & getStatistics() const;
|
||||
/** @return Optimized poses of the current local map (last graph optimization result). */
|
||||
const std::map<int, Transform> & getLocalOptimizedPoses() const {return _optimizedPoses;}
|
||||
/** @return Constraints (links) of the current local map. */
|
||||
const std::multimap<int, Link> & getLocalConstraints() const {return _constraints;}
|
||||
/**
|
||||
* @return Optimized pose of @p locationId in the current local map (identity if not present).
|
||||
*/
|
||||
Transform getPose(int locationId) const;
|
||||
/**
|
||||
* @return Transform mapping odometry frame to the optimized map frame.
|
||||
*
|
||||
* This is the correction applied to incoming odometry poses so they align with the
|
||||
* latest graph optimization output. Updated whenever a loop closure or proximity
|
||||
* detection re-optimizes the graph.
|
||||
*
|
||||
* In ROS terms, this corresponds to the standard @c /map -> @c /odom TF transform
|
||||
* published by SLAM systems: composing it with the live odometry pose
|
||||
* (@c /odom -> @c /base_link) yields the robot pose in the map frame.
|
||||
*/
|
||||
Transform getMapCorrection() const {return _mapCorrection;}
|
||||
/** @return Owned @ref Memory (may be null before @ref init()). */
|
||||
const Memory * getMemory() const {return _memory;}
|
||||
/** @return Radius (meters) under which the current path goal is considered reached. */
|
||||
float getGoalReachedRadius() const {return _goalReachedRadius;}
|
||||
/** @return Local radius (meters) used by proximity detection and path planning queries. */
|
||||
float getLocalRadius() const {return _localRadius;}
|
||||
/**
|
||||
* @return Last localized pose in the map frame.
|
||||
*
|
||||
* In **localization mode**, this is the corrected odometry pose of the last
|
||||
* processed frame. In **mapping mode**, this is the last pose returned by
|
||||
* @ref getLocalOptimizedPoses().
|
||||
*/
|
||||
const Transform & getLastLocalizationPose() const {return _lastLocalizationPose;}
|
||||
|
||||
float getTimeThreshold() const {return _maxTimeAllowed;} // in ms
|
||||
void setTimeThreshold(float maxTimeAllowed); // in ms
|
||||
int getMemoryThreshold() const {return _maxMemoryAllowed;} // in nodes
|
||||
void setMemoryThreshold(int maxMemoryAllowed); // in nodes
|
||||
/**
|
||||
* @return Maximum allowed processing time per @ref process() call, in milliseconds.
|
||||
* @see Parameters::kRtabmapTimeThr()
|
||||
*/
|
||||
float getTimeThreshold() const {return _maxTimeAllowed;}
|
||||
/**
|
||||
* @brief Sets the per-iteration time budget (ms).
|
||||
*
|
||||
* Drives how aggressively WM is transferred to LTM to keep iterations under the
|
||||
* threshold. 0 disables the time bound.
|
||||
*
|
||||
* @note This setting and @ref setMemoryThreshold() are the only two switches that
|
||||
* enable RTAB-Map's memory management (WM-to-LTM transfer, retrieval and node
|
||||
* immunization). When both are 0, memory management is disabled and all
|
||||
* signatures stay in working memory.
|
||||
*
|
||||
* @see Parameters::kRtabmapTimeThr()
|
||||
*/
|
||||
void setTimeThreshold(float maxTimeAllowed);
|
||||
/**
|
||||
* @return Maximum allowed WM size (number of signatures).
|
||||
* @see Parameters::kRtabmapMemoryThr()
|
||||
*/
|
||||
int getMemoryThreshold() const {return _maxMemoryAllowed;}
|
||||
/**
|
||||
* @brief Sets the maximum number of signatures kept in WM (0 = unbounded).
|
||||
*
|
||||
* @note This setting and @ref setTimeThreshold() are the only two switches that
|
||||
* enable RTAB-Map's memory management (WM-to-LTM transfer, retrieval and node
|
||||
* immunization). When both are 0, memory management is disabled and all
|
||||
* signatures stay in working memory.
|
||||
*
|
||||
* @see Parameters::kRtabmapMemoryThr()
|
||||
*/
|
||||
void setMemoryThreshold(int maxMemoryAllowed);
|
||||
|
||||
/**
|
||||
* @brief Sets the localization prior pose used to seed the next @ref process() call
|
||||
* (localization mode only).
|
||||
*
|
||||
* Tells RTAB-Map where the robot is currently located in the map frame, so that the
|
||||
* very next call to @ref process() can align incoming odometry with the persisted
|
||||
* map without waiting for a loop closure. Typical use cases: restoring localization
|
||||
* after a session restart, applying an external pose estimate (e.g. from a GPS or
|
||||
* a known starting point), or recovering from "kidnapped robot" situations.
|
||||
*
|
||||
* This call only stages state; it does **not** itself produce a non-identity
|
||||
* @ref getMapCorrection(). The alignment between the odometry frame and the map
|
||||
* frame is performed on the next @ref process() call, which consumes
|
||||
* @p initialPose together with the incoming odometry pose. Two branches are taken
|
||||
* depending on @ref Parameters::kRGBDOptimizeFromGraphEnd():
|
||||
* - **false (default)**: @ref getMapCorrection() is set so that the live odometry
|
||||
* pose is shifted to land on @p initialPose in the map frame (the optimized map
|
||||
* is left untouched).
|
||||
* - **true**: every optimized node pose is rigidly transformed so that the map
|
||||
* itself moves to align with @p initialPose (the map correction stays close to
|
||||
* identity).
|
||||
*
|
||||
* The transform applied is restricted by SLAM dimensionality: 3-DoF (x, y, yaw)
|
||||
* for 2D SLAM, 4-DoF (x, y, z, yaw) when gravity is available
|
||||
* (IMU orientation or @ref Memory::isOdomGravityUsed()) and
|
||||
* @ref Parameters::kOptimizerGravitySigma() is non-zero, full 6-DoF otherwise.
|
||||
*
|
||||
* Side effects on the staged state:
|
||||
* - @ref getLastLocalizationPose() is replaced by @p initialPose; the localization
|
||||
* covariance, the last localization node id and the odometry cache used for
|
||||
* loop-closure rejection are all cleared.
|
||||
* - @ref getMapCorrection() is reset to identity and any backup is cleared.
|
||||
* - If the current map has not been optimized yet (no entries in
|
||||
* @ref getLocalOptimizedPoses()) and a last working signature exists, the map
|
||||
* is optimized around that signature so the next @ref process() has something
|
||||
* to localize against.
|
||||
*
|
||||
* After the next @ref process() consumes the prior, the nearest optimized node to
|
||||
* @p initialPose is recorded as the last localization node.
|
||||
*
|
||||
* @param initialPose Robot pose in the map frame.
|
||||
*
|
||||
* @note No-op (with warning) in mapping mode.
|
||||
*
|
||||
* @see Parameters::kMemIncrementalMemory()
|
||||
* @see Parameters::kRGBDOptimizeFromGraphEnd()
|
||||
*/
|
||||
void setInitialPose(const Transform & initialPose);
|
||||
/**
|
||||
* @brief Starts a new map session (next @ref process() will create a fresh map id).
|
||||
*
|
||||
* In **mapping mode**, this increments the map id, clears the local optimized graph
|
||||
* and resets the Bayes filter.
|
||||
* In **localization mode**, it resets the map correction, the localization node and
|
||||
* the odometry cache; if @ref Parameters::kRtabmapRestartAtOrigin() is enabled, the
|
||||
* last localization pose is reset to identity.
|
||||
*
|
||||
* @return The new map id (mapping mode), or -1 (localization mode).
|
||||
*/
|
||||
int triggerNewMap();
|
||||
/**
|
||||
* @brief Assigns or clears a label on signature @p id.
|
||||
* @return True if the label was applied.
|
||||
*/
|
||||
bool labelLocation(int id, const std::string & label);
|
||||
/**
|
||||
* 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.
|
||||
* If you have one dimension unsigned 8 bits raw data, make sure to transpose it
|
||||
* (to have multiple rows instead of multiple columns) in order to be detected as
|
||||
* not compressed.
|
||||
* @brief Attaches user data to signature @p id, compressing it on the fly if needed.
|
||||
*
|
||||
* The format is detected automatically: a single-row @c CV_8UC1 matrix is treated
|
||||
* as already-compressed data and stored as-is; anything else is considered raw and
|
||||
* compressed before being stored.
|
||||
*
|
||||
* @note If you pass one-dimensional unsigned 8-bit raw data, transpose it so it has
|
||||
* multiple rows (not multiple columns), otherwise it will be misdetected as
|
||||
* already compressed.
|
||||
*
|
||||
* @param id Target signature id (must be in WM/STM or LTM).
|
||||
* @param data Raw or pre-compressed user data.
|
||||
* @return True if the data was attached.
|
||||
*/
|
||||
bool setUserData(int id, const cv::Mat & data);
|
||||
/**
|
||||
* @brief Writes a Graphviz DOT file of the pose graph.
|
||||
* @param path Output file path.
|
||||
* @param id If non-zero, root the graph at @p id; otherwise use the last signature.
|
||||
* @param margin Maximum graph depth around @p id to include.
|
||||
*/
|
||||
void generateDOTGraph(const std::string & path, int id=0, int margin=5);
|
||||
/**
|
||||
* @brief Exports the current pose graph to a text file.
|
||||
*
|
||||
* Forwards to @ref graph::exportPoses() after collecting either the optimized or
|
||||
* the raw odometry poses (and the matching constraints when needed).
|
||||
*
|
||||
* @param path Output file path.
|
||||
* @param optimized If true, export optimized poses; otherwise raw odometry poses.
|
||||
* @param global If true, include nodes from LTM as well; otherwise only WM/STM.
|
||||
* @param format Output format code; see @ref graph::exportPoses() for the full
|
||||
* list of supported values (raw, RGBD-SLAM/TUM, KITTI, TORO, g2o, ...).
|
||||
*
|
||||
* @see graph::exportPoses()
|
||||
*/
|
||||
void exportPoses(
|
||||
const std::string & path,
|
||||
bool optimized,
|
||||
bool global,
|
||||
int format // 0=raw, 1=rgbd-slam format, 2=KITTI format, 3=TORO, 4=g2o
|
||||
int format
|
||||
);
|
||||
/**
|
||||
* @brief Clears all in-memory state and resets the database.
|
||||
*
|
||||
* In incremental mode, also clears the persisted map. In read-only memory mode,
|
||||
* resets the in-memory state but leaves the database untouched.
|
||||
*/
|
||||
void resetMemory();
|
||||
/** @brief Dumps the Bayes-filter prediction matrix to a file in the working directory. */
|
||||
void dumpPrediction() const;
|
||||
/** @brief Dumps the @ref Memory state (signatures, words, dictionary) to the working directory. */
|
||||
void dumpData() const;
|
||||
/**
|
||||
* @brief Re-parses parameters and propagates them to owned sub-objects
|
||||
* (@ref Memory, @ref BayesFilter, @ref Optimizer, ...).
|
||||
*/
|
||||
void parseParameters(const ParametersMap & parameters);
|
||||
/** @return Current effective parameter map. */
|
||||
const ParametersMap & getParameters() const {return _parameters;}
|
||||
/**
|
||||
* @brief Sets the working directory used for dumps, logs and temporary files.
|
||||
*
|
||||
* Can also be configured through @ref Parameters::kRtabmapWorkingDirectory() in the
|
||||
* parameter map passed to @ref init() or @ref parseParameters().
|
||||
*
|
||||
* @see Parameters::kRtabmapWorkingDirectory()
|
||||
*/
|
||||
void setWorkingDirectory(std::string path);
|
||||
/**
|
||||
* @brief Removes the loop-closure link added at the last @ref process() iteration.
|
||||
*
|
||||
* Looks at the last non-intermediate signature in STM and erases any
|
||||
* @ref Link::kGlobalClosure, @ref Link::kLocalSpaceClosure, @ref Link::kLocalTimeClosure
|
||||
* or @ref Link::kUserClosure attached to it. The current optimized map is updated
|
||||
* accordingly.
|
||||
*/
|
||||
void rejectLastLoopClosure();
|
||||
/**
|
||||
* @brief Deletes the most recent (non-intermediate) location from the map.
|
||||
*
|
||||
* Used by tools to undo the very last @ref process() iteration. In mapping mode,
|
||||
* the optimized graph is recomputed without the deleted node.
|
||||
*
|
||||
* @note Locations whose neighbors include intermediate nodes are not supported.
|
||||
*/
|
||||
void deleteLastLocation();
|
||||
/**
|
||||
* @brief Replaces the current optimized poses and constraints with externally
|
||||
* provided ones.
|
||||
*
|
||||
* Useful when graph optimization is performed outside of Rtabmap.
|
||||
*
|
||||
* @warning No consistency check is performed against the current @ref Memory state:
|
||||
* @p poses and @p constraints overwrite the internal containers verbatim.
|
||||
* The caller is responsible for ensuring that every id in @p poses (and
|
||||
* every endpoint of every link in @p constraints) belongs to a signature
|
||||
* currently in STM or WM (see @ref Memory::isInSTM() / @ref Memory::isInWM()).
|
||||
* Passing poses for ids that are no longer loaded will leave dangling
|
||||
* entries that may confuse subsequent @ref process() calls.
|
||||
*/
|
||||
void setOptimizedPoses(const std::map<int, Transform> & poses, const std::multimap<int, Link> & constraints);
|
||||
/**
|
||||
* @brief Returns a copy of signature @p id with optional payloads attached.
|
||||
*
|
||||
* Loads from WM/STM if present, otherwise from LTM. Selectively populates the
|
||||
* returned @ref Signature with images, scan, user data, occupancy grid, visual
|
||||
* words and global descriptors.
|
||||
*/
|
||||
Signature getSignatureCopy(int id, bool images, bool scan, bool userData, bool occupancyGrid, bool withWords, bool withGlobalDescriptors) const;
|
||||
// Use getGraph() instead with withImages=true, withScan=true, withUserData=true and withGrid=true.
|
||||
/**
|
||||
* @brief Deprecated: use @ref getGraph() instead with @c withImages=true,
|
||||
* @c withScan=true, @c withUserData=true and @c withGrid=true.
|
||||
*/
|
||||
RTABMAP_DEPRECATED
|
||||
void get3DMap(std::map<int, Signature> & signatures,
|
||||
std::map<int, Transform> & poses,
|
||||
std::multimap<int, Link> & constraints,
|
||||
bool optimized,
|
||||
bool global) const;
|
||||
/**
|
||||
* @brief Extracts a full snapshot of the current pose graph.
|
||||
*
|
||||
* @param poses Output: pose for every selected node.
|
||||
* @param constraints Output: links between selected nodes.
|
||||
* @param optimized If true, return optimized poses; otherwise raw odometry poses.
|
||||
* @param global If true, include nodes from LTM as well; otherwise only WM/STM.
|
||||
* @param signatures Optional output: a copy of each node's @ref Signature (with the
|
||||
* payloads requested by the @p with* flags).
|
||||
* @param withImages Attach compressed RGB/depth images to @p signatures.
|
||||
* @param withScan Attach laser scan blob.
|
||||
* @param withUserData Attach user data blob.
|
||||
* @param withGrid Attach occupancy grid cells.
|
||||
* @param withWords Attach visual words (id, keypoints, 3D points, descriptors).
|
||||
* @param withGlobalDescriptors Attach global descriptors.
|
||||
*/
|
||||
void getGraph(std::map<int, Transform> & poses,
|
||||
std::multimap<int, Link> & constraints,
|
||||
bool optimized,
|
||||
@@ -201,8 +612,55 @@ public:
|
||||
bool withGrid = false,
|
||||
bool withWords = true,
|
||||
bool withGlobalDescriptors = true) const;
|
||||
std::map<int, Transform> getNodesInRadius(const Transform & pose, float radius, int k=0, std::map<int, float> * distsSqr=0); // If radius=0 and k=0, RGBD/LocalRadius is used. Can return landmarks.
|
||||
std::map<int, Transform> getNodesInRadius(int nodeId, float radius, int k=0, std::map<int, float> * distsSqr=0); // If nodeId==0, return poses around latest node. If radius=0 and k=0, RGBD/LocalRadius is used. Can return landmarks and use landmark id (negative) as request.
|
||||
/**
|
||||
* @brief Returns optimized poses within a metric radius of @p pose.
|
||||
*
|
||||
* @param pose Query pose in the map frame.
|
||||
* @param radius Search radius in meters (0 falls back to @ref Parameters::kRGBDLocalRadius()).
|
||||
* @param k If non-zero, also cap the result to the @p k nearest neighbors.
|
||||
* @param distsSqr Optional output: per-id squared distance to @p pose.
|
||||
* @return Nodes (and possibly landmarks) within the radius, mapped to their pose.
|
||||
* Landmarks have a negative id.
|
||||
*/
|
||||
std::map<int, Transform> getNodesInRadius(const Transform & pose, float radius, int k=0, std::map<int, float> * distsSqr=0);
|
||||
/**
|
||||
* @brief Returns optimized poses within a metric radius of node @p nodeId.
|
||||
*
|
||||
* @param nodeId Query node id. Pass 0 to query around the latest node. A negative
|
||||
* id requests neighbors of the corresponding landmark.
|
||||
* @param radius Search radius in meters (0 falls back to @ref Parameters::kRGBDLocalRadius()).
|
||||
* @param k If non-zero, cap the result to the @p k nearest neighbors.
|
||||
* @param distsSqr Optional output: per-id squared distance to @p nodeId.
|
||||
* @return Nodes (and possibly landmarks) within the radius.
|
||||
*/
|
||||
std::map<int, Transform> getNodesInRadius(int nodeId, float radius, int k=0, std::map<int, float> * distsSqr=0);
|
||||
/**
|
||||
* @brief Post-processing: searches for additional loop closures over the existing graph.
|
||||
*
|
||||
* Clusters nearby optimized poses and runs registration between candidates that are
|
||||
* not yet linked. New links are added to @ref Memory and the graph is re-optimized.
|
||||
*
|
||||
* @note The registration approach used here is the one configured in @ref Memory via
|
||||
* @ref Parameters::kRegStrategy() (0=Vis, 1=Icp, 2=VisIcp), so the quality and
|
||||
* sensor requirements of this pass mirror the live loop-closure pipeline.
|
||||
*
|
||||
* @note Candidate cluster pairs whose ids differ by less than
|
||||
* @ref Parameters::kMemSTMSize(), or that are already reachable from each
|
||||
* other within that many graph hops, are filtered out. This prevents trivial
|
||||
* "loop closures" between temporally or topologically adjacent nodes.
|
||||
*
|
||||
* @param clusterRadiusMax Maximum metric distance (m) between two candidate nodes.
|
||||
* @param clusterAngle Maximum angular distance (rad) between two candidate nodes.
|
||||
* @param iterations Number of refinement passes.
|
||||
* @param intraSession Include loop closures within the same map session.
|
||||
* @param interSession Include loop closures between different map sessions.
|
||||
* @param state Optional progress sink; cancellation requests are honored.
|
||||
* @param clusterRadiusMin Minimum metric distance (m); pairs closer than this are
|
||||
* considered already linked through neighbor links.
|
||||
* @param toFromMapId If >=0, restrict candidate pairs to nodes belonging to this map id.
|
||||
* @return Number of loop closures added, or -1 on error
|
||||
* (e.g. not in RGB-D mode, no optimizer iterations).
|
||||
*/
|
||||
int detectMoreLoopClosures(
|
||||
float clusterRadiusMax = 0.5f,
|
||||
float clusterAngle = M_PI/6.0f,
|
||||
@@ -212,11 +670,31 @@ public:
|
||||
const ProgressState * state = 0,
|
||||
float clusterRadiusMin = 0.0f,
|
||||
int toFromMapId = -1);
|
||||
/**
|
||||
* @brief Runs a global bundle adjustment over the optimized graph.
|
||||
*
|
||||
* @param optimizerType Backend optimizer (e.g. 1=g2o); availability depends on
|
||||
* what RTAB-Map was built with.
|
||||
* @param rematchFeatures If true, re-match visual features between connected nodes
|
||||
* before BA (otherwise reuse existing word-id correspondences).
|
||||
* @param iterations Solver iterations (0 falls back to @ref Parameters::kOptimizerIterations()).
|
||||
* @param pixelVariance Pixel reprojection variance used by the cost (0 falls back
|
||||
* to @ref Parameters::kg2oPixelVariance()).
|
||||
* @return True if BA was run and improved poses were stored.
|
||||
*/
|
||||
bool globalBundleAdjustment(
|
||||
int optimizerType = 1 /*g2o*/,
|
||||
bool rematchFeatures = true,
|
||||
int iterations = 0,
|
||||
float pixelVariance = 0.0f);
|
||||
/**
|
||||
* @brief Filters spurious obstacles from every node's local grid using a reference 2D map.
|
||||
*
|
||||
* Thin wrapper around @ref Memory::cleanupLocalGrids(); see that method for the
|
||||
* exact filtering rule and the meaning of @p cropRadius and @p filterScans.
|
||||
*
|
||||
* @return Number of (node, grid or scan) modifications, or -1 on error.
|
||||
*/
|
||||
int cleanupLocalGrids(
|
||||
const std::map<int, Transform> & mapPoses,
|
||||
const cv::Mat & map,
|
||||
@@ -225,28 +703,189 @@ public:
|
||||
float cellSize,
|
||||
int cropRadius = 1,
|
||||
bool filterScans = false);
|
||||
/**
|
||||
* @brief Re-runs registration on every link of the current graph and updates the
|
||||
* ones that converge.
|
||||
*
|
||||
* Useful after parameter changes to refresh stored transforms.
|
||||
*
|
||||
* @note The registration approach is the one configured in @ref Memory via
|
||||
* @ref Parameters::kRegStrategy() (0=Vis, 1=Icp, 2=VisIcp). For each link,
|
||||
* the link's existing relative transform (the constraint produced by the
|
||||
* current optimized local graph) is passed as the initial guess to
|
||||
* @ref Memory::computeTransform(), so links already close to convergence
|
||||
* are refined locally rather than re-estimated from scratch.
|
||||
*
|
||||
* @return Number of links refined, or -1 if not in RGB-D mode.
|
||||
*/
|
||||
int refineLinks();
|
||||
/**
|
||||
* @brief Adds an external link to the map.
|
||||
*
|
||||
* The link's "from" and "to" endpoints must exist in memory (incremental mode) or
|
||||
* in the optimized poses (localization mode). RGB-D mode only.
|
||||
*
|
||||
* @return True if the link was added.
|
||||
*/
|
||||
bool addLink(const Link & link);
|
||||
/**
|
||||
* @brief Converts an odometry covariance into an information matrix, clipping by
|
||||
* @ref Memory::getOdomMaxInf() when @ref Parameters::kRGBDLoopCovLimited()
|
||||
* is enabled.
|
||||
*/
|
||||
cv::Mat getInformation(const cv::Mat & covariance) const;
|
||||
/**
|
||||
* @brief Marks node ids whose data should be re-emitted on the next @ref process().
|
||||
*
|
||||
* The requested signatures are attached to the @ref Statistics object produced by
|
||||
* the next @ref process() call (via the same mechanism as the regular "last signature
|
||||
* data"), so consumers reading @ref getStatistics() pick them up alongside the
|
||||
* normal output. Up to @ref Parameters::kRtabmapMaxRepublished() ids are emitted
|
||||
* per iteration; any leftover ids stay queued for subsequent iterations until they
|
||||
* are republished or fall out of the current graph.
|
||||
*
|
||||
* Pass an empty vector to clear the request set. Requires
|
||||
* @ref Parameters::kRtabmapMaxRepublished() > 0 and
|
||||
* @ref Parameters::kRtabmapPublishLastSignature() = true.
|
||||
*/
|
||||
void addNodesToRepublish(const std::vector<int> & ids);
|
||||
|
||||
int getPathStatus() const {return _pathStatus;} // -1=failed 0=idle/executing 1=success
|
||||
void clearPath(int status); // -1=failed 0=idle/executing 1=success
|
||||
/** @return Current path status: -1 = failed, 0 = idle / executing, 1 = success. */
|
||||
int getPathStatus() const {return _pathStatus;}
|
||||
/**
|
||||
* @brief Clears the current path and sets its terminal status.
|
||||
* @param status -1 = failed, 0 = idle / executing, 1 = success.
|
||||
*/
|
||||
void clearPath(int status);
|
||||
/**
|
||||
* @brief Plans a path from the current location to node @p targetNode.
|
||||
*
|
||||
* RGB-D mode only (requires @ref Parameters::kRGBDEnabled() = true).
|
||||
*
|
||||
* @param targetNode Destination node id (positive) or landmark id (negative).
|
||||
* @param global If true, also search nodes in LTM; otherwise only the current
|
||||
* optimized map.
|
||||
* @return True if a path was computed; the result is available via @ref getPath().
|
||||
*
|
||||
* @see Parameters::kRGBDEnabled()
|
||||
*/
|
||||
bool computePath(int targetNode, bool global);
|
||||
bool computePath(const Transform & targetPose, float tolerance = -1.0f); // only in current optimized map, tolerance (m) < 0 means RGBD/LocalRadius, 0 means infinite
|
||||
/**
|
||||
* @brief Plans a path in the current optimized map toward a metric goal pose.
|
||||
*
|
||||
* @param targetPose Goal pose in the map frame.
|
||||
* @param tolerance Goal-acceptance tolerance (meters). A negative value falls back
|
||||
* to @ref Parameters::kRGBDLocalRadius(); 0 means infinite tolerance.
|
||||
* @return True if a path was computed.
|
||||
*/
|
||||
bool computePath(const Transform & targetPose, float tolerance = -1.0f);
|
||||
/** @return The currently planned path as a sequence of (node id, pose) waypoints. */
|
||||
const std::vector<std::pair<int, Transform> > & getPath() const {return _path;}
|
||||
/** @return Upcoming waypoints (from the current path index onward). */
|
||||
std::vector<std::pair<int, Transform> > getPathNextPoses() const;
|
||||
/** @return Upcoming node ids (from the current path index onward). */
|
||||
std::vector<int> getPathNextNodes() const;
|
||||
/** @return Id of the current intermediate path goal (the node currently being chased). */
|
||||
int getPathCurrentGoalId() const;
|
||||
/** @return Index of the current waypoint in @ref getPath(). */
|
||||
unsigned int getPathCurrentIndex() const {return _pathCurrentIndex;}
|
||||
/** @return Index of the current intermediate goal in @ref getPath(). */
|
||||
unsigned int getPathCurrentGoalIndex() const {return _pathGoalIndex;}
|
||||
/** @return Transform from the final waypoint pose to the requested goal pose. */
|
||||
const Transform & getPathTransformToGoal() const {return _pathTransformToGoal;}
|
||||
|
||||
/**
|
||||
* @brief Returns optimized poses of WM nodes located in front of @p fromId.
|
||||
*
|
||||
* Candidates are first gathered around @p fromId, then STM nodes are excluded, the
|
||||
* survivors are cropped to a forward-facing box of width @p radius (1 m behind,
|
||||
* @p radius ahead, +/-@p radius laterally), and a KdTree radius search keeps the
|
||||
* @p maxNearestNeighbors closest poses in that box.
|
||||
*
|
||||
* @note Mapping vs. localization mode differs only in how the initial candidate
|
||||
* set is built:
|
||||
* - In **mapping mode** (incremental), candidates are produced by a
|
||||
* graph-radius walk from @p fromId: nodes reachable within @p maxDiffID
|
||||
* graph hops AND within @p radius meters in the optimized poses.
|
||||
* - In **localization mode**, the graph-hop restriction is ignored: every
|
||||
* optimized pose within @p radius meters of @p fromId is considered.
|
||||
* The forward-box crop and KdTree radius search that follow are identical
|
||||
* in both modes.
|
||||
*
|
||||
* @param fromId Reference node (must be in @ref Memory and @ref getLocalOptimizedPoses()).
|
||||
* @param maxNearestNeighbors Cap on the number of nodes returned.
|
||||
* @param radius Maximum metric distance from @p fromId (meters).
|
||||
* @param maxDiffID Maximum graph depth from @p fromId in mapping mode (0 = unlimited).
|
||||
* Ignored in localization mode.
|
||||
*/
|
||||
std::map<int, Transform> getForwardWMPoses(int fromId, int maxNearestNeighbors, float radius, int maxDiffID) const;
|
||||
/**
|
||||
* @brief Segments a set of optimized poses into paths connected by neighbor links.
|
||||
*
|
||||
* Designed to be called on the result of a radius search around @p target (a set
|
||||
* of @p poses already constrained to be metrically close to the goal). Within that
|
||||
* radius, the method partitions the @p poses into one or more "paths" where each
|
||||
* path is a connected component reachable from its starting node using **only
|
||||
* neighbor (sequential) links** -- loop-closure links, landmark links and
|
||||
* intermediate nodes are not used to traverse between members. Paths are produced
|
||||
* one at a time, each starting from the still-unclaimed pose nearest to @p target;
|
||||
* a candidate is added to the current path only if it has at least one neighbor
|
||||
* link to a node already in the path.
|
||||
*
|
||||
* Used internally by proximity detection by space (see
|
||||
* @ref Parameters::kRGBDProximityBySpace()) in two independent stages, each
|
||||
* iterating over the segmented paths:
|
||||
* - **One-to-one** (visual registration): runs registration between the current
|
||||
* node and at most one node per neighbor-connected path, avoiding redundant
|
||||
* attempts against nearby members of the same local trajectory.
|
||||
* - **One-to-many** (scan matching, enabled when
|
||||
* @ref Parameters::kRGBDProximityPathMaxNeighbors() > 0): on each path,
|
||||
* neighboring nodes are assembled around the nearest pose on the path (up to
|
||||
* the configured count, walked forward and backward) and their laser scans are
|
||||
* merged for an ICP registration against the current scan. The
|
||||
* neighbor-link-only structure of each path is what makes this assembly
|
||||
* geometrically consistent.
|
||||
*
|
||||
* @param poses Candidate nodes with their optimized poses (typically pre-filtered
|
||||
* to a radius around @p target).
|
||||
* @param target Reference pose used to order paths: each path's starting node is
|
||||
* the still-unclaimed pose closest to @p target.
|
||||
* @param maxGraphDepth Maximum graph depth traversed from the starting node when
|
||||
* gathering candidates for a path (0 = unlimited).
|
||||
* @return Map from the starting node id of each path to its (node id -> pose) chain.
|
||||
*/
|
||||
std::map<int, std::map<int, Transform> > getPaths(const std::map<int, Transform> & poses, const Transform & target, int maxGraphDepth = 0) const;
|
||||
/**
|
||||
* @brief Applies the standard RTAB-Map likelihood adjustment.
|
||||
*
|
||||
* Normalizes raw likelihoods using mean and standard deviation across non-null
|
||||
* values. Real-place entries with @c value <= @c mean + @c stdDev are clamped to
|
||||
* @c 1.0; only entries above that threshold are scaled. The virtual place (the
|
||||
* first key in @p likelihood, representing the "new place" hypothesis) is then
|
||||
* set so that its likelihood reflects how peaked the real distribution is.
|
||||
*
|
||||
* The exact formulas are selected by @ref Parameters::kRtabmapVirtualPlaceLikelihoodRatio()
|
||||
* (default 0, Angeli PhD formulation):
|
||||
*
|
||||
* - **Ratio = 0** (mean / std-dev formulation):
|
||||
* - Real place above threshold: @c (value - (stdDev - epsilon)) / mean
|
||||
* - Virtual place: @c mean / stdDev + 1 (when @c stdDev is non-trivial and a
|
||||
* maximum exists; otherwise 2).
|
||||
* The virtual place "wins" when the real-place distribution is flat
|
||||
* (small @c stdDev relative to @c mean).
|
||||
*
|
||||
* - **Ratio != 0** (z-score formulation):
|
||||
* - Real place above threshold: @c (value - mean) / stdDev (i.e. the z-score).
|
||||
* - Virtual place: @c stdDev / (max - mean) + 1 (when @c max > @c mean;
|
||||
* otherwise 2). The virtual place "wins" when no real candidate stands out
|
||||
* far above the mean.
|
||||
*
|
||||
* In both formulations a low virtual-place likelihood favors a real-place loop
|
||||
* closure on the next Bayes update; a high one favors the "new place" hypothesis.
|
||||
*
|
||||
* @see Parameters::kRtabmapVirtualPlaceLikelihoodRatio()
|
||||
*/
|
||||
void adjustLikelihood(std::map<int, float> & likelihood) const;
|
||||
std::pair<int, float> selectHypothesis(const std::map<int, float> & posterior,
|
||||
const std::map<int, float> & likelihood) const;
|
||||
|
||||
private:
|
||||
void optimizeCurrentMap(int id,
|
||||
@@ -289,8 +928,8 @@ private:
|
||||
bool _publishRAMUsage;
|
||||
bool _computeRMSE;
|
||||
bool _saveWMState;
|
||||
float _maxTimeAllowed; // in ms
|
||||
unsigned int _maxMemoryAllowed; // signatures count in WM
|
||||
float _maxTimeAllowed; ///< Per-iteration time budget (ms).
|
||||
unsigned int _maxMemoryAllowed; ///< Maximum number of signatures kept in WM.
|
||||
float _loopThr;
|
||||
float _loopRatio;
|
||||
float _aggressiveLoopThr;
|
||||
@@ -331,7 +970,7 @@ private:
|
||||
float _optimizationMaxErrorRepairRadius;
|
||||
bool _startNewMapOnLoopClosure;
|
||||
bool _startNewMapOnGoodSignature;
|
||||
float _goalReachedRadius; // meters
|
||||
float _goalReachedRadius; ///< Path-goal acceptance radius (meters).
|
||||
bool _goalsSavedInUserData;
|
||||
int _pathStuckIterations;
|
||||
float _pathLinearVelocity;
|
||||
@@ -377,16 +1016,16 @@ private:
|
||||
std::map<int, Transform> _optimizedPoses;
|
||||
std::multimap<int, Link> _constraints;
|
||||
Transform _mapCorrection;
|
||||
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
|
||||
Transform _mapCorrectionBackup; ///< Used in localization mode when odometry is lost.
|
||||
Transform _lastLocalizationPose; ///< Corrected odometry pose; in mapping mode, last pose of getLocalOptimizedPoses().
|
||||
int _lastLocalizationNodeId; ///< Last localization node id (localization mode).
|
||||
cv::Mat _localizationCovariance;
|
||||
std::map<int, std::pair<cv::Point3d, Transform> > _gpsGeocentricCache;
|
||||
bool _currentSessionHasGPS;
|
||||
LaserScan _globalScanMap;
|
||||
std::map<int, Transform> _globalScanMapPoses;
|
||||
std::map<int, Transform> _odomCachePoses; // used in localization mode to reject loop closures
|
||||
std::multimap<int, Link> _odomCacheConstraints; // used in localization mode to reject loop closures
|
||||
std::map<int, Transform> _odomCachePoses; ///< Odometry cache used to reject loop closures (localization mode).
|
||||
std::multimap<int, Link> _odomCacheConstraints; ///< Odometry cache constraints (localization mode).
|
||||
std::map<int, Transform> _markerPriors;
|
||||
std::pair<int, int> _lastRejectedLoopClosureIds;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user