mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-24 01:31:44 +00:00
Add VisionModule order determinism (#245)
This makes sure that VisionModules always appear in the same order.
This commit is contained in:
@@ -332,8 +332,8 @@ public class ConfigManager {
|
||||
return loadedConfigurations;
|
||||
}
|
||||
|
||||
public void addCameraConfigurations(HashMap<VisionSource, CameraConfiguration> sources) {
|
||||
getConfig().addCameraConfigs(sources.values());
|
||||
public void addCameraConfigurations(List<VisionSource> sources) {
|
||||
getConfig().addCameraConfigs(sources);
|
||||
requestSave();
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ import org.photonvision.common.util.SerializationUtils;
|
||||
import org.photonvision.raspi.PicamJNI;
|
||||
import org.photonvision.vision.processes.VisionModule;
|
||||
import org.photonvision.vision.processes.VisionModuleManager;
|
||||
import org.photonvision.vision.processes.VisionSource;
|
||||
|
||||
// TODO rename this class
|
||||
public class PhotonConfiguration {
|
||||
@@ -75,9 +76,9 @@ public class PhotonConfiguration {
|
||||
return cameraConfigurations;
|
||||
}
|
||||
|
||||
public void addCameraConfigs(Collection<CameraConfiguration> config) {
|
||||
for (var c : config) {
|
||||
addCameraConfig(c);
|
||||
public void addCameraConfigs(Collection<VisionSource> sources) {
|
||||
for (var s : sources) {
|
||||
addCameraConfig(s.getCameraConfiguration());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,8 @@
|
||||
|
||||
package org.photonvision.vision.processes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import org.photonvision.common.configuration.CameraConfiguration;
|
||||
|
||||
/** VisionModuleManager has many VisionModules, and provides camera configuration data to them. */
|
||||
@@ -52,25 +51,31 @@ public class VisionModuleManager {
|
||||
return visionModules.get(i);
|
||||
}
|
||||
|
||||
public List<VisionModule> addSources(HashMap<VisionSource, CameraConfiguration> visionSources) {
|
||||
var addedModules = new ArrayList<VisionModule>();
|
||||
for (var entry : visionSources.entrySet()) {
|
||||
var visionSource = entry.getKey();
|
||||
var pipelineManager = new PipelineManager(entry.getValue());
|
||||
public List<VisionModule> addSources(List<VisionSource> visionSources) {
|
||||
var addedModules = new HashMap<Integer, VisionModule>();
|
||||
|
||||
assignCameraIndex(visionSource.getSettables().getConfiguration());
|
||||
for (var visionSource : visionSources) {
|
||||
var pipelineManager = new PipelineManager(visionSource.getCameraConfiguration());
|
||||
assignCameraIndex(visionSource.getCameraConfiguration());
|
||||
|
||||
var module = new VisionModule(pipelineManager, visionSource, visionModules.size());
|
||||
visionModules.add(module);
|
||||
addedModules.add(module);
|
||||
addedModules.put(visionSource.getCameraConfiguration().streamIndex, module);
|
||||
}
|
||||
return addedModules;
|
||||
|
||||
var sortedModulesList =
|
||||
addedModules.entrySet().stream()
|
||||
.sorted(Comparator.comparingInt(Map.Entry::getKey)) // sort by stream index
|
||||
.map(Map.Entry::getValue) // map to Stream of VisionModule
|
||||
.collect(Collectors.toList()); // collect in a List
|
||||
|
||||
return sortedModulesList;
|
||||
}
|
||||
|
||||
private void assignCameraIndex(CameraConfiguration config) {
|
||||
var max =
|
||||
visionModules.stream()
|
||||
.mapToInt(it -> it.visionSource.getSettables().getConfiguration().streamIndex)
|
||||
.mapToInt(it -> it.visionSource.getCameraConfiguration().streamIndex)
|
||||
.max()
|
||||
.orElse(-1);
|
||||
|
||||
|
||||
@@ -75,12 +75,12 @@ public class VisionSourceManager {
|
||||
() -> List.of(UsbCamera.enumerateUsbCameras());
|
||||
|
||||
protected void tryMatchUSBCams() {
|
||||
var visionSourceMap = tryMatchUSBCamImpl();
|
||||
if (visionSourceMap == null) return;
|
||||
var visionSourceList = tryMatchUSBCamImpl();
|
||||
if (visionSourceList == null) return;
|
||||
|
||||
logger.info("Adding " + visionSourceMap.size() + " configs to VMM.");
|
||||
ConfigManager.getInstance().addCameraConfigurations(visionSourceMap);
|
||||
var addedSources = VisionModuleManager.getInstance().addSources(visionSourceMap);
|
||||
logger.info("Adding " + visionSourceList.size() + " configs to VMM.");
|
||||
ConfigManager.getInstance().addCameraConfigurations(visionSourceList);
|
||||
var addedSources = VisionModuleManager.getInstance().addSources(visionSourceList);
|
||||
addedSources.forEach(VisionModule::start);
|
||||
DataChangeService.getInstance()
|
||||
.publishEvent(
|
||||
@@ -88,7 +88,7 @@ public class VisionSourceManager {
|
||||
"fullsettings", ConfigManager.getInstance().getConfig().toHashMap()));
|
||||
}
|
||||
|
||||
protected HashMap<VisionSource, CameraConfiguration> tryMatchUSBCamImpl() {
|
||||
protected List<VisionSource> tryMatchUSBCamImpl() {
|
||||
// Detect cameras using CSCore
|
||||
List<UsbCameraInfo> connectedCameras =
|
||||
new ArrayList<>(filterAllowedDevices(cameraInfoSupplier.get()));
|
||||
@@ -154,20 +154,18 @@ public class VisionSourceManager {
|
||||
// Turn these camera configs into vision sources
|
||||
var sources = loadVisionSourcesFromCamConfigs(matchedCameras);
|
||||
|
||||
// We want to return a map between vision sources and camera configurations
|
||||
var visionSourceMap = new HashMap<VisionSource, CameraConfiguration>();
|
||||
// Print info about each vision source
|
||||
for (var src : sources) {
|
||||
var usbSrc = src;
|
||||
visionSourceMap.put(usbSrc, usbSrc.getSettables().getConfiguration());
|
||||
logger.debug(
|
||||
() ->
|
||||
"Matched config for camera \""
|
||||
+ src.getFrameProvider().getName()
|
||||
+ "\" and loaded "
|
||||
+ usbSrc.getSettables().getConfiguration().pipelineSettings.size()
|
||||
+ src.getCameraConfiguration().pipelineSettings.size()
|
||||
+ " pipelines");
|
||||
}
|
||||
return visionSourceMap;
|
||||
|
||||
return sources;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -292,12 +290,12 @@ public class VisionSourceManager {
|
||||
|
||||
private static List<VisionSource> loadVisionSourcesFromCamConfigs(
|
||||
List<CameraConfiguration> camConfigs) {
|
||||
List<VisionSource> cameraSources = new ArrayList<>();
|
||||
var cameraSources = new ArrayList<VisionSource>();
|
||||
for (var configuration : camConfigs) {
|
||||
if (configuration.baseName.startsWith("mmal service") && PicamJNI.isSupported()) {
|
||||
configuration.cameraType = CameraType.ZeroCopyPicam;
|
||||
VisionSource picamSrc = new ZeroCopyPicamSource(configuration);
|
||||
cameraSources.add(picamSrc);
|
||||
var piCamSrc = new ZeroCopyPicamSource(configuration);
|
||||
cameraSources.add(piCamSrc);
|
||||
continue;
|
||||
}
|
||||
cameraSources.add(new USBCameraSource(configuration));
|
||||
|
||||
@@ -20,6 +20,7 @@ package org.photonvision.vision.processes;
|
||||
import edu.wpi.cscore.VideoMode;
|
||||
import edu.wpi.first.wpilibj.geometry.Rotation2d;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.*;
|
||||
import org.photonvision.common.configuration.CameraConfiguration;
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
@@ -41,8 +42,8 @@ public class VisionModuleManagerTest {
|
||||
|
||||
private final FrameProvider provider;
|
||||
|
||||
public TestSource(FrameProvider provider) {
|
||||
super(new CameraConfiguration("", "", "", ""));
|
||||
public TestSource(FrameProvider provider, CameraConfiguration cameraConfiguration) {
|
||||
super(cameraConfiguration);
|
||||
this.provider = provider;
|
||||
}
|
||||
|
||||
@@ -108,16 +109,16 @@ public class VisionModuleManagerTest {
|
||||
@Test
|
||||
public void setupManager() {
|
||||
ConfigManager.getInstance().load();
|
||||
var sources = new HashMap<VisionSource, CameraConfiguration>();
|
||||
sources.put(
|
||||
new TestSource(
|
||||
new FileFrameProvider(
|
||||
TestUtils.getWPIImagePath(
|
||||
TestUtils.WPI2019Image.kCargoStraightDark72in_HighRes, false),
|
||||
TestUtils.WPI2019Image.FOV)),
|
||||
new CameraConfiguration("Foo", "Barr"));
|
||||
|
||||
var modules = VisionModuleManager.getInstance().addSources(sources);
|
||||
var conf = new CameraConfiguration("Foo", "Bar");
|
||||
var ffp =
|
||||
new FileFrameProvider(
|
||||
TestUtils.getWPIImagePath(TestUtils.WPI2019Image.kCargoStraightDark72in_HighRes, false),
|
||||
TestUtils.WPI2019Image.FOV);
|
||||
|
||||
var testSource = new TestSource(ffp, conf);
|
||||
|
||||
var modules = VisionModuleManager.getInstance().addSources(List.of(testSource));
|
||||
var module0DataConsumer = new TestDataConsumer();
|
||||
|
||||
VisionModuleManager.getInstance().visionModules.get(0).addResultConsumer(module0DataConsumer);
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.photonvision;
|
||||
|
||||
import edu.wpi.cscore.CameraServerCvJNI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import org.apache.commons.cli.*;
|
||||
import org.photonvision.common.configuration.CameraConfiguration;
|
||||
import org.photonvision.common.configuration.ConfigManager;
|
||||
@@ -88,7 +87,7 @@ public class Main {
|
||||
}
|
||||
|
||||
private static void addTestModeSources() {
|
||||
var collectedSources = new HashMap<VisionSource, CameraConfiguration>();
|
||||
var collectedSources = new ArrayList<VisionSource>();
|
||||
|
||||
var camConf2019 =
|
||||
new CameraConfiguration("WPI2019", TestUtils.getTestMode2019ImagePath().toString());
|
||||
@@ -121,12 +120,10 @@ public class Main {
|
||||
|
||||
var fvs2020 = new FileVisionSource(camConf2020);
|
||||
|
||||
var cfg2019 = new CameraConfiguration("2019", "2019");
|
||||
cfg2019.pipelineSettings = psList2019;
|
||||
var cfg2020 = new CameraConfiguration("2019", "2019");
|
||||
cfg2020.pipelineSettings = psList2020;
|
||||
collectedSources.put(fvs2019, cfg2019);
|
||||
collectedSources.put(fvs2020, cfg2020);
|
||||
fvs2019.getCameraConfiguration().pipelineSettings = psList2019;
|
||||
fvs2020.getCameraConfiguration().pipelineSettings = psList2020;
|
||||
collectedSources.add(fvs2019);
|
||||
collectedSources.add(fvs2020);
|
||||
|
||||
// logger.info("Adding " + allSources.size() + " configs to VMM.");
|
||||
VisionModuleManager.getInstance().addSources(collectedSources).forEach(VisionModule::start);
|
||||
|
||||
Reference in New Issue
Block a user