using RobotNet10.RobotApp.SLAM.Cartographer.Geometry; using RobotNet10.RobotApp.SLAM.Cartographer.Helpers; using RobotNet10.Shared.Geometry; namespace RobotNet10.RobotApp.SLAM.Cartographer; /// /// Immutable snapshot of robot pose with confidence metrics and drift detection status. /// Reference type enables lock-free atomic swap via volatile field. /// public sealed class PoseSnapshot { public static readonly PoseSnapshot Empty = new(); /// Pose in GLOBAL (map) frame. public Pose Pose { get; } /// Pose covariance (Localizing mode only). public Matrix3x3? Covariance { get; } /// /// Confidence score: /// - ScanMapping: PoseConfidence from scan matcher /// - Localizing: LocalizationScore from covariance/constraints/scanMatchScore /// - Relocalizing: MCL reliability /// public double? Score { get; } /// /// Scan match score (PoseConfidence) from Cartographer. /// This is the most direct indicator of how well the current scan matches the map. /// Available in both ScanMapping and Localizing states. /// public double? ScanMatchScore { get; } /// /// Drift detection status (Localizing mode only). /// Indicates whether the robot may be experiencing map drift. /// public DriftDetector.DriftStatus DriftStatus { get; } /// Timestamp when this snapshot was created. public long TimestampTicks { get; } public PoseSnapshot() { Pose = new Pose(); DriftStatus = DriftDetector.DriftStatus.Stable; TimestampTicks = DateTime.UtcNow.Ticks; } public PoseSnapshot(Pose pose, Matrix3x3? covariance = null, double? score = null) { Pose = pose; Covariance = covariance; Score = score; DriftStatus = DriftDetector.DriftStatus.Stable; TimestampTicks = DateTime.UtcNow.Ticks; } /// /// Creates a PoseSnapshot with full drift detection information. /// public PoseSnapshot( Pose pose, Matrix3x3? covariance, double? score, double? scanMatchScore, DriftDetector.DriftStatus driftStatus) { Pose = pose; Covariance = covariance; Score = score; ScanMatchScore = scanMatchScore; DriftStatus = driftStatus; TimestampTicks = DateTime.UtcNow.Ticks; } }