diff --git a/Main/src/main/java/com/chameleonvision/Main.java b/Main/src/main/java/com/chameleonvision/Main.java index e24da500f..6941cb7ea 100644 --- a/Main/src/main/java/com/chameleonvision/Main.java +++ b/Main/src/main/java/com/chameleonvision/Main.java @@ -128,22 +128,22 @@ public class Main { try { CameraServerJNI.forceLoad(); CameraServerCvJNI.forceLoad(); - } catch (IOException e) { + } catch (UnsatisfiedLinkError | IOException e) { + if(Platform.getCurrentPlatform().isWindows()) + System.err.println("Try to download the VC++ Redistributable, see announcements in discord"); throw new RuntimeException("Failed to load JNI Libraries!"); } - if (CameraManager.initializeCameras()) { SettingsManager.initialize(); NetworkManager.initialize(manageNetwork); CameraManager.initializeThreads(); - if (ntServerMode) { System.out.println("Starting NT Server"); NetworkTableInstance.getDefault().startServer(); } else { NetworkTableInstance.getDefault().addLogger(new NTLogger(), 0, 255); // to hide error messages if (ntClientModeServer != null) { - NetworkTableInstance.getDefault().startClient(ntClientModeServer); + NetworkTableInstance.getDefault().startClient(ntClientModeServer); } else { NetworkTableInstance.getDefault().startClientTeam(SettingsManager.GeneralSettings.teamNumber); } diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/Camera.java b/Main/src/main/java/com/chameleonvision/vision/camera/Camera.java index 102b08886..a9721ab49 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/Camera.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/Camera.java @@ -7,6 +7,8 @@ import com.chameleonvision.vision.Pipeline; import com.chameleonvision.web.ServerHandler; import edu.wpi.cscore.*; import edu.wpi.first.cameraserver.CameraServer; +import edu.wpi.first.networktables.NetworkTable; +import edu.wpi.first.networktables.NetworkTableInstance; import org.opencv.core.Mat; import java.nio.channels.Pipe; @@ -65,9 +67,11 @@ public class Camera { public Camera(String cameraName, double fov, List pipelines, int videoModeIndex, StreamDivisor divisor) { this(cameraName, CameraManager.AllUsbCameraInfosByName.get(cameraName), fov, pipelines, videoModeIndex, divisor); } + public Camera(String cameraName, double fov, int videoModeIndex, StreamDivisor divisor) { this(cameraName, fov, new ArrayList<>(), videoModeIndex, divisor); } + public Camera(String cameraName, UsbCameraInfo usbCamInfo, double fov, List pipelines, int videoModeIndex, StreamDivisor divisor) { FOV = fov; name = cameraName; @@ -140,18 +144,21 @@ public class Camera { ServerHandler.sendFullSettings(); } } + public void addPipeline() { Pipeline p = new Pipeline(); p.nickname = "New pipeline " + pipelines.size(); addPipeline(p); } - public void addPipeline(Pipeline p){ + + public void addPipeline(Pipeline p) { this.pipelines.add(p); } public void deletePipeline(int index) { pipelines.remove(index); } + public void deletePipeline() { deletePipeline(getCurrentPipelineIndex()); } @@ -184,7 +191,8 @@ public class Camera { public List getPipelines() { return pipelines; } - public List getPipelinesNickname(){ + + public List getPipelinesNickname() { var pipelines = getPipelines(); return pipelines.stream().map(pipeline -> pipeline.nickname).collect(Collectors.toList()); } @@ -220,7 +228,13 @@ public class Camera { public void setExposure(int exposure) { getCurrentPipeline().exposure = exposure; - UsbCam.setExposureManual(exposure); + try { + UsbCam.setExposureManual(exposure); + } + catch (VideoException e) + { + System.err.println("Camera Does not support exposure change"); + } } public long grabFrame(Mat image) { @@ -244,10 +258,17 @@ public class Camera { } public void setNickname(String newNickname) { + //Deletes old camera nt table + NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + this.nickname).getInstance().deleteAllEntries(); nickname = newNickname; + if (CameraManager.AllVisionProcessesByName.containsKey(this.name)) { + NetworkTable newNT = NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + this.nickname); + CameraManager.AllVisionProcessesByName.get(this.name).resetNT(newNT); + } } public String getNickname() { return nickname == null ? name : nickname; } + } diff --git a/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java b/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java index c16fb0cbd..2356fcdea 100644 --- a/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java +++ b/Main/src/main/java/com/chameleonvision/vision/camera/CameraManager.java @@ -22,7 +22,7 @@ public class CameraManager { private static final Path CamConfigPath = Paths.get(SettingsManager.SettingsPath.toString(), "cameras"); private static LinkedHashMap AllCamerasByName = new LinkedHashMap<>(); - private static HashMap AllVisionProcessesByName = new HashMap<>(); + public static HashMap AllVisionProcessesByName = new HashMap<>(); static HashMap AllUsbCameraInfosByName = new HashMap<>() {{ var suffix = 0; diff --git a/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java b/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java index eac1772b9..1ed5d91a6 100644 --- a/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java +++ b/Main/src/main/java/com/chameleonvision/vision/process/VisionProcess.java @@ -23,6 +23,8 @@ public class VisionProcess implements Runnable { // NetworkTables public NetworkTableEntry ntPipelineEntry; public NetworkTableEntry ntDriverModeEntry; + private int ntDriveModeListenerID; + private int ntPipelineListenerID; private NetworkTableEntry ntYawEntry; private NetworkTableEntry ntPitchEntry; private NetworkTableEntry ntDistanceEntry; @@ -48,18 +50,9 @@ public class VisionProcess implements Runnable { this.cameraName = camera.name; // NetworkTables - NetworkTable ntTable = NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + cameraName); - ntPipelineEntry = ntTable.getEntry("pipeline"); - ntDriverModeEntry = ntTable.getEntry("driver_mode"); - ntPitchEntry = ntTable.getEntry("pitch"); - ntYawEntry = ntTable.getEntry("yaw"); - ntDistanceEntry = ntTable.getEntry("distance"); - ntTimeStampEntry = ntTable.getEntry("timestamp"); - ntValidEntry = ntTable.getEntry("is_valid"); - ntDriverModeEntry.addListener(this::driverModeListener, EntryListenerFlags.kUpdate); - ntPipelineEntry.addListener(this::pipelineListener, EntryListenerFlags.kUpdate); - ntDriverModeEntry.setBoolean(false); - ntPipelineEntry.setNumber(camera.getCurrentPipelineIndex()); +// NetworkTable ntTable = NetworkTableInstance.getDefault().getTable("/chameleon-vision/" + cameraName); +// NetworkTable ntTable = camera.getNtTable(); + initNT(NetworkTableInstance.getDefault().getTable("/chameleon-vision/"+processCam.getNickname())); // camera settings cvProcess = new CVProcess(camera.getCamVals()); @@ -79,9 +72,9 @@ public class VisionProcess implements Runnable { private void pipelineListener(EntryNotification entryNotification) { var ntPipelineIndex = (int) entryNotification.value.getDouble(); - if (ntPipelineIndex >= camera.getPipelines().size()){ + if (ntPipelineIndex >= camera.getPipelines().size()) { ntPipelineEntry.setNumber(camera.getCurrentPipelineIndex()); - } else{ + } else { var pipeline = camera.getCurrentPipeline(); camera.setCurrentPipelineIndex(ntPipelineIndex); try { @@ -159,7 +152,7 @@ public class VisionProcess implements Runnable { filteredContours = cvProcess.filterContours(foundContours, currentPipeline.area, currentPipeline.ratio, currentPipeline.extent); if (filteredContours.size() > 0) { deSpeckledContours = cvProcess.rejectSpeckles(filteredContours, currentPipeline.speckle.doubleValue()); - if (deSpeckledContours.size() > 0){ + if (deSpeckledContours.size() > 0) { groupedContours = cvProcess.groupTargets(deSpeckledContours, currentPipeline.targetIntersection, currentPipeline.targetGroup); if (groupedContours.size() > 0) { var finalRect = cvProcess.sortTargetsToOne(groupedContours, currentPipeline.sortMode); @@ -271,5 +264,37 @@ public class VisionProcess implements Runnable { // System.out.printf("%s - Process time: %-5.2fms, FPS: %-5.2f, FoundContours: %d, FilteredContours: %d, GroupedContours: %d\n", cameraName, processTimeMs, fps, FoundContours.size(), FilteredContours.size(), GroupedContours.size()); } } + +} + /** + * Removes the old value change listeners + * calls {@link #initNT} + * @param newTable passed to {@link #initNT} + * + */ + public void resetNT(NetworkTable newTable) + { + ntDriverModeEntry.removeListener(ntDriveModeListenerID); + ntPipelineEntry.removeListener(ntPipelineListenerID); + initNT(newTable); + } + + /** + * Rebases the writing location for the vision process - pipeline output + * @param newTable the new writing location + */ + private void initNT(NetworkTable newTable) + { + ntPipelineEntry = newTable.getEntry("pipeline"); + ntDriverModeEntry = newTable.getEntry("driver_mode"); + ntPitchEntry = newTable.getEntry("pitch"); + ntYawEntry = newTable.getEntry("yaw"); + ntDistanceEntry = newTable.getEntry("distance"); + ntTimeStampEntry = newTable.getEntry("timestamp"); + ntValidEntry = newTable.getEntry("is_valid"); + ntDriveModeListenerID = ntDriverModeEntry.addListener(this::driverModeListener, EntryListenerFlags.kUpdate); + ntPipelineListenerID = ntPipelineEntry.addListener(this::pipelineListener, EntryListenerFlags.kUpdate); + ntDriverModeEntry.setBoolean(false); + ntPipelineEntry.setNumber(camera.getCurrentPipelineIndex()); } } diff --git a/Main/src/main/java/com/chameleonvision/web/Server.java b/Main/src/main/java/com/chameleonvision/web/Server.java index 56ee93ef2..e90657c97 100644 --- a/Main/src/main/java/com/chameleonvision/web/Server.java +++ b/Main/src/main/java/com/chameleonvision/web/Server.java @@ -10,8 +10,7 @@ public class Server { public static void main(int port) { handler = new ServerHandler(); - Javalin app = Javalin.create(); - + Javalin app = Javalin.create(javalinConfig -> javalinConfig.showJavalinBanner=false); app.config.addStaticFiles("web"); app.ws("/websocket", ws -> { ws.onConnect(ctx -> { diff --git a/Main/src/main/java/com/chameleonvision/web/ServerHandler.java b/Main/src/main/java/com/chameleonvision/web/ServerHandler.java index 12f15b2f1..8930d42ea 100644 --- a/Main/src/main/java/com/chameleonvision/web/ServerHandler.java +++ b/Main/src/main/java/com/chameleonvision/web/ServerHandler.java @@ -103,7 +103,7 @@ public class ServerHandler { case "deleteCurrentPipeline": int currentIndex = cam.getCurrentPipelineIndex(); int nextIndex; - if (currentIndex == cam.getPipelines().size() - 1){ + if (currentIndex == cam.getPipelines().size() - 1) { nextIndex = currentIndex - 1; } else { nextIndex = currentIndex; @@ -132,7 +132,7 @@ public class ServerHandler { try { cam.setBrightness(cam.getCurrentPipeline().brightness); cam.setExposure(cam.getCurrentPipeline().exposure); - }catch (Exception e){ + } catch (Exception e) { continue; } break; @@ -141,11 +141,7 @@ public class ServerHandler { setField(CameraManager.getCurrentCamera().getCurrentPipeline(), entry.getKey(), entry.getValue()); switch (entry.getKey()) { case "exposure": { - try { - CameraManager.getCurrentCamera().setExposure((Integer) entry.getValue()); - } catch (Exception e) { - System.err.println("Camera Does not support exposure change"); - } + CameraManager.getCurrentCamera().setExposure((Integer) entry.getValue()); } case "brightness": { CameraManager.getCurrentCamera().setBrightness((Integer) entry.getValue()); @@ -247,7 +243,7 @@ public class ServerHandler { fullSettings.put("pipelineList", currentCamera.getPipelinesNickname()); fullSettings.put("resolutionList", currentCamera.getResolutionList()); fullSettings.put("port", currentCamera.getStreamPort()); - fullSettings.put("currentPipelineIndex",CameraManager.getCurrentCamera().getCurrentPipelineIndex()); + fullSettings.put("currentPipelineIndex", CameraManager.getCurrentCamera().getCurrentPipelineIndex()); fullSettings.put("currentCameraIndex", CameraManager.getCurrentCameraIndex()); } catch (CameraException | IllegalAccessException e) { System.err.println("No camera found!");