Skip to content

Seeded vision faults for stress tests; three edge-bug fixes - #34

Open
featurescript wants to merge 4 commits into
mainfrom
test/vision-stress
Open

featurescript wants to merge 4 commits into
mainfrom
test/vision-stress

Conversation

@featurescript

Copy link
Copy Markdown
Contributor

What

Seeded, deterministic camera faults for stress-testing vision code, and fixes for three edge bugs they found.

  • VisionFaults: an immutable config with a builder. It covers heavier pixel and angle noise, extra latency and jitter, dropped, repeated (same capture stamp) and out-of-order frames, missed detections, blackouts, an occluding patch, false detections, and wrong IDs or kinds. Each fault draws from its own seeded stream, so turning one fault on does not change the draws of another.
  • VisionFaultInjector: applies the content faults to CameraSightings, TagSightings and SimFrames.
  • FaultedFrameStream<T>: applies the timing faults to frames of any type, using offer and pollDue on the sim clock.
  • FakeLimelight3A.Builder.faults(VisionFaults): with no faults set, every output is unchanged. With faults on, a correctly identified tag still solves the true pose. Wrong IDs and false tags pull both botposes.
  • Docs: docs/packages/vision.md ("Faults for stress tests") and docs/packages/fakehardware.md.

Bugs found and fixed

Where Bug Regression test
FakeLimelight3A Heavy tx/ty noise could report a tag far outside the image (tx = -188 deg). FakeLimelight3AFaultsTest.heavyNoiseNeverReportsATagOutsideTheImage
SimCamera.groundPointInRobotFrame On a lens whose distortion folds over, a pixel past the fold returned a mirrored floor point. CameraLensDistortionTest.aPixelNoRayReachesHasNoGroundPoint
SimFrameRenderer Corner pixels past that fold were drawn along the mirrored ray. SimFrameRendererTest.cornersPastAFoldingLensesReachAreBlackAndUnlabelled

Known limit (documented)

FakeLimelight3A serves the newest frame delivered in a loop. A repeated frame is therefore invisible to it. An out-of-order frame shows only when the camera's frame rate is below the loop rate.

Verified

  • ./gradlew test, counted from the JUnit XML:
    • :SimLoop:testDebugUnitTest: 1277 tests, 0 failures. That is 26 new tests; the base count, derived, is 1251.
    • :SimLoop:desktop:test: 6 tests, 0 failures.
    • examples: 2 tests, 0 failures.
  • ./gradlew :SimLoop:docsSite passes.
  • tools/leak-gate/leak-gate.sh passes: 10 rules, 413 files, no violations.

From Horizon (FTC 36596).

featurescript and others added 4 commits October 31, 2026 16:40
…ound

VisionFaults configures injectable, seeded, deterministic camera faults:
heavier pixel and angle noise, extra latency and jitter, dropped,
repeated and out-of-order frames, missed detections, blackouts, an
occluding patch, false detections and wrong IDs or kinds. Each fault
draws from its own seeded stream, so turning one on does not change
another's draws. VisionFaultInjector applies the content faults to
sightings, tag sightings and rendered frames; FaultedFrameStream applies
the timing faults to frames of any type. FakeLimelight3A takes them via
Builder.faults(VisionFaults); with none set, every output is unchanged.

Bugs the faults exposed, each with a regression test:

- FakeLimelight3A: heavy tx/ty noise could report a tag far outside the
  image (tx of -188 degrees). A noisy tag whose centre leaves the image is
  now dropped (heavyNoiseNeverReportsATagOutsideTheImage).
- SimCamera.groundPointInRobotFrame: on a lens whose distortion folds
  over, a pixel past the fold returned a mirrored floor point. It now
  returns null when the undistorted ray does not project back to the
  pixel (aPixelNoRayReachesHasNoGroundPoint).
- SimFrameRenderer: corner pixels past such a fold were drawn along the
  mirrored ray. They are now black and unlabelled
  (cornersPastAFoldingLensesReachAreBlackAndUnlabelled).
…and empty Limelight results

reorderFrames(1.0) never delivers a frame: documented in VisionFaults.Builder#reorderFrames and FaultedFrameStream, pinned by a test.
With no faults set, a frame whose tags the noise pushed out of the image returned before its five pose
draws, so every later frame's noise moved, tags well inside the image included. The frame now makes those
draws and discards them. A test runs one seed through a narrow and a wide lens and checks the tag angles
and MegaTag1 agree frame by frame; without the fix it fails at frame 9.

Two doc sentences said more than the code does: turning on misses or drops changes which sightings get
wrong ids and which frames are held back, and a repeated frame can hide an out-of-order one released on
the same tick.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants