Add VisionModule order determinism (#245)

This makes sure that VisionModules always appear in the same order.
This commit is contained in:
Banks T
2021-01-29 13:57:18 -05:00
committed by GitHub
parent fccb395564
commit b0504cbef5
6 changed files with 53 additions and 51 deletions

View File

@@ -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();
}

View File

@@ -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());
}
}

View File

@@ -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);

View File

@@ -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));

View File

@@ -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);

View File

@@ -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);