Merge branch 'main' into py-docs

This commit is contained in:
Sam Freund
2025-05-08 18:29:37 -05:00
committed by GitHub
230 changed files with 6791 additions and 6964 deletions

View File

@@ -50,7 +50,6 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.opencv.core.Core;
import org.photonvision.common.hardware.VisionLEDMode;
import org.photonvision.common.networktables.PacketSubscriber;
@@ -138,7 +137,7 @@ public class PhotonCamera implements AutoCloseable {
.getRawTopic("rawBytes")
.subscribe(
PhotonPipelineResult.photonStruct.getTypeString(),
new byte[] {},
new byte[0],
PubSubOption.periodic(0.01),
PubSubOption.sendAll(true),
PubSubOption.pollStorage(20));
@@ -175,65 +174,77 @@ public class PhotonCamera implements AutoCloseable {
}
public static void verifyDependencies() {
// spotless:off
if (!WPILibVersion.Version.equals(PhotonVersion.wpilibTargetVersion)) {
String bfw =
"\n\n\n\n\n"
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
+ ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+ ">>> \n"
+ ">>> You are running an incompatible version \n"
+ ">>> of PhotonVision ! \n"
+ ">>> \n"
+ ">>> PhotonLib "
+ PhotonVersion.versionString
+ " is built for WPILib "
+ PhotonVersion.wpilibTargetVersion
+ "\n"
+ ">>> but you are using WPILib "
+ WPILibVersion.Version
+ ">>> \n"
+ ">>> This is neither tested nor supported. \n"
+ ">>> You MUST update PhotonVision, \n"
+ ">>> PhotonLib, or both. \n"
+ ">>> Verify the output of `./gradlew dependencies` \n"
+ ">>> \n"
+ ">>> Your code will now crash. \n"
+ ">>> We hope your day gets better. \n"
+ ">>> \n"
+ ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
String bfw = """
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s
>>> \s
>>> You are running an incompatible version \s
>>> of PhotonVision ! \s
>>> \s
>>> PhotonLib """
+ PhotonVersion.versionString
+ " is built for WPILib "
+ PhotonVersion.wpilibTargetVersion
+ "\n"
+ ">>> but you are using WPILib "
+ WPILibVersion.Version
+ """
>>> \s
>>> This is neither tested nor supported. \s
>>> You MUST update PhotonVision, \s
>>> PhotonLib, or both. \s
>>> Verify the output of `./gradlew dependencies`
>>> \s
>>> Your code will now crash. \s
>>> We hope your day gets better. \s
>>> \s
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s
""";
DriverStation.reportWarning(bfw, false);
DriverStation.reportError(bfw, false);
throw new UnsupportedOperationException(bfw);
}
if (!Core.VERSION.equals(PhotonVersion.opencvTargetVersion)) {
String bfw =
"\n\n\n\n\n"
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
+ ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+ ">>> \n"
+ ">>> You are running an incompatible version \n"
+ ">>> of PhotonVision ! \n"
+ ">>> \n"
+ ">>> PhotonLib "
+ PhotonVersion.versionString
+ " is built for OpenCV "
+ PhotonVersion.opencvTargetVersion
+ "\n"
+ ">>> but you are using OpenCV "
+ Core.VERSION
+ ">>> \n"
+ ">>> This is neither tested nor supported. \n"
+ ">>> You MUST update PhotonVision, \n"
+ ">>> PhotonLib, or both. \n"
+ ">>> Verify the output of `./gradlew dependencies` \n"
+ ">>> \n"
+ ">>> Your code will now crash. \n"
+ ">>> We hope your day gets better. \n"
+ ">>> \n"
+ ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
String bfw = """
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s
>>> \s
>>> You are running an incompatible version \s
>>> of PhotonVision ! \s
>>> \s
>>> PhotonLib """
+ PhotonVersion.versionString
+ " is built for OpenCV "
+ PhotonVersion.opencvTargetVersion
+ "\n"
+ ">>> but you are using OpenCV "
+ Core.VERSION
+ """
>>> \s
>>> This is neither tested nor supported. \s
>>> You MUST update PhotonVision, \s
>>> PhotonLib, or both. \s
>>> Verify the output of `./gradlew dependencies`
>>> \s
>>> Your code will now crash. \s
>>> We hope your day gets better. \s
>>> \s
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\s
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\s
""";
// spotless:on
DriverStation.reportWarning(bfw, false);
DriverStation.reportError(bfw, false);
@@ -533,23 +544,30 @@ public class PhotonCamera implements AutoCloseable {
// Error on a verified version mismatch
// But stay silent otherwise
String bfw =
"\n\n\n\n\n"
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
+ ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+ ">>> \n"
+ ">>> You are running an incompatible version \n"
+ ">>> of PhotonVision on your coprocessor! \n"
+ ">>> \n"
+ ">>> This is neither tested nor supported. \n"
+ ">>> You MUST update PhotonVision, \n"
+ ">>> PhotonLib, or both. \n"
+ ">>> \n"
+ ">>> Your code will now crash. \n"
+ ">>> We hope your day gets better. \n"
+ ">>> \n"
+ ">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
+ ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
// spotless:off
String bfw = """
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>> \s
>>> You are running an incompatible version \s
>>> of PhotonVision on your coprocessor! \s
>>> \s
>>> This is neither tested nor supported. \s
>>> You MUST update PhotonVision, \s
>>> PhotonLib, or both. \s
>>> \s
>>> Your code will now crash. \s
>>> We hope your day gets better. \s
>>> \s
>>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
""";
// spotless:on
DriverStation.reportWarning(bfw, false);
var versionMismatchMessage =
@@ -575,6 +593,6 @@ public class PhotonCamera implements AutoCloseable {
it -> {
return rootPhotonTable.getSubTable(it).getEntry("rawBytes").exists();
})
.collect(Collectors.toList());
.toList();
}
}

View File

@@ -336,6 +336,19 @@ public class PhotonPoseEstimator {
headingBuffer.addSample(timestampSeconds, heading);
}
/**
* Clears all heading data in the buffer, and adds a new seed. Useful for preventing estimates
* from utilizing heading data provided prior to a pose or rotation reset.
*
* @param timestampSeconds timestamp of the robot heading data.
* @param heading Field-relative robot heading at given timestamp. Standard WPILIB field
* coordinates.
*/
public void resetHeadingData(double timestampSeconds, Rotation2d heading) {
headingBuffer.clear();
addHeadingData(timestampSeconds, heading);
}
/**
* @return The current transform from the center of the robot to the camera mount position
*/

View File

@@ -171,7 +171,7 @@ public class SimCameraProperties {
DriverStation.reportError(
"Requested invalid FOV! Clamping between (1, 179) degrees...", false);
}
double resDiag = Math.sqrt(resWidth * resWidth + resHeight * resHeight);
double resDiag = Math.hypot(resWidth, resHeight);
double diagRatio = Math.tan(fovDiag.getRadians() / 2);
var fovWidth = new Rotation2d(Math.atan(diagRatio * (resWidth / resDiag)) * 2);
var fovHeight = new Rotation2d(Math.atan(diagRatio * (resHeight / resDiag)) * 2);
@@ -202,24 +202,20 @@ public class SimCameraProperties {
this.distCoeffs = distCoeffs;
// left, right, up, and down view planes
var p =
new Translation3d[] {
new Translation3d(
1,
new Rotation3d(0, 0, getPixelYaw(0).plus(new Rotation2d(-Math.PI / 2)).getRadians())),
new Translation3d(
1,
new Rotation3d(
0, 0, getPixelYaw(resWidth).plus(new Rotation2d(Math.PI / 2)).getRadians())),
new Translation3d(
1,
new Rotation3d(
0, getPixelPitch(0).plus(new Rotation2d(Math.PI / 2)).getRadians(), 0)),
new Translation3d(
1,
new Rotation3d(
0, getPixelPitch(resHeight).plus(new Rotation2d(-Math.PI / 2)).getRadians(), 0))
};
Translation3d[] p = {
new Translation3d(
1, new Rotation3d(0, 0, getPixelYaw(0).plus(new Rotation2d(-Math.PI / 2)).getRadians())),
new Translation3d(
1,
new Rotation3d(
0, 0, getPixelYaw(resWidth).plus(new Rotation2d(Math.PI / 2)).getRadians())),
new Translation3d(
1, new Rotation3d(0, getPixelPitch(0).plus(new Rotation2d(Math.PI / 2)).getRadians(), 0)),
new Translation3d(
1,
new Rotation3d(
0, getPixelPitch(resHeight).plus(new Rotation2d(-Math.PI / 2)).getRadians(), 0))
};
viewplanes.clear();
for (Translation3d translation3d : p) {
viewplanes.add(

View File

@@ -39,7 +39,6 @@ import java.util.Map;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
import org.opencv.core.Point;
@@ -85,14 +84,16 @@ public class VideoSimUtil {
* through a Mat, the point (0,0) actually represents the center of the top-left pixel and not the
* actual top-left corner.
*
* <p>Order of corners returned is: [BL, BR, TR, TL]
*
* @param size Size of image
*/
public static Point[] getImageCorners(Size size) {
return new Point[] {
new Point(-0.5, -0.5),
new Point(size.width - 0.5, -0.5),
new Point(-0.5, size.height - 0.5),
new Point(size.width - 0.5, size.height - 0.5),
new Point(-0.5, size.height - 0.5)
new Point(size.width - 0.5, -0.5),
new Point(-0.5, -0.5)
};
}
@@ -103,16 +104,8 @@ public class VideoSimUtil {
*/
private static Mat get36h11TagImage(int id) {
RawFrame frame = AprilTag.generate36h11AprilTagImage(id);
var buf = frame.getData();
byte[] arr = new byte[buf.remaining()];
buf.get(arr);
// frame.close();
var mat = new MatOfByte(arr).reshape(1, 10).submat(new Rect(0, 0, 10, 10));
mat.dump();
return mat;
return new Mat(
frame.getHeight(), frame.getWidth(), CvType.CV_8UC1, frame.getData(), frame.getStride());
}
/** Gets the points representing the marker(black square) corners. */

View File

@@ -41,7 +41,6 @@ import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import org.photonvision.PhotonCamera;
import org.photonvision.estimation.TargetModel;
@@ -357,10 +356,7 @@ public class VisionSystemSim {
entry ->
dbgField
.getObject(entry.getKey())
.setPoses(
entry.getValue().stream()
.map(t -> t.getPose().toPose2d())
.collect(Collectors.toList())));
.setPoses(entry.getValue().stream().map(t -> t.getPose().toPose2d()).toList()));
if (robotPoseMeters == null) return;

View File

@@ -76,10 +76,10 @@ static std::unordered_map<int, cv::Mat> LoadAprilTagImages() {
static std::vector<cv::Point2f> GetImageCorners(const cv::Size& size) {
std::vector<cv::Point2f> retVal{};
retVal.emplace_back(cv::Point2f{-0.5f, -0.5f});
retVal.emplace_back(cv::Point2f{size.width - 0.5f, -0.5f});
retVal.emplace_back(cv::Point2f{size.width - 0.5f, size.height - 0.5f});
retVal.emplace_back(cv::Point2f{-0.5f, size.height - 0.5f});
retVal.emplace_back(cv::Point2f{size.width - 0.5f, size.height - 0.5f});
retVal.emplace_back(cv::Point2f{size.width - 0.5f, -0.5f});
retVal.emplace_back(cv::Point2f{-0.5f, -0.5f});
return retVal;
}

View File

@@ -46,7 +46,6 @@ import java.util.List;
import java.util.Optional;
import java.util.stream.Stream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -95,7 +94,7 @@ class PhotonCameraTest {
@Test
public void testEmpty() {
Assertions.assertDoesNotThrow(
assertDoesNotThrow(
() -> {
var packet = new Packet(1);
var ret = new PhotonPipelineResult();

View File

@@ -24,9 +24,10 @@
package org.photonvision;
import static org.junit.jupiter.api.Assertions.assertEquals;
import edu.wpi.first.math.geometry.*;
import edu.wpi.first.math.util.Units;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
class PhotonUtilTest {
@@ -40,7 +41,7 @@ class PhotonUtilTest {
var dist =
PhotonUtils.calculateDistanceToTargetMeters(camHeight, targetHeight, camPitch, targetPitch);
Assertions.assertEquals(3.464, dist, 0.01);
assertEquals(3.464, dist, 0.01);
camHeight = 1;
targetHeight = 2;
@@ -49,7 +50,7 @@ class PhotonUtilTest {
dist =
PhotonUtils.calculateDistanceToTargetMeters(camHeight, targetHeight, camPitch, targetPitch);
Assertions.assertEquals(5.671, dist, 0.01);
assertEquals(5.671, dist, 0.01);
}
@Test
@@ -75,9 +76,9 @@ class PhotonUtilTest {
fieldToTarget,
cameraToRobot);
Assertions.assertEquals(-3.464, fieldToRobot.getX(), 0.1);
Assertions.assertEquals(0, fieldToRobot.getY(), 0.1);
Assertions.assertEquals(0, fieldToRobot.getRotation().getDegrees(), 0.1);
assertEquals(-3.464, fieldToRobot.getX(), 0.1);
assertEquals(0, fieldToRobot.getY(), 0.1);
assertEquals(0, fieldToRobot.getRotation().getDegrees(), 0.1);
}
@Test
@@ -94,8 +95,8 @@ class PhotonUtilTest {
new Translation2d(Units.inchesToMeters(324), Units.inchesToMeters(162)),
new Rotation2d());
var currentPose = new Pose2d(0, 0, Rotation2d.fromDegrees(0));
Assertions.assertEquals(4.0, fieldToRobot.getX());
Assertions.assertEquals(
assertEquals(4.0, fieldToRobot.getX());
assertEquals(
Math.toDegrees(Math.atan2((Units.inchesToMeters(162)), (Units.inchesToMeters(324)))),
PhotonUtils.getYawToPose(currentPose, targetPose).getDegrees());
}

View File

@@ -25,10 +25,11 @@
package org.photonvision;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
public class PhotonVersionTest {
@@ -52,11 +53,11 @@ public class PhotonVersionTest {
@Test
public void testVersion() {
Assertions.assertTrue(versionMatches("v2021.1.6", "v2021.1.6"));
Assertions.assertTrue(versionMatches("dev-v2021.1.6", "v2021.1.6"));
Assertions.assertTrue(versionMatches("dev-v2021.1.6-5-gca49ea50", "v2021.1.6"));
Assertions.assertFalse(versionMatches("", "v2021.1.6"));
Assertions.assertFalse(versionMatches("v2021.1.6", ""));
assertTrue(versionMatches("v2021.1.6", "v2021.1.6"));
assertTrue(versionMatches("dev-v2021.1.6", "v2021.1.6"));
assertTrue(versionMatches("dev-v2021.1.6-5-gca49ea50", "v2021.1.6"));
assertFalse(versionMatches("", "v2021.1.6"));
assertFalse(versionMatches("v2021.1.6", ""));
}
@Test

View File

@@ -24,6 +24,7 @@
package org.photonvision;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -50,7 +51,6 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -111,7 +111,7 @@ class VisionSystemSimTest {
@Test
public void testEmpty() {
Assertions.assertDoesNotThrow(
assertDoesNotThrow(
() -> {
var sysUnderTest = new VisionSystemSim("Test");
sysUnderTest.addVisionTargets(