mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-06-21 22:11:12 +00:00
4fdf1968af
Batch 5a of the cycle-1 doc sync. For each of the four foundation helpers (imu_preintegrator, se3_utils, lightglue_runtime, wgs_converter): - Append "Cycle-1 operational reality" section to the existing common-helpers/<NN>_*.md, documenting what the shipped implementation actually exposes vs. the design- intent sketch (interfaces, exception types, public constants, AZ-task lineage). Specific cycle-1 facts captured per helper: - imu_preintegrator (AZ-276): make_imu_preintegrator factory, BMI088-class noise defaults, single ImuPreintegrationError exception, actual return type is PreintegratedCombinedMeasurements (consumer builds the CombinedImuFactor), destructive reset_with_bias semantics, first-sample-not-integrated dt=0 handling. - se3_utils (AZ-277): SE3 = gtsam.Pose3 re-export, Se3InvalidMatrixError, strict caller-orthogonalisation invariant, _DEFAULT_ROT_ATOL=1e-6 and small-angle Taylor cutoff for exp_map, is_valid_rotation predicate, strict dtype=float64 everywhere. - lightglue_runtime (AZ-278 / R14 fix): EngineHandle Protocol-typed constructor, LightGlueRuntimeError + LightGlueConcurrentAccessError, non-blocking concurrent- access guard (raises rather than serialises), match_batch equal-length precondition, composition-root single-instance into C2.5 + C3. - wgs_converter (AZ-279 + AZ-490): WEB_MERCATOR_MAX_LAT_DEG and MAX_ZOOM constants, WgsConversionError, ECEF arrays are ndarray(3,) float64, new horizontal_distance_m method (AZ-490 takeoff-origin bounded-delta gate), slippy-map tile math hand-rolled to match satellite-provider on-disk layout. Two contract files (imu_preintegrator.md and wgs_converter.md) need follow-up minor revisions to match shipped surface; queued for the next contracts-folder sweep, noted inline in each helper's new section. Also refresh D-CROSS-CVE-1 opencv-pin leftover replay timestamp (8-min debounce — gtsam upstream state cannot change in that window). Bumps _docs/_autodev_state.md sub_step detail. Co-authored-by: Cursor <cursoragent@cursor.com>
3.6 KiB
3.6 KiB
Common Helper — SE3Utils
Purpose
SE(3) ↔ pose-matrix conversion and Lie-algebra exponential/logarithm. Used wherever a 4×4 transformation matrix needs to be converted to/from a 6-vector, or where Jacobians of SE(3) operations are needed for covariance recovery.
Used By
- C1 — Visual / Visual-Inertial Odometry (relative pose updates).
- C4 — Pose Estimation (
solvePnPRansac4×4 → SE(3) for the GTSAM factor). - C5 — State Estimator (iSAM2 graph keys + smoothed history).
Interface (sketch)
def matrix_to_se3(T_4x4: ndarray) -> SE3
def se3_to_matrix(pose: SE3) -> ndarray
def exp_map(xi: Vector6) -> SE3
def log_map(pose: SE3) -> Vector6
def adjoint(pose: SE3) -> Matrix6
Implementation Notes
- Backed by GTSAM
Pose3+ Eigen Lie-algebra primitives where available; otherwise pure numpy. - All-positive-determinant rotation guarantee — caller is responsible for orthogonalising input rotation matrices before calling
matrix_to_se3.
Caveats
- Library-grade Lie-algebra functions exist in
manifpyandpylie; we use GTSAM's primitives directly to avoid pulling in a second math library. If a future strategy needs richer manifold ops, evaluatemanifpythen.
Cycle-1 operational reality
The shipped surface in src/gps_denied_onboard/helpers/se3_utils.py (AZ-277) extends the sketch above; this section is the authoritative inventory of what cycle-1 consumers actually see.
- Type alias —
SE3 = gtsam.Pose3is re-exported by the helper. Consumers MUST importSE3fromhelpers.se3_utilsand nevergtsam.Pose3directly (keeps the Lie-algebra backend swappable without touching C1/C4/C5). Se3InvalidMatrixError— single public exception type. Raised on (a) wrong array shape, (b)dtype != float64, (c) bottom row !=[0, 0, 0, 1], (d) rotation drift‖R^TR − I‖_F > atol, (e) negative-determinant rotation (mirror), (f) non-ndarray inputs.matrix_to_se3andexp_mapraise this;se3_to_matrix,log_map,adjointare no-throw on the typed input.- Strict caller-orthogonalisation invariant — the helper does NOT silently re-orthogonalise. AC-7 /
matrix_to_se3always validates‖R^TR − I‖_F ≤ atoland rejects drift. Callers (C4 in particular, sincesolvePnPRansacoutput is not orthogonal to numerical precision) MUST run their own orthogonalisation (cv2.Rodriguesround-trip orscipy.linalg.polar) before callingmatrix_to_se3. Default tolerance:_DEFAULT_ROT_ATOL = 1e-6; callers can pass a looseratolfor relaxed contexts (none in cycle-1). exp_mapnear-identity fallback — twist vectors with‖xi‖ < _SMALL_ANGLE_THRESHOLD = 1e-10return the identitySE3()instead of delegating to GTSAM'sPose3.Expmap. This guards against thesin(theta)/thetaunder-flow that surfaces when iSAM2's relinearisation produces a near-identity twist after a converged step.is_valid_rotation(R_3x3, *, atol=1e-6)— predicate (no exception) for "is this matrix safe to feed tomatrix_to_se3?". Returns False for non-ndarray, wrong shape, wrong dtype, orthogonality drift > atol, or negative determinant. Cycle-1 consumers: C4'sMarginalsAdaptershort-circuit (opencv_gtsam_marginals.pyfrom AZ-358) and the contract test for AC-7.dtype=float64everywhere — every public function enforcesfloat64.np.ndarrayreturned fromse3_to_matrix,log_map,adjointisnp.ascontiguousarray(..., dtype=np.float64)so callers can pass it through to GTSAM/Eigen without a copy.
Cycle-1 task lineage
- AZ-277 — initial helper, contract producer.
- No cycle-1 follow-up tasks touched this helper.