Overview¶
The MagPoseFactor<POSE>
is a templated factor designed to constrain the orientation component of a Pose2
or Pose3
variable using magnetometer readings. It’s similar in purpose to MagFactor1
but operates directly on pose types and explicitly handles an optional transformation between the body frame and the sensor frame.
It assumes the magnetometer calibration parameters (scale, bias) and the local magnetic field direction are known.
Measurement Model¶
The underlying model is the same as for MagFactor
:
However, MagPoseFactor
allows specifying an optional body_P_sensor
transform. If provided, the factor internally adjusts the measurement and bias to be consistent with the body frame before calculating the error.
Let:
- be the
Pose
state. - be the pose of the sensor in the body frame (
body_P_sensor
). If not given, is identity. - be the raw measurement in the sensor frame.
- be the bias in the sensor frame.
- , be the known scale and nav-frame direction.
The factor computes the predicted measurement in the body frame:
where .
Alternatively, and perhaps more clearly, it predicts the field in the sensor frame and compares it to the measurement:
The implementation transforms the measurement and bias to the body frame first for efficiency if body_P_sensor
is provided.
The error is calculated in the body frame.
Key Functionality / API¶
- Template Parameter:
POSE
(must begtsam.Pose2
orgtsam.Pose3
). - Constructor:
MagPoseFactor(poseKey, measured, scale, direction, bias, model, body_P_sensor=None)
poseKey
: Key of thePose2
orPose3
variable.measured
: Measured magnetic field vector (Point2
orPoint3
) in the sensor frame.scale
: Known scale factor.direction
: Known magnetic field direction (Point2
orPoint3
) in the navigation frame.bias
: Known bias vector (Point2
orPoint3
) in the sensor frame.model
: Noise model (2D or 3D).body_P_sensor
: OptionalPose2
orPose3
describing the sensor’s pose relative to the body frame.
evaluateError(nPb)
: Calculates the error vector (2D or 3D) based on the current pose estimatenPb
.
Usage Example (Pose3)¶
Using a magnetometer to help estimate a Pose3
orientation, assuming known calibration and a sensor offset.
import gtsam
import numpy as np
from gtsam.symbol_shorthand import X
# --- Assumed Known Calibration & Field (NED Frame) ---
n_direction_point = gtsam.Point3(0.7, 0.1, 0.7) # Example simplified direction in NED
mag_scale = 50000.0 # nT
mag_bias_sensor = gtsam.Point3(15.0, 10.0, -5.0) # Bias in sensor frame (nT)
# --- Sensor Pose ---
# Assume sensor is rotated 90 deg yaw right w.r.t body
body_P_sensor = gtsam.Pose3(gtsam.Rot3.Yaw(np.deg2rad(90)), gtsam.Point3(0.1, 0, 0))
sensor_P_body = body_P_sensor.inverse()
# --- Simulation: Generate Measurement ---
# Assume a ground truth body pose (e.g., 10 deg pitch up in NED)
truth_nPb = gtsam.Pose3(gtsam.Rot3.Pitch(np.deg2rad(10)), gtsam.Point3(1,2,3))
truth_nRb = truth_nPb.rotation()
truth_bRn = truth_nRb.inverse()
# Calculate field in nav frame
n_field_vector = mag_scale * (n_direction_point / np.linalg.norm(n_direction_point))
# Calculate field in sensor frame
truth_nRs = truth_nRb * body_P_sensor.rotation()
truth_sRn = truth_nRs.inverse()
s_field_ideal = truth_sRn.rotate(n_field_vector)
# Calculate the measured value including bias (in sensor frame)
s_measured = s_field_ideal + mag_bias_sensor
# --- Factor Creation ---
pose_key = X(0)
# Noise model for the magnetometer measurement (nT)
mag_noise_sigma = 50.0 # nT
noise_model = gtsam.noiseModel.Isotropic.Sigma(3, mag_noise_sigma)
# Create MagPoseFactor (providing body_P_sensor)
# Note: measurement and bias are in SENSOR frame when body_P_sensor is specified
mag_factor = gtsam.MagPoseFactorPose3(pose_key, s_measured, mag_scale,
n_direction_point, mag_bias_sensor,
noise_model, body_P_sensor)
print("Created MagPoseFactor<Pose3>:")
mag_factor.print()
# --- Evaluate Error ---
# Evaluate at the ground truth pose (error should be zero)
error_at_truth = mag_factor.evaluateError(truth_nPb)
print("\nError at ground truth pose (should be zero):", error_at_truth)
# Evaluate at a different pose (error should be non-zero)
test_nPb = gtsam.Pose3(gtsam.Rot3.Pitch(np.deg2rad(15)), gtsam.Point3(1,2,3))
error_at_test = mag_factor.evaluateError(test_nPb)
print("Error at test pose:", error_at_test)
Created MagPoseFactor<Pose3>:
keys = { x0 }
isotropic dim=3 sigma=50
local field (nM): [35176.3235; 5025.18908; 35176.3235];
measured field (bM): [28523.6117; 5040.18908; 40745.2206];
magnetometer bias: [-10; 15; -5];
Error at ground truth pose (should be zero): [0. 0. 0.]
Error at test pose: [-3660.19475195 0. 2331.80122523]
Important Considerations¶
- Frame Consistency: Ensure
direction
is in the nav frame, whilemeasured
andbias
are in the sensor frame whenbody_P_sensor
is provided. Ifbody_P_sensor
isNone
, thenmeasured
andbias
are assumed to be in the body frame. - Units: Maintain consistent units (e.g., nT) for scale, bias, measurement, and noise sigma.