AprilTag Vision: Knowing Where You Are with PhotonVision
Use a coprocessor and PhotonVision to read AprilTags and fuse vision into WPILib pose estimation for field-relative positioning.
Sign in to track progress, earn XP, and save lessons.
AprilTags are the fiducial markers placed around the FRC field. By detecting them with a camera, your robot can compute its own position on the field — enabling automated alignment, reliable autos, and shot-aiming. The 2026 REBUILT field uses the 36h11 tag family (IDs 1-32), with 8.125-inch tags on the Hub, Tower Wall, Outpost, and Trenches.
The architecture. Image processing is too heavy for the roboRIO, so it runs on a coprocessor — commonly an Orange Pi or Raspberry Pi running PhotonVision — connected by Ethernet to the radio. The camera (e.g. an Arducam OV9281 global-shutter or a Limelight) feeds PhotonVision, which detects tags and publishes results over NetworkTables. Your robot code reads them with the PhotonLib vendor library.
Calibrate first — this is non-negotiable for 3D. To get a tag's 3D pose you must calibrate the camera at the resolution you will run. In PhotonVision you photograph a ChArUco/chessboard board from many angles and distances. Calibration solves for focal length, optical center, and distortion. Skipping or rushing this is a top cause of garbage pose data.
Use the right field layout. For 2026 there are two official field layouts — the welded layout (which PhotonVision ships with) and the AndyMark layout. Select the one matching the event field, both on the coprocessor and in your pose-estimation setup, or every pose will be subtly wrong (the AndyMark vs welded difference can be ~0.5 inch).
MultiTag and pose estimation. Enabling MultiTag estimation lets PhotonVision combine all visible tags using the field-layout JSON to produce one robust camera-to-field pose. In code, PhotonPoseEstimator turns pipeline results into a robot pose. The professional move is to fuse vision into a SwerveDrivePoseEstimator (or DifferentialDrivePoseEstimator) with addVisionMeasurement(). Conceptually:
// Pull unread results, run the estimator, push valid poses in.
for (var result : camera.getAllUnreadResults()) {
Optional<EstimatedRobotPose> est = photonEstimator.update(result);
est.ifPresent(e ->
poseEstimator.addVisionMeasurement(
e.estimatedPose.toPose2d(), e.timestampSeconds));
}
The exact PhotonLib API moves between seasons — recent versions deprecated getLatestResult() in favor of getAllUnreadResults() and added strategy-specific estimate methods — so check the current PhotonVision docs for your installed version. The fusion idea is stable: blend fast wheel/gyro odometry with absolute vision corrections, so odometry gives smooth high-rate position while vision periodically snaps out accumulated drift. Tune the trust (standard deviations) so noisy single-tag readings don't yank the pose around.
The REBUILT payoff: a robot that knows its field pose can auto-align to the Hub for consistent Fuel shots and run repeatable autos that don't drift over the 20-second period. Create one PhotonPoseEstimator per camera; multiple cameras give more frequent corrections and fewer blind spots.
Key takeaways
- Run PhotonVision on a coprocessor (Pi/Orange Pi) reading 36h11 AprilTags; the roboRIO consumes results via PhotonLib over NetworkTables
- Calibrate the camera at your run resolution and select the correct 2026 field layout (welded vs AndyMark) on both coprocessor and pose estimator
- Fuse vision into a WPILib pose estimator with addVisionMeasurement(); the PhotonLib result API shifts by season (getAllUnreadResults replaced getLatestResult), so verify against your version's docs
Go deeper
Lesson quiz
RequiredAnswer all 3 questions correctly to complete this lesson.
1.What is the main advantage of PhotonVision's MultiTag localization?
2.What must be done before using 3D AprilTag tracking in PhotonVision?
3.What does PhotonPoseEstimator with a strategy like MULTI_TAG_PNP/PNP_DISTANCE_TRIG provide to the robot's pose estimation?
Answer every question to submit.