基于udev规则固定相机名称
我们使用 usb 相机时候,经常出现相机的名称改变,有时候是:/dev/video0 有时候是:/dev/video2,这时候我们可以修改 udev 规则,使用相同的名称来调用相机。
查询摄像头信息
- 连接你的摄像头,并使用 lsusb 命令来找到摄像头的详细信息(如厂商 ID 和产品 ID)。
例如我插了两个相机,lsusb 输出如下:
Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 002 Device 004: ID 1bcf:2cd1 Sunplus Innovation Technology Inc. DECXIN CAMERA
Bus 002 Device 003: ID 0bda:c820 Realtek Semiconductor Corp. 802.11ac NIC
Bus 002 Device 002: ID 1a40:0101 Terminus Technology Inc. Hub
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
Bus 001 Device 002: ID 1bcf:2cd1 Sunplus Innovation Technology Inc. DECXIN CAMERA
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
lsusb
命令的输出提供了一个系统上所有 USB 设备的列表。每行代表一个设备,并包含了有关该设备的一些基本信息。
输出解析
-
Bus 006 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 006
: 表示这是连接在总线编号为 6 上的设备。Device 001
: 设备编号,每个总线上的第一个设备通常是根集线器,编号从 1 开始。ID 1d6b:0003
: 前面的部分(1d6b
)是供应商 ID(Vendor ID),表示 Linux Foundation;后面的部分(0003
)是产品 ID(Product ID),具体指 3.0 版本的 USB root hub。Linux Foundation 3.0 root hub
: 描述了设备的身份和类型。
-
Bus 005 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
- 类似上面的解释,但这里的设备是一个 2.0 版本的 USB root hub。
-
Bus 004 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
- 这里描述的是一个 1.1 版本的 USB root hub。
-
Bus 002 Device 004: ID 1bcf:2cd1 Sunplus Innovation Technology Inc. DECXIN CAMERA
Bus 002 Device 004
: 表明这是连接在总线 2 上的第 4 个设备。ID 1bcf:2cd1
:1bcf
是 Sunplus Innovation Technology Inc.的供应商 ID,2cd1
是 DECXIN CAMERA 的产品 ID。Sunplus Innovation Technology Inc. DECXIN CAMERA
: 指出这是一个由 Sunplus Innovation Technology 生产的 DECXIN 摄像头。
-
Bus 002 Device 003: ID 0bda:c820 Realtek Semiconductor Corp. 802.11ac NIC
- 这是一个 Realtek Semiconductor Corp.生产的 802.11ac 无线网络接口控制器(NIC),其供应商 ID 为
0bda
,产品 ID 为c820
。
- 这是一个 Realtek Semiconductor Corp.生产的 802.11ac 无线网络接口控制器(NIC),其供应商 ID 为
-
Bus 002 Device 002: ID 1a40:0101 Terminus Technology Inc. Hub
- 这是由 Terminus Technology Inc.制造的一个 USB 集线器,供应商 ID 为
1a40
,产品 ID 为0101
。
- 这是由 Terminus Technology Inc.制造的一个 USB 集线器,供应商 ID 为
-
Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
- 和之前提到的类似,这是一台 2.0 版本的 USB root hub。
-
Bus 003 Device 001: ID 1d6b:0001 Linux Foundation 1.1 root hub
- 又是一个 1.1 版本的 USB root hub。
-
Bus 001 Device 002: ID 1bcf:2cd1 Sunplus Innovation Technology Inc. DECXIN CAMERA
- 这是另一个 DECXIN 摄像头,与总线 2 上的设备相同,但位于不同的总线(总线 1)上。
可以看到 6 和 9 都是我插入的 USB 摄像头。
只有单一的摄像头
- 创建一个新的 Udev 规则文件,例如
/etc/udev/rules.d/99-camera.rules
,并在其中添加一行描述你的摄像头的信息。格式可能如下:
将SUBSYSTEM=="usb", ATTRS{idVendor}=="xxxx", ATTRS{idProduct}=="yyyy", SYMLINK+="mycamera"
xxxx
和yyyy
替换为你从lsusb
命令得到的厂商 ID 和产品 ID。 - 保存文件并重新加载 Udev 规则:
sudo udevadm control --reload-rules
。 - 最后,重新插拔你的摄像头,应该可以在
/dev
目录下看到名为mycamera
的链接。 - 使用
ls -l /dev/mycamera
确认符号链接是否指向了正确的设备节点。
按照我查询的第 6 个数据,这个 udev 规则应该是这样的:
SUBSYSTEM=="usb", ATTRS{idVendor}=="1bcf", ATTRS{idProduct}=="2cd1", SYMLINK+="/dev/mycamera"
之后就可以使用/dev/mycamera
来控制这个 USB 摄像头了。
多个相同的 USB 摄像头
可以看到我使用 lsusb 命令,我找到了两个相同的 USB 摄像头,厂商 ID 和产品 ID 都一样,如果仍然使用同一个规则,那么可能会导致多个相同的 USB 摄像头被分配相同的设备名称。
当两个摄像头拥有相同的厂商 ID(idVendor
)和产品 ID(idProduct
)时,仅靠这两个属性无法唯一标识每个设备。
SUBSYSTEM=="usb", ATTRS{idVendor}=="1bcf", ATTRS{idProduct}=="2cd1", SYMLINK+="mycamera"
这个规则的意思是:
- 当系统识别到一个 USB 子系统中的设备
- 并且它的 厂商 ID 是
1bcf
- 并且它的 产品 ID 是
2cd1
- 就为它创建一个符号链接
/dev/mycamera
但是,如果你有两个这样的设备(如你的情况),那么:
- 系统会为第一个设备创建
/dev/mycamera
- 然后也会为第二个设备创建
/dev/mycamera
- 最终,只有最后一个插入的设备才会“占用”这个名字,或者出现冲突。
所以,这种规则在这种情况下 不能稳定地区分两个相同型号的摄像头。
正确做法:添加更多区分条件
为了给两个相同型号的摄像头分配固定的、唯一的名称(比如 /dev/camera_left
和 /dev/camera_right
),需要在 Udev 规则中加入 更具体的属性来区分它们。
常用的区分方式有:
属性 | 是否常用 | 说明 |
---|---|---|
ATTRS{serial} | ✅ 推荐 | 如果摄像头提供了序列号,这是最稳定的区分方法 |
KERNELS 或 ATTRS{devpath} | ✅ 推荐 | 表示设备连接的物理 USB 端口路径 |
ATTRS{busnum} + ATTRS{devnum} | ⚠️ 可用但不稳定 | 设备所在的总线号和设备号 |
ENV{ID_PATH} 或 ENV{ID_SERIAL} | ✅ 推荐 | udev 自动解析出的设备路径或序列号 |
🔍 如何找到这些属性?
使用以下命令查看某个摄像头的详细信息:
udevadm info -a -n /dev/bus/usb/BBB/DDD
将 BBB
替换为总线号(Bus),DDD
替换为设备号(Device),例如:
udevadm info -a -n /dev/bus/usb/002/004
udevadm info -a -n /dev/bus/usb/001/002
你会看到类似下面的输出片段:
looking at device '/devices/platform/xhci-hcd.1.auto/usb2/2-1':KERNEL=="2-1"SUBSYSTEM=="usb"ATTR{configuration}==""ATTR{bNumInterfaces}==" 1"ATTR{bConfigurationValue}=="1"ATTR{bmAttributes}=="80"ATTR{bMaxPower}=="500mA"ATTR{idVendor}=="1bcf"ATTR{idProduct}=="2cd1"ATTR{bcdDevice}=="0100"ATTR{manufacturer}=="SunplusIT Inc"ATTR{product}=="DECXIN CAMERA"ATTR{serial}=="A1234567" # <-- 这个很重要!如果有的话
✅ 示例:基于物理位置(KERNELS
)的 Udev 规则
假设:
- 左边摄像头连接在
KERNELS=="1-1"
- 右边摄像头连接在
KERNELS=="2-1"
你可以创建如下规则文件(例如 /etc/udev/rules.d/99-camera.rules
):
# 左边摄像头
SUBSYSTEM=="usb", ATTRS{idVendor}=="1bcf", ATTRS{idProduct}=="2cd1", KERNELS=="1-1", SYMLINK+="camera_left"# 右边摄像头
SUBSYSTEM=="usb", ATTRS{idVendor}=="1bcf", ATTRS{idProduct}=="2cd1", KERNELS=="2-1", SYMLINK+="camera_right"
✅ 示例:基于序列号(如果支持)
如果你发现摄像头有唯一的序列号,比如:
ATTR{serial}=="A1234567"
你可以这样写规则:
SUBSYSTEM=="usb", ATTRS{idVendor}=="1bcf", ATTRS{idProduct}=="2cd1", ATTRS{serial}=="A1234567", SYMLINK+="camera_left"
SUBSYSTEM=="usb", ATTRS{idVendor}=="1bcf", ATTRS{idProduct}=="2cd1", ATTRS{serial}=="B7654321", SYMLINK+="camera_right"
最终我使用的 udev 规则是:
SUBSYSTEMS=="usb", KERNELS=="1-1", ATTR{index}=="0", ATTRS{idVendor}=="1bcf", ATTRS{idProduct}=="2cd1", SYMLINK+="leftCam"
SUBSYSTEMS=="usb", KERNELS=="2-1.2", ATTR{index}=="0", ATTRS{idVendor}=="1bcf", ATTRS{idProduct}=="2cd1", SYMLINK+="rightCam"