Can't connect to USB camera device on a RaspberryPi4 using OpenCV2 if I startup the Pi without the cam attached first

735 Views Asked by At

I'm having trouble with an app I'm writing for a monitoring device. I've got a RaspberryPi4 that runs a python script with three threads. One of these threads manages a camera for recording video. When I startup the pi with the camera attached, it works just fine. However, when I startup the device without this USB camera attached my program fails to find the camera.

As is, the program looks for a valid video device under the /dev folder of the raspberrypi. I've noticed that when I disconnect the camera or reconnect it, these video devices will appear and disappear under the /def folder. However, my python program fails to detect these changes. It's like it has one chance to detect if the camera is attached at boot and then cannot detect it after.

What's interesting is that if it starts with the camera attached, I can disconnect and reconnect the camera without issue. Has anyone else run into an issue like this? Here is the part of my code that is meant to try and connect to the camera.

def cameraConnect(self,device):
    # Clear the cache
    os.sync()
    # try connecting to camera
    self.cap = cv2.VideoCapture(-1)
    #Find the camera devices
    devices = []
    files = os.listdir('/dev/')
    print(files)
    for file in files:
        if file.startswith('video'):
            devices.append(os.path.join('/dev', file))
    print("Devices found: ", devices)
    #Check if the camera is attached
    
   
    if len(devices) < 1:
        print("No devices found, trying defaults")
        devices = ['/dev/video0', '/dev/video1', '/dev/video2', '/dev/video3', '/dev/video4','-1']
    for dev in devices:
        print("Connecting to ", dev)
        self.cap = cv2.VideoCapture(dev)
        if self.cap.isOpened():
            print(f"Successfully opened {dev}")
            device = dev
            self.is_camera_attached = True 
            break
        else:
            print(f"Failed to open {dev}")

Using os.listdir and os.scandir I try and find these video devices under /dev. Those being video0 through video3 which the code will then try to connect to each of them. This program will loop, trying to connect to either the default or found video devices under /dev but the devices are either found when the program starts or not at all. That is dependent on whether or not the camera is connected. I thought maybe it was a caching issue, but I believe os.sync should prove that is not the case. I'm uncertain if this is a python or a raspberrypi issue?

Any help would be greatly appreciated, thanks.

Edited for more detail.

1

There are 1 best solutions below

2
Velimir Mlaker On

Instead of using /dev/video* paths in your code, install the v4l-utils Apt package, and then use the explicit ID paths that become visible under directories /dev/v4l/by-id/ or /dev/v4l/by-path/.

The enumerations of paths /dev/video* may change boot-to-boot or even during continuous uptime when hot-unplugging/replugging a USB camera, or even as power and bandwidth limits toggle a connected USB camera ON/OFF, with the camera acquiring a different number each time (often incrementing).

The way to assure getting a consistent path to your USB camera device, use instead paths visible in the /dev/v4l/ directory. These remain the same, even when a device toggles OFF and back ON intermittently.

For example, my system shows:

$ ls -la /dev/video*
crw-rw----+ 1 root video 81, 0 Apr 26 17:06 /dev/video0
crw-rw----+ 1 root video 81, 1 Apr 26 17:06 /dev/video1
$
$
$ tree /dev/v4l/
/dev/v4l/
├── by-id
│   ├── usb-046d_0809_440639A4-video-index0 -> ../../video0
│   └── usb-046d_0809_440639A4-video-index1 -> ../../video1
└── by-path
    ├── pci-0000:00:14.0-usb-0:9:1.0-video-index0 -> ../../video0
    └── pci-0000:00:14.0-usb-0:9:1.0-video-index1 -> ../../video1

With the example above, instead of using,

/dev/video0

I would prefer to use,

/dev/v4l/by-id/usb-046d_0809_440639A4-video-index0

While /dev/video0 may change to a different enumeration over time, the specific ID path will always point to originally-intended device since it is identified by a unique manufacturer-assigned ID.