Ubuntu 22.04 USB 设备固定命名配置文档
一、问题背景
当多个相同的USB串口设备(相同 VID/PID)插入电脑时,系统会随机分配 ttyUSB0、ttyUSB1 等名称,导致设备识别混乱。本文档提供通过 udev 规则为每个设备创建固定名称的方法。
二、解决方案原理
利用设备的唯一硬件信息(序列号或物理端口路径)创建 udev 规则,为每个设备生成固定的符号链接(如 /dev/device_A、/dev/device_B),应用程序直接使用这些固定名称。
三、准备工作
3.1 查看系统已连接的USB设备
bash
ls -la /dev/ttyUSB*
3.2 安装必要工具(如未安装)
bash
sudo apt-get update sudo apt-get install usbutils
四、两种绑定方法
方法A:使用序列号绑定(推荐,最稳定)
步骤1:获取设备序列号
bash
# 只插一个设备
udevadm info -a -n /dev/ttyUSB0 | grep -i serial | head -1
# 输出示例:ATTRS{serial}=="A1B2C3D4"
# 拔掉,插另一个设备,重复命令
udevadm info -a -n /dev/ttyUSB0 | grep -i serial | head -1
# 输出示例:ATTRS{serial}=="E5F6G7H8"
步骤2:编写规则
bash
sudo nano /etc/udev/rules.d/99-usb-serial.rules
添加:
text
ACTION=="add", SUBSYSTEM=="tty", ATTRS{serial}=="A1B2C3D4", MODE:="0666", SYMLINK+="device_A"
ACTION=="add", SUBSYSTEM=="tty", ATTRS{serial}=="E5F6G7H8", MODE:="0666", SYMLINK+="device_B"
方法B:使用物理端口绑定(当序列号不存在或相同时使用)
步骤1:获取物理端口路径
bash
# 设备A udevadm info -a -n /dev/ttyUSB0 | grep -A 5 "looking at parent device.*usb" | grep KERNELS # 输出示例:KERNELS=="1-4" # 设备B udevadm info -a -n /dev/ttyUSB1 | grep -A 5 "looking at parent device.*usb" | grep KERNELS # 输出示例:KERNELS=="1-13"
步骤2:编写规则
bash
sudo nano /etc/udev/rules.d/99-usb-serial.rules
添加:
text
ACTION=="add", SUBSYSTEM=="tty", KERNELS=="1-4", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", SYMLINK+="device_A"
ACTION=="add", SUBSYSTEM=="tty", KERNELS=="1-13", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", SYMLINK+="device_B"
注意:idVendor 和 idProduct 值需根据实际设备修改,可通过 lsusb 查看。device_A或device_B修改为硬件名称,如myimu、myAstraPro等。
五、规则文件详解
5.1 规则文件位置
-
目录:
/etc/udev/rules.d/ -
命名:
[数字]-[名称].rules(如99-usb-serial.rules) -
数字越小越先执行,用户自定义建议用
99-
5.2 常用规则参数
| 参数 | 说明 | 示例 |
|---|---|---|
ACTION | 触发动作 | ACTION=="add" |
SUBSYSTEM | 子系统 | SUBSYSTEM=="tty" |
KERNEL | 内核名称 | KERNEL=="ttyUSB*" |
KERNELS | 父设备内核名称(物理端口) | KERNELS=="1-4" |
ATTRS{idVendor} | USB厂商ID | ATTRS{idVendor}=="1a86" |
ATTRS{idProduct} | USB产品ID | ATTRS{idProduct}=="7523" |
ATTRS{serial} | 序列号 | ATTRS{serial}=="A1B2C3D4" |
MODE | 权限模式 | MODE:="0666"(所有用户可读写) |
SYMLINK | 创建的符号链接名 | SYMLINK+="my_device" |
六、应用规则
6.1 重新加载规则
bash
sudo udevadm control --reload-rules
6.2 触发规则生效
bash
# 方法1:触发特定设备 sudo udevadm trigger --subsystem-match=tty --attr-match=idVendor=1a86 # 方法2:拔插USB设备(最可靠) # 拔掉所有设备,等3秒,重新插上 # 方法3:重启 udev 服务 sudo systemctl restart systemd-udevd # 方法4:重启系统(100%有效) sudo reboot
6.3 验证规则
bash
# 查看创建的符号链接 ls -la /dev/device_* /dev/my_* # 查看实际指向 ls -la /dev/ttyUSB* # 测试权限 cat /dev/device_A 2>&1 | head -3
七、多设备配置示例
7.1 同一个文件管理多个设备
bash
sudo nano /etc/udev/rules.d/99-usb-serial.rules
text
# === USB转串口设备规则 ===
# CH340设备1 (端口1-4)
ACTION=="add", SUBSYSTEM=="tty", KERNELS=="1-4", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", SYMLINK+="imu_1"
# CH340设备2 (端口1-13)
ACTION=="add", SUBSYSTEM=="tty", KERNELS=="1-13", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", SYMLINK+="imu_2"
# FTDI设备 (使用序列号)
ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="FTDI12345", MODE:="0666", SYMLINK+="gps_device"
# Arduino (VID/PID直接匹配)
ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="2341", ATTRS{idProduct}=="0043", MODE:="0666", SYMLINK+="arduino"
八、调试技巧
8.1 监控 udev 事件
bash
# 实时监控设备插拔事件 sudo udevadm monitor --property --subsystem-match=tty
8.2 测试规则匹配
bash
# 测试特定设备匹配的规则 sudo udevadm test $(udevadm info -q path -n /dev/ttyUSB0) 2>&1 | grep -E "SYMLINK|my_device"
8.3 查看设备详细信息
bash
# 查看完整设备树 udevadm info -a -n /dev/ttyUSB0 # 查看USB设备列表 lsusb lsusb -t
8.4 查看系统日志
bash
# 查看 udev 相关日志 sudo journalctl -u systemd-udevd | tail -50
九、常见问题及解决
9.1 规则不生效
可能原因:
-
规则语法错误
-
没有重新加载规则
-
KERNELS 值获取错误
解决方法:
bash
# 重新获取 KERNELS 值 udevadm info -a -n /dev/ttyUSB0 | grep -A 5 "looking at parent device.*usb" | grep KERNELS # 重新加载 sudo udevadm control --reload-rules sudo udevadm trigger
9.2 符号链接未创建
检查:
bash
# 手动测试规则 sudo udevadm test $(udevadm info -q path -n /dev/ttyUSB0) # 拔插设备后查看 ls -la /dev/ | grep -E "ttyUSB|my_device"
9.3 权限问题
在规则中添加:
text
MODE:="0666"
或指定用户组:
text
GROUP:="dialout", MODE:="0660"
9.4 设备换口后失效(物理端口绑定)
解决方法:
-
重新获取新端口的 KERNELS 值
-
更新规则文件
-
或改用序列号绑定
十、最佳实践建议
10.1 命名规范
-
使用有意义的名称:
imu_left、gps_rear、lidar_front -
避免使用空格和特殊字符
-
全部小写,用下划线分隔
10.2 规则文件管理
-
所有USB设备规则写在同一文件:
99-usb-serial.rules -
添加注释说明每个设备的用途
-
备份重要规则:
sudo cp /etc/udev/rules.d/99-usb-serial.rules ~/
10.3 优先级使用
-
系统自带规则:
00-79 -
用户自定义:
80-99 -
推荐使用
99-确保最后执行
十一、完整操作流程速查
bash
# 1. 插入设备,查看当前分配
ls -la /dev/ttyUSB*
# 2. 获取物理端口
udevadm info -a -n /dev/ttyUSB0 | grep -A 5 "looking at parent device.*usb" | grep KERNELS
# 3. 编辑规则文件
sudo nano /etc/udev/rules.d/99-usb-serial.rules
# 添加规则:ACTION=="add", SUBSYSTEM=="tty", KERNELS=="1-4", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", SYMLINK+="my_device"
# 4. 重新加载规则
sudo udevadm control --reload-rules
sudo udevadm trigger
# 5. 验证结果
ls -la /dev/my_device
十二、参考资料
-
udev 手册:
man udev -
udevadm 手册:
man udevadm -
Ubuntu udev 文档:https://wiki.ubuntu.com/Udev
文档版本:1.0
最后更新:2024-03-02
适用系统:Ubuntu 22.04 / 20.04 / Debian 系列
调试问题:
zhping@zhping-Legion:~$ ls -la /dev/ttyUSB* crw-rw-rw- 1 root dialout 188, 0 3月 3 20:11 /dev/ttyUSB0 crw-rw---- 1 root dialout 188, 1 3月 3 20:12 /dev/ttyUSB1 zhping@zhping-Legion:~$
看到问题了!两个设备的权限不一致:
-
/dev/ttyUSB0:crw-rw-rw-(666权限,所有用户可读写) ✅ -
/dev/ttyUSB1:crw-rw----(660权限,只有root和dialout组可读写) ❌
问题原因
你的规则文件里最后两行都有 MODE:="0666",但只对 ttyUSB0 生效了,ttyUSB1 没有正确应用权限设置。
解决方法
1. 检查当前规则文件
bash
cat /etc/udev/rules.d/*.rules | grep -E "1a86|7523|myimu|sc_mini"
2. 确保两条规则都完整且正确
bash
sudo nano /etc/udev/rules.d/99-usb-serial.rules
确认最后两行是:
text
ACTION=="add", SUBSYSTEM=="tty", KERNELS=="1-4", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", SYMLINK+="sc_mini"
ACTION=="add", SUBSYSTEM=="tty", KERNELS=="1-13", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", SYMLINK+="myimu"
3. 强制重新应用规则
bash
# 重新加载规则 sudo udevadm control --reload-rules # 删除现有符号链接(如果存在) sudo rm -f /dev/sc_mini /dev/myimu # 重新触发所有ttyUSB设备 sudo udevadm trigger --action=add --subsystem-match=tty --attr-match=idVendor=1a86 # 或者直接重启 udev 服务 sudo systemctl restart systemd-udevd
4. 拔插设备
最简单可靠的方法:
bash
# 拔掉两个USB设备,等3秒,重新插上
5. 验证结果
bash
# 检查权限 ls -la /dev/ttyUSB* # 检查符号链接 ls -la /dev/sc_mini /dev/myimu 2>/dev/null
应该看到两个设备都是 crw-rw-rw- 权限。
如果问题依旧,试试这个强力方法:
bash
# 1. 临时手动修改权限(临时解决) sudo chmod 666 /dev/ttyUSB1 # 2. 完全删除规则文件并重建 sudo rm /etc/udev/rules.d/99-usb-serial.rules sudo nano /etc/udev/rules.d/99-usb-serial.rules # 重新粘贴规则 # 3. 重启系统 sudo reboot
验证最终结果:
bash
ls -la /dev/ttyUSB*
应该显示:
text
crw-rw-rw- 1 root dialout 188, 0 ... /dev/ttyUSB0 crw-rw-rw- 1 root dialout 188, 1 ... /dev/ttyUSB1
完成后告诉我结果!
zhping@zhping-Legion:~$ cat /etc/udev/rules.d/*.rules | grep -E "1a86|7523|myimu|sc_mini" ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", ENV{ID_MM_DEVICE_MANUAL_SCAN_ONLY}="1" ACTION=="add", SUBSYSTEM=="tty", KERNELS=="1-4", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", SYMLINK+="sc_mini" ACTION=="add", SUBSYSTEM=="tty", KERNELS=="1-13", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", SYMLINK+="myimu" zhping@zhping-Legion:~$ sudo nano /etc/udev/rules.d/99-usb-serial.rules
规则文件内容看起来是正确的!两条规则都有 MODE:="0666"。现在让我们强制重新应用规则:
完整修复步骤:
1. 先停止当前 udev 对这两个设备的处理
bash
# 删除现有的符号链接 sudo rm -f /dev/sc_mini /dev/myimu
2. 重新加载规则并强制触发
bash
# 重新加载所有规则 sudo udevadm control --reload-rules # 删除内核中已有的设备状态 echo 'ACTION=="remove", SUBSYSTEM=="tty", KERNEL=="ttyUSB*", RUN+="/bin/true"' | sudo tee /etc/udev/rules.d/99-cleanup.rules sudo udevadm control --reload-rules
3. 最简单可靠的方法:拔插设备
bash
# 1. 拔掉两个USB设备 # 2. 等待3秒 # 3. 重新插上两个设备
4. 检查结果
bash
ls -la /dev/ttyUSB*
如果还是不行,试试:
5. 重启 udev 服务
bash
sudo systemctl restart systemd-udevd # 等待几秒 ls -la /dev/ttyUSB*
6. 终极方法:重启系统
bash
sudo reboot
重启后检查:
bash
ls -la /dev/ttyUSB* ls -la /dev/sc_mini /dev/myimu 2>/dev/null
如果重启后还是只有 ttyUSB0 有 666 权限
可能是 ModemManager 在干扰。可以临时禁用 ModemManager 测试:
bash
# 暂停 ModemManager 服务 sudo systemctl stop ModemManager # 拔插设备,检查权限 ls -la /dev/ttyUSB* # 如果正常了,永久禁用 sudo systemctl disable ModemManager

被折叠的 条评论
为什么被折叠?



