mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-19 00:41:41 +00:00
Make the latency/fps setting per camera instead of global (#2260)
There's a new `low latency mode` switch on the input tab. This replaces use_new_cscore_frametime and makes it per pipeline. <img width="684" height="535" alt="image" src="https://github.com/user-attachments/assets/a7ba8bc0-69b6-44f3-83e3-9b88d8219dfa" /> The default behavior is still to block for new frames (ie, preserve old behavior) --------- Co-authored-by: Matt Morley <matthew.morley.ca@gmail.com>
This commit is contained in:
@@ -158,6 +158,16 @@ const interactiveCols = computed(() =>
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ cameraWhiteBalanceTemp: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-switch
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.blockForFrames"
|
||||
:disabled="!useCameraSettingsStore().currentCameraSettings.matchedCameraInfo.PVUsbCameraInfo"
|
||||
label="Low Latency Mode"
|
||||
:switch-cols="interactiveCols"
|
||||
tooltip="When enabled, USB cameras wait for the next camera frame for lowest latency. When disabled, uses the most recent available frame for higher FPS."
|
||||
@update:modelValue="
|
||||
(args) => useCameraSettingsStore().changeCurrentPipelineSetting({ blockForFrames: args }, false)
|
||||
"
|
||||
/>
|
||||
<pv-select
|
||||
v-model="useCameraSettingsStore().currentPipelineSettings.inputImageRotationMode"
|
||||
label="Orientation"
|
||||
|
||||
@@ -84,6 +84,8 @@ export interface PipelineSettings {
|
||||
|
||||
cameraAutoWhiteBalance: boolean;
|
||||
cameraWhiteBalanceTemp: number;
|
||||
|
||||
blockForFrames: boolean;
|
||||
}
|
||||
export type ConfigurablePipelineSettings = Partial<
|
||||
Omit<
|
||||
@@ -148,7 +150,8 @@ export const DefaultPipelineSettings: Omit<
|
||||
cameraAutoWhiteBalance: false,
|
||||
cameraWhiteBalanceTemp: 4000,
|
||||
cameraMinExposureRaw: 1,
|
||||
cameraMaxExposureRaw: 2
|
||||
cameraMaxExposureRaw: 2,
|
||||
blockForFrames: true
|
||||
};
|
||||
|
||||
export interface ReflectivePipelineSettings extends PipelineSettings {
|
||||
|
||||
@@ -191,9 +191,10 @@ public class CameraConfiguration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a calibration from our list.
|
||||
* Remove a calibration from our list. If found, the calibration will be "released". If not found,
|
||||
* no-op.
|
||||
*
|
||||
* @param calibration The calibration to remove
|
||||
* @param unrotatedImageSize The resolution to remove.
|
||||
*/
|
||||
public void removeCalibration(Size unrotatedImageSize) {
|
||||
logger.info("deleting calibration " + unrotatedImageSize);
|
||||
|
||||
@@ -81,6 +81,12 @@ public class TestSource extends VisionSource {
|
||||
throw new UnsupportedOperationException("Unimplemented method 'requestHsvSettings'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestBlockForFrames(boolean blockForFrames) {
|
||||
// TODO Auto-generated method stub
|
||||
throw new UnsupportedOperationException("Unimplemented method 'requestBlockForFrames'");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
@@ -59,4 +59,7 @@ public abstract class FrameProvider implements Supplier<Frame>, Releasable {
|
||||
|
||||
/** Ask the camera to rotate frames it outputs */
|
||||
public abstract void requestHsvSettings(HSVPipe.HSVParams params);
|
||||
|
||||
/** Ask the camera to block for new frames (true) or use latest available (false) */
|
||||
public abstract void requestBlockForFrames(boolean blockForFrames);
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ public abstract class CpuImageProcessor extends FrameProvider {
|
||||
private final RotateImagePipe m_rImagePipe = new RotateImagePipe();
|
||||
private final GrayscalePipe m_grayPipe = new GrayscalePipe();
|
||||
FrameThresholdType m_processType;
|
||||
boolean m_blockForFrames = true;
|
||||
|
||||
private final Object m_mutex = new Object();
|
||||
|
||||
@@ -129,4 +130,11 @@ public abstract class CpuImageProcessor extends FrameProvider {
|
||||
public void requestFrameCopies(boolean copyInput, boolean copyOutput) {
|
||||
// We don't actually do zero-copy, so this method is a no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestBlockForFrames(boolean blockForFrames) {
|
||||
synchronized (m_mutex) {
|
||||
this.m_blockForFrames = blockForFrames;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +135,11 @@ public class LibcameraGpuFrameProvider extends FrameProvider {
|
||||
LibCameraJNI.setFramesToCopy(settables.r_ptr, copyInput, copyOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestBlockForFrames(boolean blockForFrames) {
|
||||
// GPU provider always blocks for frames, so this is a no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
synchronized (settables.CAMERA_LOCK) {
|
||||
|
||||
@@ -20,11 +20,9 @@ package org.photonvision.vision.frame.provider;
|
||||
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;
|
||||
@@ -44,9 +42,6 @@ public class USBFrameProvider extends CpuImageProcessor {
|
||||
|
||||
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) {
|
||||
@@ -59,10 +54,6 @@ public class USBFrameProvider extends CpuImageProcessor {
|
||||
|
||||
this.settables = visionSettables;
|
||||
|
||||
var useNewBehaviorTopic =
|
||||
NetworkTablesManager.getInstance().kRootTable.getBooleanTopic("use_new_cscore_frametime");
|
||||
|
||||
useNewBehaviorSub = useNewBehaviorTopic.subscribe(false);
|
||||
this.connectedCallback = connectedCallback;
|
||||
}
|
||||
|
||||
@@ -86,7 +77,7 @@ public class USBFrameProvider extends CpuImageProcessor {
|
||||
onCameraConnected();
|
||||
}
|
||||
|
||||
if (!useNewBehaviorSub.get()) {
|
||||
if (m_blockForFrames) {
|
||||
// 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
|
||||
|
||||
@@ -61,6 +61,8 @@ public class CVPipelineSettings implements Cloneable {
|
||||
public boolean cameraAutoWhiteBalance = false;
|
||||
public double cameraWhiteBalanceTemp = 4000;
|
||||
|
||||
public boolean blockForFrames = true;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -181,6 +181,7 @@ public class VisionRunner {
|
||||
}
|
||||
frameSupplier.requestFrameRotation(settings.inputImageRotationMode);
|
||||
frameSupplier.requestFrameCopies(settings.inputShouldShow, settings.outputShouldShow);
|
||||
frameSupplier.requestBlockForFrames(settings.blockForFrames);
|
||||
|
||||
// Grab the new camera frame
|
||||
var frame = frameSupplier.get();
|
||||
|
||||
@@ -49,7 +49,6 @@ public class EstimatedRobotPose {
|
||||
* @param estimatedPose estimated pose
|
||||
* @param timestampSeconds timestamp of the estimate
|
||||
* @param targetsUsed list of targets used
|
||||
* @param strategy pose strategy
|
||||
*/
|
||||
public EstimatedRobotPose(
|
||||
Pose3d estimatedPose, double timestampSeconds, List<PhotonTrackedTarget> targetsUsed) {
|
||||
|
||||
Reference in New Issue
Block a user