Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

KnownLandmarkFactor

This guide explains how to use KnownLandmarkFactor and KnownLandmarkFactor2 for localization against fixed landmarks. Prefer KnownLandmarkFactor for normal GTSAM use. It follows the conventional pose direction used throughout GTSAM. KnownLandmarkFactor2 accepts the same physical measurement in the opposite state direction and is intended specifically for exact QCQP and certifiable optimization.

Open In Colab
import numpy as np
import gtsam

Choose the pose convention first

We use the convention that TbaT^a_b transforms coordinates from frame bb into frame aa. A conventional GTSAM pose TkwT^w_k maps frame kk into the world. Its inverse Twk=(Tkw)1T^k_w=(T^w_k)^{-1} maps world coordinates into frame kk. A fixed landmark is LwL^w, and its Cartesian measurement in frame kk is P~k\widetilde{P}^k.

Use caseFactorState stored in ValuesPrediction
Ordinary GTSAM localization (preferred)KnownLandmarkFactorTkwT^w_kwTk.transformTo(wL)
Exact QCQP/certifiable formulation onlyKnownLandmarkFactor2TwkT^k_wkTw.transformFrom(wL)

KnownLandmarkFactor should be the default choice. It uses the standard TkwT^w_k convention and therefore combines naturally with conventional PriorFactor<Pose3>, BetweenFactor<Pose3>, initial values, plotting utilities, and other GTSAM APIs.

Use KnownLandmarkFactor2 only when building an exact QCQP or certifiable optimization in which the rest of the graph also optimizes TwkT^k_w. The second variant is not a more accurate measurement model; its only advantage is the algebraic form required by those solvers. It also requires explicit inversion whenever data enter from, or results return to, conventional GTSAM code. Do not insert a TkwT^w_k value under a key expected to hold TwkT^k_w, or vice versa.

Both C++ templates support Pose2 and Pose3. Python exposes KnownLandmarkFactorPose2, KnownLandmarkFactorPose3, KnownLandmarkFactor2Pose2, and KnownLandmarkFactor2Pose3.

Prepare one Cartesian landmark measurement

Each factor needs four inputs:

  1. the pose key k;

  2. a fixed world landmark wL;

  3. the observed Cartesian point measured_kP; and

  4. a noise model for errors expressed in frame kk.

The residual is a Cartesian vector, so a Pose3 factor requires a three-dimensional noise model and a Pose2 factor requires a two-dimensional model. A full Gaussian model is appropriate when the observation has anisotropic or correlated uncertainty. In mathematical notation, the covariance below is ΣPk\Sigma_{P^k}.

k = 0
wL = np.array([4.0, 1.0, 2.0])
measured_kP = np.array([3.1, 0.8, 1.7])

kPCovariance = np.array(
    [
        [0.0100, 0.0015, 0.0005],
        [0.0015, 0.0040, 0.0008],
        [0.0005, 0.0008, 0.0060],
    ]
)
model = gtsam.noiseModel.Gaussian.Covariance(kPCovariance)

Conventional localization with KnownLandmarkFactor

For a conventional pose TkwT^w_k, the predicted frame-kk point is

P^k=(Tkw)1Lw,\widehat{P}^k=(T^w_k)^{-1}L^w,

implemented by wTk.transformTo(wL). The factor residual is P^kP~k\widehat{P}^k-\widetilde{P}^k. Add the factor to an ordinary nonlinear graph and insert a conventional wTk initial value under the same key.

graph = gtsam.NonlinearFactorGraph()
graph.add(
    gtsam.KnownLandmarkFactorPose3(k, wL, measured_kP, model)
)

wTk_initial = gtsam.Pose3(
    gtsam.Rot3.RzRyRx(0.05, -0.02, 0.10),
    np.array([0.2, -0.1, 0.3]),
)
initial_wTks = gtsam.Values()
initial_wTks.insert(k, wTk_initial)

Build a well-constrained graph

One point observation does not determine all six Pose3 degrees of freedom. In a real localization graph, add factors for several geometrically distinct known landmarks and, where appropriate, pose priors or odometry factors. Each observation should carry its own measured_kP and noise model. Reusing the same pose key connects all observations made from that pose.

A known landmark is fixed factor data, not a variable in Values. If the landmark itself must be estimated, use a binary measurement factor such as BearingRangeFactor<Pose3, Point3> instead.

Inverse-state localization with KnownLandmarkFactor2

The inverse-state factor predicts the same measured point from TwkT^k_w:

P^k=TwkLw.\widehat{P}^k=T^k_w L^w.

In code this is kTw.transformFrom(wL). Writing Twk=[Rwk,twk]T^k_w=[R^k_w,t^k_w], the prediction is

P^k=RwkLw+twk,\widehat{P}^k=R^k_w L^w+t^k_w,

which is affine in the entries of the homogeneous matrix TwkT^k_w. After whitening, its squared residual is therefore an exact quadratic cost, so KnownLandmarkFactor2 can contribute directly to a D=1 QcqpProblem.

The preferred conventional prediction uses the inverse action of Tkw=[Rkw,tkw]T^w_k=[R^w_k,t^w_k]:

P^k=(Rkw)T(Lwtkw).\widehat{P}^k=(R^w_k)^{\mathsf T}(L^w-t^w_k).

When parameterized by the entries of TkwT^w_k, the term (Rkw)Ttkw(R^w_k)^{\mathsf T}t^w_k is bilinear. The residual is therefore not affine in those matrix entries, and its squared norm does not give the exact quadratic cost required by the current QCQP conversion. This algebraic limitation—not a difference in the physical observation—is the reason the second factor exists.

Use this variant only when every factor sharing the pose key expects the inverse convention. For relative measurements, FrobeniusLeftBetweenFactor uses the compatible relation Twi=TjiTwjT^i_w=T^i_j T^j_w. For ordinary nonlinear optimization, return to the preferred KnownLandmarkFactor.

certifiable_graph = gtsam.NonlinearFactorGraph()
certifiable_graph.add(
    gtsam.KnownLandmarkFactor2Pose3(k, wL, measured_kP, model)
)

kTw_initial = wTk_initial.inverse()
initial_kTws = gtsam.Values()
initial_kTws.insert(k, kTw_initial)

# The factor contributes its exact quadratic cost and Pose3 constraints.
qcqp = gtsam.QcqpProblem(certifiable_graph, 1)

Practical checklist

  • Prefer KnownLandmarkFactorPose2/Pose3 with conventional wTk states.

  • Use KnownLandmarkFactor2Pose2/Pose3 only for QCQP or certifiable optimization over inverse kTw states.

  • Express wL in the world frame and measured_kP in the observing frame kk.

  • Supply a Cartesian noise model with dimension two for Pose2 or three for Pose3.

  • Add enough non-degenerate observations or other factors to constrain the pose.

  • Use a binary landmark factor when the landmark is unknown rather than fixed.

  • Convert optimized kTw results back to wTk before combining them with conventional GTSAM pose values.