Broadcast the control loop's own health with STATUS - #9
Closed
Jepson2k wants to merge 1 commit into
Closed
Conversation
Whether the loop is keeping up is a question a display asks continuously, and answering it through the LOOP_STATS query means polling for something the controller already knows every tick. The period tail and the deadline-miss count now ride the status broadcast instead, appended at the tail so a decoder that stops at the fields it knows is unaffected. The status cache re-encodes on change, and these two change slowly: the percentile is recomputed once per stats window and overruns are rare, so the payload turns over about as often as the window does rather than every tick. StatusBuffer also declares drive_health, which PAROL6 never fills: the drivers report per-joint error FLAGS over the serial link, not analog temperature or current registers, and flags are a fault surface rather than a trend. An empty dict is the honest answer, and it is what tells a consumer "this backend has no such sensor" rather than "all zero". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GdLL4oE6RejS9yPeSkQXpF
Jepson2k
force-pushed
the
claude/par6-backend-setup-q9l7bx
branch
from
September 4, 2026 00:43
e424955 to
426b1d6
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Whether the control loop is keeping up is a question a display asks continuously, and today the only way to answer it is the
LOOP_STATSquery — polling for something the controller already knows on every tick. This puts the two numbers that actually say a loop is unwell on the status broadcast instead.What changes
pack_statusgains a trailingloop_healthelement:(p99_period_s, overruns). It appends at the tail, so a decoder that stops at the fields it knows is unaffected, anddecode_status_bin_intofills it only when present.StatusBuffergainsloop_healthanddrive_healthdicts, matching thewaldoctlstatus contract. Empty from producers that predate the fields, which is how a consumer tells "loop healthy" from "loop not reported".StatusCachecarries the two values and includes them in its change detection.Why only the tail and the miss count
The mean, the rest of the distribution and the boot constants (target rate, scheduling policy) stay in
LOOP_STATS: a display reads those once, and putting them on every frame would be bloat. The percentile is what breaks a control loop, and the overrun count is what proves it already did.Why
drive_healthis declared but never filledPAROL6's drivers report per-joint error flags over the serial link (
Temperature_error_in,Position_error_in), not analog temperature, current or supply registers. An empty dict is the honest answer for a backend with no such sensor, and it is what tells a consumer "not reported" rather than "all zero". Nothing here invents a reading.Cache cost
The status payload is re-encoded only when something changed. The percentile is recomputed once per stats window and overruns are rare, so this turns the payload over about as often as the window does rather than on every tick.
Tests
tests/integration/test_loop_health_broadcast.pywaits for a frame carrying a warmed-up percentile and checks it against whatloop_stats()answers about the same loop, so a stale or invented copy fails it.Full suite: 275 passed, 1 failed, 8 skipped. The failure is
tests/unit/test_pdeathsig.py::test_child_exits_on_parent_death, which fails identically on this branch's base in the same container (it needs a parent-death signal this environment does not deliver).ruff checkandruff formatare clean.ty check parol6/reports the same 7 diagnostics as the base — all pre-existing overrides that lag newerwaldoctlclient signatures.🤖 Generated with Claude Code
https://claude.ai/code/session_01GdLL4oE6RejS9yPeSkQXpF
Generated by Claude Code