Skip to content

Commit

Permalink
Raspberry Pi 5 Support (#1008)
Browse files Browse the repository at this point in the history
Deals with new otherpaths on pi 5 CSI cameras and bumps libcamera driver to latest from the pi 5 PR

---------

Co-authored-by: Matt <[email protected]>
  • Loading branch information
BytingBulldogs3539 and mcm001 authored Dec 16, 2023
1 parent 6b8882f commit 82b82fe
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public enum SensorModel {
Disconnected,
OV5647, // Picam v1
IMX219, // Picam v2
IMX708, // Picam v3
IMX477, // Picam HQ
OV9281,
OV7251,
Expand All @@ -77,6 +78,8 @@ public String getFriendlyName() {
return "Camera Module v1";
case IMX219:
return "Camera Module v2";
case IMX708:
return "Camera Module v3";
case IMX477:
return "HQ Camera";
case OV9281:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@ public LibcameraGpuSettables(CameraConfiguration configuration) {
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.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,15 @@ protected List<VisionSource> tryMatchUSBCamImpl(boolean createSources) {
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(
Expand Down Expand Up @@ -198,6 +206,22 @@ protected List<VisionSource> tryMatchUSBCamImpl(boolean createSources) {
*/
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<>();

Expand Down Expand Up @@ -320,7 +344,11 @@ && cameraNameToBaseName(usbCameraInfo.name).equals(config.baseName))
// 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 =
Expand All @@ -342,6 +370,7 @@ private CameraConfiguration mergeInfoIntoConfig(CameraConfiguration cfg, UsbCame
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(
Expand Down Expand Up @@ -373,16 +402,56 @@ public void setIgnoredCamerasRegex(String ignoredCamerasRegex) {

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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,19 @@ public void visionSourceTest() {
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"});

Expand All @@ -61,7 +62,8 @@ public void visionSourceTest() {
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);

Expand All @@ -75,10 +77,10 @@ public void visionSourceTest() {
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);

Expand Down Expand Up @@ -118,7 +120,80 @@ public void visionSourceTest() {

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.

0 comments on commit 82b82fe

Please sign in to comment.