mirror of
https://github.com/PhotonVision/photonvision
synced 2026-07-03 03:01:40 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ec66645667 | ||
|
|
39aaa34520 | ||
|
|
4a3200d0c0 | ||
|
|
01dc7ea5ce | ||
|
|
2a9502be3d | ||
|
|
39216db143 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -290,13 +290,13 @@ jobs:
|
|||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
artifact-name: LinuxArm64
|
artifact-name: LinuxArm64
|
||||||
image_suffix: orangepi5
|
image_suffix: orangepi5
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2024.0.6/photonvision_opi5.img.xz
|
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2024.0.9/photonvision_opi5.img.xz
|
||||||
cpu: cortex-a8
|
cpu: cortex-a8
|
||||||
image_additional_mb: 4096
|
image_additional_mb: 4096
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
artifact-name: LinuxArm64
|
artifact-name: LinuxArm64
|
||||||
image_suffix: orangepi5plus
|
image_suffix: orangepi5plus
|
||||||
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2024.0.6/photonvision_opi5plus.img.xz
|
image_url: https://github.com/PhotonVision/photon-image-modifier/releases/download/v2024.0.9/photonvision_opi5plus.img.xz
|
||||||
cpu: cortex-a8
|
cpu: cortex-a8
|
||||||
image_additional_mb: 4096
|
image_additional_mb: 4096
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ plugins {
|
|||||||
id "com.diffplug.spotless" version "6.24.0"
|
id "com.diffplug.spotless" version "6.24.0"
|
||||||
id "edu.wpi.first.NativeUtils" version "2024.6.1" apply false
|
id "edu.wpi.first.NativeUtils" version "2024.6.1" apply false
|
||||||
id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2"
|
id "edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin" version "2020.2"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
id 'edu.wpi.first.WpilibTools' version '1.3.0'
|
id 'edu.wpi.first.WpilibTools' version '1.3.0'
|
||||||
id 'com.google.protobuf' version '0.9.4' apply false
|
id 'com.google.protobuf' version '0.9.4' apply false
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ allprojects {
|
|||||||
apply from: "versioningHelper.gradle"
|
apply from: "versioningHelper.gradle"
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
wpilibVersion = "2024.2.1"
|
wpilibVersion = "2024.3.1"
|
||||||
wpimathVersion = wpilibVersion
|
wpimathVersion = wpilibVersion
|
||||||
openCVversion = "4.8.0-2"
|
openCVversion = "4.8.0-2"
|
||||||
joglVersion = "2.4.0-rc-20200307"
|
joglVersion = "2.4.0-rc-20200307"
|
||||||
|
|||||||
@@ -281,11 +281,29 @@ watchEffect(() => {
|
|||||||
</v-banner>
|
</v-banner>
|
||||||
<pv-switch
|
<pv-switch
|
||||||
v-model="tempSettingsStruct.matchCamerasOnlyByPath"
|
v-model="tempSettingsStruct.matchCamerasOnlyByPath"
|
||||||
label="Match cameras by-path ONLY"
|
label="Strictly match ONLY known cameras"
|
||||||
tooltip="ONLY match cameras by the USB port they're plugged into + (basename or USB VID/PID), and never only by the device product string"
|
tooltip="ONLY match cameras by the USB port they're plugged into + (basename or USB VID/PID), and never only by the device product string. Also disables automatic detection of new cameras."
|
||||||
class="mt-3 mb-2"
|
class="mt-3 mb-2"
|
||||||
:label-cols="4"
|
:label-cols="4"
|
||||||
/>
|
/>
|
||||||
|
<v-banner
|
||||||
|
v-show="tempSettingsStruct.matchCamerasOnlyByPath"
|
||||||
|
rounded
|
||||||
|
color="red"
|
||||||
|
class="mb-3"
|
||||||
|
text-color="white"
|
||||||
|
icon="mdi-information-outline"
|
||||||
|
>
|
||||||
|
Physical cameras will be strictly matched to camera configurations using physical USB port they are plugged
|
||||||
|
into, in addition to device name and other USB metadata. Additionally, no new cameras are allowed to be added.
|
||||||
|
This setting is useful for guaranteeing that an already known and configured camera can never be matched as an
|
||||||
|
"unknown"/"new" camera, which resets pipelines and calibration data.
|
||||||
|
<p />
|
||||||
|
Cameras will NOT be matched if they change USB ports, and new cameras plugged into this coprocessor will NOT
|
||||||
|
be automatically recognized or configured for vision processing.
|
||||||
|
<p />
|
||||||
|
To add a new camera to this coprocessor, disable this setting, connect the camera, and re-enable.
|
||||||
|
</v-banner>
|
||||||
<v-divider class="mb-3" />
|
<v-divider class="mb-3" />
|
||||||
</v-form>
|
</v-form>
|
||||||
<v-btn
|
<v-btn
|
||||||
|
|||||||
@@ -41,7 +41,9 @@ public class NetworkConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* If we should ONLY match cameras by path, and NEVER only by base-name. For now default to false
|
* If we should ONLY match cameras by path, and NEVER only by base-name. For now default to false
|
||||||
* to preserve old matching logic
|
* to preserve old matching logic.
|
||||||
|
*
|
||||||
|
* <p>This also disables creating new CameraConfigurations for detected "new" cameras.
|
||||||
*/
|
*/
|
||||||
public boolean matchCamerasOnlyByPath = false;
|
public boolean matchCamerasOnlyByPath = false;
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ package org.photonvision.vision.camera;
|
|||||||
import edu.wpi.first.cscore.UsbCameraInfo;
|
import edu.wpi.first.cscore.UsbCameraInfo;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import org.photonvision.common.hardware.Platform;
|
||||||
|
|
||||||
public class CameraInfo extends UsbCameraInfo {
|
public class CameraInfo extends UsbCameraInfo {
|
||||||
public final CameraType cameraType;
|
public final CameraType cameraType;
|
||||||
@@ -80,15 +81,27 @@ public class CameraInfo extends UsbCameraInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(Object o) {
|
public boolean equals(Object obj) {
|
||||||
if (o == this) return true;
|
if (this == obj) return true;
|
||||||
if (!(o instanceof UsbCameraInfo || o instanceof CameraInfo)) return false;
|
if (obj == null) return false;
|
||||||
UsbCameraInfo other = (UsbCameraInfo) o;
|
if (getClass() != obj.getClass()) return false;
|
||||||
return path.equals(other.path)
|
CameraInfo other = (CameraInfo) obj;
|
||||||
// && a.dev == b.dev (dev is not constant in Windows)
|
|
||||||
&& name.equals(other.name)
|
// Windows device number is not significant. See
|
||||||
&& productId == other.productId
|
// https://github.com/wpilibsuite/allwpilib/blob/4b94a64b06057c723d6fcafeb1a45f55a70d179a/cscore/src/main/native/windows/UsbCameraImpl.cpp#L1128
|
||||||
&& vendorId == other.vendorId;
|
if (!Platform.isWindows()) {
|
||||||
|
if (dev != other.dev) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!path.equals(other.path)) return false;
|
||||||
|
if (!name.equals(other.name)) return false;
|
||||||
|
if (!Arrays.asList(this.otherPaths).containsAll(Arrays.asList(other.otherPaths))) return false;
|
||||||
|
if (vendorId != other.vendorId) return false;
|
||||||
|
if (productId != other.productId) return false;
|
||||||
|
|
||||||
|
// Don't trust super.equals, as it compares references. Should PR this to allwpilib at some
|
||||||
|
// point
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -101,6 +114,8 @@ public class CameraInfo extends UsbCameraInfo {
|
|||||||
+ vendorId
|
+ vendorId
|
||||||
+ ", pid="
|
+ ", pid="
|
||||||
+ productId
|
+ productId
|
||||||
|
+ ", path="
|
||||||
|
+ path
|
||||||
+ ", otherPaths="
|
+ ", otherPaths="
|
||||||
+ Arrays.toString(otherPaths)
|
+ Arrays.toString(otherPaths)
|
||||||
+ "]";
|
+ "]";
|
||||||
|
|||||||
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* 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/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.photonvision.vision.camera;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import org.photonvision.common.configuration.CameraConfiguration;
|
||||||
|
import org.photonvision.vision.frame.Frame;
|
||||||
|
import org.photonvision.vision.frame.FrameProvider;
|
||||||
|
import org.photonvision.vision.frame.FrameThresholdType;
|
||||||
|
import org.photonvision.vision.opencv.ImageRotationMode;
|
||||||
|
import org.photonvision.vision.pipe.impl.HSVPipe.HSVParams;
|
||||||
|
import org.photonvision.vision.processes.VisionSource;
|
||||||
|
import org.photonvision.vision.processes.VisionSourceSettables;
|
||||||
|
|
||||||
|
/** Dummy class for unit testing the vision source manager */
|
||||||
|
public class TestSource extends VisionSource {
|
||||||
|
private FrameProvider usbFrameProvider;
|
||||||
|
|
||||||
|
public TestSource(CameraConfiguration config) {
|
||||||
|
super(config);
|
||||||
|
|
||||||
|
if (getCameraConfiguration().cameraQuirks == null)
|
||||||
|
getCameraConfiguration().cameraQuirks =
|
||||||
|
QuirkyCamera.getQuirkyCamera(config.usbVID, config.usbVID, config.baseName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FrameProvider getFrameProvider() {
|
||||||
|
return new FrameProvider() {
|
||||||
|
@Override
|
||||||
|
public Frame get() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'get'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return cameraConfiguration.uniqueName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestFrameThresholdType(FrameThresholdType type) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'requestFrameThresholdType'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestFrameRotation(ImageRotationMode rotationMode) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'requestFrameRotation'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestFrameCopies(boolean copyInput, boolean copyOutput) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'requestFrameCopies'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void requestHsvSettings(HSVParams params) {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'requestHsvSettings'");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VisionSourceSettables getSettables() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'getSettables'");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVendorCamera() {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
throw new UnsupportedOperationException("Unimplemented method 'isVendorCamera'");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -57,8 +57,8 @@ public class USBCameraSource extends VisionSource {
|
|||||||
cvSink = CameraServer.getVideo(this.camera);
|
cvSink = CameraServer.getVideo(this.camera);
|
||||||
|
|
||||||
// set vid/pid if not done already for future matching
|
// set vid/pid if not done already for future matching
|
||||||
if (config.usbVID < 0) config.usbVID = this.camera.getInfo().vendorId;
|
if (config.usbVID <= 0) config.usbVID = this.camera.getInfo().vendorId;
|
||||||
if (config.usbPID < 0) config.usbPID = this.camera.getInfo().productId;
|
if (config.usbPID <= 0) config.usbPID = this.camera.getInfo().productId;
|
||||||
|
|
||||||
if (getCameraConfiguration().cameraQuirks == null)
|
if (getCameraConfiguration().cameraQuirks == null)
|
||||||
getCameraConfiguration().cameraQuirks =
|
getCameraConfiguration().cameraQuirks =
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import org.photonvision.vision.camera.CameraInfo;
|
|||||||
import org.photonvision.vision.camera.CameraQuirk;
|
import org.photonvision.vision.camera.CameraQuirk;
|
||||||
import org.photonvision.vision.camera.CameraType;
|
import org.photonvision.vision.camera.CameraType;
|
||||||
import org.photonvision.vision.camera.LibcameraGpuSource;
|
import org.photonvision.vision.camera.LibcameraGpuSource;
|
||||||
|
import org.photonvision.vision.camera.TestSource;
|
||||||
import org.photonvision.vision.camera.USBCameraSource;
|
import org.photonvision.vision.camera.USBCameraSource;
|
||||||
|
|
||||||
public class VisionSourceManager {
|
public class VisionSourceManager {
|
||||||
@@ -146,8 +147,8 @@ public class VisionSourceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return no new sources because there are no new sources
|
// Return no new sources because there are no new sources
|
||||||
if (connectedCameras.isEmpty() && !cameraInfos.isEmpty()) {
|
if (connectedCameras.isEmpty()) {
|
||||||
if (hasWarnedNoCameras) {
|
if (!hasWarnedNoCameras) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"No cameras were detected! Check that all cameras are connected, and that the path is correct.");
|
"No cameras were detected! Check that all cameras are connected, and that the path is correct.");
|
||||||
hasWarnedNoCameras = true;
|
hasWarnedNoCameras = true;
|
||||||
@@ -186,7 +187,7 @@ public class VisionSourceManager {
|
|||||||
"Unloaded configs: "
|
"Unloaded configs: "
|
||||||
+ unmatchedLoadedConfigs.stream()
|
+ unmatchedLoadedConfigs.stream()
|
||||||
.map(it -> it.nickname)
|
.map(it -> it.nickname)
|
||||||
.collect(Collectors.joining()));
|
.collect(Collectors.joining(", ")));
|
||||||
hasWarned = true;
|
hasWarned = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,13 +196,8 @@ public class VisionSourceManager {
|
|||||||
|
|
||||||
if (matchedCameras.isEmpty()) return null;
|
if (matchedCameras.isEmpty()) return null;
|
||||||
|
|
||||||
// for unit tests only!
|
|
||||||
if (!createSources) {
|
|
||||||
return List.of();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Turn these camera configs into vision sources
|
// Turn these camera configs into vision sources
|
||||||
var sources = loadVisionSourcesFromCamConfigs(matchedCameras);
|
var sources = loadVisionSourcesFromCamConfigs(matchedCameras, createSources);
|
||||||
|
|
||||||
// Print info about each vision source
|
// Print info about each vision source
|
||||||
for (var src : sources) {
|
for (var src : sources) {
|
||||||
@@ -317,26 +313,32 @@ public class VisionSourceManager {
|
|||||||
logger.info("Matching by usb port & name & USB VID/PID...");
|
logger.info("Matching by usb port & name & USB VID/PID...");
|
||||||
cameraConfigurations.addAll(
|
cameraConfigurations.addAll(
|
||||||
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, true, true, true, false));
|
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, true, true, true, false));
|
||||||
} else
|
}
|
||||||
logger.debug("Skipping match by usb port/name/vid/pid, no configs or cameras left to match");
|
|
||||||
|
|
||||||
// On windows, the v4l path is actually useful and tells us the port the camera is physically
|
// On windows, the v4l path is actually useful and tells us the port the camera is physically
|
||||||
// connected to which is neat
|
// connected to which is neat
|
||||||
if (Platform.isWindows()) {
|
if (Platform.isWindows() && !matchCamerasOnlyByPath) {
|
||||||
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
||||||
logger.info("Matching by windows-path & USB VID/PID only...");
|
logger.info("Matching by windows-path & USB VID/PID only...");
|
||||||
cameraConfigurations.addAll(
|
cameraConfigurations.addAll(
|
||||||
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, false, true, true, true));
|
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, false, true, true, true));
|
||||||
} else
|
}
|
||||||
logger.debug(
|
|
||||||
"Skipping matching by windiws-path/name/vid/pid, no configs or cameras left to match");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
||||||
logger.info("Matching by usb port & USB VID/PID...");
|
logger.info("Matching by usb port & USB VID/PID...");
|
||||||
cameraConfigurations.addAll(
|
cameraConfigurations.addAll(
|
||||||
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, true, true, false, false));
|
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, true, true, false, false));
|
||||||
} else logger.debug("Skipping match by port/vid/pid, no configs or cameras left to match");
|
}
|
||||||
|
|
||||||
|
// Legacy migration -- VID/PID will be unset, so we have to try with our most relaxed strategy
|
||||||
|
// at least once. We _should_ still have a valid USB path (assuming cameras have not moved), so
|
||||||
|
// try that first, then fallback to base name only beloow
|
||||||
|
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
||||||
|
logger.info("Matching by base-name & usb port...");
|
||||||
|
cameraConfigurations.addAll(
|
||||||
|
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, true, false, true, false));
|
||||||
|
}
|
||||||
|
|
||||||
// handle disabling only-by-base-name matching
|
// handle disabling only-by-base-name matching
|
||||||
if (!matchCamerasOnlyByPath) {
|
if (!matchCamerasOnlyByPath) {
|
||||||
@@ -344,13 +346,29 @@ public class VisionSourceManager {
|
|||||||
logger.info("Matching by base-name & USB VID/PID only...");
|
logger.info("Matching by base-name & USB VID/PID only...");
|
||||||
cameraConfigurations.addAll(
|
cameraConfigurations.addAll(
|
||||||
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, false, true, true, false));
|
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, false, true, true, false));
|
||||||
} else
|
}
|
||||||
logger.debug("Skipping match by base-name/viid/pid, no configs or cameras left to match");
|
|
||||||
|
// Legacy migration for if no USB VID/PID set
|
||||||
|
if (detectedCameraList.size() > 0 || unloadedConfigs.size() > 0) {
|
||||||
|
logger.info("Matching by base-name only...");
|
||||||
|
cameraConfigurations.addAll(
|
||||||
|
matchCamerasByStrategy(detectedCameraList, unloadedConfigs, false, false, true, false));
|
||||||
|
}
|
||||||
} else logger.info("Skipping match by filepath/vid/pid, disabled by user");
|
} else logger.info("Skipping match by filepath/vid/pid, disabled by user");
|
||||||
|
|
||||||
if (detectedCameraList.size() > 0) {
|
if (detectedCameraList.size() > 0) {
|
||||||
cameraConfigurations.addAll(
|
// handle disabling only-by-base-name matching
|
||||||
createConfigsForCameras(detectedCameraList, unloadedConfigs, cameraConfigurations));
|
if (!matchCamerasOnlyByPath) {
|
||||||
|
cameraConfigurations.addAll(
|
||||||
|
createConfigsForCameras(detectedCameraList, unloadedConfigs, cameraConfigurations));
|
||||||
|
} else {
|
||||||
|
logger.warn(
|
||||||
|
"Not creating 'new' Photon CameraConfigurations for ["
|
||||||
|
+ detectedCamInfos.stream()
|
||||||
|
.map(CameraInfo::toString)
|
||||||
|
.collect(Collectors.joining(";"))
|
||||||
|
+ "], disabled by user");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.debug("Matched or created " + cameraConfigurations.size() + " camera configs!");
|
logger.debug("Matched or created " + cameraConfigurations.size() + " camera configs!");
|
||||||
@@ -434,7 +452,8 @@ public class VisionSourceManager {
|
|||||||
int suffix = 0;
|
int suffix = 0;
|
||||||
while (containsName(loadedConfigs, uniqueName)
|
while (containsName(loadedConfigs, uniqueName)
|
||||||
|| containsName(uniqueName)
|
|| containsName(uniqueName)
|
||||||
|| containsName(unloadedCamConfigs, uniqueName)) {
|
|| containsName(unloadedCamConfigs, uniqueName)
|
||||||
|
|| containsName(ret, uniqueName)) {
|
||||||
suffix++;
|
suffix++;
|
||||||
uniqueName = String.format("%s (%d)", uniqueName, suffix);
|
uniqueName = String.format("%s (%d)", uniqueName, suffix);
|
||||||
}
|
}
|
||||||
@@ -514,11 +533,17 @@ public class VisionSourceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static List<VisionSource> loadVisionSourcesFromCamConfigs(
|
private static List<VisionSource> loadVisionSourcesFromCamConfigs(
|
||||||
List<CameraConfiguration> camConfigs) {
|
List<CameraConfiguration> camConfigs, boolean createSources) {
|
||||||
var cameraSources = new ArrayList<VisionSource>();
|
var cameraSources = new ArrayList<VisionSource>();
|
||||||
for (var configuration : camConfigs) {
|
for (var configuration : camConfigs) {
|
||||||
logger.debug("Creating VisionSource for " + camCfgToString(configuration));
|
logger.debug("Creating VisionSource for " + camCfgToString(configuration));
|
||||||
|
|
||||||
|
// In unit tests, create dummy
|
||||||
|
if (!createSources) {
|
||||||
|
cameraSources.add(new TestSource(configuration));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
boolean is_pi = Platform.isRaspberryPi();
|
boolean is_pi = Platform.isRaspberryPi();
|
||||||
|
|
||||||
if (configuration.cameraType == CameraType.ZeroCopyPicam && is_pi) {
|
if (configuration.cameraType == CameraType.ZeroCopyPicam && is_pi) {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.photonvision.common.configuration.CameraConfiguration;
|
import org.photonvision.common.configuration.CameraConfiguration;
|
||||||
import org.photonvision.common.configuration.ConfigManager;
|
import org.photonvision.common.configuration.ConfigManager;
|
||||||
@@ -271,4 +272,268 @@ public class VisionSourceManagerTest {
|
|||||||
assertEquals(10, inst.knownCameras.size());
|
assertEquals(10, inst.knownCameras.size());
|
||||||
assertEquals(0, inst.unmatchedLoadedConfigs.size());
|
assertEquals(0, inst.unmatchedLoadedConfigs.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisableInhibitPathChangeIdenticalCams() {
|
||||||
|
Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG);
|
||||||
|
|
||||||
|
var inst = new VisionSourceManager();
|
||||||
|
ConfigManager.getInstance().clearConfig();
|
||||||
|
ConfigManager.getInstance().load();
|
||||||
|
ConfigManager.getInstance().getConfig().getNetworkConfig().matchCamerasOnlyByPath = false;
|
||||||
|
|
||||||
|
var CAM2_OLD_PATH =
|
||||||
|
new String[] {"/dev/v4l/by-path/platform-fc880000.usb-usb-0:1:1.0-video-index0"};
|
||||||
|
var CAM2_NEW_PATH =
|
||||||
|
new String[] {"/dev/v4l/by-path/platform-fc880080.usb-usb-0:1:1.3-video-index0"};
|
||||||
|
|
||||||
|
var CAM1_OLD_PATHS =
|
||||||
|
new String[] {
|
||||||
|
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||||
|
"/dev/v4l/by-path/platform-fc800000.usb-usb-0:1:1.0-video-index0"
|
||||||
|
};
|
||||||
|
|
||||||
|
var camera1_saved_config =
|
||||||
|
new CameraConfiguration(
|
||||||
|
"Arducam OV2311 USB Camera",
|
||||||
|
"Arducam OV2311 USB Camera",
|
||||||
|
"fromt-left",
|
||||||
|
"/dev/video0",
|
||||||
|
CAM1_OLD_PATHS);
|
||||||
|
camera1_saved_config.usbVID = 3141;
|
||||||
|
camera1_saved_config.usbPID = 25446;
|
||||||
|
var camera2_saved_config =
|
||||||
|
new CameraConfiguration(
|
||||||
|
"Arducam OV2311 USB Camera",
|
||||||
|
"Arducam OV2311 USB Camera (1)",
|
||||||
|
"fromt-left",
|
||||||
|
"/dev/video2",
|
||||||
|
CAM2_OLD_PATH);
|
||||||
|
camera2_saved_config.usbVID = 3141;
|
||||||
|
camera2_saved_config.usbPID = 25446;
|
||||||
|
|
||||||
|
// And load our "old" configs
|
||||||
|
inst.registerLoadedConfigs(camera1_saved_config, camera2_saved_config);
|
||||||
|
|
||||||
|
// Camera attached to new port, but strict matching disabled
|
||||||
|
{
|
||||||
|
CameraInfo info1 =
|
||||||
|
new CameraInfo(
|
||||||
|
0, "/dev/video11", "Arducam OV2311 USB Camera", CAM1_OLD_PATHS, 3141, 25446);
|
||||||
|
CameraInfo info2 =
|
||||||
|
new CameraInfo(
|
||||||
|
0, "/dev/video12", "Arducam OV2311 USB Camera", CAM2_NEW_PATH, 3141, 25446);
|
||||||
|
|
||||||
|
var cameraInfos = new ArrayList<CameraInfo>();
|
||||||
|
cameraInfos.add(info1);
|
||||||
|
cameraInfos.add(info2);
|
||||||
|
List<VisionSource> ret1 = inst.tryMatchCamImpl(cameraInfos);
|
||||||
|
|
||||||
|
// and check the new one got matched got matched
|
||||||
|
assertEquals(2, ret1.size());
|
||||||
|
assertEquals(
|
||||||
|
1, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info1.path)).count());
|
||||||
|
assertEquals(
|
||||||
|
1, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info2.path)).count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInhibitPathChangeIdenticalCams() {
|
||||||
|
Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG);
|
||||||
|
|
||||||
|
var inst = new VisionSourceManager();
|
||||||
|
ConfigManager.getInstance().clearConfig();
|
||||||
|
ConfigManager.getInstance().load();
|
||||||
|
ConfigManager.getInstance().getConfig().getNetworkConfig().matchCamerasOnlyByPath = true;
|
||||||
|
|
||||||
|
var CAM2_OLD_PATH =
|
||||||
|
new String[] {"/dev/v4l/by-path/platform-fc880000.usb-usb-0:1:1.0-video-index0"};
|
||||||
|
var CAM2_NEW_PATH =
|
||||||
|
new String[] {"/dev/v4l/by-path/platform-fc880080.usb-usb-0:1:1.3-video-index0"};
|
||||||
|
|
||||||
|
var CAM1_OLD_PATHS =
|
||||||
|
new String[] {
|
||||||
|
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||||
|
"/dev/v4l/by-path/platform-fc800000.usb-usb-0:1:1.0-video-index0"
|
||||||
|
};
|
||||||
|
|
||||||
|
var camera1_saved_config =
|
||||||
|
new CameraConfiguration(
|
||||||
|
"Arducam OV2311 USB Camera",
|
||||||
|
"Arducam OV2311 USB Camera (1)",
|
||||||
|
"fromt-left",
|
||||||
|
"/dev/video0",
|
||||||
|
CAM1_OLD_PATHS);
|
||||||
|
camera1_saved_config.usbVID = 3141;
|
||||||
|
camera1_saved_config.usbPID = 25446;
|
||||||
|
var camera2_saved_config =
|
||||||
|
new CameraConfiguration(
|
||||||
|
"Arducam OV2311 USB Camera",
|
||||||
|
"Arducam OV2311 USB Camera (1)",
|
||||||
|
"fromt-left",
|
||||||
|
"/dev/video2",
|
||||||
|
CAM2_OLD_PATH);
|
||||||
|
camera2_saved_config.usbVID = 3141;
|
||||||
|
camera2_saved_config.usbPID = 25446;
|
||||||
|
|
||||||
|
// And load our "old" configs
|
||||||
|
inst.registerLoadedConfigs(camera1_saved_config, camera2_saved_config);
|
||||||
|
|
||||||
|
// initial pass with camera in the wrong spot
|
||||||
|
{
|
||||||
|
// Give our cameras new "paths" to fake the windows logic out. this should not
|
||||||
|
// affect strict matching
|
||||||
|
CameraInfo info1 =
|
||||||
|
new CameraInfo(
|
||||||
|
0, "/dev/video11", "Arducam OV2311 USB Camera", CAM1_OLD_PATHS, 3141, 25446);
|
||||||
|
CameraInfo info2 =
|
||||||
|
new CameraInfo(
|
||||||
|
0, "/dev/video12", "Arducam OV2311 USB Camera", CAM2_NEW_PATH, 3141, 25446);
|
||||||
|
|
||||||
|
var cameraInfos = new ArrayList<CameraInfo>();
|
||||||
|
cameraInfos.add(info1);
|
||||||
|
cameraInfos.add(info2);
|
||||||
|
List<VisionSource> ret1 = inst.tryMatchCamImpl(cameraInfos);
|
||||||
|
|
||||||
|
// Our cameras should be "known"
|
||||||
|
assertTrue(inst.knownCameras.contains(info1));
|
||||||
|
assertTrue(inst.knownCameras.contains(info2));
|
||||||
|
assertEquals(2, inst.knownCameras.size());
|
||||||
|
|
||||||
|
// And we should have matched one camera
|
||||||
|
assertEquals(1, ret1.size());
|
||||||
|
// and only matched camera1, not 2
|
||||||
|
assertEquals(
|
||||||
|
1, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info1.path)).count());
|
||||||
|
assertEquals(
|
||||||
|
0, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info2.path)).count());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now move our camera back
|
||||||
|
{
|
||||||
|
CameraInfo info1 =
|
||||||
|
new CameraInfo(
|
||||||
|
0, "/dev/video11", "Arducam OV2311 USB Camera", CAM1_OLD_PATHS, 3141, 25446);
|
||||||
|
CameraInfo info2 =
|
||||||
|
new CameraInfo(
|
||||||
|
0, "/dev/video12", "Arducam OV2311 USB Camera", CAM2_OLD_PATH, 3141, 25446);
|
||||||
|
|
||||||
|
var cameraInfos = new ArrayList<CameraInfo>();
|
||||||
|
cameraInfos.add(info1);
|
||||||
|
cameraInfos.add(info2);
|
||||||
|
List<VisionSource> ret1 = inst.tryMatchCamImpl(cameraInfos);
|
||||||
|
|
||||||
|
// and check the new one got matched got matched
|
||||||
|
assertEquals(1, ret1.size());
|
||||||
|
assertEquals(
|
||||||
|
0, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info1.path)).count());
|
||||||
|
assertEquals(
|
||||||
|
1, ret1.stream().filter(it -> it.cameraConfiguration.path.equals(info2.path)).count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIdenticalCameras() {
|
||||||
|
Logger.setLevel(LogGroup.Camera, LogLevel.DEBUG);
|
||||||
|
|
||||||
|
// List of known cameras
|
||||||
|
var cameraInfos = new ArrayList<CameraInfo>();
|
||||||
|
|
||||||
|
var inst = new VisionSourceManager();
|
||||||
|
ConfigManager.getInstance().clearConfig();
|
||||||
|
ConfigManager.getInstance().load();
|
||||||
|
ConfigManager.getInstance().getConfig().getNetworkConfig().matchCamerasOnlyByPath = false;
|
||||||
|
|
||||||
|
// Match empty camera infos
|
||||||
|
inst.tryMatchCamImpl(cameraInfos);
|
||||||
|
|
||||||
|
CameraInfo info1 =
|
||||||
|
new CameraInfo(
|
||||||
|
0,
|
||||||
|
"/dev/video0",
|
||||||
|
"Arducam OV2311 USB Camera",
|
||||||
|
new String[] {
|
||||||
|
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||||
|
"/dev/v4l/by-path/platform-fc800000.usb-usb-0:1:1.0-video-index0"
|
||||||
|
},
|
||||||
|
3141,
|
||||||
|
25446);
|
||||||
|
CameraInfo info2 =
|
||||||
|
new CameraInfo(
|
||||||
|
0,
|
||||||
|
"/dev/video2",
|
||||||
|
"Arducam OV2311 USB Camera",
|
||||||
|
new String[] {
|
||||||
|
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||||
|
"/dev/v4l/by-path/platform-fc880000.usb-usb-0:1:1.0-video-index0"
|
||||||
|
},
|
||||||
|
3141,
|
||||||
|
25446);
|
||||||
|
|
||||||
|
cameraInfos.add(info1);
|
||||||
|
cameraInfos.add(info2);
|
||||||
|
|
||||||
|
// Match two "new" cameras
|
||||||
|
var ret1 = inst.tryMatchCamImpl(cameraInfos);
|
||||||
|
|
||||||
|
// Our cameras should be "known"
|
||||||
|
assertTrue(inst.knownCameras.contains(info1));
|
||||||
|
assertTrue(inst.knownCameras.contains(info2));
|
||||||
|
assertEquals(2, inst.knownCameras.size());
|
||||||
|
assertEquals(2, ret1.size());
|
||||||
|
|
||||||
|
// Exactly one camera should have the path we put in
|
||||||
|
for (int i = 0; i < cameraInfos.size(); i++) {
|
||||||
|
var testPath = cameraInfos.get(i).getUSBPath().get();
|
||||||
|
assertEquals(
|
||||||
|
1,
|
||||||
|
ret1.stream()
|
||||||
|
.filter(it -> testPath.equals(it.cameraConfiguration.getUSBPath().get()))
|
||||||
|
.count());
|
||||||
|
}
|
||||||
|
|
||||||
|
// and the names should be unique
|
||||||
|
for (int i = 0; i < ret1.size(); i++) {
|
||||||
|
var thisName = ret1.get(i).cameraConfiguration.uniqueName;
|
||||||
|
assertEquals(
|
||||||
|
1,
|
||||||
|
ret1.stream().filter(it -> thisName.equals(it.cameraConfiguration.uniqueName)).count());
|
||||||
|
}
|
||||||
|
|
||||||
|
// duplciate cameras, same info, new ref
|
||||||
|
var duplicateCameraInfos = new ArrayList<CameraInfo>();
|
||||||
|
CameraInfo info1_dup =
|
||||||
|
new CameraInfo(
|
||||||
|
0,
|
||||||
|
"/dev/video0",
|
||||||
|
"Arducam OV2311 USB Camera",
|
||||||
|
new String[] {
|
||||||
|
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||||
|
"/dev/v4l/by-path/platform-fc800000.usb-usb-0:1:1.0-video-index0"
|
||||||
|
},
|
||||||
|
3141,
|
||||||
|
25446);
|
||||||
|
CameraInfo info2_dup =
|
||||||
|
new CameraInfo(
|
||||||
|
0,
|
||||||
|
"/dev/video2",
|
||||||
|
"Arducam OV2311 USB Camera",
|
||||||
|
new String[] {
|
||||||
|
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Arducam_OV2311_USB_Camera_UC621-video-index0",
|
||||||
|
"/dev/v4l/by-path/platform-fc880000.usb-usb-0:1:1.0-video-index0"
|
||||||
|
},
|
||||||
|
3141,
|
||||||
|
25446);
|
||||||
|
|
||||||
|
duplicateCameraInfos.add(info1_dup);
|
||||||
|
duplicateCameraInfos.add(info2_dup);
|
||||||
|
|
||||||
|
inst.tryMatchCamImpl(duplicateCameraInfos);
|
||||||
|
|
||||||
|
// Our cameras should be "known", and we should only "know" two cameras still
|
||||||
|
assertTrue(inst.knownCameras.contains(info1_dup));
|
||||||
|
assertTrue(inst.knownCameras.contains(info2_dup));
|
||||||
|
assertEquals(2, inst.knownCameras.size());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -431,7 +431,7 @@ public class PhotonCameraSim implements AutoCloseable {
|
|||||||
|
|
||||||
detectableTgts.add(
|
detectableTgts.add(
|
||||||
new PhotonTrackedTarget(
|
new PhotonTrackedTarget(
|
||||||
Math.toDegrees(centerRot.getZ()),
|
-Math.toDegrees(centerRot.getZ()),
|
||||||
-Math.toDegrees(centerRot.getY()),
|
-Math.toDegrees(centerRot.getY()),
|
||||||
areaPercent,
|
areaPercent,
|
||||||
Math.toDegrees(centerRot.getX()),
|
Math.toDegrees(centerRot.getX()),
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ class PhotonCameraSim {
|
|||||||
std::vector<std::pair<double, double>> cornersDouble{cornersFloat.begin(),
|
std::vector<std::pair<double, double>> cornersDouble{cornersFloat.begin(),
|
||||||
cornersFloat.end()};
|
cornersFloat.end()};
|
||||||
detectableTgts.emplace_back(PhotonTrackedTarget{
|
detectableTgts.emplace_back(PhotonTrackedTarget{
|
||||||
centerRot.Z().convert<units::degrees>().to<double>(),
|
-centerRot.Z().convert<units::degrees>().to<double>(),
|
||||||
-centerRot.Y().convert<units::degrees>().to<double>(), areaPercent,
|
-centerRot.Y().convert<units::degrees>().to<double>(), areaPercent,
|
||||||
centerRot.X().convert<units::degrees>().to<double>(), tgt.fiducialId,
|
centerRot.X().convert<units::degrees>().to<double>(), tgt.fiducialId,
|
||||||
pnpSim.best, pnpSim.alt, pnpSim.ambiguity, smallVec, cornersDouble});
|
pnpSim.best, pnpSim.alt, pnpSim.ambiguity, smallVec, cornersDouble});
|
||||||
|
|||||||
@@ -256,7 +256,8 @@ class VisionSystemSimTest {
|
|||||||
cameraSim.setMinTargetAreaPixels(0.0);
|
cameraSim.setMinTargetAreaPixels(0.0);
|
||||||
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(0.5, 0.5), 3));
|
visionSysSim.addVisionTargets(new VisionTargetSim(targetPose, new TargetModel(0.5, 0.5), 3));
|
||||||
|
|
||||||
var robotPose = new Pose2d(new Translation2d(10, 0), Rotation2d.fromDegrees(-1.0 * testYaw));
|
// If the robot is rotated x deg (CCW+), the target yaw should be x deg (CW+)
|
||||||
|
var robotPose = new Pose2d(new Translation2d(10, 0), Rotation2d.fromDegrees(testYaw));
|
||||||
visionSysSim.update(robotPose);
|
visionSysSim.update(robotPose);
|
||||||
var res = camera.getLatestResult();
|
var res = camera.getLatestResult();
|
||||||
assertTrue(res.hasTargets());
|
assertTrue(res.hasTargets());
|
||||||
|
|||||||
@@ -220,8 +220,9 @@ TEST_P(VisionSystemSimTestWithParamsTest, YawAngles) {
|
|||||||
visionSysSim.AddVisionTargets({photon::VisionTargetSim{
|
visionSysSim.AddVisionTargets({photon::VisionTargetSim{
|
||||||
targetPose, photon::TargetModel{0.5_m, 0.5_m}, 3}});
|
targetPose, photon::TargetModel{0.5_m, 0.5_m}, 3}});
|
||||||
|
|
||||||
robotPose = frc::Pose2d{frc::Translation2d{10_m, 0_m},
|
// If the robot is rotated x deg (CCW+), the target yaw should be x deg (CW+)
|
||||||
frc::Rotation2d{-1 * GetParam()}};
|
robotPose =
|
||||||
|
frc::Pose2d{frc::Translation2d{10_m, 0_m}, frc::Rotation2d{GetParam()}};
|
||||||
visionSysSim.Update(robotPose);
|
visionSysSim.Update(robotPose);
|
||||||
ASSERT_TRUE(camera.GetLatestResult().HasTargets());
|
ASSERT_TRUE(camera.GetLatestResult().HasTargets());
|
||||||
ASSERT_NEAR(GetParam().to<double>(),
|
ASSERT_NEAR(GetParam().to<double>(),
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "cpp"
|
id "cpp"
|
||||||
id "google-test-test-suite"
|
id "google-test-test-suite"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
|
|
||||||
id "com.dorongold.task-tree" version "2.1.0"
|
id "com.dorongold.task-tree" version "2.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "cpp"
|
id "cpp"
|
||||||
id "google-test-test-suite"
|
id "google-test-test-suite"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
|
|
||||||
id "com.dorongold.task-tree" version "2.1.0"
|
id "com.dorongold.task-tree" version "2.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "cpp"
|
id "cpp"
|
||||||
id "google-test-test-suite"
|
id "google-test-test-suite"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
|
|
||||||
id "com.dorongold.task-tree" version "2.1.0"
|
id "com.dorongold.task-tree" version "2.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "cpp"
|
id "cpp"
|
||||||
id "google-test-test-suite"
|
id "google-test-test-suite"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
|
|
||||||
id "com.dorongold.task-tree" version "2.1.0"
|
id "com.dorongold.task-tree" version "2.1.0"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "cpp"
|
id "cpp"
|
||||||
id "google-test-test-suite"
|
id "google-test-test-suite"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
|
|
||||||
id "com.dorongold.task-tree" version "2.1.0"
|
id "com.dorongold.task-tree" version "2.1.0"
|
||||||
}
|
}
|
||||||
@@ -12,8 +12,8 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
wpi.maven.useDevelopment = true
|
wpi.maven.useDevelopment = true
|
||||||
wpi.versions.wpilibVersion = "2024.2.1"
|
wpi.versions.wpilibVersion = "2024.3.1"
|
||||||
wpi.versions.wpimathVersion = "2024.2.1"
|
wpi.versions.wpimathVersion = "2024.3.1"
|
||||||
|
|
||||||
apply from: "${rootDir}/../shared/examples_common.gradle"
|
apply from: "${rootDir}/../shared/examples_common.gradle"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id "java"
|
id "java"
|
||||||
id "edu.wpi.first.GradleRIO" version "2024.2.1"
|
id "edu.wpi.first.GradleRIO" version "2024.3.1"
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceCompatibility = JavaVersion.VERSION_11
|
sourceCompatibility = JavaVersion.VERSION_11
|
||||||
@@ -11,8 +11,8 @@ apply from: "${rootDir}/../shared/examples_common.gradle"
|
|||||||
def ROBOT_MAIN_CLASS = "frc.robot.Main"
|
def ROBOT_MAIN_CLASS = "frc.robot.Main"
|
||||||
|
|
||||||
wpi.maven.useDevelopment = true
|
wpi.maven.useDevelopment = true
|
||||||
wpi.versions.wpilibVersion = "2024.2.1"
|
wpi.versions.wpilibVersion = "2024.3.1"
|
||||||
wpi.versions.wpimathVersion = "2024.2.1"
|
wpi.versions.wpimathVersion = "2024.3.1"
|
||||||
|
|
||||||
|
|
||||||
// Define my targets (RoboRIO) and artifacts (deployable files)
|
// Define my targets (RoboRIO) and artifacts (deployable files)
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ if [[ "$DISTRO" = "Ubuntu" && "$INSTALL_NETWORK_MANAGER" != "true" && -z "$QUIET
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "Update package list"
|
||||||
|
apt-get update
|
||||||
|
|
||||||
echo "Installing curl..."
|
echo "Installing curl..."
|
||||||
apt-get install --yes curl
|
apt-get install --yes curl
|
||||||
echo "curl installation complete."
|
echo "curl installation complete."
|
||||||
@@ -136,6 +139,9 @@ echo "Installing v4l-utils..."
|
|||||||
apt-get install --yes v4l-utils
|
apt-get install --yes v4l-utils
|
||||||
echo "v4l-utils installation complete."
|
echo "v4l-utils installation complete."
|
||||||
|
|
||||||
|
echo "Installing sqlite3"
|
||||||
|
apt-get install --yes sqlite3
|
||||||
|
|
||||||
echo "Downloading latest stable release of PhotonVision..."
|
echo "Downloading latest stable release of PhotonVision..."
|
||||||
mkdir -p /opt/photonvision
|
mkdir -p /opt/photonvision
|
||||||
cd /opt/photonvision
|
cd /opt/photonvision
|
||||||
|
|||||||
Reference in New Issue
Block a user