Skip to content

Commit e5161ff

Browse files
committed
Add withMultiTagFallbackStrategy()
1 parent 0f705d4 commit e5161ff

1 file changed

Lines changed: 50 additions & 4 deletions

File tree

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

Lines changed: 50 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(
@@ -114,6 +118,24 @@ public Builder<C> withPoseFilter(Predicate<EstimatedRobotPose> isPoseValid) {
114118
return this;
115119
}
116120

121+
/**
122+
* Set the Position Estimation Strategy used in multi-tag mode when only one tag can be seen.
123+
* Must NOT be {@link PhotonPoseEstimator.PoseStrategy#MULTI_TAG_PNP_ON_COPROCESSOR} or {@link
124+
* PhotonPoseEstimator.PoseStrategy#MULTI_TAG_PNP_ON_RIO}.
125+
*
126+
* <p>If this is not called, {@link PhotonPoseEstimator.PoseStrategy#LOWEST_AMBIGUITY} will be
127+
* used.
128+
*
129+
* @param strategy the strategy to set
130+
*/
131+
public Builder<C> withMultiTagFallbackStrategy(PhotonPoseEstimator.PoseStrategy strategy) {
132+
if (isMultiTagStrategy(strategy)) {
133+
throw new IllegalArgumentException("Fallback strategy cannot be " + strategy);
134+
}
135+
fallbackStrategy = strategy;
136+
return this;
137+
}
138+
117139
/** Builds a configured MultiPhotonPoseEstimator. */
118140
public MultiPhotonPoseEstimator<C> build() {
119141
return new MultiPhotonPoseEstimator<>(this);
@@ -249,11 +271,13 @@ public void close() {
249271
/** Creates an instance using values from a {@code Builder}. */
250272
private MultiPhotonPoseEstimator(Builder<C> builder) {
251273
poseEstimatorStrategy = builder.poseEstimatorStrategy;
274+
fallbackStrategy = builder.fallbackStrategy;
252275
isPoseValid = poseIsInField(builder.aprilTagFieldLayout).and(builder.isPoseValid);
253276
cameraWrappers =
254277
builder.cameras.values().stream()
255278
.map(camera -> createCameraWrapper(builder, camera))
256279
.collect(toCollection(ArrayList::new));
280+
needHeadingData = calculateNeedHeadingData();
257281
}
258282

259283
/**
@@ -268,6 +292,7 @@ private static <C extends Camera> PhotonCameraWrapper<C> createCameraWrapper(
268292
PhotonPoseEstimator estimator =
269293
new PhotonPoseEstimator(
270294
builder.aprilTagFieldLayout, builder.poseEstimatorStrategy, camera.robotToCamera());
295+
estimator.setMultiTagFallbackStrategy(builder.fallbackStrategy);
271296

272297
// Create NetworkTables publishers for 1) the position of the camera relative to the robot and
273298
// 2) the estimated position provided by the camera.
@@ -300,6 +325,7 @@ public void setPrimaryStrategy(PhotonPoseEstimator.PoseStrategy poseStrategy) {
300325
if (!poseStrategy.equals(poseEstimatorStrategy)) {
301326
cameraWrappers.forEach(wrapper -> wrapper.estimator.setPrimaryStrategy(poseStrategy));
302327
poseEstimatorStrategy = poseStrategy;
328+
needHeadingData = calculateNeedHeadingData();
303329
}
304330
}
305331

@@ -309,10 +335,7 @@ public void setPrimaryStrategy(PhotonPoseEstimator.PoseStrategy poseStrategy) {
309335
* @return {@code true} if the pose strategy is documented to require addHeadingData().
310336
*/
311337
public boolean poseStrategyRequiresHeadingData() {
312-
return switch (poseEstimatorStrategy) {
313-
case PNP_DISTANCE_TRIG_SOLVE, CONSTRAINED_SOLVEPNP -> true;
314-
default -> false;
315-
};
338+
return needHeadingData;
316339
}
317340

318341
/**
@@ -428,6 +451,29 @@ public void close() {
428451
cameraWrappers.clear();
429452
}
430453

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

0 commit comments

Comments
 (0)