【udev重命名详细教程】放弃硬编码,从重命名开始
前言上一期我们在讲双雷达的时候使用过串口udev重命名这一期我们详细讲一下背后的原理和具体查询过程本文包括1 串口udev重命名教程2 udev原理1 串口udev重命名教程1-1 串口查询查询串口ls/dev/tty*通过插拔可以短暂确认本轮的临时串口号1-2 串口信息确认查询串口的信息dmesg|grepttyUSB11-3 设备详细信息查询具体信息-n /dev/ttyUSB1代表 name名称-a代表“向上遍历设备树”udevadm info-a-n/dev/ttyUSB1|grep-E{idVendor}|{idProduct}|KERNELS通过上述输出我们可以看到整个层级结构第一层软件虚拟层,这是 Linux 内核驱动ch341 驱动最终创建的设备节点名称。KERNELSttyUSB1第二层USB 接口层,代表 USB 设备的“配置1接口0KERNELS1-1.2.4:1.0第三层真正的目标硬件KERNELS1-1.2.4这是物理 USB 拓扑路径1a86:7523这是南京沁恒WCHCH341 芯片的绝对唯一身份证号。不管你插在电脑的哪个口这两个值都不会变。KERNELS1-1.2.4ATTRS{idProduct}7523ATTRS{idVendor}1a86第四层上游 USB 集线器 Hub这里我的32是经过拓展坞接到板子上的KERNELS1-1.2ATTRS{idProduct}2813ATTRS{idVendor}2109KERNELS1-1ATTRS{idProduct}0610ATTRS{idVendor}05e3第五层主板根控制器操作系统提供,这是你电脑主板上实际的 USB 控制器根集线器KERNELSusb1ATTRS{idProduct}0002ATTRS{idVendor}1d6b第六层最底层的硬件总线硬核底层KERNELSxhci-hcd.2.autoKERNELS35100000.usbKERNELS35100000.usb3KERNELS35000000.hsio_apbKERNELSsocKERNELSplatform1-4 编写 udev 规则通过上一节的信息确认我们得知了不会变的设备物理idKERNELS1-1.2.4ATTRS{idProduct}7523ATTRS{idVendor}1a86这时候我们只需要修改udev规则文件即可sudonano/etc/udev/rules.d/99-stm32-ch341.rules把下述代码粘贴进去SUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}7523,SYMLINKstm32,MODE06661-5 重新加载udev规则sudoudevadm control --reload-rulessudoudevadm trigger1-6 插拔验证我们重新查找ls/dev/st*2 udev原理2-1 为什么需要 udev在早期的 Linux 中/dev目录下的设备节点是静态的。这就导致了一个致命问题“插拔风暴”。假设你只有一个串口设备它永远是/dev/ttyUSB0这没什么问题。但在我们的机器人开发中比如双雷达 STM32 底盘如果你先插雷达雷达可能抢占ttyUSB0和ttyUSB1如果你先插 STM32STM32 就变成了ttyUSB0。设备的命名完全取决于你插线的先后顺序。这会导致我们的 ROS launch 文件或代码配置极其脆弱每次重启或换 USB 口都要改代码。udev就是为了解决这个问题而诞生的——它负责在用户层动态管理设备实现“按硬件身份固定名字”。2-2 udev 的工作机制udev并不是一直在后台轮询死循环检测USB 口它是事件驱动的。核心流程如下内核发现硬件当你插入 USB 设备时Linux 内核的驱动程序如 ch341会检测到这一物理动作。发送 uevent内核会通过 Netlink 套接字向用户空间广播一个“设备变更事件”。udev 守护进程接单后台运行的udevdudev 守护进程监听到这个事件拿到设备的信息。规则匹配udevd会按照字典顺序遍历/etc/udev/rules.d/目录下的所有.rules文件。执行动作一旦匹配到某条规则比如我们写的 99-stm32-ch341.rulesudev就会执行规则里指定的动作创建软链接、修改权限等。2-3 规则文件的底层逻辑我们在1-4节写的这行代码SUBSYSTEMtty, ATTRS{idVendor}1a86, ATTRS{idProduct}7523,SYMLINKstm32,MODE0666它可以分为两类关键字匹配键条件和赋值键动作。匹配键用表示必须全部满足才会触发SUBSYSTEMtty告诉 udev “我只关心串口类设备”。如果你插了个 CH341 的鼠标也是 1a86:7523但属于 input subsystem这条规则不会拦截它防止误杀。ATTRS{idVendor}1a86和ATTRS{idProduct}7523精准狙击对照前面讲的“设备树第三层”直接锁定这个具体的硬件。赋值键用或表示触发后执行的操作SYMLINKstm32的意思是“追加一个别名”。udev 会在/dev/下创建一个名为stm32的快捷方式指向真实的ttyUSBx。注意它不会抹除系统原本生成的ttyUSB1两者共存。MODE0666的意思是“强制赋值”。把该设备的权限改为0666即所有用户可读可写。这样我们的普通用户比如运行 ROS 节点的用户就不需要每次都加sudo才能打开串口了。2-4 关于“设备树层级”与规则的避坑指南结合我们在1-3节看到的六层结构udev在匹配ATTRS{}时是允许跨层级向上查找的。为什么不能匹配第四层Hub如果你把规则写成ATTRS{idVendor}2109扩展坞的 ID那么只要这个扩展坞一通电或者你往扩展坞上插个 U 盘udev 都会试图执行动作导致系统混乱。最佳实践写 udev 规则时匹配条件要尽量贴近设备树的底层即目标硬件本身那一层通常包含idVendor和idProduct的那一层这样才能保证规则的唯一性和稳定性。总结本文系统讲解了如何彻底解决Linux系统中多串口设备如STM32因插拔顺序导致命名随机变化的痛点通过演示使用udevadm命令向上遍历设备树以精准提取芯片唯一硬件ID的全流程并深入剖析udev基于事件驱动的底层匹配与赋值机制最终实现了为设备创建固定的软链接与权限配置确保了开发环境的绝对稳定。如有错误欢迎指出!感谢你的观看