From 3b8046373172e78b1e2f3f36f894855f48bbdea6 Mon Sep 17 00:00:00 2001 From: Kevin Cooney Date: Sat, 10 Jan 2026 16:32:27 -0800 Subject: [PATCH 1/5] Remove deprecated APIs in Limelight code --- .../team2813/lib2813/limelight/Limelight.java | 47 +---------- .../lib2813/limelight/LocationalData.java | 48 ----------- .../limelight/NetworkTablesLimelight.java | 56 +------------ .../lib2813/limelight/RestLimelight.java | 53 +----------- .../lib2813/limelight/StubLocationalData.java | 25 ------ .../lib2813/limelight/LimelightTestCase.java | 81 ++++++------------- 6 files changed, 34 insertions(+), 276 deletions(-) diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java index 31823f3d..0c5ddad8 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java @@ -15,14 +15,11 @@ */ package com.team2813.lib2813.limelight; -import edu.wpi.first.math.geometry.Pose3d; import edu.wpi.first.wpilibj.Filesystem; -import java.io.*; -import java.util.List; -import java.util.Optional; -import java.util.OptionalDouble; -import java.util.Set; -import org.json.JSONObject; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; public interface Limelight { @@ -35,20 +32,6 @@ static Limelight getDefaultLimelight() { return RestLimelight.getDefaultLimelight(); } - /** - * @deprecated use methods in {@link LocationalData} that return a {@link BotPoseEstimate}. - */ - @Deprecated - OptionalDouble getTimestamp(); - - /** - * Returns {@code true} if the limelight has identified a target. - * - * @deprecated use {@link LocationalData#hasTarget()} - */ - @Deprecated - boolean hasTarget(); - /** Gets an object for getting locational data. */ LocationalData getLocationalData(); @@ -70,26 +53,4 @@ default void setFieldMap(String filepath, boolean updateLimelight) throws IOExce setFieldMap(stream, updateLimelight); } } - - /** - * Gets the locations of the given AprilTags. - * - * @deprecated use {@link LocationalData#getVisibleAprilTagPoses()} - */ - @Deprecated - List getLocatedAprilTags(Set visibleTags); - - /** - * @deprecated use {@link LocationalData#getCaptureLatency()} - */ - @Deprecated - OptionalDouble getCaptureLatency(); - - /** - * Gets the most recent JSON from the Limelight. Does not work for all implementations. - * - * @deprecated use {@link LocationalData#isValid()}. - */ - @Deprecated - Optional getJsonDump(); } diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java b/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java index dcf02541..76e6ea76 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java @@ -18,8 +18,6 @@ import edu.wpi.first.math.geometry.Pose3d; import java.util.Map; import java.util.Optional; -import java.util.OptionalDouble; -import java.util.Set; /** * Get positional data from limelight @@ -64,52 +62,6 @@ public interface LocationalData { /** Gets the estimated position of the robot with the red driverstation as the origin. */ Optional getBotPoseEstimateRed(); - /** - * Capture latency in milliseconds. - * - *

Per the Limelight docs, this is the time between the end of the exposure of the middle row - * to the beginning of the tracking loop. - * - * @deprecated Use {@link #getBotPoseEstimateBlue()} or {@link #getBotPoseEstimateRed()} - */ - @Deprecated - OptionalDouble getCaptureLatency(); - - /** - * Targeting latency in milliseconds. - * - *

Per the Limelight docs, this is the time consumed by the tracking loop this frame. - * - * @deprecated Use {@link #getBotPoseEstimateBlue()} or {@link #getBotPoseEstimateRed()} - */ - @Deprecated - OptionalDouble getTargetingLatency(); - - /** - * @deprecated use methods that return a {@link BotPoseEstimate}. - */ - @Deprecated - OptionalDouble getTimestamp(); - - @Deprecated - default OptionalDouble lastMSDelay() { - OptionalDouble a = getCaptureLatency(); - OptionalDouble b = getTargetingLatency(); - if (a.isPresent() && b.isPresent()) { - return OptionalDouble.of(a.getAsDouble() + b.getAsDouble()); - } - return OptionalDouble.empty(); - } - - /** - * Gets the set of all visible tags - * - * @return The visible tags - * @deprecated use {@link #getVisibleAprilTagPoses()} - */ - @Deprecated - Set getVisibleTags(); - /** Gets the visible AprilTags as a map from ID to position. */ Map getVisibleAprilTagPoses(); } diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java index daeefe7b..cdd363b1 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java @@ -23,12 +23,11 @@ import edu.wpi.first.math.geometry.Pose3d; import java.io.IOException; import java.io.InputStream; -import java.util.*; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; -import java.util.OptionalDouble; -import java.util.stream.Collectors; -import org.json.JSONObject; +import java.util.Set; class NetworkTablesLimelight implements Limelight { private static final double[] ZEROS = new double[6]; @@ -40,16 +39,6 @@ class NetworkTablesLimelight implements Limelight { aprilTagMapPoseHelper = new AprilTagMapPoseHelper(new LimelightClient(limelightName)); } - @Override - public OptionalDouble getTimestamp() { - return getLocationalData().getTimestamp(); - } - - @Override - public boolean hasTarget() { - return getLocationalData().hasTarget(); - } - @Override public void setFieldMap(InputStream stream, boolean updateLimelight) throws IOException { // The updateLimelight assumes we have the hostname of the limelight, which we don't. For now, @@ -57,21 +46,6 @@ public void setFieldMap(InputStream stream, boolean updateLimelight) throws IOEx aprilTagMapPoseHelper.setFieldMap(stream, false); } - @Override - public List getLocatedAprilTags(Set visibleTags) { - return aprilTagMapPoseHelper.getVisibleTagPoses(visibleTags); - } - - @Override - public Optional getJsonDump() { - return Optional.empty(); - } - - @Override - public OptionalDouble getCaptureLatency() { - return getLocationalData().getCaptureLatency(); - } - @Override public LocationalData getLocationalData() { LimelightHelpers.LimelightResults results = LimelightHelpers.getLatestResults(limelightName); @@ -109,7 +83,7 @@ private Map getVisibleAprilTagPoses(LimelightResults results) { return unmodifiableMap(map); } - private class NTLocationalData implements LocationalData { + private static class NTLocationalData implements LocationalData { private final LimelightResults results; private final Optional poseEstimate; private final Optional redPoseEstimate; @@ -169,28 +143,6 @@ public Optional getBotPoseEstimateRed() { return redPoseEstimate; } - @Override - public OptionalDouble getCaptureLatency() { - return OptionalDouble.of(results.latency_capture); - } - - @Override - public OptionalDouble getTargetingLatency() { - return OptionalDouble.of(results.latency_pipeline); - } - - @Override - public OptionalDouble getTimestamp() { - return OptionalDouble.of(results.timestamp_LIMELIGHT_publish); - } - - @Override - public Set getVisibleTags() { - return Arrays.stream(results.targets_Fiducials) - .map(fiducial -> (int) fiducial.fiducialID) - .collect(Collectors.toUnmodifiableSet()); - } - @Override public Map getVisibleAprilTagPoses() { return aprilTags; diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java index 0be768f4..83774c1e 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java @@ -17,7 +17,6 @@ import static com.team2813.lib2813.limelight.JSONHelper.*; import static com.team2813.lib2813.limelight.Optionals.unboxDouble; -import static com.team2813.lib2813.limelight.Optionals.unboxLong; import static java.util.Collections.*; import edu.wpi.first.math.geometry.Pose3d; @@ -63,20 +62,6 @@ void runThread() { collectionThread.run(); } - @Override - public Optional getJsonDump() { - return collectionThread.getMostRecent().map(DataCollection.Result::json); - } - - public OptionalDouble getCaptureLatency() { - return getLocationalData().getCaptureLatency(); - } - - @Override - public OptionalDouble getTimestamp() { - return getLocationalData().getTimestamp(); - } - /** * Sets the field map for the limelight. Additionally, this may also upload the field map to the * Limelight if desired. This will likely be a slow operation, and should not be regularly called. @@ -89,11 +74,6 @@ public void setFieldMap(InputStream stream, boolean updateLimelight) throws IOEx aprilTagMapPoseHelper.setFieldMap(stream, updateLimelight); } - @Override - public List getLocatedAprilTags(Set visibleTags) { - return aprilTagMapPoseHelper.getVisibleTagPoses(visibleTags); - } - private static Function not(Function fnc) { return (t) -> !fnc.apply(t); } @@ -198,18 +178,11 @@ private Optional parseArr(JSONArray arr) { new Pose3d(arr.getDouble(0), arr.getDouble(1), arr.getDouble(2), rotation)); } - @Override - public OptionalDouble getTimestamp() { - return unboxDouble(getDouble(root, "ts")); - } - - @Override - public OptionalDouble getCaptureLatency() { + private OptionalDouble getCaptureLatency() { return unboxDouble(getDouble(root, "cl")); } - @Override - public OptionalDouble getTargetingLatency() { + private OptionalDouble getTargetingLatency() { return unboxDouble(getDouble(root, "tl")); } @@ -257,28 +230,6 @@ private BotPoseEstimate toBotPoseEstimate(Pose3d pose) { pose.toPose2d(), timestampSeconds, getVisibleAprilTagPoses().keySet()); } - /** Gets the id of the targeted tag. */ - OptionalLong getTagID() { - return unboxLong(getLong(root, "pID")); - } - - @Override - public Set getVisibleTags() { - return getArr(root, "Fiducial") - .map( - arr -> { - Set ints = new HashSet<>(); - for (int i = 0; i < arr.length(); i++) { - JSONObject obj = arr.optJSONObject(i); - if (obj != null && obj.has("fID")) { - ints.add(obj.getInt("fID")); - } - } - return unmodifiableSet(ints); - }) - .orElseGet(Set::of); - } - @Override public Map getVisibleAprilTagPoses() { return getArr(root, "Fiducial") diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java b/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java index 28505cdf..d122f212 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java @@ -69,31 +69,6 @@ public Optional getBotPoseEstimateRed() { return Optional.empty(); } - @Override - public OptionalDouble getCaptureLatency() { - return OptionalDouble.empty(); - } - - @Override - public OptionalDouble getTargetingLatency() { - return OptionalDouble.empty(); - } - - @Override - public OptionalDouble getTimestamp() { - return OptionalDouble.empty(); - } - - @Override - public OptionalDouble lastMSDelay() { - return OptionalDouble.empty(); - } - - @Override - public Set getVisibleTags() { - return Set.of(); - } - @Override public Map getVisibleAprilTagPoses() { return Collections.emptyMap(); diff --git a/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java b/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java index 7447cb49..328ca7e0 100644 --- a/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java +++ b/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java @@ -32,7 +32,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.List; import java.util.Map; import java.util.Optional; import java.util.OptionalDouble; @@ -44,9 +43,17 @@ abstract class LimelightTestCase { @Test - public final void emptyValues() { + public final void noData() { Limelight limelight = createLimelight(); - assertWithMessage("JSON should be empty").that(limelight.getCaptureLatency()).isEmpty(); + + LocationalData locationalData = limelight.getLocationalData(); + assertThat(locationalData.getBotpose()).isEmpty(); + assertThat(locationalData.getBotPoseEstimate()).isEmpty(); + assertThat(locationalData.getBotPoseEstimateBlue()).isEmpty(); + assertThat(locationalData.getBotposeBlue()).isEmpty(); + assertThat(locationalData.getBotposeRed()).isEmpty(); + assertThat(locationalData.getBotPoseEstimateRed()).isEmpty(); + // assertThat(locationalData.isValid()).isFalse(); } @Test @@ -59,10 +66,11 @@ public final void invalidDataTest() throws Exception { LocationalData locationalData = limelight.getLocationalData(); assertThat(locationalData.isValid()).isFalse(); assertThat(locationalData.getBotpose()).isEmpty(); - OptionalDouble actualCaptureLatency = locationalData.getCaptureLatency(); - assertThat(actualCaptureLatency).isEmpty(); - OptionalDouble actualTargetingLatency = locationalData.getTargetingLatency(); - assertThat(actualTargetingLatency).isEmpty(); + assertThat(locationalData.getBotPoseEstimate()).isEmpty(); + assertThat(locationalData.getBotPoseEstimateBlue()).isEmpty(); + assertThat(locationalData.getBotposeBlue()).isEmpty(); + assertThat(locationalData.getBotposeRed()).isEmpty(); + assertThat(locationalData.getBotPoseEstimateRed()).isEmpty(); } @Test @@ -75,13 +83,10 @@ public final void absentTest1() throws Exception { LocationalData locationalData = limelight.getLocationalData(); assertThat(locationalData.isValid()).isTrue(); assertThat(locationalData.getBotpose()).isEmpty(); - OptionalDouble actualCaptureLatency = locationalData.getCaptureLatency(); - double expectedCaptureLatencyMs = 37.40; - assertAlmostEqual(expectedCaptureLatencyMs, actualCaptureLatency, 0.005); - OptionalDouble actualTargetingLatency = locationalData.getTargetingLatency(); - double expectedTargetingLatencyMs = 38.95; - assertAlmostEqual(expectedTargetingLatencyMs, actualTargetingLatency, 0.005); + assertThat(locationalData.getBotPoseEstimate()).isEmpty(); assertThat(locationalData.getBotPoseEstimateBlue()).isEmpty(); + assertThat(locationalData.getBotposeBlue()).isEmpty(); + assertThat(locationalData.getBotposeRed()).isEmpty(); assertThat(locationalData.getBotPoseEstimateRed()).isEmpty(); } @@ -95,13 +100,10 @@ public final void absentTest2() throws Exception { LocationalData locationalData = limelight.getLocationalData(); assertThat(locationalData.isValid()).isTrue(); assertThat(locationalData.getBotpose()).isEmpty(); - OptionalDouble actualCaptureLatency = locationalData.getCaptureLatency(); - double expectedCaptureLatencyMs = 37.40; - assertAlmostEqual(expectedCaptureLatencyMs, actualCaptureLatency, 0.005); - OptionalDouble actualTargetingLatency = locationalData.getTargetingLatency(); - double expectedTargetingLatencyMs = 54.64; - assertAlmostEqual(expectedTargetingLatencyMs, actualTargetingLatency, 0.005); + assertThat(locationalData.getBotPoseEstimate()).isEmpty(); assertThat(locationalData.getBotPoseEstimateBlue()).isEmpty(); + assertThat(locationalData.getBotposeBlue()).isEmpty(); + assertThat(locationalData.getBotposeRed()).isEmpty(); assertThat(locationalData.getBotPoseEstimateRed()).isEmpty(); } @@ -116,13 +118,6 @@ public final void presentTest1() throws Exception { LocationalData locationalData = limelight.getLocationalData(); assertThat(locationalData.isValid()).isTrue(); - OptionalDouble actualCaptureLatency = locationalData.getCaptureLatency(); - double expectedCaptureLatencyMs = 37.40; - assertAlmostEqual(expectedCaptureLatencyMs, actualCaptureLatency, 0.005); - OptionalDouble actualTargetingLatency = locationalData.getTargetingLatency(); - double expectedTargetingLatencyMs = 66.61; - assertAlmostEqual(expectedTargetingLatencyMs, actualTargetingLatency, 0.005); - assertThat(locationalData.getBotpose()).isPresent(); Pose3d actualPose = locationalData.getBotpose().get(); Rotation3d rotation = @@ -159,13 +154,6 @@ public final void presentTest2() throws Exception { LocationalData locationalData = limelight.getLocationalData(); assertThat(locationalData.isValid()).isTrue(); - OptionalDouble actualCaptureLatency = locationalData.getCaptureLatency(); - double expectedCaptureLatencyMs = 37.40; - assertAlmostEqual(expectedCaptureLatencyMs, actualCaptureLatency, 0.005); - OptionalDouble actualTargetingLatency = locationalData.getTargetingLatency(); - double expectedTargetingLatencyMs = 59.20; - assertAlmostEqual(expectedTargetingLatencyMs, actualTargetingLatency, 0.005); - assertThat(locationalData.getBotpose()).isPresent(); Pose3d actualPose = locationalData.getBotpose().get(); Rotation3d rotation = @@ -219,15 +207,6 @@ public final void getBotposeRed() throws Exception { assertThat(actualPose).isWithin(0.005).of(expectedPose); } - @Test - public final void getVisibleTags() throws Exception { - JSONObject obj = readJSON("BotposeBlueRedTest.json"); - setJson(obj); - Limelight limelight = createLimelight(); - assertHasTarget(limelight); - assertThat(limelight.getLocationalData().getVisibleTags()).containsExactly(20); - } - @Test public final void getVisibleAprilTagPoses() throws Exception { JSONObject obj = readJSON("BotposeBlueRedTest.json"); @@ -254,20 +233,6 @@ public final void getVisibleAprilTagPoses() throws Exception { assertThat(locationalData.getBotPoseEstimateRed().get().visibleAprilTags()).isEqualTo(tags); } - @Test - public final void visibleTagLocation() throws Exception { - JSONObject obj = readJSON("BotposeBlueRedTest.json"); - setJson(obj); - Limelight limelight = createLimelight(); - uploadFieldMap(limelight); - - Set visibleTags = limelight.getLocationalData().getVisibleTags(); - List aprilTags = limelight.getLocatedAprilTags(visibleTags); - assertThat(aprilTags).hasSize(1); - Pose3d pose = aprilTags.get(0); - assertThat(pose.getTranslation()).isWithin(0.005).of(new Translation3d(-3.87, 0.72, 0.31)); - } - protected abstract Limelight createLimelight(); protected abstract void setJson(JSONObject json); @@ -292,7 +257,9 @@ private JSONObject readJSON(String fileName) throws IOException { } private void assertHasTarget(Limelight limelight) { - assertWithMessage("Should have target").that(limelight.hasTarget()).isTrue(); + assertWithMessage("Should have target") + .that(limelight.getLocationalData().hasTarget()) + .isTrue(); assertWithMessage("Should have target") .that(limelight.getLocationalData().hasTarget()) .isTrue(); From be3f1cb3638c77ee821d4be94fa1baa10dde480b Mon Sep 17 00:00:00 2001 From: Kevin Cooney Date: Sat, 10 Jan 2026 19:30:48 -0800 Subject: [PATCH 2/5] RestLimelight.getLocationalData() should return invalid if no data yet --- .../main/java/com/team2813/lib2813/limelight/RestLimelight.java | 2 +- .../java/com/team2813/lib2813/limelight/LimelightTestCase.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java index 83774c1e..4864fee8 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java @@ -85,7 +85,7 @@ public boolean hasTarget() { public LocationalData getLocationalData() { Optional locationalData = collectionThread.getMostRecent().map(RestLocationalData::new); - return locationalData.orElse(StubLocationalData.VALID); + return locationalData.orElse(StubLocationalData.INVALID); } private void clean() { diff --git a/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java b/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java index 328ca7e0..d5a17517 100644 --- a/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java +++ b/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java @@ -47,13 +47,13 @@ public final void noData() { Limelight limelight = createLimelight(); LocationalData locationalData = limelight.getLocationalData(); + assertThat(locationalData.isValid()).isFalse(); assertThat(locationalData.getBotpose()).isEmpty(); assertThat(locationalData.getBotPoseEstimate()).isEmpty(); assertThat(locationalData.getBotPoseEstimateBlue()).isEmpty(); assertThat(locationalData.getBotposeBlue()).isEmpty(); assertThat(locationalData.getBotposeRed()).isEmpty(); assertThat(locationalData.getBotPoseEstimateRed()).isEmpty(); - // assertThat(locationalData.isValid()).isFalse(); } @Test From 9ccf835c0b421d869c94c2bff9a5f392bff85630 Mon Sep 17 00:00:00 2001 From: Kevin Cooney Date: Sat, 10 Jan 2026 19:07:03 -0800 Subject: [PATCH 3/5] Fix problems found via IntelliJ IDEA Inspection Results --- .../lib2813/limelight/AprilTagMapPoseHelper.java | 2 +- .../lib2813/limelight/BotPoseEstimate.java | 9 ++------- .../lib2813/limelight/DataCollection.java | 4 +--- .../team2813/lib2813/limelight/Limelight.java | 2 +- .../lib2813/limelight/LimelightHelpers.java | 16 ++++++---------- 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/AprilTagMapPoseHelper.java b/limelight/src/main/java/com/team2813/lib2813/limelight/AprilTagMapPoseHelper.java index e58a0892..8eb222ac 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/AprilTagMapPoseHelper.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/AprilTagMapPoseHelper.java @@ -69,7 +69,7 @@ public List getVisibleTagPoses(Set ids) { return List.of(); } return retriever.getFiducialMap().values().stream() - .filter(fidicual -> ids.contains(fidicual.getId())) + .filter(fiducial -> ids.contains(fiducial.getId())) .map(Fiducial::getPosition) .toList(); } diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/BotPoseEstimate.java b/limelight/src/main/java/com/team2813/lib2813/limelight/BotPoseEstimate.java index 574b9238..89e750ff 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/BotPoseEstimate.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/BotPoseEstimate.java @@ -25,10 +25,5 @@ * @param timestampSeconds The timestamp, in seconds, using the drivetrain clock * @param visibleAprilTags All April Tags that are visible from the vision source. */ -public record BotPoseEstimate(Pose2d pose, double timestampSeconds, Set visibleAprilTags) { - - @Deprecated - public BotPoseEstimate(Pose2d pose, double timestampSeconds) { - this(pose, timestampSeconds, Set.of()); - } -} +public record BotPoseEstimate( + Pose2d pose, double timestampSeconds, Set visibleAprilTags) {} diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/DataCollection.java b/limelight/src/main/java/com/team2813/lib2813/limelight/DataCollection.java index 151fc051..f76246ee 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/DataCollection.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/DataCollection.java @@ -60,9 +60,7 @@ public BodySubscriber apply(ResponseInfo responseInfo) { return BodySubscribers.mapping( BodyHandlers.ofString(Charset.defaultCharset()).apply(responseInfo), - body -> { - return new Result(new JSONObject(body), responseTimestamp); - }); + body -> new Result(new JSONObject(body), responseTimestamp)); } } diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java index 0c5ddad8..ad9f01c6 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java @@ -42,7 +42,7 @@ static Limelight getDefaultLimelight() { * may also upload the field map to the Limelight if desired. This will likely be a slow * operation, and should not be regularly called. * - * @param filepath The path to the file from the deploy directory (using UNIX file seperators) + * @param filepath The path to the file from the deploy directory (using UNIX file separators) * @param updateLimelight If the limelight should be updated with this field map * @throws IOException If the given filepath does not exist in the deploy directory or could not * be read diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/LimelightHelpers.java b/limelight/src/main/java/com/team2813/lib2813/limelight/LimelightHelpers.java index 27e51bfc..e8be4d39 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/LimelightHelpers.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/LimelightHelpers.java @@ -919,16 +919,10 @@ public static String[] getLimelightNTStringArray(String tableName, String entryN return getLimelightNTTableEntry(tableName, entryName).getStringArray(new String[0]); } - public static URL getLimelightURLString(String tableName, String request) { + public static URL getLimelightURLString(String tableName, String request) + throws MalformedURLException { String urlString = "http://" + sanitizeName(tableName) + ".local:5807/" + request; - URL url; - try { - url = new URL(urlString); - return url; - } catch (MalformedURLException e) { - System.err.println("bad LL URL"); - } - return null; + return new URL(urlString); } ///// @@ -1658,8 +1652,8 @@ public static CompletableFuture takeSnapshot(String tableName, String s } private static boolean SYNCH_TAKESNAPSHOT(String tableName, String snapshotName) { - URL url = getLimelightURLString(tableName, "capturesnapshot"); try { + URL url = getLimelightURLString(tableName, "capturesnapshot"); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("GET"); if (snapshotName != null && !snapshotName.isEmpty()) { @@ -1672,6 +1666,8 @@ private static boolean SYNCH_TAKESNAPSHOT(String tableName, String snapshotName) } else { System.err.println("Bad LL Request"); } + } catch (MalformedURLException e) { + System.err.println("bad Limelight URL: " + e.getMessage()); } catch (IOException e) { System.err.println(e.getMessage()); } From a49e61447f609df930aa0d542f4690b8504b3212 Mon Sep 17 00:00:00 2001 From: Kevin Cooney Date: Sat, 31 Jan 2026 23:44:02 -0800 Subject: [PATCH 4/5] Add back getCaptureLatency() and getTargetingLatency() to LocationalData --- .../lib2813/limelight/LocationalData.java | 16 ++++++++++++++++ .../limelight/NetworkTablesLimelight.java | 11 +++++++++++ .../lib2813/limelight/RestLimelight.java | 6 ++++-- .../lib2813/limelight/StubLocationalData.java | 10 ++++++++++ .../lib2813/limelight/LimelightTestCase.java | 14 ++++++++++++++ 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java b/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java index 76e6ea76..74e36741 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java @@ -18,6 +18,7 @@ import edu.wpi.first.math.geometry.Pose3d; import java.util.Map; import java.util.Optional; +import java.util.OptionalDouble; /** * Get positional data from limelight @@ -62,6 +63,21 @@ public interface LocationalData { /** Gets the estimated position of the robot with the red driverstation as the origin. */ Optional getBotPoseEstimateRed(); + /** + * Capture latency in milliseconds. + * + *

Per the Limelight docs, this is the time between the end of the exposure of the middle row + * to the beginning of the tracking loop. + */ + OptionalDouble getCaptureLatency(); + + /** + * Targeting latency in milliseconds. + * + *

Per the Limelight docs, this is the time consumed by the tracking loop this frame. + */ + OptionalDouble getTargetingLatency(); + /** Gets the visible AprilTags as a map from ID to position. */ Map getVisibleAprilTagPoses(); } diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java index cdd363b1..69479b08 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java @@ -27,6 +27,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; +import java.util.OptionalDouble; import java.util.Set; class NetworkTablesLimelight implements Limelight { @@ -143,6 +144,16 @@ public Optional getBotPoseEstimateRed() { return redPoseEstimate; } + @Override + public OptionalDouble getCaptureLatency() { + return OptionalDouble.of(results.latency_capture); + } + + @Override + public OptionalDouble getTargetingLatency() { + return OptionalDouble.of(results.latency_pipeline); + } + @Override public Map getVisibleAprilTagPoses() { return aprilTags; diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java index 4864fee8..b8c73e2e 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java @@ -178,11 +178,13 @@ private Optional parseArr(JSONArray arr) { new Pose3d(arr.getDouble(0), arr.getDouble(1), arr.getDouble(2), rotation)); } - private OptionalDouble getCaptureLatency() { + @Override + public OptionalDouble getCaptureLatency() { return unboxDouble(getDouble(root, "cl")); } - private OptionalDouble getTargetingLatency() { + @Override + public OptionalDouble getTargetingLatency() { return unboxDouble(getDouble(root, "tl")); } diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java b/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java index d122f212..9a5cd4e5 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java @@ -69,6 +69,16 @@ public Optional getBotPoseEstimateRed() { return Optional.empty(); } + @Override + public OptionalDouble getCaptureLatency() { + return OptionalDouble.empty(); + } + + @Override + public OptionalDouble getTargetingLatency() { + return OptionalDouble.empty(); + } + @Override public Map getVisibleAprilTagPoses() { return Collections.emptyMap(); diff --git a/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java b/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java index d5a17517..b6340fbb 100644 --- a/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java +++ b/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java @@ -118,6 +118,13 @@ public final void presentTest1() throws Exception { LocationalData locationalData = limelight.getLocationalData(); assertThat(locationalData.isValid()).isTrue(); + OptionalDouble actualCaptureLatency = locationalData.getCaptureLatency(); + double expectedCaptureLatencyMs = 37.40; + assertAlmostEqual(expectedCaptureLatencyMs, actualCaptureLatency, 0.005); + OptionalDouble actualTargetingLatency = locationalData.getTargetingLatency(); + double expectedTargetingLatencyMs = 66.61; + assertAlmostEqual(expectedTargetingLatencyMs, actualTargetingLatency, 0.005); + assertThat(locationalData.getBotpose()).isPresent(); Pose3d actualPose = locationalData.getBotpose().get(); Rotation3d rotation = @@ -154,6 +161,13 @@ public final void presentTest2() throws Exception { LocationalData locationalData = limelight.getLocationalData(); assertThat(locationalData.isValid()).isTrue(); + OptionalDouble actualCaptureLatency = locationalData.getCaptureLatency(); + double expectedCaptureLatencyMs = 37.40; + assertAlmostEqual(expectedCaptureLatencyMs, actualCaptureLatency, 0.005); + OptionalDouble actualTargetingLatency = locationalData.getTargetingLatency(); + double expectedTargetingLatencyMs = 59.20; + assertAlmostEqual(expectedTargetingLatencyMs, actualTargetingLatency, 0.005); + assertThat(locationalData.getBotpose()).isPresent(); Pose3d actualPose = locationalData.getBotpose().get(); Rotation3d rotation = From ffc1b2e7de7a2774dcd5c9e172b8492e0e45935f Mon Sep 17 00:00:00 2001 From: Kevin Cooney Date: Sat, 31 Jan 2026 23:47:23 -0800 Subject: [PATCH 5/5] Update copyrights --- .../com/team2813/lib2813/limelight/AprilTagMapPoseHelper.java | 2 +- .../java/com/team2813/lib2813/limelight/BotPoseEstimate.java | 2 +- .../java/com/team2813/lib2813/limelight/DataCollection.java | 2 +- .../src/main/java/com/team2813/lib2813/limelight/Limelight.java | 2 +- .../java/com/team2813/lib2813/limelight/LimelightHelpers.java | 2 +- .../java/com/team2813/lib2813/limelight/LocationalData.java | 2 +- .../com/team2813/lib2813/limelight/NetworkTablesLimelight.java | 2 +- .../main/java/com/team2813/lib2813/limelight/RestLimelight.java | 2 +- .../java/com/team2813/lib2813/limelight/StubLocationalData.java | 2 +- .../java/com/team2813/lib2813/limelight/LimelightTestCase.java | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/AprilTagMapPoseHelper.java b/limelight/src/main/java/com/team2813/lib2813/limelight/AprilTagMapPoseHelper.java index 8eb222ac..f629e246 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/AprilTagMapPoseHelper.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/AprilTagMapPoseHelper.java @@ -1,5 +1,5 @@ /* -Copyright 2025 Prospect Robotics SWENext Club +Copyright 2025-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/BotPoseEstimate.java b/limelight/src/main/java/com/team2813/lib2813/limelight/BotPoseEstimate.java index 89e750ff..848c6ef9 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/BotPoseEstimate.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/BotPoseEstimate.java @@ -1,5 +1,5 @@ /* -Copyright 2025 Prospect Robotics SWENext Club +Copyright 2025-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/DataCollection.java b/limelight/src/main/java/com/team2813/lib2813/limelight/DataCollection.java index f76246ee..a0fd0147 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/DataCollection.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/DataCollection.java @@ -1,5 +1,5 @@ /* -Copyright 2024-2025 Prospect Robotics SWENext Club +Copyright 2024-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java index ad9f01c6..5c7f4db0 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/Limelight.java @@ -1,5 +1,5 @@ /* -Copyright 2024-2025 Prospect Robotics SWENext Club +Copyright 2024-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/LimelightHelpers.java b/limelight/src/main/java/com/team2813/lib2813/limelight/LimelightHelpers.java index e8be4d39..7696ce78 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/LimelightHelpers.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/LimelightHelpers.java @@ -1,5 +1,5 @@ /* -Copyright 2025 Prospect Robotics SWENext Club +Copyright 2025-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java b/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java index 74e36741..d08ed393 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/LocationalData.java @@ -1,5 +1,5 @@ /* -Copyright 2024-2025 Prospect Robotics SWENext Club +Copyright 2024-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java index 69479b08..b215990b 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/NetworkTablesLimelight.java @@ -1,5 +1,5 @@ /* -Copyright 2025 Prospect Robotics SWENext Club +Copyright 2025-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java b/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java index b8c73e2e..29bc8683 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/RestLimelight.java @@ -1,5 +1,5 @@ /* -Copyright 2024-2025 Prospect Robotics SWENext Club +Copyright 2024-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java b/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java index 9a5cd4e5..6c6c110f 100644 --- a/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java +++ b/limelight/src/main/java/com/team2813/lib2813/limelight/StubLocationalData.java @@ -1,5 +1,5 @@ /* -Copyright 2025 Prospect Robotics SWENext Club +Copyright 2025-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java b/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java index b6340fbb..3a0c5c57 100644 --- a/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java +++ b/limelight/src/test/java/com/team2813/lib2813/limelight/LimelightTestCase.java @@ -1,5 +1,5 @@ /* -Copyright 2024-2025 Prospect Robotics SWENext Club +Copyright 2024-2026 Prospect Robotics SWENext Club Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.