Fix periodic coverage-map freeze on large fields (#34)#63
Merged
Conversation
The web UI froze for ~1s and jumped the tractor forward whenever the coverage grid changed, worsening with field size. Root causes + fixes, all in the coverage streaming path: - Full-coverage snapshot walked the ENTIRE field bounding box at 0.1m (O(field area), ~130ms on a 40ha field even with 0.63ha painted) on the 10Hz broadcast loop, stalling pose/tick frames. Now enumerates only painted display cells via GetPaintedDisplayCells (O(worked area), ~9ms) and builds off the broadcast loop so pose never stalls. - Client drained a full snapshot in one render frame (unbounded per-cell drawRect). Now time-sliced (COV_DRAIN_BUDGET/frame). - Bounds expansion re-sent the entire accumulated coverage. The added ground is empty, so the host now announces the new grid (reset=false) and the client re-anchors its existing coverage into the larger grid (exact integer-offset pixel copy) — zero rescan, zero resend. A new CoverageInit `reset` flag distinguishes grow (re-anchor) from new field / reload / cell-size change (tear down + rebuild). - The first no-boundary expansion crosses the 0.1->0.2m resolution band (rebuild path). GetPaintedDisplayCells read the display buffer lock-free and could catch it cleared-but-not-yet-resampled, yielding an empty snapshot that permanently dropped pre-expansion coverage. Now materialized under _coverageLock (alpha folded in) for a consistent read. - Pre-existing edge-ribbon bug surfaced by the no-boundary test path: the auto-init SetFieldBounds->ClearEdges wiped an active section's ribbon while it stayed on, so StartMapping never re-opened it and the crisp worked-area perimeter silently never rendered. AccumulateEdge now re-opens a ribbon on a miss (self-heals). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Fixes #34 — the web UI froze for ~1s and jumped the tractor forward periodically once sections were enabled, worse the larger the field. Device-verified on the internal simulator (no-boundary + boundary paths) through multiple bounds expansions.
Root cause
Coverage streaming is normally push-based (the host records every cell it paints and streams incremental deltas — cheap). The freeze came entirely from the full-state rebuild, which fired on grid changes and dumbly scanned the whole field.
Fixes (all in the coverage streaming path)
GetPaintedDisplayCellswalks only the tracked painted bounding box of the display buffer (measured ~130ms → ~9ms on a 40ha field with 0.63ha worked), and it builds off the 10Hz broadcast loop so pose/tick frames never stall.COV_DRAIN_BUDGET/frame) so a one-time seed paints over a few frames instead of blocking one.reset=false) and the client re-anchors its existing coverage into the larger grid via an exact integer-offset pixel copy. A newCoverageInit.resetflag separates grow (re-anchor) from new-field/reload/cell-size-change (tear down + rebuild)._coverageLock.ClearEdgeswiped an active section's ribbon while it stayed on, so the crisp worked-area perimeter silently never rendered.AccumulateEdgenow re-opens a ribbon on a miss. Logically separable from the freeze fix — flag if you'd prefer it split out.Testing
🤖 Generated with Claude Code