docker 容器中,当需要读取外接usb 设备,每次插拔 sub 设备,设备编号一直变化怎么办?

docker 容器中,当需要读取外接usb 设备,每次插拔 sub 设备,设备编号一直变化怎么办?这会影响程序的读取。因此每次创建容器时候,设备编号就固定在 容器中了。比如:

在容器中运行:

root@h-pc:~/ros_ws# lsusb
Bus 002 Device 002: ID 174c:3074 ASMedia Technology Inc. ASM1074 SuperSpeed hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 031: ID 10c4:ea60 Cygnal Integrated Products, Inc. CP210x UART Bridge / myAVR mySmartUSB light
Bus 001 Device 030: ID 2bc5:0502  
Bus 001 Device 029: ID 2bc5:0403  
Bus 001 Device 028: ID 05e3:0610 Genesys Logic, Inc. 4-port hub
Bus 001 Device 002: ID 174c:2074 ASMedia Technology Inc. ASM1074 High-Speed hub
Bus 001 Device 005: ID 8087:0032 Intel Corp. 
Bus 001 Device 004: ID 26ce:01a2  
Bus 001 Device 003: ID 17ef:608c Lenovo 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

我们重新插拔 usb 设备后,设备编号 变为了 029 等等。

而 我们在容器中:

root@h-pc:~/ros_ws# ls -l /dev/bus/usb/001/
total 0
crw-rw-r-- 1 root root 189,  0 Jun 19 17:58 001
crw-rw-r-- 1 root root 189,  1 Jun 19 17:58 002
crw-rw-r-- 1 root root 189,  2 Jun 19 17:58 003
crw-rw-r-- 1 root root 189,  3 Jun 19 17:58 004
crw-rw-r-- 1 root root 189,  4 Jun 19 17:58 005
crw-rw-r-- 1 root root 189,  6 Jun 19 17:58 007
crw-rw-r-- 1 root root 189,  7 Jun 20 13:33 008
crw-rw-r-- 1 root root 189,  8 Jun 20 13:33 009
crw-rw-r-- 1 root root 189, 10 Jun 19 17:58 011

发现并没有这个设备编号。这会导致启动 launch 文件时候报错:

[ INFO] [1718863863.439322079]: Query device
[ INFO] [1718863863.539486552]: Device connected: (name, Astra) (uri, 2bc5/0403@1/29) (vendor, Orbbec)
[ INFO] [1718863863.539548038]: Trying to open device: 2bc5/0403@1/29
[ INFO] [1718863863.639677743]: OBCameraNodeFactory::onDeviceConnected Open device start
[ INFO] [1718863863.642548470]: OBCameraNodeFactory::onDeviceConnected Open device done, STATUS 4099
[ERROR] [1718863863.642597179]: Failed to open device: 2bc5/0403@1/29 	Could not open "2bc5/0403@1/29": USB device not found!

解释:Bus 001 Device 026: ID 2bc5:0403 分别都是什么意思?

lsusb 命令的输出中,每行表示一个已连接的 USB 设备。以下是每个部分的含义:

详细说明

  1. Bus 001:
    表示设备连接到的 USB 总线。USB 端口可以分布在多个总线(bus)上,每个总线有一个编号。这里,设备连接到总线编号为 001 的 USB 总线上。
  2. Device 026:
    表示设备在该总线上的设备编号。每个连接到同一总线的设备都有一个唯一的编号。这里,该设备的编号为 026。
  3. ID 2bc5:0403:
    表示设备的供应商 ID 和产品 ID。这两个值用于唯一标识设备的类型和制造商。
    2bc5: 供应商 ID (Vendor ID),表示设备的制造商。这里,2bc5 是 Orbbec 的供应商 ID。
    0403: 产品 ID (Product ID),表示特定型号的设备。这里,0403 是 Orbbec Astra 的产品 ID。

检查设备信息
你可以使用 lsusb -v 获取详细的设备信息。lsusb -v 命令输出非常详细,包含了设备的各种描述符信息。

lsusb -v -s 001:026

其中 -s 001:026 指定总线编号和设备编号,可以替换成实际的编号。

root@h-pc:~/ros_ws# ls /dev/bus/usb
001  002

检查usb 总线是否存在。


让我们重新梳理下我们遇到的问题:

这个问题是我在 容器 中 使用 usb 设备遇到的问题,接上回:https://www.cnblogs.com/odesey/p/18256384

问题:

假设我已经启动了一个容器了,但是我把 usb 设备进行了 插拔,设备编号发生了改变。即:

在容器内: ls /dev/bus/usb/001/026
ls: cannot access '/dev/bus/usb/001/026': No such file or directory
在宿主机:ls -l /dev/bus/usb/001/026
crw-rw-r-- 1 root root 189, 25 6月 20 13:53 /dev/bus/usb/001/026在容器内: ls /dev/bus/usb/001/026
ls:无法访问“/dev/bus/usb/001/026”:没有这样的文件或目录
在宿主机:ls -l /dev/bus/usb/001/026
crw-rw-r-- 1 根根 189, 25 6月 20 13:53 /dev/bus/usb/001/026

容器内只有:

ls /dev/bus/usb/001
001 002 003 004 005 007 008 009 011ls /dev/总线/usb/001
001 002 003 004 005 007 008 009 011

这是怎么回事呢?

解决:

在你将 USB 设备插拔后,宿主机会分配一个新的设备编号,而 Docker 容器启动时仅映射了当时存在的设备编号。这导致了容器内不能访问新的设备编号对应的设备文件。

以下是如何解决这个问题的几种方法:

方法 1: 重新启动容器
最简单的方法是重新启动 Docker 容器,使其重新映射当前所有的 USB 设备:

docker restart <container_name>

方法 2: 使用 --device-cgroup-rule
使用 --device-cgroup-rule 来允许容器访问任何 USB 设备,而不是特定的设备文件:

docker run --device-cgroup-rule='c 189:* rmw' -it --name ros_container ubuntu:18.04 /bin/bash

这将允许容器访问所有的 USB 设备,即使设备编号发生变化。

方法 3: 使用 --privileged 模式
--privileged 模式允许容器访问主机上的所有设备,这也解决了 USB 设备编号变化的问题:

docker run --privileged -it --name ros_container ubuntu:18.04 /bin/bash

方法 4: 使用 --device 映射整个 USB 总线
需要创建容器时候使用,这种方法确保所有设备在插拔后仍然可访问:

docker run --device=/dev/bus/usb -it --name ros_container ubuntu:18.04 /bin/bash

方法 5: 重新映射设备到正在运行的容器
如果不想重启容器,可以使用 docker exec 命令将新的设备映射到正在运行的容器。首先找到设备的路径:

在宿主机上运行以下命令以确定新设备路径:

ls -l /dev/bus/usb/001/

然后,将新设备路径映射到容器内:

docker exec -it ros_container bash -c "mount --bind /dev/bus/usb /dev/bus/usb"

方法 6: 使用 Udev 规则和固定设备路径
确保在 Udev 规则中创建固定的符号链接,以便在设备插拔后路径不变。例如:

  1. 创建 Udev 规则:

编辑或创建 /etc/udev/rules.d/99-usb-devices.rules 文件,添加以下内容:

# Orbbec Astra camera
SUBSYSTEM=="usb", ATTR{idProduct}=="0403", ATTR{idVendor}=="2bc5", MODE:="0666", OWNER:="root", GROUP:="video", SYMLINK+="astra_pro"

# IMU device (假设供应商 ID 和产品 ID 为 1234 和 5678)
SUBSYSTEM=="usb", ATTR{idProduct}=="5678", ATTR{idVendor}=="1234", MODE:="0666", OWNER:="root", GROUP:="video", SYMLINK+="imu_device"
  1. 重新加载 Udev 规则:

    sudo udevadm control --reload-rules
    sudo udevadm trigger

  2. 验证符号链接:

插入设备后,验证符号链接是否创建成功:

ls -l /dev/astra_pro
ls -l /dev/imu_device
  1. 启动 Docker 容器时映射这些符号链接:

    docker run --device=/dev/astra_pro --device=/dev/imu_device -it --name ros_container ubuntu:18.04 /bin/bash

方法 7: 动态添加设备到容器

通过以下命令动态添加设备到已经运行的容器中:

docker update --device-add /dev/bus/usb/001/026 <container_name>

总结
为了避免每次插拔 USB 设备后重新启动容器或手动重新映射设备,最推荐的方法是使用 --device=/dev/bus/usb 或 --privileged 模式启动容器。这两种方法都可以确保容器能够访问所有 USB 设备,而不受设备编号变化的影响。如果你更注重安全性,可以结合 Udev 规则为设备创建固定的符号链接。


首先,我们不想重新创建一个容器,因此:方法 2、3、4 不再适用。

方法1 值得推荐。

方法5 看起来也不错。

方法6 Udev 不能在 容器内执行。我们需要在宿主机执行该操作。然后在启动容器时候就可以加载进去了。

我们就暂时使用 方法1 吧。


https://www.cnblogs.com/odesey/p/18256384

在容器中 执行脚本: ./scripts/create_udev_rules
报错:

udev does not support containers, not started

在宿主机下:

  1. 那我们把 src/ros_astra_camera/56-orbbec-usb.rules 该文件 copy 到宿主机下:

    sudo cp 56-orbbec-usb.rules /etc/udev/rules.d/

  2. 重新加载 Udev 规则:

    sudo udevadm control --reload-rules
    sudo udevadm trigger

  3. 验证符号链接:

插入设备后,验证符号链接是否创建成功:

ls -l /dev/astra_pro
lrwxrwxrwx 1 root root 15 6月  20 15:41 /dev/astra_pro -> bus/usb/001/029

ls -l /dev/astrauvc
lrwxrwxrwx 1 root root 15 6月  20 15:41 /dev/astrauvc -> bus/usb/001/030

然后我们重启容器:

docker restart <container_name>

在容器内:

/dev/astra_pro 和 /dev/astrauvc我们依旧找不到

不行我们就做个软链接吧:

ln -s bus/usb/001/029 /dev/astra_pro
ln -s bus/usb/001/030 /dev/astrauvc

后面有问题再说。

我们打包容器为镜像后,再启动容器这些问题都可以解决了。

posted @ 2024-06-20 15:56  cold_moon  阅读(112)  评论(0编辑  收藏  举报