This tutorial covers GTSAM, a factor graph-based optimization library widely used in robotics and SLAM.
GTSAM is a C++ library that implements:
- Factor Graphs: Probabilistic graphical models for optimization
- Smoothing and Mapping: State estimation for robotics
- iSAM2: Incremental smoothing for real-time SLAM
Used in production systems like Boston Dynamics' Spot robot.
Variables (X):
- Robot poses
- 3D landmarks
- Calibration parameters
Factors (constraints):
- Prior factors: Initial knowledge
- Between factors: Odometry
- Projection factors: Camera observations
| Feature | GTSAM | g2o |
|---|---|---|
| API Style | Factor-based | Vertex/Edge-based |
| Incremental | iSAM2 | Not built-in |
| Documentation | Excellent | Limited |
| Python bindings | Native | Limited |
Local build:
mkdir build && cd build
cmake ..
make -j4Docker build:
docker build . -t slam_zero_to_hero:3_14#include <gtsam/nonlinear/NonlinearFactorGraph.h>
#include <gtsam/nonlinear/Values.h>
NonlinearFactorGraph graph;
Values initial_estimate;#include <gtsam/slam/PriorFactor.h>
#include <gtsam/slam/BetweenFactor.h>
// Prior factor (anchor)
auto noise = noiseModel::Diagonal::Sigmas(Vector3(0.1, 0.1, 0.05));
graph.addPrior(Symbol('x', 0), Pose2(0, 0, 0), noise);
// Between factor (odometry)
graph.add(BetweenFactor<Pose2>(
Symbol('x', 0), Symbol('x', 1),
Pose2(1.0, 0.0, 0.0), // measurement
noise
));#include <gtsam/inference/Symbol.h>
#include <gtsam/geometry/Pose2.h>
// Using Symbol for named keys
initial_estimate.insert(Symbol('x', 0), Pose2(0, 0, 0));
initial_estimate.insert(Symbol('x', 1), Pose2(1, 0, 0));
// Or using shorthand
using namespace gtsam::symbol_shorthand;
initial_estimate.insert(X(0), Pose2(0, 0, 0));#include <gtsam/nonlinear/LevenbergMarquardtOptimizer.h>
LevenbergMarquardtParams params;
params.setVerbosity("SUMMARY");
params.setMaxIterations(100);
LevenbergMarquardtOptimizer optimizer(graph, initial_estimate, params);
Values result = optimizer.optimize();
// Access results
Pose2 pose = result.at<Pose2>(Symbol('x', 0));#include <gtsam/nonlinear/Marginals.h>
Marginals marginals(graph, result);
Matrix cov = marginals.marginalCovariance(Symbol('x', 0));| Factor | Description |
|---|---|
PriorFactor<T> |
Prior knowledge on variable |
BetweenFactor<T> |
Relative constraint between poses |
GenericProjectionFactor |
3D point to 2D image projection |
RangeFactor |
Range measurement |
BearingFactor |
Bearing measurement |
| Type | Description |
|---|---|
Pose2 |
2D pose (x, y, theta) |
Pose3 |
3D pose (SE3) |
Point2 |
2D point |
Point3 |
3D point |
Rot2 |
2D rotation |
Rot3 |
3D rotation (SO3) |
// Diagonal (independent noise per dimension)
auto noise = noiseModel::Diagonal::Sigmas(Vector3(0.1, 0.1, 0.05));
// Isotropic (same noise all dimensions)
auto noise = noiseModel::Isotropic::Sigma(3, 0.1);
// Robust (outlier rejection)
auto huber = noiseModel::Robust::Create(
noiseModel::mEstimator::Huber::Create(1.345),
noiseModel::Isotropic::Sigma(2, 1.0)
);#include <gtsam/nonlinear/ISAM2.h>
// Create iSAM2 instance
ISAM2Params params;
params.relinearizeThreshold = 0.01;
ISAM2 isam(params);
// Incremental update
NonlinearFactorGraph new_factors;
Values new_values;
// ... add new factors and values ...
isam.update(new_factors, new_values);
Values current_estimate = isam.calculateEstimate();#include <gtsam/slam/GeneralSFMFactor.h>
#include <gtsam/geometry/Cal3Bundler.h>
// Camera intrinsics (f, k1, k2, u0, v0)
Cal3Bundler K(500.0, 0.0, 0.0, 320.0, 240.0);
// Projection factor
graph.emplace_shared<GeneralSFMFactor2<Cal3Bundler>>(
Point2(100, 200), // measured pixel
measurement_noise,
Symbol('c', camera_id), // camera pose
Symbol('p', point_id), // 3D point
Symbol('K', camera_id) // intrinsics
);# 2D pose graph
./gtsam_basics
# Bundle adjustment with BAL dataset
./gtsam_bundle_adjustment problem-49-7776-pre.txtDocker:
docker run -it --rm slam_zero_to_hero:3_14- Use Symbols for readable variable names:
Symbol('x', 0)instead of raw integers - Start with priors to anchor the optimization
- Check marginals to verify optimization quality
- Use iSAM2 for real-time applications
- Leverage robust noise models for outlier handling