问题陈述
在无人机或智能车上需要用到多个usb设备,例如usb摄像,串口等,很多情况下需要要求开机自启动程序,而在opencv的cv2.VideoCapture()函数中需要调用参数。Linux 或 Windows 系统中,每次插拔 USB 摄像头、重启系统、或切换 USB 接口后,设备在系统中的索引(比如 /dev/video0
, /dev/video1
)可能会发生变化。VideoCapture函数中的参数就是/dev/video*中的*。因此要实现每次开机都不需要考虑设备与代码中参数的兼容性问题,就需要配置udev规则。
解决方案
为设备创建固定符号链接(Linux),配置udev规则。
1.查看摄像头对应的索引
lsusb
结果以本机自带摄像头为例,结果如下:
Bus 003 Device 004: ID 0c45:6a14 Microdia Integrated_Webcam_HD
其中:
——Bus 003代表摄像头挂载在003号总线上。
——device 004表示该总线上的设备编号(Device Number)。这个编号是系统启动或设备插入时动态分配的,在拔插或重启后可能会变化。
——ID:0c45,6a14:厂商ID和产品ID。例如所有Intel的D435i相机对应的ID 8086:0b3a,其中8086是所有intel厂商对应的id,而0b3a是D435i相机独有的。请记住这两个序号。
2 创建udev规则
sudo nano /etc/udev/rules.d/99-my-webcam.rules
其中:
——/etc/udev/rules.d/目录是所有udev规则应当保存在的目录。
——99-my-webcam.rules:99代表顺序,数字越小,顺序越靠前,当前创建99代表可以创建98个优先级更高的udev规则,覆盖当前规则。后面的文件名根据需求更改。
SUBSYSTEM=="video4linux", KERNEL=="video*",ATTRS{idVendor}=="0c45", ATTRS{idProduct}=="6a14", SYMLINK+="webcam"
其中:
——SUBSYSTEM=="video4linux"代表摄像头设备,如果是串口设备则对应SUBSYSTEM=="tty"
KERNEL=="ttyUSB*",*代表着索引的不确定性,所以要根据后面的两个参数进一步确定摄像头。
——ATTRS{idVendor}=="0c45", ATTRS{idProduct}=="6a14":这两个参数对应的就是厂商id和产品id,是确定摄像头索引的关键依据。
——SYMLINK+="webcam":webcam是用户可以自定义的名称,定义好后,相当于将/dev/video0映射成了/dev/webcam。
注意
很多USB摄像头都会占用两个接口,例如一个设备同时占用了video0和video1两个接口,其中一个代表视频流,另一个代表控制端口,此时需要在上述udev规则中再添加一条,保证不会映射到控制端口上:
1 查看端口信息
v4l2-ctl --list-devices
结果:
USB 2.0 Camera: USB Camera (usb-0000:00:14.0-5):
/dev/video0
/dev/video1
再进行详细查看,哪一个是视频流端口:
v4l2-ctl --all -d /dev/video0
结果
Driver Info:
Driver name : uvcvideo
Card type : USB 2.0 Camera: USB Camera
Bus info : usb-0000:00:14.0-5
...
Video input : 0 (Camera 1: ok)
如果是视频流则会看到Format
, Resolution
, Input
, Streaming Parameters
等字段。一般来讲视频流端口都是0,2这类偶数。因此在代码上添加:ATTR{index}=="0"
SUBSYSTEM=="video4linux", KERNEL=="video*",ATTRS{idVendor}=="0c45", ATTRS{idProduct}=="6a14",ATTR{index}=="0", SYMLINK+="webcam"
这样就完成了udev规则的配置。
接下来应用规则
sudo udevadm control --reload
sudo udevadm trigger
然后在python中调用opencv库进行摄像头视频流运行。
import cv2
cap = cv2.VideoCapture("/dev/usb_webcam")