Skip to content

Commit 9f3cb58

Browse files
committed
Add withMultiTagFallbackStrategy()
1 parent 8ad1607 commit 9f3cb58

1 file changed

Lines changed: 52 additions & 4 deletions

File tree

vision/src/main/java/com/team2813/lib2813/vision/MultiPhotonPoseEstimator.java

Lines changed: 52 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,18 @@
6767
public class MultiPhotonPoseEstimator<C extends Camera> implements AutoCloseable {
6868
private final List<PhotonCameraWrapper<C>> cameraWrappers;
6969
private final Predicate<EstimatedRobotPose> isPoseValid;
70+
private final PhotonPoseEstimator.PoseStrategy fallbackStrategy;
7071
private PhotonPoseEstimator.PoseStrategy poseEstimatorStrategy;
72+
private boolean needHeadingData;
7173

7274
/** A builder for {@code MultiPhotonPoseEstimator}. */
7375
public static final class Builder<C extends Camera> {
7476
private final Map<String, C> cameras = new HashMap<>();
7577
private final AprilTagFieldLayout aprilTagFieldLayout;
7678
private final NetworkTableInstance ntInstance;
7779
private final PhotonPoseEstimator.PoseStrategy poseEstimatorStrategy;
80+
private PhotonPoseEstimator.PoseStrategy fallbackStrategy =
81+
PhotonPoseEstimator.PoseStrategy.LOWEST_AMBIGUITY;
7882
private Predicate<EstimatedRobotPose> isPoseValid = pose -> true;
7983

8084
Builder(
@@ -116,6 +120,26 @@ public Builder<C> withPoseFilter(Predicate<EstimatedRobotPose> isPoseValid) {
116120
return this;
117121
}
118122

123+
/**
124+
* Set the Position Estimation Strategy used in multi-tag mode when only one tag can be seen.
125+
* Must NOT be {@link PhotonPoseEstimator.PoseStrategy#MULTI_TAG_PNP_ON_COPROCESSOR} or {@link
126+
* PhotonPoseEstimator.PoseStrategy#MULTI_TAG_PNP_ON_RIO}.
127+
*
128+
* <p>If this is not called, {@link PhotonPoseEstimator.PoseStrategy#LOWEST_AMBIGUITY} will be
129+
* used.
130+
*
131+
* @param strategy the strategy to set
132+
* @return Builder instance.
133+
* @since 2.1.0
134+
*/
135+
public Builder<C> withMultiTagFallbackStrategy(PhotonPoseEstimator.PoseStrategy strategy) {
136+
if (isMultiTagStrategy(strategy)) {
137+
throw new IllegalArgumentException("Fallback strategy cannot be " + strategy);
138+
}
139+
fallbackStrategy = strategy;
140+
return this;
141+
}
142+
119143
/** Builds a configured MultiPhotonPoseEstimator. */
120144
public MultiPhotonPoseEstimator<C> build() {
121145
return new MultiPhotonPoseEstimator<>(this);
@@ -251,11 +275,13 @@ public void close() {
251275
/** Creates an instance using values from a {@code Builder}. */
252276
private MultiPhotonPoseEstimator(Builder<C> builder) {
253277
poseEstimatorStrategy = builder.poseEstimatorStrategy;
278+
fallbackStrategy = builder.fallbackStrategy;
254279
isPoseValid = poseIsInField(builder.aprilTagFieldLayout).and(builder.isPoseValid);
255280
cameraWrappers =
256281
builder.cameras.values().stream()
257282
.map(camera -> createCameraWrapper(builder, camera))
258283
.collect(toCollection(ArrayList::new));
284+
needHeadingData = calculateNeedHeadingData();
259285
}
260286

261287
/**
@@ -270,6 +296,7 @@ private static <C extends Camera> PhotonCameraWrapper<C> createCameraWrapper(
270296
PhotonPoseEstimator estimator =
271297
new PhotonPoseEstimator(
272298
builder.aprilTagFieldLayout, builder.poseEstimatorStrategy, camera.robotToCamera());
299+
estimator.setMultiTagFallbackStrategy(builder.fallbackStrategy);
273300

274301
// Create NetworkTables publishers for 1) the position of the camera relative to the robot and
275302
// 2) the estimated position provided by the camera.
@@ -302,6 +329,7 @@ public void setPrimaryStrategy(PhotonPoseEstimator.PoseStrategy poseStrategy) {
302329
if (!poseStrategy.equals(poseEstimatorStrategy)) {
303330
cameraWrappers.forEach(wrapper -> wrapper.estimator.setPrimaryStrategy(poseStrategy));
304331
poseEstimatorStrategy = poseStrategy;
332+
needHeadingData = calculateNeedHeadingData();
305333
}
306334
}
307335

@@ -311,10 +339,7 @@ public void setPrimaryStrategy(PhotonPoseEstimator.PoseStrategy poseStrategy) {
311339
* @return {@code true} if the pose strategy is documented to require addHeadingData().
312340
*/
313341
public boolean poseStrategyRequiresHeadingData() {
314-
return switch (poseEstimatorStrategy) {
315-
case PNP_DISTANCE_TRIG_SOLVE, CONSTRAINED_SOLVEPNP -> true;
316-
default -> false;
317-
};
342+
return needHeadingData;
318343
}
319344

320345
/**
@@ -431,6 +456,29 @@ public void close() {
431456
cameraWrappers.clear();
432457
}
433458

459+
private static boolean poseStrategyRequiresHeadingData(
460+
PhotonPoseEstimator.PoseStrategy strategy) {
461+
return switch (strategy) {
462+
case PNP_DISTANCE_TRIG_SOLVE, CONSTRAINED_SOLVEPNP -> true;
463+
default -> false;
464+
};
465+
}
466+
467+
private static boolean isMultiTagStrategy(PhotonPoseEstimator.PoseStrategy strategy) {
468+
return switch (strategy) {
469+
case MULTI_TAG_PNP_ON_COPROCESSOR, MULTI_TAG_PNP_ON_RIO -> true;
470+
default -> false;
471+
};
472+
}
473+
474+
private boolean calculateNeedHeadingData() {
475+
if (poseStrategyRequiresHeadingData(poseEstimatorStrategy)) {
476+
return true;
477+
}
478+
return isMultiTagStrategy(poseEstimatorStrategy)
479+
&& poseStrategyRequiresHeadingData(fallbackStrategy);
480+
}
481+
434482
/** Creates a predicate that determines if a pose is inside the field. */
435483
private static <C extends Camera> Predicate<EstimatedRobotPose> poseIsInField(
436484
AprilTagFieldLayout aprilTagFieldLayout) {

0 commit comments

Comments
 (0)