Upgrade to wpilib alpha-6 (#2434)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Ryanforce08 <rradtke1208@gmail.com>
Co-authored-by: PJ Reiniger <pj.reiniger@gmail.com>
Co-authored-by: Jade Turner <spacey-sooty@proton.me>
Co-authored-by: Matt Morley <matthew.morley.ca@gmail.com>
This commit is contained in:
Sam Freund
2026-05-26 21:47:48 -04:00
committed by GitHub
parent d3de87f72b
commit e9006a2803
97 changed files with 732 additions and 1139 deletions

View File

@@ -3,7 +3,7 @@
"name": "photonlib",
"version": "${photon_version}",
"uuid": "515fe07e-bfc6-11fa-b3de-0242ac130004",
"frcYear": "${frc_year}",
"year": "${year}",
"mavenUrls": [
"https://maven.photonvision.org/repository/internal",
"https://maven.photonvision.org/repository/snapshots"

View File

@@ -34,7 +34,7 @@ import org.photonvision.common.networktables.PacketSubscriber;
import org.photonvision.targeting.PhotonPipelineResult;
import org.photonvision.timesync.TimeSyncSingleton;
import org.wpilib.driverstation.Alert;
import org.wpilib.driverstation.DriverStation;
import org.wpilib.driverstation.DriverStationErrors;
import org.wpilib.hardware.hal.HAL;
import org.wpilib.math.linalg.MatBuilder;
import org.wpilib.math.linalg.Matrix;
@@ -189,9 +189,12 @@ public class PhotonCamera implements AutoCloseable {
verifyDependencies();
}
/** This is something we only need to check for java because of the way java packages opencv. */
static void verifyDependencies() {
// spotless:off
if (!Core.VERSION.equals(PhotonVersion.opencvTargetVersion)) {
// WPILIB names their opencv version in the format YEAR-OPENCVVERSION-PATCH
// so we split on '-' and take the middle part to get the version number
if (!Core.VERSION.equals(PhotonVersion.opencvTargetVersion.split("-")[1])) {
String bfw = """
@@ -232,8 +235,8 @@ public class PhotonCamera implements AutoCloseable {
""";
// spotless:on
DriverStation.reportWarning(bfw, false);
DriverStation.reportError(bfw, false);
DriverStationErrors.reportWarning(bfw, false);
DriverStationErrors.reportError(bfw, false);
throw new UnsupportedOperationException(bfw);
}
}
@@ -316,10 +319,10 @@ public class PhotonCamera implements AutoCloseable {
timesyncAlert.setText(warningText);
timesyncAlert.set(true);
if (Timer.getFPGATimestamp() > (prevTimeSyncWarnTime + WARN_DEBOUNCE_SEC)) {
prevTimeSyncWarnTime = Timer.getFPGATimestamp();
if (Timer.getMonotonicTimestamp() > (prevTimeSyncWarnTime + WARN_DEBOUNCE_SEC)) {
prevTimeSyncWarnTime = Timer.getMonotonicTimestamp();
DriverStation.reportWarning(
DriverStationErrors.reportWarning(
warningText
+ "\n\nCheck /photonvision/.timesync/{COPROCESSOR_HOSTNAME} for more information.",
false);
@@ -465,7 +468,7 @@ public class PhotonCamera implements AutoCloseable {
*/
public boolean isConnected() {
var curHeartbeat = heartbeatSubscriber.get();
var now = Timer.getFPGATimestamp();
var now = Timer.getMonotonicTimestamp();
if (curHeartbeat < 0) {
// we have never heard from the camera
@@ -518,19 +521,19 @@ public class PhotonCamera implements AutoCloseable {
void verifyVersion() {
if (!VERSION_CHECK_ENABLED) return;
if ((Timer.getFPGATimestamp() - lastVersionCheckTime) < VERSION_CHECK_INTERVAL) return;
lastVersionCheckTime = Timer.getFPGATimestamp();
if ((Timer.getMonotonicTimestamp() - lastVersionCheckTime) < VERSION_CHECK_INTERVAL) return;
lastVersionCheckTime = Timer.getMonotonicTimestamp();
// Heartbeat entry is assumed to always be present. If it's not present, we
// assume that a camera with that name was never connected in the first place.
if (!heartbeatSubscriber.exists()) {
var cameraNames = getTablesThatLookLikePhotonCameras();
if (cameraNames.isEmpty()) {
DriverStation.reportError(
DriverStationErrors.reportError(
"Could not find **any** PhotonVision coprocessors on NetworkTables. Double check that PhotonVision is running, and that your camera is connected!",
false);
} else {
DriverStation.reportError(
DriverStationErrors.reportError(
"PhotonVision coprocessor at path "
+ path
+ " not found on NetworkTables. Double check that your camera names match!",
@@ -543,7 +546,7 @@ public class PhotonCamera implements AutoCloseable {
cameraNameStr.append("\n");
}
DriverStation.reportError(
DriverStationErrors.reportError(
"Found the following PhotonVision cameras on NetworkTables:\n"
+ cameraNameStr.toString(),
false);
@@ -551,7 +554,7 @@ public class PhotonCamera implements AutoCloseable {
}
// Check for connection status. Warn if disconnected.
else if (!isConnected()) {
DriverStation.reportWarning(
DriverStationErrors.reportWarning(
"PhotonVision coprocessor at path " + path + " is not sending new data.", false);
}
@@ -563,7 +566,7 @@ public class PhotonCamera implements AutoCloseable {
if (remote_uuid == null || remote_uuid.isEmpty()) {
// not connected yet?
DriverStation.reportWarning(
DriverStationErrors.reportWarning(
"PhotonVision coprocessor at path "
+ path
+ " has not reported a message interface UUID - is your coprocessor's camera started?",
@@ -597,7 +600,7 @@ public class PhotonCamera implements AutoCloseable {
""";
// spotless:on
DriverStation.reportWarning(bfw, false);
DriverStationErrors.reportWarning(bfw, false);
String versionMismatchMessage =
"Photon version "
+ PhotonVersion.versionString
@@ -610,7 +613,7 @@ public class PhotonCamera implements AutoCloseable {
+ remote_uuid
+ ")"
+ "!";
DriverStation.reportError(versionMismatchMessage, false);
DriverStationErrors.reportError(versionMismatchMessage, false);
throw new UnsupportedOperationException(versionMismatchMessage);
}
}

View File

@@ -29,7 +29,7 @@ import org.photonvision.estimation.TargetModel;
import org.photonvision.estimation.VisionEstimation;
import org.photonvision.targeting.PhotonPipelineResult;
import org.photonvision.targeting.PhotonTrackedTarget;
import org.wpilib.driverstation.DriverStation;
import org.wpilib.driverstation.DriverStationErrors;
import org.wpilib.hardware.hal.HAL;
import org.wpilib.math.geometry.Pose2d;
import org.wpilib.math.geometry.Pose3d;
@@ -608,7 +608,7 @@ public class PhotonPoseEstimator {
return Optional.empty();
}
if (referencePose == null) {
DriverStation.reportError(
DriverStationErrors.reportError(
"[PhotonPoseEstimator] Tried to use reference pose strategy without setting the reference!",
false);
return Optional.empty();
@@ -760,7 +760,7 @@ public class PhotonPoseEstimator {
private void reportFiducialPoseError(int fiducialId) {
if (!reportedErrors.contains(fiducialId)) {
DriverStation.reportError(
DriverStationErrors.reportError(
"[PhotonPoseEstimator] Tried to get pose of unknown AprilTag: " + fiducialId, false);
reportedErrors.add(fiducialId);
}

View File

@@ -153,7 +153,7 @@ public class PhotonCameraSim implements AutoCloseable {
videoSimRaw =
CameraServer.putVideo(camera.getName() + "-raw", prop.getResWidth(), prop.getResHeight());
videoSimRaw.setPixelFormat(PixelFormat.kGray);
videoSimRaw.setPixelFormat(PixelFormat.GRAY);
videoSimProcessed =
CameraServer.putVideo(
camera.getName() + "-processed", prop.getResWidth(), prop.getResHeight());
@@ -649,7 +649,7 @@ public class PhotonCameraSim implements AutoCloseable {
}
// put this simulated data to NT
var now = RobotController.getFPGATime();
var now = RobotController.getMonotonicTime();
var ret =
new PhotonPipelineResult(
heartbeatCounter,

View File

@@ -41,7 +41,7 @@ import org.opencv.core.Point;
import org.opencv.imgproc.Imgproc;
import org.photonvision.estimation.OpenCVHelp;
import org.photonvision.estimation.RotTrlTransform3d;
import org.wpilib.driverstation.DriverStation;
import org.wpilib.driverstation.DriverStationErrors;
import org.wpilib.math.geometry.Pose3d;
import org.wpilib.math.geometry.Rotation2d;
import org.wpilib.math.geometry.Rotation3d;
@@ -169,7 +169,7 @@ public class SimCameraProperties {
public SimCameraProperties setCalibration(int resWidth, int resHeight, Rotation2d fovDiag) {
if (fovDiag.getDegrees() < 1 || fovDiag.getDegrees() > 179) {
fovDiag = Rotation2d.fromDegrees(Math.clamp(fovDiag.getDegrees(), 1, 179));
DriverStation.reportError(
DriverStationErrors.reportError(
"Requested invalid FOV! Clamping between (1, 179) degrees...", false);
}
double resDiag = Math.hypot(resWidth, resHeight);

View File

@@ -106,7 +106,7 @@ public class VisionSystemSim {
camTrfMap.put(cameraSim, TimeInterpolatableBuffer.createBuffer(kBufferLengthSeconds));
camTrfMap
.get(cameraSim)
.addSample(Timer.getFPGATimestamp(), new Pose3d().plus(robotToCamera));
.addSample(Timer.getMonotonicTimestamp(), new Pose3d().plus(robotToCamera));
}
}
@@ -137,7 +137,7 @@ public class VisionSystemSim {
* @return The transform of this camera, or an empty optional if it is invalid
*/
public Optional<Transform3d> getRobotToCamera(PhotonCameraSim cameraSim) {
return getRobotToCamera(cameraSim, Timer.getFPGATimestamp());
return getRobotToCamera(cameraSim, Timer.getMonotonicTimestamp());
}
/**
@@ -164,7 +164,7 @@ public class VisionSystemSim {
* @return The pose of this camera, or an empty optional if it is invalid
*/
public Optional<Pose3d> getCameraPose(PhotonCameraSim cameraSim) {
return getCameraPose(cameraSim, Timer.getFPGATimestamp());
return getCameraPose(cameraSim, Timer.getMonotonicTimestamp());
}
/**
@@ -191,7 +191,7 @@ public class VisionSystemSim {
public boolean adjustCamera(PhotonCameraSim cameraSim, Transform3d robotToCamera) {
var trfBuffer = camTrfMap.get(cameraSim);
if (trfBuffer == null) return false;
trfBuffer.addSample(Timer.getFPGATimestamp(), new Pose3d().plus(robotToCamera));
trfBuffer.addSample(Timer.getMonotonicTimestamp(), new Pose3d().plus(robotToCamera));
return true;
}
@@ -207,7 +207,7 @@ public class VisionSystemSim {
* @return If the cameraSim was valid and transforms were reset
*/
public boolean resetCameraTransforms(PhotonCameraSim cameraSim) {
double now = Timer.getFPGATimestamp();
double now = Timer.getMonotonicTimestamp();
var trfBuffer = camTrfMap.get(cameraSim);
if (trfBuffer == null) return false;
var lastTrf = new Transform3d(new Pose3d(), trfBuffer.getSample(now).orElse(new Pose3d()));
@@ -339,7 +339,7 @@ public class VisionSystemSim {
* @return The latest robot pose
*/
public Pose3d getRobotPose() {
return getRobotPose(Timer.getFPGATimestamp());
return getRobotPose(Timer.getMonotonicTimestamp());
}
/**
@@ -368,7 +368,7 @@ public class VisionSystemSim {
*/
public void resetRobotPose(Pose3d robotPose) {
robotPoseBuffer.clear();
robotPoseBuffer.addSample(Timer.getFPGATimestamp(), robotPose);
robotPoseBuffer.addSample(Timer.getMonotonicTimestamp(), robotPose);
}
public Field2d getDebugField() {
@@ -403,7 +403,7 @@ public class VisionSystemSim {
if (robotPoseMeters == null) return;
// save "real" robot poses over time
double now = Timer.getFPGATimestamp();
double now = Timer.getMonotonicTimestamp();
robotPoseBuffer.addSample(now, robotPoseMeters);
dbgField.setRobotPose(robotPoseMeters.toPose2d());

View File

@@ -46,51 +46,6 @@
static constexpr wpi::units::second_t WARN_DEBOUNCE_SEC = 5_s;
static constexpr wpi::units::second_t HEARTBEAT_DEBOUNCE_SEC = 500_ms;
inline void verifyDependencies() {
if (!(std::string_view{cv::getVersionString()} ==
std::string_view{photon::PhotonVersion::opencvTargetVersion})) {
std::string bfw =
"\n\n\n\n\n"
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
">>> \n"
">>> You are running an incompatible version \n"
">>> of PhotonVision ! \n"
">>> \n"
">>> PhotonLib ";
bfw += photon::PhotonVersion::versionString;
bfw += " is built for OpenCV ";
bfw += photon::PhotonVersion::opencvTargetVersion;
bfw +=
"\n"
">>> but you are using OpenCV ";
bfw += cv::getVersionString();
bfw +=
"\n>>> \n"
">>> This is neither tested nor supported. \n"
">>> You MUST update WPILib, PhotonLib, or both.\n"
">>> Check `./gradlew dependencies` and ensure\n"
">>> all mentions of OpenCV match the version \n"
">>> that PhotonLib was built for. If you find a"
">>> a mismatched version in a dependency, you\n"
">>> must take steps to update the version of \n"
">>> OpenCV used in that dependency. If you do\n"
">>> not control that dependency and an updated\n"
">>> version is not available, contact the \n"
">>> developers of that dependency. \n"
">>> \n"
">>> Your code will now crash. \n"
">>> We hope your day gets better. \n"
">>> \n"
">>> !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n";
WPILIB_ReportWarning(bfw);
WPILIB_ReportError(wpi::err::Error, bfw);
throw new std::runtime_error(std::string{bfw});
}
}
// bit of a hack -- start a TimeSync server on port 5810 (hard-coded). We want
// to avoid calling this from static initialization
static void InitTspServer() {
@@ -169,7 +124,6 @@ PhotonCamera::PhotonCamera(wpi::nt::NetworkTableInstance instance,
"' is disconnected.",
wpi::Alert::Level::MEDIUM),
timesyncAlert(PHOTON_ALERT_GROUP, "", wpi::Alert::Level::MEDIUM) {
verifyDependencies();
InstanceCount++;
HAL_ReportUsage("PhotonVision/PhotonCamera", InstanceCount, "");
@@ -195,7 +149,7 @@ PhotonPipelineResult PhotonCamera::GetLatestResult() {
// Fill the packet with latest data and populate result.
wpi::units::microsecond_t now =
wpi::units::microsecond_t(wpi::RobotController::GetFPGATime());
wpi::units::microsecond_t(wpi::RobotController::GetMonotonicTime());
const auto value = rawBytesEntry.Get();
if (!value.size()) return PhotonPipelineResult{};
@@ -265,9 +219,9 @@ void PhotonCamera::CheckTimeSyncOrWarn(photon::PhotonPipelineResult& result) {
timesyncAlert.SetText(warningText);
timesyncAlert.Set(true);
if (wpi::Timer::GetFPGATimestamp() <
if (wpi::Timer::GetMonotonicTimestamp() >
(prevTimeSyncWarnTime + WARN_DEBOUNCE_SEC)) {
prevTimeSyncWarnTime = wpi::Timer::GetFPGATimestamp();
prevTimeSyncWarnTime = wpi::Timer::GetMonotonicTimestamp();
WPILIB_ReportWarning(
warningText +
@@ -325,7 +279,7 @@ const std::string_view PhotonCamera::GetCameraName() const {
bool PhotonCamera::IsConnected() {
auto currentHeartbeat = heartbeatSubscriber.Get();
auto now = wpi::Timer::GetFPGATimestamp();
auto now = wpi::Timer::GetMonotonicTimestamp();
if (currentHeartbeat < 0) {
// we have never heard from the camera
@@ -373,10 +327,10 @@ void PhotonCamera::VerifyVersion() {
return;
}
if ((wpi::Timer::GetFPGATimestamp() - lastVersionCheckTime) <
if ((wpi::Timer::GetMonotonicTimestamp() - lastVersionCheckTime) <
VERSION_CHECK_INTERVAL)
return;
this->lastVersionCheckTime = wpi::Timer::GetFPGATimestamp();
this->lastVersionCheckTime = wpi::Timer::GetMonotonicTimestamp();
const std::string& versionString = versionEntry.Get("");
if (versionString.empty()) {

View File

@@ -51,7 +51,7 @@ PhotonCameraSim::PhotonCameraSim(
videoSimRaw =
wpi::CameraServer::PutVideo(std::string{camera->GetCameraName()} + "-raw",
prop.GetResWidth(), prop.GetResHeight());
videoSimRaw.SetPixelFormat(wpi::util::PixelFormat::kGray);
videoSimRaw.SetPixelFormat(wpi::util::PixelFormat::GRAY);
videoSimProcessed = wpi::CameraServer::PutVideo(
std::string{camera->GetCameraName()} + "-processed", prop.GetResWidth(),
prop.GetResHeight());

View File

@@ -30,6 +30,5 @@ extern const char* versionString;
extern const char* buildDate;
extern const bool isRelease;
extern const char* wpilibTargetVersion;
extern const char* opencvTargetVersion;
} // namespace PhotonVersion
} // namespace photon

View File

@@ -101,7 +101,7 @@ class VisionSystemSim {
std::make_pair(std::move(cameraSim),
wpi::math::TimeInterpolatableBuffer<wpi::math::Pose3d>{
bufferLength}));
camTrfMap.at(cameraSim).AddSample(wpi::Timer::GetFPGATimestamp(),
camTrfMap.at(cameraSim).AddSample(wpi::Timer::GetMonotonicTimestamp(),
wpi::math::Pose3d{} + robotToCamera);
}
}
@@ -138,7 +138,7 @@ class VisionSystemSim {
*/
std::optional<wpi::math::Transform3d> GetRobotToCamera(
PhotonCameraSim* cameraSim) {
return GetRobotToCamera(cameraSim, wpi::Timer::GetFPGATimestamp());
return GetRobotToCamera(cameraSim, wpi::Timer::GetMonotonicTimestamp());
}
/**
@@ -175,7 +175,7 @@ class VisionSystemSim {
* @return The pose of this camera, or an empty optional if it is invalid
*/
std::optional<wpi::math::Pose3d> GetCameraPose(PhotonCameraSim* cameraSim) {
return GetCameraPose(cameraSim, wpi::Timer::GetFPGATimestamp());
return GetCameraPose(cameraSim, wpi::Timer::GetMonotonicTimestamp());
}
/**
@@ -207,7 +207,7 @@ class VisionSystemSim {
bool AdjustCamera(PhotonCameraSim* cameraSim,
const wpi::math::Transform3d& robotToCamera) {
if (camTrfMap.find(cameraSim) != camTrfMap.end()) {
camTrfMap.at(cameraSim).AddSample(wpi::Timer::GetFPGATimestamp(),
camTrfMap.at(cameraSim).AddSample(wpi::Timer::GetMonotonicTimestamp(),
wpi::math::Pose3d{} + robotToCamera);
return true;
} else {
@@ -230,7 +230,7 @@ class VisionSystemSim {
* @return If the cameraSim was valid and transforms were reset
*/
bool ResetCameraTransforms(PhotonCameraSim* cameraSim) {
wpi::units::second_t now = wpi::Timer::GetFPGATimestamp();
wpi::units::second_t now = wpi::Timer::GetMonotonicTimestamp();
if (camTrfMap.find(cameraSim) != camTrfMap.end()) {
auto trfBuffer = camTrfMap.at(cameraSim);
wpi::math::Transform3d lastTrf{
@@ -369,7 +369,7 @@ class VisionSystemSim {
* @return The latest robot pose
*/
wpi::math::Pose3d GetRobotPose() {
return GetRobotPose(wpi::Timer::GetFPGATimestamp());
return GetRobotPose(wpi::Timer::GetMonotonicTimestamp());
}
/**
@@ -398,7 +398,7 @@ class VisionSystemSim {
*/
void ResetRobotPose(const wpi::math::Pose3d& robotPose) {
robotPoseBuffer.Clear();
robotPoseBuffer.AddSample(wpi::Timer::GetFPGATimestamp(), robotPose);
robotPoseBuffer.AddSample(wpi::Timer::GetMonotonicTimestamp(), robotPose);
}
wpi::Field2d& GetDebugField() { return dbgField; }
@@ -427,7 +427,7 @@ class VisionSystemSim {
dbgField.GetObject(set.first)->SetPoses(posesToAdd);
}
wpi::units::second_t now = wpi::Timer::GetFPGATimestamp();
wpi::units::second_t now = wpi::Timer::GetMonotonicTimestamp();
robotPoseBuffer.AddSample(now, robotPose);
dbgField.SetRobotPose(robotPose.ToPose2d());

View File

@@ -125,7 +125,7 @@ class PhotonCameraTest {
var res = camera.getLatestResult();
var captureTime = res.getTimestampSeconds();
var now = Timer.getFPGATimestamp();
var now = Timer.getMonotonicTimestamp();
// expectTrue(captureTime < now);