机器人上接了激光雷达、IMU、电机控制器和几个串口设备。开机后它们通常出现在 /dev/ttyACM0、/dev/ttyUSB0 这类名字下。这些名字由内核按枚举顺序分配,拔插一次、重启一次或者少接一个设备,顺序就可能改变。
把这类名字写进配置文件,故障现象通常是“开机后电机不动,但报错说找不到设备”,或者更糟:找到了设备,但其实是另一个。这篇文章讨论如何用稳定标识代替顺序编号,以及权限该怎么给。
先确认设备的稳定属性
1 | udevadm info --name=/dev/ttyACM0 --attribute-walk |
重点看三类属性。serial 是设备序列号,同型号多台设备也能区分,通常是最佳选择。idVendor 与 idProduct 识别型号,适合同型号只有一台的情况。KERNELS 或 DEVPATH 描述物理端口位置,适合设备固定焊在整机内部、端口不会变的产品。
只看 idVendor/idProduct 就写规则是常见错误。两块同型号的 USB 转串口同时接上时,两条规则会匹配到同一个设备顺序,符号链接互相覆盖,最终哪个是哪个取决于枚举顺序。
规则要既匹配又命名
1 | # /etc/udev/rules.d/60-robot-devices.rules |
几个要点。SUBSYSTEM 加上可以避免匹配到非 tty 设备。ATTRS 会沿设备父链向上查找,比只匹配当前节点的 ATTR 更常用,因为序列号往往在 USB 设备层而不是 tty 层。SYMLINK 使用带目录的名字能把设备集中到一处,便于查看。
MODE 和 GROUP 是为了避免程序必须以 root 运行。给 0660 加专用属组,比给全局可读写更安全,也让权限范围可以审计。
顺序名要主动修掉
创建符号链接之后,/dev/ttyACM0 仍然存在。如果程序里还残留着顺序名,故障依旧存在。检查方式是搜索配置和启动文件:
1 | grep -rn "ttyACM\|ttyUSB" /opt/robot/config /etc/systemd/system 2>/dev/null |
需要改的是所有引用点:ROS 2 节点的参数、launch 文件、unit 文件的参数。只改一处,剩下的仍然按顺序名打开。
重载和验证
1 | sudo udevadm control --reload-rules |
验证时应该做拔插和重启测试,而不只是执行命令看链接是否存在。判断规则是否真的稳定,标准是多次拔插和重启后符号链接始终指向同一个物理设备。
一个实用的确认方式是记录设备序列号并和打开的文件对比:先读 /dev/robot/motor 的序列号,再确认程序打开的就是这个设备。如果两处不一致,规则匹配范围过宽。
和容器、权限的关系
在容器里运行程序时,符号链接需要在容器内可见,通常通过挂载设备或转发 udev 事件实现。只挂载 /dev 而不处理设备属性,容器内可能看不到稳定名字。
权限方面,还要注意程序运行用户的属组是否包含规则里指定的组。修改属组后需要重新登录或重启相关服务才会生效,这一点在排查“权限明明给了却打不开”时经常被忽略。
参考资料
证据边界
本文讨论设备命名的稳定性和权限配置方式,不包含任何具体硬件的规则文件。文中示例中的 VID、序列号需替换为实际设备属性;符号链接是否稳定必须通过重复拔插和重启验证,单次成功不足以说明问题已经解决。