Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
DevonRD committed Jan 13, 2025
2 parents 899f787 + a17efab commit cdf8ffc
Show file tree
Hide file tree
Showing 65 changed files with 1,163 additions and 508 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/photonvision-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ name: PhotonVision Sphinx Documentation Checks

on:
push:
branches: [ master ]
branches: [ main ]
pull_request:
branches: [ master ]
branches: [ main ]
merge_group:

concurrency:
Expand Down
14 changes: 2 additions & 12 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ plugins {
id "cpp"
id "com.diffplug.spotless" version "6.24.0"
id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2"
id "edu.wpi.first.GradleRIO" version "2025.1.1"
id "edu.wpi.first.GradleRIO" version "2025.2.1"
id 'edu.wpi.first.WpilibTools' version '1.3.0'
id 'com.google.protobuf' version '0.9.3' apply false
id 'edu.wpi.first.GradleJni' version '1.1.0'
Expand Down Expand Up @@ -33,7 +33,7 @@ ext.allOutputsFolder = file("$project.buildDir/outputs")
apply from: "versioningHelper.gradle"

ext {
wpilibVersion = "2025.1.1"
wpilibVersion = "2025.2.1"
wpimathVersion = wpilibVersion
openCVYear = "2025"
openCVversion = "4.10.0-3"
Expand Down Expand Up @@ -90,16 +90,6 @@ spotless {
trimTrailingWhitespace()
endWithNewline()
}
format 'xml', {
target fileTree('.') {
include '**/*.xml'
exclude '**/build/**', '**/build-*/**', "**/.idea/**"
}
eclipseWtp('xml')
trimTrailingWhitespace()
indentWithSpaces(2)
endWithNewline()
}
format 'misc', {
target fileTree('.') {
include '**/*.md', '**/.gitignore'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Bonjour provides more stable networking when using Windows PCs. Install [Bonjour

## Installing Java

PhotonVision requires a JDK installed and on the system path. **JDK 17 is needed. Windows Users must use the JDK that ships with WPILib.** [Download and install it from here.](https://github.com/wpilibsuite/allwpilib/releases/tag/v2025.1.1) Either ensure the only Java on your PATH is the WPILIB Java or specify it to gradle with `-Dorg.gradle.java.home=C:\Users\Public\wpilib\2025\jdk`:
PhotonVision requires a JDK installed and on the system path. **JDK 17 is needed. Windows Users must use the JDK that ships with WPILib.** [Download and install it from here.](https://github.com/wpilibsuite/allwpilib/releases/tag/v2025.2.1) Either ensure the only Java on your PATH is the WPILIB Java or specify it to gradle with `-Dorg.gradle.java.home=C:\Users\Public\wpilib\2025\jdk`:

```
> ./gradlew run "-Dorg.gradle.java.home=C:\Users\Public\wpilib\2025\jdk"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@
import edu.wpi.first.cameraserver.CameraServer;
import edu.wpi.first.cscore.CvSink;
import edu.wpi.first.cscore.UsbCamera;
import edu.wpi.first.networktables.BooleanSubscriber;
import edu.wpi.first.util.PixelFormat;
import edu.wpi.first.util.RawFrame;
import org.opencv.core.Mat;
import org.photonvision.common.dataflow.networktables.NetworkTablesManager;
import org.photonvision.common.logging.LogGroup;
import org.photonvision.common.logging.Logger;
import org.photonvision.jni.CscoreExtras;
import org.photonvision.vision.opencv.CVMat;
import org.photonvision.vision.processes.VisionSourceSettables;

Expand All @@ -36,6 +42,11 @@ public class USBFrameProvider extends CpuImageProcessor {

private Runnable connectedCallback;

private long lastTime = 0;

// subscribers are lightweight, and I'm lazy
private final BooleanSubscriber useNewBehaviorSub;

@SuppressWarnings("SpellCheckingInspection")
public USBFrameProvider(
UsbCamera camera, VisionSourceSettables visionSettables, Runnable connectedCallback) {
Expand All @@ -47,6 +58,11 @@ public USBFrameProvider(
this.cvSink.setEnabled(true);

this.settables = visionSettables;

var useNewBehaviorTopic =
NetworkTablesManager.getInstance().kRootTable.getBooleanTopic("use_new_cscore_frametime");

useNewBehaviorSub = useNewBehaviorTopic.subscribe(false);
this.connectedCallback = connectedCallback;
}

Expand All @@ -62,28 +78,66 @@ public boolean checkCameraConnected() {
return connected;
}

final double CSCORE_DEFAULT_FRAME_TIMEOUT = 1.0 / 4.0;

@Override
public CapturedFrame getInputMat() {
if (!cameraPropertiesCached && camera.isConnected()) {
onCameraConnected();
}

// We allocate memory so we don't fill a Mat in use by another thread (memory
// model is easier)
var mat = new CVMat();
// This is from wpi::Now, or WPIUtilJNI.now(). The epoch from grabFrame is uS
// since
// Hal::initialize was called. Timeout is in seconds
// TODO - under the hood, this incurs an extra copy. We should avoid this, if we
// can.
long captureTimeNs = cvSink.grabFrame(mat.getMat(), 1.0) * 1000;

if (captureTimeNs == 0) {
var error = cvSink.getError();
logger.error("Error grabbing image: " + error);
if (!useNewBehaviorSub.get()) {
// We allocate memory so we don't fill a Mat in use by another thread (memory model is easier)
var mat = new CVMat();
// This is from wpi::Now, or WPIUtilJNI.now(). The epoch from grabFrame is uS since
// Hal::initialize was called
// TODO - under the hood, this incurs an extra copy. We should avoid this, if we
// can.
long captureTimeNs = cvSink.grabFrame(mat.getMat(), CSCORE_DEFAULT_FRAME_TIMEOUT) * 1000;

if (captureTimeNs == 0) {
var error = cvSink.getError();
logger.error("Error grabbing image: " + error);
}

return new CapturedFrame(mat, settables.getFrameStaticProperties(), captureTimeNs);
} else {
// We allocate memory so we don't fill a Mat in use by another thread (memory model is easier)
// TODO - consider a frame pool
// TODO - getCurrentVideoMode is a JNI call for us, but profiling indicates it's fast
var cameraMode = settables.getCurrentVideoMode();
var frame = new RawFrame();
frame.setInfo(
cameraMode.width,
cameraMode.height,
// hard-coded 3 channel
cameraMode.width * 3,
PixelFormat.kBGR);

// This is from wpi::Now, or WPIUtilJNI.now(). The epoch from grabFrame is uS since
// Hal::initialize was called
long captureTimeUs =
CscoreExtras.grabRawSinkFrameTimeoutLastTime(
cvSink.getHandle(), frame.getNativeObj(), CSCORE_DEFAULT_FRAME_TIMEOUT, lastTime);
lastTime = captureTimeUs;

CVMat ret;

if (captureTimeUs == 0) {
var error = cvSink.getError();
logger.error("Error grabbing image: " + error);

frame.close();
ret = new CVMat();
} else {
// No error! yay
var mat = new Mat(CscoreExtras.wrapRawFrame(frame.getNativeObj()));

ret = new CVMat(mat, frame);
}

return new CapturedFrame(ret, settables.getFrameStaticProperties(), captureTimeUs * 1000);
}

return new CapturedFrame(mat, settables.getFrameStaticProperties(), captureTimeNs);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

package org.photonvision.vision.opencv;

import edu.wpi.first.util.RawFrame;
import java.util.HashMap;
import org.opencv.core.Mat;
import org.photonvision.common.logging.LogGroup;
Expand All @@ -31,11 +32,16 @@ public class CVMat implements Releasable {
private static boolean shouldPrint;

private final Mat mat;
private final RawFrame backingFrame;

public CVMat() {
this(new Mat());
}

public CVMat(Mat mat) {
this(mat, null);
}

public void copyFrom(CVMat srcMat) {
copyFrom(srcMat.getMat());
}
Expand All @@ -56,8 +62,10 @@ private StringBuilder getStackTraceBuilder() {
return traceStr;
}

public CVMat(Mat mat) {
public CVMat(Mat mat, RawFrame frame) {
this.mat = mat;
this.backingFrame = frame;

allMatCounter++;
allMats.put(mat, allMatCounter);

Expand All @@ -69,6 +77,8 @@ public CVMat(Mat mat) {

@Override
public void release() {
if (this.backingFrame != null) this.backingFrame.close();

// If this mat is empty, all we can do is return
if (mat.empty()) return;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,24 +18,34 @@
package org.photonvision.vision.pipe.impl;

import edu.wpi.first.math.filter.LinearFilter;
import org.apache.commons.lang3.time.StopWatch;
import edu.wpi.first.wpilibj.Timer;
import org.photonvision.vision.pipe.CVPipe;

public class CalculateFPSPipe
extends CVPipe<Void, Integer, CalculateFPSPipe.CalculateFPSPipeParams> {
private final LinearFilter fpsFilter = LinearFilter.movingAverage(20);
StopWatch clock = new StopWatch();

// roll my own Timer, since this is so trivial
double lastTime = -1;

@Override
protected Integer process(Void in) {
if (!clock.isStarted()) {
clock.reset();
clock.start();
if (lastTime < 0) {
lastTime = Timer.getFPGATimestamp();
}
clock.stop();
var fps = (int) fpsFilter.calculate(1000.0 / clock.getTime());
clock.reset();
clock.start();

var now = Timer.getFPGATimestamp();
var dtSeconds = now - lastTime;
lastTime = now;

// If < 1 uS between ticks, something is probably wrong
int fps;
if (dtSeconds < 1e-6) {
fps = 0;
} else {
fps = (int) fpsFilter.calculate(1 / dtSeconds);
}

return fps;
}

Expand Down
1 change: 1 addition & 0 deletions photon-lib/py/disableUsingDevBuilds.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python3 -m pip config unset global.find-links
1 change: 1 addition & 0 deletions photon-lib/py/enableUsingDevBuilds.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
python3 -m pip config set global.find-links dist
39 changes: 23 additions & 16 deletions photon-lib/py/photonlibpy/generated/MultiTargetPNPResultSerde.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
###############################################################################
## Copyright (C) Photon Vision.
###############################################################################
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <https://www.gnu.org/licenses/>.
###############################################################################
#
# MIT License
#
# Copyright (c) PhotonVision
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#

###############################################################################
## THIS FILE WAS AUTO-GENERATED BY ./photon-serde/generate_messages.py.
Expand Down
39 changes: 23 additions & 16 deletions photon-lib/py/photonlibpy/generated/PhotonPipelineMetadataSerde.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
###############################################################################
## Copyright (C) Photon Vision.
###############################################################################
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <https://www.gnu.org/licenses/>.
###############################################################################
#
# MIT License
#
# Copyright (c) PhotonVision
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#

###############################################################################
## THIS FILE WAS AUTO-GENERATED BY ./photon-serde/generate_messages.py.
Expand Down
39 changes: 23 additions & 16 deletions photon-lib/py/photonlibpy/generated/PhotonPipelineResultSerde.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
###############################################################################
## Copyright (C) Photon Vision.
###############################################################################
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program. If not, see <https://www.gnu.org/licenses/>.
###############################################################################
#
# MIT License
#
# Copyright (c) PhotonVision
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
#

###############################################################################
## THIS FILE WAS AUTO-GENERATED BY ./photon-serde/generate_messages.py.
Expand Down
Loading

0 comments on commit cdf8ffc

Please sign in to comment.