Skip to content

rotation.hpp

ProsRotation — IRotation over pros::Rotation (chunk R1a): the tracking-wheel pods behind the HAL.

This header declares 1 type (4 members).

Extracted from include/shulib/hal/pros/rotation.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.

Contents

class ProsRotation

class ProsRotation final : public IRotation

IRotation over pros::Rotation — a tracking-wheel pod behind the HAL. It converts the sensor's int32 CENTIDEGREES to canonical radians and rad/s exactly once, at this edge, and screens the PROS_ERR sentinel by HOLDING THE LAST GOOD VALUE. That screen is the whole substance of this class: PROS_ERR is in-band for an int32 centidegree reading (INT32_MAX is ~59652 revolutions — finite, just unreachable in a match), and a faulted pod that reported zero would read as "the robot stopped", which is exactly the dead-encoder runaway the loop's cross-check exists to catch; a frozen value is what that cross-check is designed to see. ONE gap, and it is the boot case: the last-good caches are SEEDED TO ZERO and there is no have-a-value flag, so a pod that faults on its very FIRST read — unplugged, or not yet enumerated — publishes 0 rad and 0 rad/s, the exact reading the screen otherwise prevents. faultedReads() is the only way to tell that apart from a genuinely stationary robot, so check it before trusting a zero. Reversal is NOT applied here — PROS applies it when the sensor is constructed on a negative port, once, so this adapter never negates. There is deliberately no reset: odometry owns its own zero, and re-zeroing the device mid-run would step every consumer at the same instant.

class, declared at include/shulib/hal/pros/rotation.hpp:72.

ProsRotation::ProsRotation

explicit ProsRotation(std::int8_t port)

port: 1..21, NEGATIVE to reverse (PROS applies the reversal — once).

function, declared at include/shulib/hal/pros/rotation.hpp:75.

ProsRotation::position

[[nodiscard]] units::AngleDim position() const override

Cumulative radians (never wrapped). Sentinel-screened to last-good (T7).

function, declared at include/shulib/hal/pros/rotation.hpp:78.

ProsRotation::velocity

[[nodiscard]] units::AngularVelocity velocity() const override

Shaft angular velocity in rad/s, from the sensor's centidegrees/s. Sentinel-screened like position(): a faulted read returns the last good rate — but note the seed, lastVelocity_ starts at 0 rad/s, so a pod that has never once answered reports exactly the "robot stopped" rate the screen exists to suppress; check faultedReads() before trusting a zero. Both readers are const and yet ADVANCE state — the last-good caches and faultedReads() — because the screen is part of the read, not commanded state; two calls in a tick may therefore differ.

function, declared at include/shulib/hal/pros/rotation.hpp:95.

ProsRotation::faultedReads

[[nodiscard]] int faultedReads() const noexcept

How many reads were screened to last-good (T7 observability).

function, declared at include/shulib/hal/pros/rotation.hpp:106.

Design commentary, from the header

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 — 39 lines
 ProsRotation — IRotation over pros::Rotation (chunk R1a): the tracking-wheel
 pods behind the HAL.

 BINDS:
  * get_position() [int32 centidegrees, cumulative] → position()
    (rotationCentidegToCanonical — HA-11/HA-16)
  * get_velocity() [int32 centidegrees/s] → velocity()
    (rotationCentidegPerSecToCanonical — HA-105)

 REVERSAL — "exactly once" (rotation.hpp:4-6): a NEGATIVE ctor port reverses
 the sensor, applied by PROS itself (vendored rotation.hpp:46-47). This
 adapter therefore does NOT negate, ever — sign lives in the port number the
 robot config states, one owner, one application.

 SENTINELS (T7): IRotation has no validity channel. PROS_ERR (= INT32_MAX)
 is IN-BAND for an int32 centidegree reading — 2147483647 centideg is ~59652
 revolutions, unreachable in a match (HA-11's arithmetic), so it is screened
 as a sentinel HERE: hold the last good value, never propagate, never zero
 (a zeroed tracking wheel reads as "the robot stopped" — the exact
 dead-encoder runaway the loop's ODO_STUCK cross-check exists to catch; a
 frozen last-good value is what that cross-check is DESIGNED to see).
 faultedReads() exposes the screen count; raising a fault stays with the
 loop layer (health_monitor.hpp: raising is policy, hal/ is below diag/).

 SEED CAVEAT — an OPEN DEFECT, recorded rather than papered over: the
 last-good caches start at 0 and there is no have-a-value flag, so "never
 zero" only holds AFTER the first successful read. A pod that faults from
 the very first tick (unplugged, or not yet enumerated at boot) publishes
 0 rad / 0 rad/s — the precise reading the screen above claims to prevent,
 and the one the ODO_STUCK cross-check reads as a stopped robot. The tell
 is faultedReads() > 0 alongside a zero output. A validity flag (or a
 NaN/sentinel seed) is the fix; it is not applied here.

 DELIBERATELY NOT here: no reset()/set_position() calls — odometry owns its
 own zero (TrackingWheel reads deltas); re-zeroing the device mid-run would
 step every consumer at once.

 HA register: HA-11, HA-16, HA-105 (docs/hardware-assumptions.md).

Last updated 2026-08-15 — published from the main release branch, commit fa545ff. This site tracks releases, so between them it can lag the repository — that lag is deliberate, and it is what keeps the development log off the public site. For the current state of the code, see the repository.