robot.heading_drift_watchdog ============================ .. py:module:: robot.heading_drift_watchdog .. autoapi-nested-parse:: Heading-drift watchdog: warn when the chassis rotates while nothing drives. Between motion steps (servo-only phases, grabs) no controller ticks the drive, so external forces — an arm pushing off a game piece, a collision — can rotate the chassis on low-friction mecanum wheels without anything noticing. Later motion steps then inherit the heading error, which shows up as "cursed" snap corrections that are expensive to trace back. This watchdog runs on its OWN daemon thread (never on the asyncio motion loop, mirroring ``ContinuousLocalizationFusion``): it polls the firmware IMU heading and, while the ``"drive"`` resource is NOT held by any step, accumulates the rotation since the drive was released. Crossing the threshold logs a WARNING with the drifted angle, then re-arms so continued rotation warns again. Purely diagnostic — it never commands anything. Attributes ---------- .. autoapisummary:: robot.heading_drift_watchdog.DRIFT_WARN_RAD robot.heading_drift_watchdog.POLL_PERIOD_S Classes ------- .. autoapisummary:: robot.heading_drift_watchdog.HeadingDriftWatchdog Functions --------- .. autoapisummary:: robot.heading_drift_watchdog.start_heading_drift_watchdog Module Contents --------------- .. py:data:: DRIFT_WARN_RAD :type: float :value: 0.052 .. py:data:: POLL_PERIOD_S :type: float :value: 0.05 .. py:class:: HeadingDriftWatchdog(robot: raccoon.robot.api.GenericRobot, imu, threshold_rad: float = DRIFT_WARN_RAD) .. py:method:: start() -> None .. py:method:: stop() -> None .. py:function:: start_heading_drift_watchdog(robot: raccoon.robot.api.GenericRobot) -> HeadingDriftWatchdog | None Start the watchdog, or return ``None`` when no IMU is available.