Vision Fallbacks and Confidence
Make autonomous robust when vision is uncertain.
Make autonomous robust when vision is uncertain.
In this lesson, you will:
Vision should not be all-or-nothing. The robot needs a plan for low confidence, no detections, or conflicting readings.
A safe fallback is part of the vision system. It tells the robot what to do when the camera cannot provide a trustworthy answer.
You already know that a vision processor gives the program an observation, not a motor command. Let's make the decision after the observation explicit. It either passes every declared gate, or it becomes UNKNOWN with a reason and uses the team's conservative fallback. Our region processor and an AprilTag processor do not expose the same measurements. They should not pretend to share one universal confidence number. A region result can check its strongest score, the margin over the second-best score, and stability. An AprilTag result can check that the detection and metadata exist, that the ID is allowed, and that range and bearing are inside reviewed bounds. It can also check that the observation is fresh and that the same ID survives for three consecutive accepted frames. The range, bearing, age, and score limits are example numbers used to trace the decision. The team must choose and validate its real policy from labelled evidence, such as the tag's apparent size, distance, and reprojection error. What matters here is that every gate is visible and every failure has a name. The Decision object keeps three things together: the observed result, the branch the autonomous code will use, and the acceptance or rejection reason. The region-score policy rejects a weak winner, a low-margin winner, or an unstable result. The AprilTag policy rejects no detection, missing metadata, or a disallowed tag ID before its later gates can pass. After those checks pass, it counts consecutive frames for the same ID. The first two accepted frames still return UNSTABLE, but the third can select an actual branch. Any failed gate or ID change resets that count. The FTC AprilTag API supplies detections and pose fields such as range and bearing when metadata is available. Observation age and the limits in this example are team-defined policy, not a universal SDK confidence field. Back in the overall view, a weak region becomes TOO_WEAK. Two close regions become LOW_MARGIN. AprilTag failures have names such as NO_DETECTION, MISSING_METADATA, DISALLOWED_ID, OUT_OF_BOUNDS, and STALE. A candidate that has not yet survived enough frames is UNSTABLE. Only an observation that passes the whole policy with no failed gates becomes ACCEPTED. These names are more useful than a single false value because they tell us which assumption failed. They also prevent an old accepted branch from silently surviving after the newest observation was rejected. The branch table stays deliberately small. An accepted observation selects left, center, or right. Anything rejected produces the result UNKNOWN and selects CENTER_SAFE. CENTER_SAFE in this example fixture is not proof that center is safe for every season. It is only an example of what autonomous branch would run in a fallback mode. The team must choose the real fallback. Replay labelled observations with robot outputs held at zero. Record the first failed gate, result, reason, selected branch, and proof that rejected data never requests motion. Only after the policy passes should the actual camera and robot be validated. Vision becomes more complicated when hardware is involved, so use the proper precautions. A reliable system needs many checks, testing, and tuning; try the policy against real evidence and keep improving it.
Define a team acceptance policy from observable inputs such as result age, accepted IDs, consecutive stable frames, geometry bounds, or a processor-specific score. The FTC AprilTag API does not provide one universal confidence value. Log the observed result, every acceptance check, the selected branch, and the fallback reason.
VisionResult.javaJava
enum AutoBranch { LEFT, CENTER, RIGHT, CENTER_SAFE }
// getConfidence() is a team-defined processor result, not an FTC SDK field.
PropPosition observed = processor.getPosition();
double confidence = processor.getConfidence();
boolean accepted = observed != PropPosition.UNKNOWN
&& confidence >= MIN_CONFIDENCE;
AutoBranch observedBranch;
switch (observed) {
case LEFT:
observedBranch = AutoBranch.LEFT;
break;
case RIGHT:
observedBranch = AutoBranch.RIGHT;
break;
case CENTER:
observedBranch = AutoBranch.CENTER;
break;
case UNKNOWN:
default:
observedBranch = AutoBranch.CENTER_SAFE;
break;
}
AutoBranch selected = accepted ? observedBranch : AutoBranch.CENTER_SAFE;
telemetry.addData("observed", observed);
telemetry.addData("confidence", confidence);
telemetry.addData("accepted", accepted);
telemetry.addData("selected branch", selected);If the default is unsafe, the robot will fail exactly when uncertainty is highest. Make fallback conservative and tested.
With all robot outputs held at zero, test an AprilTag policy matrix for no detection, missing metadata, disallowed ID, rejected geometry, stale observation, changing IDs, and three consecutive accepted frames. Record the failed gate, rejection reason, UNKNOWN or accepted result, selected branch, and zero-motion proof for every row.
Check your understanding before moving on.
0 of 2 answered