mirror of
https://github.com/PhotonVision/photonvision
synced 2026-06-26 01:51:40 +00:00
Raspberry Pi 5 Support (#1008)
Deals with new otherpaths on pi 5 CSI cameras and bumps libcamera driver to latest from the pi 5 PR --------- Co-authored-by: Matt <matthew.morley.ca@gmail.com>
This commit is contained in:
@@ -64,6 +64,7 @@ public class LibCameraJNI {
|
||||
Disconnected,
|
||||
OV5647, // Picam v1
|
||||
IMX219, // Picam v2
|
||||
IMX708, // Picam v3
|
||||
IMX477, // Picam HQ
|
||||
OV9281,
|
||||
OV7251,
|
||||
@@ -77,6 +78,8 @@ public class LibCameraJNI {
|
||||
return "Camera Module v1";
|
||||
case IMX219:
|
||||
return "Camera Module v2";
|
||||
case IMX708:
|
||||
return "Camera Module v3";
|
||||
case IMX477:
|
||||
return "HQ Camera";
|
||||
case OV9281:
|
||||
|
||||
@@ -86,6 +86,9 @@ public class LibcameraGpuSettables extends VisionSourceSettables {
|
||||
if (sensorModel == LibCameraJNI.SensorModel.IMX477) {
|
||||
LibcameraGpuSource.logger.warn(
|
||||
"It appears you are using a Pi HQ Camera. This camera is not officially supported. You will have to set your camera FOV differently based on resolution.");
|
||||
} else if (sensorModel == LibCameraJNI.SensorModel.IMX708) {
|
||||
LibcameraGpuSource.logger.warn(
|
||||
"It appears you are using a Pi Camera V3. This camera is not officially supported. You will have to set your camera FOV differently based on resolution.");
|
||||
} else if (sensorModel == LibCameraJNI.SensorModel.Unknown) {
|
||||
LibcameraGpuSource.logger.warn(
|
||||
"You have an unknown sensor connected to your Pi over CSI! This is likely a bug. If it is not, then you will have to set your camera FOV differently based on resolution.");
|
||||
|
||||
@@ -142,7 +142,15 @@ public class VisionSourceManager {
|
||||
logger.debug("Trying to match " + usbCamConfigs.size() + " unmatched configs...");
|
||||
|
||||
// Match camera configs to physical cameras
|
||||
var matchedCameras = matchUSBCameras(notYetLoadedCams, unmatchedLoadedConfigs);
|
||||
|
||||
List<CameraConfiguration> matchedCameras;
|
||||
|
||||
if (!createSources) {
|
||||
matchedCameras = matchUSBCameras(notYetLoadedCams, unmatchedLoadedConfigs, false);
|
||||
} else {
|
||||
matchedCameras = matchUSBCameras(notYetLoadedCams, unmatchedLoadedConfigs);
|
||||
}
|
||||
|
||||
unmatchedLoadedConfigs.removeAll(matchedCameras);
|
||||
if (!unmatchedLoadedConfigs.isEmpty() && !hasWarned) {
|
||||
logger.warn(
|
||||
@@ -198,6 +206,22 @@ public class VisionSourceManager {
|
||||
*/
|
||||
protected List<CameraConfiguration> matchUSBCameras(
|
||||
List<UsbCameraInfo> detectedCamInfos, List<CameraConfiguration> loadedUsbCamConfigs) {
|
||||
return matchUSBCameras(detectedCamInfos, loadedUsbCamConfigs, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create {@link CameraConfiguration}s based on a list of detected USB cameras and the configs on
|
||||
* disk.
|
||||
*
|
||||
* @param detectedCamInfos Information about currently connected USB cameras.
|
||||
* @param loadedUsbCamConfigs The USB {@link CameraConfiguration}s loaded from disk.
|
||||
* @param useJNI If false, this is a unit test and the JNI should not be used for CSI devices.
|
||||
* @return the matched configurations.
|
||||
*/
|
||||
private List<CameraConfiguration> matchUSBCameras(
|
||||
List<UsbCameraInfo> detectedCamInfos,
|
||||
List<CameraConfiguration> loadedUsbCamConfigs,
|
||||
boolean useJNI) {
|
||||
var detectedCameraList = new ArrayList<>(detectedCamInfos);
|
||||
ArrayList<CameraConfiguration> cameraConfigurations = new ArrayList<>();
|
||||
|
||||
@@ -320,7 +344,11 @@ public class VisionSourceManager {
|
||||
// HACK -- for picams, we want to use the camera model
|
||||
String nickname = uniqueName;
|
||||
if (isCsiCamera(info)) {
|
||||
nickname = LibCameraJNI.getSensorModel().toString();
|
||||
if (useJNI) {
|
||||
nickname = LibCameraJNI.getSensorModel().toString();
|
||||
} else {
|
||||
nickname = "CSICAM-DEV";
|
||||
}
|
||||
}
|
||||
|
||||
CameraConfiguration configuration =
|
||||
@@ -342,6 +370,7 @@ public class VisionSourceManager {
|
||||
logger.debug("Updating path config from " + cfg.path + " to " + info.path);
|
||||
cfg.path = info.path;
|
||||
}
|
||||
cfg.otherPaths = info.otherPaths;
|
||||
|
||||
if (cfg.otherPaths.length != info.otherPaths.length) {
|
||||
logger.debug(
|
||||
@@ -373,16 +402,56 @@ public class VisionSourceManager {
|
||||
|
||||
private List<UsbCameraInfo> filterAllowedDevices(List<UsbCameraInfo> allDevices) {
|
||||
List<UsbCameraInfo> filteredDevices = new ArrayList<>();
|
||||
List<UsbCameraInfo> badDevices = new ArrayList<>();
|
||||
|
||||
for (var device : allDevices) {
|
||||
// Filter devices that are physically the same device but may show up as multiple devices that
|
||||
// really cant be accessed. First noticed with raspi 5 and ov5647.
|
||||
|
||||
List<String> paths = new ArrayList<>();
|
||||
|
||||
boolean skip = false;
|
||||
if (device.otherPaths.length != 0) {
|
||||
// Use the other paths to filter out devices that share the same path other than the index
|
||||
// select only the lowest index.
|
||||
// A ov5647 on a raspi 5 would show another path as
|
||||
// platform-1000880000.pisp_be-video-index0,
|
||||
// platform-1000880000.pisp_be-video-index4, and platform-1000880000.pisp_be-video-index5.
|
||||
// This code will remove "indexX" from all the other paths from all the devices and make
|
||||
// sure
|
||||
// that we only take one camera stream from each device the stream with the lowest index.
|
||||
for (String p : device.otherPaths) {
|
||||
paths.add(p.split("index")[0]);
|
||||
}
|
||||
for (var otherDevice : filteredDevices) {
|
||||
if (otherDevice.otherPaths.length == 0) continue;
|
||||
List<String> otherPaths = new ArrayList<>();
|
||||
for (String p : otherDevice.otherPaths) {
|
||||
otherPaths.add(p.split("index")[0]);
|
||||
}
|
||||
if (paths.containsAll(otherPaths)) {
|
||||
if (otherDevice.dev >= device.dev) {
|
||||
badDevices.add(otherDevice);
|
||||
} else {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filteredDevices.removeAll(badDevices);
|
||||
if (deviceBlacklist.contains(device.name)) {
|
||||
logger.trace(
|
||||
"Skipping blacklisted device: \"" + device.name + "\" at \"" + device.path + "\"");
|
||||
} else if (device.name.matches(ignoredCamerasRegex)) {
|
||||
logger.trace("Skipping ignored device: \"" + device.name + "\" at \"" + device.path);
|
||||
} else {
|
||||
} else if (!skip) {
|
||||
filteredDevices.add(device);
|
||||
logger.trace(
|
||||
"Adding local video device - \"" + device.name + "\" at \"" + device.path + "\"");
|
||||
} else {
|
||||
logger.trace("Skipping duplicate device: \"" + device.name + "\" at \"" + device.path);
|
||||
}
|
||||
}
|
||||
return filteredDevices;
|
||||
|
||||
@@ -35,18 +35,19 @@ public class VisionSourceManagerTest {
|
||||
ConfigManager.getInstance().load();
|
||||
|
||||
inst.tryMatchUSBCamImpl();
|
||||
|
||||
var config3 =
|
||||
new CameraConfiguration(
|
||||
"secondTestVideo",
|
||||
"secondTestVideo1",
|
||||
"secondTestVideo1",
|
||||
"thirdTestVideo",
|
||||
"thirdTestVideo",
|
||||
"thirdTestVideo",
|
||||
"dev/video1",
|
||||
new String[] {"by-id/123"});
|
||||
var config4 =
|
||||
new CameraConfiguration(
|
||||
"secondTestVideo",
|
||||
"secondTestVideo2",
|
||||
"secondTestVideo2",
|
||||
"fourthTestVideo",
|
||||
"fourthTestVideo",
|
||||
"fourthTestVideo",
|
||||
"dev/video2",
|
||||
new String[] {"by-id/321"});
|
||||
|
||||
@@ -61,7 +62,8 @@ public class VisionSourceManagerTest {
|
||||
assertTrue(inst.knownUsbCameras.contains(info1));
|
||||
assertEquals(2, inst.unmatchedLoadedConfigs.size());
|
||||
|
||||
UsbCameraInfo info2 = new UsbCameraInfo(0, "dev/video1", "testVideo", new String[0], 1, 2);
|
||||
UsbCameraInfo info2 =
|
||||
new UsbCameraInfo(0, "dev/video1", "secondTestVideo", new String[0], 2, 3);
|
||||
|
||||
infoList.add(info2);
|
||||
|
||||
@@ -75,10 +77,10 @@ public class VisionSourceManagerTest {
|
||||
assertEquals(2, inst.unmatchedLoadedConfigs.size());
|
||||
|
||||
UsbCameraInfo info3 =
|
||||
new UsbCameraInfo(0, "dev/video2", "secondTestVideo", new String[] {"by-id/123"}, 2, 1);
|
||||
new UsbCameraInfo(0, "dev/video2", "thirdTestVideo", new String[] {"by-id/123"}, 3, 4);
|
||||
|
||||
UsbCameraInfo info4 =
|
||||
new UsbCameraInfo(0, "dev/video3", "secondTestVideo", new String[] {"by-id/321"}, 3, 1);
|
||||
new UsbCameraInfo(0, "dev/video3", "fourthTestVideo", new String[] {"by-id/321"}, 5, 6);
|
||||
|
||||
infoList.add(info4);
|
||||
|
||||
@@ -118,7 +120,80 @@ public class VisionSourceManagerTest {
|
||||
|
||||
assertEquals(cam3.nickname, config3.nickname);
|
||||
assertEquals(cam4.nickname, config4.nickname);
|
||||
assertEquals(4, inst.knownUsbCameras.size());
|
||||
|
||||
UsbCameraInfo info5 =
|
||||
new UsbCameraInfo(
|
||||
2,
|
||||
"/dev/video2",
|
||||
"Left Camera",
|
||||
new String[] {
|
||||
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Left_Camera_12345-video-index0",
|
||||
"/dev/v4l/by-path/platform-xhci-hcd.0-usb-0:2:1.0-video-index0"
|
||||
},
|
||||
7,
|
||||
8);
|
||||
infoList.add(info5);
|
||||
inst.tryMatchUSBCamImpl(false);
|
||||
|
||||
assertTrue(inst.knownUsbCameras.contains(info5));
|
||||
|
||||
UsbCameraInfo info6 =
|
||||
new UsbCameraInfo(
|
||||
3,
|
||||
"dev/video3",
|
||||
"Right Camera",
|
||||
new String[] {
|
||||
"/dev/v4l/by-id/usb-Arducam_Technology_Co.__Ltd._Right_Camera_123456-video-index0",
|
||||
"/dev/v4l/by-path/platform-xhci-hcd.1-usb-0:1:1.0-video-index0"
|
||||
},
|
||||
9,
|
||||
10);
|
||||
infoList.add(info6);
|
||||
inst.tryMatchUSBCamImpl(false);
|
||||
|
||||
assertTrue(inst.knownUsbCameras.contains(info6));
|
||||
|
||||
// RPI 5 CSI Tests
|
||||
|
||||
UsbCameraInfo info7 =
|
||||
new UsbCameraInfo(
|
||||
4,
|
||||
"dev/video4",
|
||||
"CSICAM-DEV", // Typically rp1-cfe for unit test changed to CSICAM-DEV
|
||||
new String[] {"/dev/v4l/by-path/platform-1f00110000.csi-video-index0"},
|
||||
11,
|
||||
12);
|
||||
infoList.add(info7);
|
||||
inst.tryMatchUSBCamImpl(false);
|
||||
|
||||
assertTrue(inst.knownUsbCameras.contains(info7));
|
||||
|
||||
UsbCameraInfo info8 =
|
||||
new UsbCameraInfo(
|
||||
5,
|
||||
"dev/video8",
|
||||
"CSICAM-DEV", // Typically rp1-cfe for unit test changed to CSICAM-DEV
|
||||
new String[] {"/dev/v4l/by-path/platform-1f00110000.csi-video-index4"},
|
||||
13,
|
||||
14);
|
||||
infoList.add(info8);
|
||||
inst.tryMatchUSBCamImpl(false);
|
||||
|
||||
assertTrue(!inst.knownUsbCameras.contains(info8)); // This camera should not be recognized/used.
|
||||
|
||||
UsbCameraInfo info9 =
|
||||
new UsbCameraInfo(
|
||||
6,
|
||||
"dev/video9",
|
||||
"CSICAM-DEV", // Typically rp1-cfe for unit test changed to CSICAM-DEV
|
||||
new String[] {"/dev/v4l/by-path/platform-1f00110000.csi-video-index5"},
|
||||
15,
|
||||
16);
|
||||
infoList.add(info9);
|
||||
inst.tryMatchUSBCamImpl(false);
|
||||
|
||||
assertTrue(!inst.knownUsbCameras.contains(info9)); // This camera should not be recognized/used.
|
||||
assertEquals(7, inst.knownUsbCameras.size());
|
||||
assertEquals(0, inst.unmatchedLoadedConfigs.size());
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
Reference in New Issue
Block a user