ICorrector — the WRITE seam: one source of ABSOLUTE position fixes (V5 GPS, AprilTag PnP, LIDAR scan-match).
This header declares 2 types (10 members).
Extracted from include/shulib/localization/i_corrector.hpp — this page is that header's documentation, reformatted, so it cannot disagree with the code. Prose about how to think about the API lives in the user guide; worked recipes live in the cookbook; this page is the complete, mechanical list of what exists.
class ICorrectorOne source of ABSOLUTE field-pose fixes — V5 GPS, AprilTag PnP, LIDAR scan-match. PULL, not push: the Localizer calls propose() once per tick with its odom-predicted pose, and nothing here ever writes into the estimator. An implementation owns ALL of its own mess — HAL access, frame/lever-arm/PnP reduction, latency, staleness, gating — so the Localizer stays geometry-free and the trust math stays in one place. Pure with respect to its injected HAL handle, which is what makes a corrector host-testable against a fake.
class, declared at include/shulib/localization/i_corrector.hpp:25.
virtual ~ICorrector() = defaultPolymorphic-base boilerplate: the destructor is virtual so a concrete corrector held as ICorrector&/ICorrector* destroys correctly, and DECLARING it is what suppresses the implicit copy/move, which are re-defaulted below. The base carries no state of its own. Ownership stays with the CALLER either way: the Localizer takes a NON-OWNING span<ICorrector* const> (at most kMaxCorrectors, each checked non-null at construction), so every corrector must outlive the Localizer it was handed to.
function, declared at include/shulib/localization/i_corrector.hpp:33.
ICorrector() = defaultCovered by the comment on ~ICorrector — one comment documents this run of special members.
function, declared at include/shulib/localization/i_corrector.hpp:34.
ICorrector(const ICorrector&) = defaultCovered by the comment on ~ICorrector — one comment documents this run of special members.
function, declared at include/shulib/localization/i_corrector.hpp:35.
ICorrector(ICorrector&&) = defaultCovered by the comment on ~ICorrector — one comment documents this run of special members.
function, declared at include/shulib/localization/i_corrector.hpp:36.
ICorrector& operator=(const ICorrector&) = defaultCovered by the comment on ~ICorrector — one comment documents this run of special members.
function, declared at include/shulib/localization/i_corrector.hpp:37.
ICorrector& operator=(ICorrector&&) = defaultCovered by the comment on ~ICorrector — one comment documents this run of special members.
function, declared at include/shulib/localization/i_corrector.hpp:38.
[[nodiscard]] virtual CorrectionProposal propose(const math::Pose2d& predicted, units::Time dt) = 0Propose an absolute fix given the odom-predicted pose this tick. MUST be non-throwing and MUST return {valid=false} when it has no usable fix (off-strip GPS, no tag) — never a zero-confidence pull. dt is the tick duration (seconds).
function, declared at include/shulib/localization/i_corrector.hpp:43.
[[nodiscard]] virtual const char* name() const noexcept = 0Stable id for telemetry / per-source dead-reckon accounting.
function, declared at include/shulib/localization/i_corrector.hpp:47.
class NullCorrector final : public ICorrectorThe M2 placeholder: a registered source that never has a fix. Lets the fusion pipeline run and be tested end-to-end (it just always dead-reckons) before any real corrector exists, and keeps the seam visibly wired for telemetry. M3 replaces it with GpsCorrector/AprilTagCorrector.
class, declared at include/shulib/localization/i_corrector.hpp:53.
[[nodiscard]] CorrectionProposal propose(const math::Pose2d& /*predicted*/, units::Time /*dt*/) overrideAlways declines — a default-constructed proposal, so valid == false and selfAudit.reason == None. Both arguments are ignored, and the estimator dead-reckons this tick exactly as it would with no corrector registered at all.
function, declared at include/shulib/localization/i_corrector.hpp:58.
[[nodiscard]] const char* name() const noexcept override"null". Because this corrector never proposes and never self-audits, the Localizer never reads it — the id exists so the seam is visibly wired, not to label a record.
function, declared at include/shulib/localization/i_corrector.hpp:64.
The header opens with the reasoning behind these shapes. It is reproduced here in full because a reference that only lists signatures teaches nobody why.
The header’s own reasoning — 10 lines
ICorrector — the WRITE seam: one source of ABSOLUTE position fixes (V5 GPS, AprilTag PnP, LIDAR
scan-match) (master plan §6/§8). It is PULL, not push: the Localizer calls propose() each tick
with the odom-PREDICTED pose and the tick dt, and the corrector returns a CorrectionProposal
(or {valid=false}). The corrector owns ALL of its mess — HAL access, frame/lever-arm/PnP
reduction, latency, staleness, gating — so the Localizer stays geometry-free and the trust math
stays in one place. Pure w.r.t. its injected HAL handle; host-testable with a fake.
At M2 the registered list is empty or holds only NullCorrector (below); GpsCorrector /
AprilTagCorrector are concrete at M3 behind THIS exact signature, with no caller change.