Skip to content

Solid-state LiDAR calibration

Calibrex treats a solid-state LiDAR capture as more than an unordered point cloud. A result records the acquisition semantics that affect calibration:

  • architecture and scan_pattern (for example, non_repetitive);
  • the source field, reference, and unit for per-point capture time;
  • the integration window;
  • the source and representation of internal calibration data;
  • the temperature condition and whether temperature compensation was applied.

The contract is ROS-independent. ROS 1/ROS 2, MCAP, Livox PCD, and external tool adapters may populate it, but src/calibrex does not import ROS or GPL code. A configured profile is copied into result.yaml under solid_state with config/dataset SHA-256 provenance. The standalone artifact contract is available as schemas/solid_state_context.schema.json and through:

calibrex schema solid-state-context --output schemas/solid_state_context.schema.json
calibrex validate outputs/run/result.yaml

Configuration

The existing point_time_field remains the adapter mapping from a PointCloud2 field. solid_state.point_time_* describes its semantics; the loader checks that both declarations agree and mirrors the field into the profile.

sensors:
  livox_avia:
    type: lidar
    model: livox_avia
    topic: /livox/lidar
    point_time_field: offset_time
    solid_state:
      architecture: solid_state
      scan_pattern: non_repetitive
      point_time_field: offset_time
      point_time_reference: message_stamp
      point_time_unit: seconds
      point_time_available: true
      integration_window_s: 0.005
      intrinsic_calibration:
        source: manufacturer
        model: manufacturer_native
        artifact_path: calibration/livox_avia_intrinsics.yaml
      temperature:
        sensor_c: 34.2
        source: sensor_telemetry

evaluation:
  solid_state:
    enabled: true
    require_point_time: true
    require_temperature: false
    require_independent_holdout: true
    min_temperature_span_c: 5.0
    min_distance_span_m: 5.0
    min_fov_azimuth_deg: 20.0
    min_fov_elevation_deg: 5.0
    distance_bins_m: [0.0, 10.0, 20.0, 40.0, 80.0]
    min_points_per_distance_bin: 100
    min_known_bad_detectable_fraction: 0.5

Missing time or temperature is a WARN by default. Set the corresponding require_* option when a motion-compensated or temperature-transfer claim is not acceptable without that metadata.

Evidence protocol

The solid-state metrics are deliberately separated from accuracy claims:

  1. Existing point-to-plane metrics score a train/source map against a holdout query and record whether the holdout is independent.
  2. Existing Livox controls perturb roll, pitch, yaw, and translation by known amounts. Their detectable fraction is surfaced as solid_state_known_bad_detectable_fraction in addition to the detailed lidar_pair_known_bad_* metrics.
  3. Livox PCD diagnostics report sampled range, azimuth/elevation FOV, and distance-bin support. These are coverage/stratification metrics, not a replacement for independent spatial accuracy.
  4. ROS 1/ROS 2 online replay records capture-window timestamps and, when deskew is actually applied from decoded per-point offsets, marks the capture window's point-time observation as available. A PCD file index is never promoted to a physical sensor timestamp.
  5. ROS 1 inspection samples report range, azimuth/elevation FOV, distance-bin support, and decoded point-time bounds for each supported LiDAR topic. The TIERS native adapter uses a temporal source-map boundary and later target windows for its offline holdout; the online adapter records the same boundary decision in provenance.

The public Horizon-Horizon PCD sample is intentionally limited: it is a single source/target pair, so its point-to-plane result is useful geometry evidence but not independent temporal validation. For a publishable claim, use multiple temporally separated windows or a held-out recording and set require_independent_holdout: true.

For Livox ROS 1 data, timebase is a sensor clock whose relationship to ROS/VRPN time must be checked for the recording. Calibrex does not silently pretend that this raw value is a ROS epoch. During ROS 1 replay the bag-record timestamp is the replay-clock authority and the decoded offset_time is added to it: capture_ns = bag_record_timestamp_ns + offset_time_ns. The raw Livox timebase is retained for diagnostics, and provenance records the fitted timebase-to-bag mapping residual and a stable/unstable status. If no stable mapping can be established, pose interpolation is rejected or the result remains non-independent; this is the correct evidence outcome until a documented clock mapping is supplied.

Ground-truth solver gate

Public sensor-pair recordings generally do not include independently surveyed extrinsics or an absolute clock reference. Keep that limitation separate from the solver-mechanics check by running the deterministic synthetic benchmark:

python tools/run_solid_state_synthetic_benchmark.py \
  --output outputs/solid_state_synthetic_benchmark_v01.yaml \
  --markdown-output outputs/solid_state_synthetic_benchmark_v01.md \
  --enforce
calibrex validate outputs/solid_state_synthetic_benchmark_v01.yaml \
  --kind solid-state-synthetic-benchmark

The reference case uses a known three-plane motion scene, a perturbed initial extrinsic, and a +30 ms clock offset. The checked gate recovers the reference to below 1e-12 numerical error in this deterministic fixture and rejects a fixed-clock known-bad control with a 30 ms time error. Its output records the truth, estimate, parameter errors, thresholds, and generator SHA-256 in provenance. This is a correctness gate for the implementation, not evidence of accuracy on a physical sensor pair; absolute real-data claims still require independent extrinsic/clock ground truth.

The checked artifact is YAML with a compact Markdown report.

Public-data-only evaluation

When new hardware data cannot be collected, use the public benchmark as the primary gate. The public-data runbook freezes paired capture windows, temporal holdouts, solver budgets, sampling seeds, and known-bad/control semantics across AgRob, TIERS, and AIST GLIM:

calibrex validate \
  examples/public_datasets/solid_state_cross_dataset_benchmark.yaml \
  --kind solid-state-cross-dataset-benchmark-config
python tools/run_solid_state_cross_dataset_benchmark.py \
  examples/public_datasets/solid_state_cross_dataset_benchmark_v03.yaml \
  --output outputs/solid_state_cross_dataset_benchmark_v03.yaml \
  --markdown-output outputs/solid_state_cross_dataset_benchmark_v03.md

This produces ground-truth-free temporal-holdout evidence and comparative failure/known-bad evidence. It does not produce an absolute extrinsic or clock accuracy claim. The checked v0.3 report scores 27 paired replicates: adaptive wins 23/27 overall, while the AgRob real-pair subset remains mixed at 5/9. See the full v0.3 report for per-dataset intervals and limitations.

Optional physical ground-truth packet (future)

The independent metrology packet is retained as a future extension only. It is not required for the public-data-only project and must remain planned or inconclusive when surveyed extrinsic/clock references are unavailable. If a future user obtains those measurements, the physical collection runbook describes the schema-valid packet and integrity gate:

python tools/run_solid_state_metrology_evaluation.py \
  --prepare-collection-plan \
  --plan-sessions 4 \
  --plan-remounts 2 \
  --output outputs/solid-state-metrology/plan.yaml \
  --markdown-output outputs/solid-state-metrology/plan.md

The generated packet is a collection plan, not a physical result. After editing it with the measured reference and solver estimates, rerun it with --input ... --enforce. Relative evidence paths are resolved against the input packet directory. --enforce recomputes each declared SHA-256 and verifies the source exists; --verify-sources runs the same integrity report without requiring a numerical PASS. A physical PASS requires all of the following:

  • an independent extrinsic and clock reference for every usable session, with declared method, uncertainty, source digests, and evidence_level: independently_measured;
  • at least three usable captures across at least two remounts;
  • a held-out downstream metric that was not consumed by the solver and has a predeclared threshold.
  • every global/session reference, usable capture, and estimate source path/digest pair passes the integrity check, with unique IDs and valid estimate-to-session links. Remounted sessions are compared against their own measured reference rather than one global transform.

Missing evidence remains planned or inconclusive; it is never converted to a PASS by the tool. A missing, mismatched, or structurally inconsistent source is surfaced in evidence_integrity and blocks PASS. The checked packet is therefore an intentionally empty YAML template with a Markdown report, not a physical accuracy claim.

Livox workflow

The checked-in workflow is:

calibrex demo livox-evidence \
  --output-dir outputs/livox_horizon_horizon_pcd_sample
calibrex validate \
  outputs/livox_horizon_horizon_pcd_sample/result.yaml

The configuration is examples/public_datasets/livox_horizon_horizon_pcd_sample/config.yaml. It declares the Livox non-repetitive pattern and explicitly leaves unavailable point-time and temperature observations unknown rather than inferring them from PCD file order.

Adapter and license boundary

The core implementation is limited to typed metadata, native evidence, and adapters. GPL implementations must remain subprocess/reference adapters; they are not imported into src/calibrex. The first-party and permissive references audited for integration are:

Research references

The implementation choices are informed by, but do not reproduce, these methods: