Skip to content

Lie Groups SE(3), SO(3), Adjoints, and Jacobians ​

Lie Groups SE(3), SO(3), Adjoints, and Jacobians curated visual

Visual: manifold/tangent-space diagram showing SO(3)/SE(3), Exp/log maps, left/right perturbations, adjoint transform, and residual Jacobian linearization.

Rigid body state is not a vector space. Rotations live on SO(3), poses live on SE(3), and the local 3-vector or 6-vector used by an optimizer is only a tangent-space perturbation. Treating pose parameters as ordinary Euclidean variables is a common way to create inconsistent residuals, invalid covariance propagation, and sign errors that only appear during aggressive turns or loop closure.



2. Why Lie Groups for 3D Pose ​

Rotations and rigid transforms are not elements of a vector space — they live on curved manifolds. Standard Euclidean calculus fails because:

  • SO(3) is a 3-dimensional manifold in R^9 constrained by R^T R = I and det(R) = +1. The average of two rotation matrices is not a rotation matrix.
  • SE(3) is a 6-dimensional manifold. Adding a 6-vector to a 4x4 matrix is geometrically meaningless.

Lie theory provides a tangent space at every point — a vector space where linearization, least-squares, and covariance propagation operate. The tangent space at the identity is the Lie algebra.

ObjectSymbolDimRole
SO(3)Lie group (rotations)3-DoF manifoldorientation state
so(3)Lie algebraR^3 via hatangular perturbation / velocity
SE(3)Lie group (rigid transforms)6-DoF manifoldpose state
se(3)Lie algebraR^6 via hattwist perturbation

The exponential map Exp: algebra -> group and its inverse Log: group -> algebra connect the two. Every ICP iteration, pose-graph linearization, IMU bias correction, and CT-ICP interpolation uses this machinery.

Sources: Solà 2018, arXiv 1812.01537 — https://arxiv.org/abs/1812.01537; Eade 2017 — https://www.ethaneade.com/lie.pdf


3. SO(3) — Rotations ​

3.1 The Manifold ​

text
SO(3) = { R in R^(3x3) | R^T R = I,  det(R) = +1 }

Compact 3-dimensional manifold, not simply connected (pi_1(SO(3)) = Z/2Z) — the topological reason quaternions (S^3) form a double cover.

3.2 The Lie Algebra so(3) — Hat and Vee Operators ​

The Lie algebra so(3) is the vector space of 3x3 skew-symmetric matrices. Via the hat operator (^) any w in R^3 maps to so(3):

text
hat(w) = [  0   -wz   wy ]
         [ wz    0   -wx ]
         [-wy   wx    0  ]

Key identity: hat(w) * p = w x p for any p in R^3. The inverse vee operator recovers w from hat(w): vee(hat(w)) = w.

3.3 Exponential Map — Rodrigues' Formula ​

For w in R^3 with theta = norm(w) (rotation angle) and unit axis u = w/theta:

text
R = Exp_SO3(w) = exp(hat(w))
              = I  +  A * hat(w)  +  B * hat(w)^2

A = sin(theta) / theta
B = (1 - cos(theta)) / theta^2

For theta -> 0 use Taylor series (exact via Cayley-Hamilton, not truncated):

text
A  ~= 1 - theta^2/6 + theta^4/120
B  ~= 1/2 - theta^2/24 + theta^4/720

Switch to series when |theta| < 1e-4 (double precision).

3.4 Logarithmic Map ​

For R != I, the inverse (Log) recovers w in R^3:

text
theta = acos( (trace(R) - 1) / 2 )

hat(w) = theta / (2 * sin(theta)) * (R - R^T)

Clamp the acos argument to [-1, 1]. Two singularities: theta = 0 (return w = 0) and theta = pi (axis undefined up to sign; read from R diagonal). The log map derivative diverges near theta = pi — see Pitfall §11.6.

3.5 Left vs Right Perturbations on SO(3) ​

text
Right:  R' = R * Exp(dw)   -- dw in LOCAL (body) frame
Left:   R' = Exp(dw) * R   -- dw in GLOBAL (world) frame

These produce different Jacobians related via the adjoint: dw_left = R * dw_right. Choosing one and applying it consistently is a mandatory design decision. See §6 for library conventions.

Sources: Solà 2018 §5 — https://arxiv.org/abs/1812.01537; Barfoot 2024 Ch. 7 — https://asrl.utias.utoronto.ca/~tdb/bib/barfoot_ser24.pdf


4. SE(3) — Rigid Transforms ​

4.1 The Manifold ​

text
SE(3) = { T = [R  t]  |  R in SO(3),  t in R^3 }   subset of R^(4x4)
                [0  1]

Group multiplication:

text
T1 * T2 = [R1*R2    R1*t2 + t1]
          [  0           1    ]

Inverse:

text
T^{-1} = [R^T   -R^T * t]
         [ 0        1   ]

Action on a homogeneous point p_bar = [p; 1]:

text
T * p_bar = [R*p + t; 1]   =>   result in R^3 is R*p + t

4.2 The Lie Algebra se(3) — Twist ​

The Lie algebra se(3) consists of 4x4 matrices parametrized by a twist xi = (rho, w) in R^6 (translational part rho, angular part w):

text
hat(xi) = [ hat(w)   rho ]   in R^(4x4)
          [   0       0  ]

This 6-vector has a screw / twist interpretation: simultaneous rotation about and translation along a screw axis. By Chasles' theorem, any rigid displacement equals such a screw motion.

The ordering xi = (rho, w) vs xi = (w, rho) varies by library. This page follows (rho, w) as in Solà/Blanco; GTSAM and Modern Robotics use (w, v). Verify the convention before writing Jacobians (see Pitfall §11.5).

4.3 Exponential Map — SE(3) Closed Form ​

text
T = Exp_SE3(xi) = exp(hat(xi)) = [ Exp_SO3(w)    V(w) * rho ]
                                  [     0              1     ]

where Exp_SO3(w) is the SO(3) Rodrigues formula and the V matrix is:

text
V(w) = I  +  B * hat(w)  +  C * hat(w)^2

B = (1 - cos(theta)) / theta^2
C = (theta - sin(theta)) / theta^3

with theta = norm(w). For theta -> 0: V -> I (pure translation limit). Use Taylor for C when |theta| < 1e-4: C ~= 1/6 - theta^2/120.

4.4 Logarithmic Map for SE(3) ​

text
w = Log_SO3(R)          -- recover rotation vector from R
theta = norm(w)

V_inv = I  -  (1/2) * hat(w)
           +  (1/theta^2) * (1 - theta*sin(theta) / (2*(1 - cos(theta)))) * hat(w)^2

rho = V_inv * t
xi = [rho; w]           -- the 6-vector twist

4.5 Screw / Twist Interpretation ​

A general SE(3) element represents a screw motion (Chasles' theorem): rotation by theta about a screw axis combined with translation d along that axis; pitch = d/theta. For a vehicle moving straight ahead: xi = (t, 0), V = I, T = [I, t; 0, 1].

Sources: Eade 2017 — https://www.ethaneade.com/lie.pdf; Blanco 2010 — https://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf; Solà 2018 — https://arxiv.org/abs/1812.01537


5. Quaternions — Double Cover of SO(3) ​

5.1 Unit Quaternions and S^3 ​

q = w + x*i + y*j + z*k with i^2 = j^2 = k^2 = ijk = -1. Unit quaternion: w^2 + x^2 + y^2 + z^2 = 1, placing q on the unit 3-sphere S^3. The group of unit quaternions is isomorphic to SU(2). The map pi: S^3 -> SO(3) is a 2-to-1 double cover: both q and -q represent the same rotation (source of Pitfall §11.4).

5.2 Rotation Action ​

For unit quaternion q = (w, v) with v = (x, y, z) and a vector p in R^3 (encoded as a pure quaternion [0, p]):

text
p' = q * [0, p] * q*      (q* is conjugate = (w, -v))

5.3 Conversion Quaternion <-> Rotation Matrix ​

text
R(q) = I + 2*w*hat(v) + 2*hat(v)^2

     = [ 1 - 2(y^2+z^2)    2(xy - wz)       2(xz + wy)   ]
       [ 2(xy + wz)         1 - 2(x^2+z^2)   2(yz - wx)   ]
       [ 2(xz - wy)         2(yz + wx)        1 - 2(x^2+y^2) ]

5.4 Hamilton vs JPL Convention ​

Hamilton (ROS, Eigen, GTSAM, Sophus): q1*q2 applies q2 first, then q1 (same as matrix composition). JPL (aerospace/NASA): q1*q2 applies q1 first. Storage order (w,x,y,z) vs (x,y,z,w) also varies. Mixing produces transposed rotations. Use Hamilton unless forced by an existing JPL codebase.

5.5 Numerical Advantages ​

No gimbal lock; cheap normalization q <- q/norm(q); stable composition avoids orthogonality drift; SLERP interpolation directly on S^3.

Sources: Solà 2018 §5.4 — https://arxiv.org/abs/1812.01537; Wikipedia Charts on SO(3) — https://en.wikipedia.org/wiki/Charts_on_SO(3)


6. Left vs Right Perturbation Conventions ​

6.1 Definitions ​

text
Right:  T' = T * Exp(d_xi)   -- d_xi in LOCAL (body) frame
Left:   T' = Exp(d_xi) * T   -- d_xi in GLOBAL (world) frame

Related via the group adjoint (§7.3): d_xi_left = Ad_T * d_xi_right.

6.2 Jacobian Consequences and Residual Rule ​

J_left = J_right * Ad_T^{-1}. Practical rule:

text
Right residual:  r = Log( T_est^{-1} * T_gt )  -->  use right Jacobians
Left residual:   r = Log( T_gt * T_est^{-1} )  -->  use left Jacobians

Mixing introduces a sign flip or adjoint-conjugation error (Pitfall §11.1).

6.4 Library Conventions ​

LibraryDefaultNotes
GTSAMLeftretract(xi) = Exp(xi) * X; left-invariant factors
SophusRightBoxPlus(T,x) = T*Exp(x); leftJacobian() available
CeresRight (common)Plus(x,delta) = x*Exp(delta); user-defined
manifRightBased on Solà 2018; all ops expose right Jacobian
g2oVariesTypically right

GTSAM note: Pose3 retract is Exp(xi)*X (left) despite some docs saying "right". Verify with a numerical Jacobian check.

Sources: Solà 2018 §7 — https://arxiv.org/abs/1812.01537; Sophus docs — https://deepwiki.com/strasdat/Sophus/2.1-3d-transformations-(so3-and-se3); Blanco 2010 — https://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf


7. Jacobians of Common Operations ​

7.1 d(R*p)/dR — Rotation of a Point ​

Under right R' = R * Exp(dw) and left R' = Exp(dw) * R:

text
Right:  d(R*p)/d(dw) |_0  =  - hat(R*p)       in R^(3x3)
Left:   d(R*p)/d(dw) |_0  =  - R * hat(p)     in R^(3x3)

Note: hat(R*p) = R * hat(p) * R^T — the two differ by conjugation.

7.2 d(T*p_bar)/dT — Rigid Transform of a Point ​

For T = [R, t] in SE(3), p_bar = [p; 1]:

text
Right (T' = T*Exp(d_xi)):  d(T*p_bar)/d(d_xi) |_0  =  R * [ -hat(p)     I_3 ]   R^(3x6)
Left  (T' = Exp(d_xi)*T):  d(T*p_bar)/d(d_xi) |_0  =      [ -hat(T*p)   I_3 ]   R^(3x6)

where T*p = R*p + t. The left form is used in ICP Jacobian (§9.1).

Sources: Solà 2018 Tab. 4 — https://arxiv.org/abs/1812.01537; Blanco 2010 — https://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf; https://daniel.lawrence.lu/blog/y2021m09d08/

7.3 Adjoint Ad_T and Small Adjoint ad_xi ​

Group adjoint Ad_T: se(3) -> se(3): T * Exp(xi) = Exp(Ad_T * xi) * T

For T = [R, t], twist ordering (rho, w):

text
Ad_T  =  [ R          0  ]   in R^(6x6)
          [ hat(t)*R   R  ]

Block layout changes for (w, rho) ordering — see Pitfall §11.5.

Algebra adjoint (small ad) for xi = (rho, w):

text
ad_xi  =  [ hat(w)    0     ]
           [ hat(rho)  hat(w) ]

satisfying d/dt Ad_{Exp(t*xi)} |_0 = ad_xi. For SO(3): Ad_R = R and ad_w = hat(w).

7.4 Right and Left Jacobians of SO(3) ​

The right Jacobian J_R(w) in R^(3x3) relates a perturbation in the algebra to its first-order effect under right composition:

text
Exp(w + dw) ~= Exp(w) * Exp(J_R(w) * dw)      (right BCH approximation)

Exact formula with theta = norm(w):

text
J_R(w)  =  I  -  B * hat(w)  +  C * hat(w)^2

B = (1 - cos(theta)) / theta^2
C = (theta - sin(theta)) / theta^3

For theta -> 0: J_R -> I. Inverse:

text
J_R^{-1}(w) = I  +  (1/2) * hat(w)
                 +  (1/theta^2) * (1 - theta*sin(theta)/(2*(1-cos(theta)))) * hat(w)^2

The left Jacobian J_L(w) = J_R(-w): same formula but +B instead of -B on the hat(w) term. J_L^{-1}(w) = J_R^{-1}(-w).

Both appear throughout IMU pre-integration, pose-graph linearization, and covariance propagation. Omitting J_R in IMU bias correction is Pitfall §11.3.

Sources: Solà 2018 §C — https://arxiv.org/abs/1812.01537; Eade 2017 — https://www.ethaneade.com/lie.pdf

7.5 BCH Formula — Baker-Campbell-Hausdorff ​

text
log(exp(A)*exp(B)) = A + B + (1/2)[A,B] + (1/12)([A,[A,B]] - [B,[A,B]]) + ...

First-order small-dw approximation:

text
Exp(w) * Exp(dw)  ~=  Exp(w + J_L(w)^{-1} * dw)
Exp(dw) * Exp(w)  ~=  Exp(w + J_R(w)^{-1} * dw)

For both A and B small: Exp(A)*Exp(B) ~= Exp(A+B). Used in IMU bias correction to fuse a small db_omega into the accumulated rotation (§9.3).


8. On-Manifold Optimization ​

8.1 Boxplus / Boxminus (Hertzberg et al. 2013) ​

Hertzberg et al. (arXiv 1107.1119) formalize on-manifold optimization via:

text
boxplus:   S x R^n -> S       X boxplus delta
boxminus:  S x S   -> R^n     Y boxminus X

Four axioms: (1) X boxplus 0 = X; (2) X boxplus (Y boxminus X) = Y; (3) (X boxplus d) boxminus X = d; (4) Lipschitz in d.

For SO(3) right: R boxplus dw = R * Exp(dw), R2 boxminus R1 = Log(R1^{-1} * R2). For SE(3) right: T boxplus d_xi = T * Exp(d_xi), T2 boxminus T1 = Log(T1^{-1} * T2).

8.2 On-Manifold Gauss-Newton ​

Replace vector addition with boxplus; compute J = dr/d(delta) in the local tangent space:

text
Standard:  x_{k+1}  =  x_k  -  (J^T W J)^{-1} J^T W r(x_k)
Manifold:  X_{k+1}  =  X_k  boxplus  (- (J^T W J)^{-1} J^T W r(X_k))

8.3 GTSAM LieGroup Traits ​

Every group type (SO3, Pose3 etc.) provides a traits<T> struct with: Retract(X, xi) = Exp(xi) * X (left); LocalCoordinates(X, Y) = boxminus; between(X, Y) = X^{-1} * Y; optional analytic Jacobian H pointers. BetweenFactor<Pose3> implements relative-pose residuals under left convention.

8.4 Ceres Manifold API ​

Plus(x, delta) implements boxplus; ComputeJacobian(x) returns J_GL = d(x boxplus delta)/d(delta)|_0. Chain rule: J_residual_local = J_residual_global * J_GL. QuaternionParameterization lifts a 3D tangent update to a 4D quaternion update.

Sources: Hertzberg 2013 — https://arxiv.org/abs/1107.1119; GTSAM Concepts — https://gtsam.org/notes/GTSAM-Concepts.html; Ceres — http://ceres-solver.org/nnls_modeling.html; Solà 2018 — https://arxiv.org/abs/1812.01537


9. Applications in the LiDAR Pipeline ​

9.1 ICP Linearization — Point-to-Plane Jacobian ​

Objective: E(T) = sum_i ( n_i^T * (T*p_s_i - p_t_i) )^2

Under left perturbation T' = Exp(d_xi) * T, the per-correspondence row:

text
j_i^T  =  n_i^T * [ -hat(T*p_s_i)   I_3 ]   in R^(1x6)

Under right perturbation T' = T*Exp(d_xi):

text
J_T  =  R(T) * [ -hat(p_s_i)   I_3 ]   in R^(3x6)

Stack all rows; solve normal equations or QR. This is the core of LOAM-family odometry. Jacobian follows directly from d(T*p)/dT in §7.2. Full context: Point Cloud Registration Math.

Sources: Blanco 2010 — https://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf; https://daniel.lawrence.lu/blog/y2021m09d08/

9.2 Pose-Graph Optimization — Relative SE(3) Constraints ​

Residual: r_ij = Log( Z_ij^{-1} * T_i^{-1} * T_j ) in R^6

Jacobians (right perturbation):

text
d r_ij / d d_xi_i  =  - Ad_{T_j^{-1} T_i}^{-1}  *  J_R(r_ij)^{-1}
d r_ij / d d_xi_j  =    J_R(r_ij)^{-1}

Omitting J_R^{-1} is valid only at near-zero residuals; freshly closed loops will converge slowly or incorrectly without it. Solvers: g2o (LeGO-LOAM), GTSAM iSAM2 (LIO-SAM), Ceres.

Sources: Forster 2017 — https://arxiv.org/abs/1512.02363; Blanco 2010 — https://ingmec.ual.es/~jlblanco/papers/jlblanco2010geometry3D_techrep.pdf

9.3 IMU Pre-Integration on SO(3) (Forster / Carlone 2017) ​

Integrate the rotation increment on the SO(3) manifold between keyframes:

text
DeltaR_ij  =  product_{k=i}^{j-1}  Exp(omega_k * dt)     in SO(3)

where omega_k = omega_measured_k - b_omega. First-order bias correction:

text
DeltaR_ij(b + db)  ~=  DeltaR_ij(b) * Exp(J^DeltaR_{b} * db)

J^DeltaR_{b}  =  - sum_{k=i}^{j-1}  DeltaR_{k+1,j}^T * J_R(omega_k*dt) * dt

J_R appears because integration uses right composition R_{k+1} = R_k * Exp(omega_k*dt). Covariance propagation: F_k includes d Exp(omega*dt)/d omega = J_R(omega*dt)*dt. Full derivation in 2017 TRO supplemental. See IMU Error Models and Preintegration.

Sources: Forster, Carlone, Dellaert, Scaramuzza (2017 TRO) — https://arxiv.org/abs/1512.02363; Supplementary — https://rpg.ifi.uzh.ch/docs/RSS15_Forster_Supplementary.pdf

9.4 CT-ICP — Continuous-Time Geodesic Interpolation on SE(3) ​

CT-ICP (Dellenbach et al., ICRA 2022) corrects per-point motion distortion via SE(3) geodesic interpolation (SE(3) analogue of SLERP):

text
T(tau)  =  T_0 * Exp( tau * Log(T_0^{-1} * T_1) )      tau in [0, 1]

Per-point Jacobians via chain rule:

text
d r_k / d xi_0  =  J_pointplane * d T(tau_k) / d xi_0
d r_k / d xi_1  =  J_pointplane * d T(tau_k) / d xi_1

Essential for platforms with <20 Hz LiDAR or fast manoeuvres (aircraft tow, AGVs). The same formula appears in calibration deskewing: Sensor Calibration §5.3. Full treatment: Rolling Shutter / LiDAR Deskew.

Sources: CT-ICP ICRA 2022 — https://arxiv.org/abs/2109.12979

9.5 LiDAR Bundle Adjustment ​

3D points and poses jointly optimized. Pose nodes are SE(3); residuals linearized via d(T*p)/dT from §7.2; Schur complement marginalizes points. True LiDAR BA is less mature than visual BA as of 2025; pose graph + loop closure + raw-scan re-aggregation is the current production approach.


10. Numerical Considerations ​

10.1 Small-Angle Approximations ​

Near theta = 0, Rodrigues and J_R have 0/0 forms; use Taylor series:

text
sin(theta)/theta         ~= 1 - theta^2/6 + theta^4/120
(1-cos(theta))/theta^2   ~= 1/2 - theta^2/24
(theta-sin(theta))/theta^3 ~= 1/6 - theta^2/120

Switch at |theta| < 1e-4. Reference: https://github.com/nurlanov-zh/so3_log_map.

10.2 Re-Orthogonalization ​

Rotation matrix drift: re-orthogonalize via SVD [U,S,V^T] = svd(R), R <- U*V^T. Quaternion drift: re-normalize q <- q/norm(q) after each update.

10.3 Library Implementations ​

LibraryGroupsNotes
SophusSO2/3, SE2/3, Sim3Right BoxPlus default; leftJacobian() available; Ceres-compatible
GTSAMRot3, Pose3, SO3/4Left perturbation; full factor-graph integration
manifSO2/3, SE2/3, S2Right Jacobians; auto-diff; based on Solà 2018
smoothSO3, SE3, Rn, SnRight and left Jacobians; dr_exp, dl_exp, dr_expinv
pytransform3dSO3, SE3Python; quaternion + matrix

11. Common Pitfalls ​

Six pitfalls that appear in LiDAR SLAM, calibration, and IMU fusion code and produce symptoms easy to misdiagnose as data quality problems.

11.1 Left vs Right Convention Mismatch ​

Copying a Jacobian from a paper with the opposite convention is the most common error. Symptom: optimizer converges to wrong values; factor-of-2 bias in EKFs. Diagnosis: r = Log(T_est^{-1} * T_gt) => right Jacobians; r = Log(T_gt * T_est^{-1}) => left Jacobians. Always verify with a finite-difference Jacobian check.

11.2 Skew-Matrix Sign Convention ​

Convention A (Solà/Eade/Barfoot — standard): see §3.2 matrix. Satisfies hat(w)*p = w x p. Convention B (some older texts) has opposite signs. Mixing flips every rotation Jacobian. Test: hat(e1)*e2 = e3 under A.

11.3 Missing J_R in IMU Pre-Integration ​

Correct formula: DeltaR_corrected ~= DeltaR * Exp(J^DeltaR_{b} * db). A common error sets J^DeltaR = I (i.e., Exp(db) directly). Valid only for very small omega_k * dt; introduces systematic bias for large angular rates or long integration windows.

11.4 Quaternion Antipodal Inconsistency ​

q and -q represent the same rotation. SLERP across a hemisphere boundary without sign flip produces a spurious 360° spin. Fix: if dot(q_a, q_b) < 0, negate q_b before interpolating. Same issue corrupts EKF updates with inconsistent sign.

11.5 Incorrect Adjoint Block Order ​

Block layout depends on twist ordering: (rho, w) [Solà/Blanco] places [hat(t)*R, R] in the lower row; (w, rho) [Modern Robotics] rearranges blocks. Verify numerically: T * Exp(xi) = Exp(Ad_T * xi) * T for a sample T and xi.

11.6 Log Map Singularity at theta = pi ​

The SO(3) log is not smooth at theta = pi: the axis is only defined up to sign and the derivative diverges. Pose-graph edges spanning near-180 deg require special handling (split rotation or use angle-axis directly). In scan-to-map matching after long dead-reckoning this can produce NaN or an inconsistent axis.


12. Algorithm Steps ​

12.1 Pose Optimization (Manifold-Correct) ​

  1. Store state as T in SE(3), not as six unconstrained scalars.
  2. Compute residuals via group ops: r = Log(T_meas^{-1} * T_pred).
  3. Compute Jacobians w.r.t. local tangent delta; document left or right.
  4. Solve normal equations or damped LS for delta in R^6.
  5. Retract: right T <- T * Exp(delta) or left T <- Exp(delta) * T.
  6. Re-normalize rotation if storing as matrix.
  7. Stop on tangent norm, residual change, and cost change.

12.2 Covariance Propagation ​

text
T_ac = T_ab * T_bc:
  Sigma_ac  ~=  J_ab * Sigma_ab * J_ab^T  +  J_bc * Sigma_bc * J_bc^T

Frame change only:
  Sigma_a  =  Ad_{T_ab} * Sigma_b * Ad_{T_ab}^T

Do not rotate a mean transform and leave its covariance in the old tangent frame.


13. Implementation Notes ​

  • Use library Lie operations: GTSAM Pose3, Sophus, manif, Ceres Manifold.
  • Clamp acos input to [-1, 1] before the SO(3) log map.
  • Use series expansions (§10.1) when |theta| < 1e-4.
  • Keep quaternion storage normalized; never optimize 4 components as 4 free DoF.
  • Name transforms by direction: T_map_base, not base_pose.
  • Include a point-transform sanity test for every extrinsic.
  • In code reviews: check perturbation side, tangent ordering (rho,w vs w,rho), and residual invariance under global frame changes.
  • When integrating between libraries (Sophus rotation into GTSAM factor), write an explicit convention-translation adapter and add a numerical Jacobian test.
  • Finite-difference Jacobian checks must use the same retraction as the analytic Jacobian; raw matrix addition will not test the manifold correctly.

14. Failure Modes and Diagnostics ​

SymptomLikely causeDiagnostic
Optimizer converges for small rotations but fails on U-turnsEuler-angle or small-angle approximation used outside its domainCompare analytic residuals with finite differences at 90, 170, and 179 degrees
Optimizer converges slowly near the true optimum; first step looks correctLeft/right perturbation mismatch in JacobianRun finite-difference Jacobian check using the same retraction as the solver
EKF rotation estimate has a systematic factor-of-2 biasLeft/right convention mismatch; adjoint applied on wrong sideCheck convention of every Jacobian source against the filter's retraction
Covariance ellipse points in the wrong direction after a transformMissing adjoint or wrong 6-vector orderingTransform sampled perturbations; compare empirical covariance to Ad_T * Sigma * Ad_T^T
Loop closure moves the graph in the opposite directionRelative-pose residual is invertedEvaluate a one-edge graph with a known 1 m error; inspect the first Gauss-Newton step
IMU bias correction causes drift to grow rather than shrinkJ_R accumulation omitted in pre-integration bias JacobianVerify bias-corrected DeltaR against re-integrated rotation; check for J_R = I substitution
Pose jumps when crossing a 180 deg rotationSO(3) log branch cutPlot norm(Log(R_ref^T * R)) across the sequence; inspect discontinuities near pi
SLERP trajectory has a 360 deg spin at one pointQuaternion antipodal flipCheck dot(q_a, q_b) before each SLERP; negate q_b when dot < 0
Adjoint-transformed covariance is clearly wrongAdjoint block layout mismatches twist orderingVerify numerically: sample perturbations, transform via group multiplication, compare to Ad_T prediction
Map ghost structures appear when using CT-ICPSE(3) geodesic interpolation convention wrongVerify T(0) = T_0 and T(1) = T_1 analytically; check that tau is normalized to [0,1]

15. Sources ​

Public research notes collected from public sources.