串口绑定(或者叫串口别名)与权限
linux默认对dialout组的设备文件命名根据设备类型与插入顺序确定。多个串口设备开机前插在主机上,这些设备在开机时载入顺序是不确定的,所以需要绑定设备名(就是一个链接文件到确定的设备),非root用户还会需要串口的读写权限。
a.绑定设备名:
1.具有唯一码的设备
查看需要绑定的设备的idVendor 和idpProduct
$ lsusb -vv
$ sudo gedit /etc/udev/rules.d/10-local.rules
自定义打开文件写入自定义规则(如:通过lsusb -vv 看到设备的idVendor与idProduct分别为0x067b Prolific Technology, Inc.,0x2303 PL2303 Serial Port)。这里最好新建一个文件,不要覆盖以前的文件了。如果是相同设备还需要额外的辨别参数也可以添加额外的参数。我们只取前面的数值0x067b,0x2303,后面的描述不要
ACTION=="add", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", SYMLINK+="MyArduino"
#####还有其他额外的设备需要则加一行,方法一样。
参数说明:
ACTION 事件 (udevent)的行为,例如:add( 添加设备 )、remove(删除设备 )。
SYMLINK 为 /dev/下的设备文件产生符号链接。由于 udev只能为某个设备产生一个设备文件,所以为了不覆盖系统默认的 udev规则所产生的文件,推荐使用符号链接。
== 匹配 相等比较
+= 赋值 追加特定的值给已经存在的键
更多内容查看udev规则。
$ udevadm info -a -p $(udevadm info -q path -n /dev/ttyACM0)
##### 如果不止一个串口,比如还有/dev/ttyUSB0,在/dev/ttyACM0后添加 /dev/ttyUSB0
##### 只是看看串口设备信息
重启后生效。
重启后查看:
$ ls -l /dev/My*
应该会看到类似的输出:
lrwxrwxrwx 1 root root 7 4月 11 10:32 MyArduino -> ttyACM0
lrwxrwxrwx 1 root root 7 4月 11 10:32 MyPL0 -> ttyUSB0 ####这是我的另一个设备
2.不具有唯一码的设备
以下为2个以上相同串口设备情况:
在前面已经提及不同串口设备的绑定方式。如果是相同设备以上绑定方式就不能应对了,lsusb -vv显示相同设备信息全部都是一样的,这时/dev/MyArduino指向/dev/ttyACM1(2个相同设备分别是/dev/ttyACM0,/dev/ttyACM1,总是指向末尾数值最大的一个)。对于大多数廉价适配器它们并没有特别的编号进行区分。
因此我们考虑一种更麻烦的绑定方式,根据usb的物理端口来区分(一般来说对于一台机器,usb硬件端口都是固定的,也因此我们考虑这种方式来解决绑定问题)。这不同于相同串口设备具有相同的硬件信息,每台计算机的usb物理端口信息可能都是不同的,所以每台计算机都得单独配置,而且一旦串口设备绑定某个物理usb端口,换个usb端口将会导致不能正确识别。
因此我们需要设备更详细的信息,比如我们需要/dev/ttyUSB0的信息:
$ udevadm info -a /dev/ttyUSB0
可以看到类似以下信息
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.
looking at device '/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/ttyUSB0/tty/ttyUSB0':
KERNEL=="ttyUSB0"
SUBSYSTEM=="tty"
DRIVER==""
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0/ttyUSB0':
KERNELS=="ttyUSB0"
SUBSYSTEMS=="usb-serial"
DRIVERS=="pl2303"
ATTRS{port_number}=="0"
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0':
KERNELS=="3-2:1.0"
SUBSYSTEMS=="usb"
DRIVERS=="pl2303"
ATTRS{authorized}=="1"
ATTRS{bAlternateSetting}==" 0"
ATTRS{bInterfaceClass}=="ff"
ATTRS{bInterfaceNumber}=="00"
ATTRS{bInterfaceProtocol}=="00"
ATTRS{bInterfaceSubClass}=="00"
ATTRS{bNumEndpoints}=="03"
ATTRS{supports_autosuspend}=="1"
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-2':
KERNELS=="3-2"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bDeviceClass}=="00"
ATTRS{bDeviceProtocol}=="00"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{bMaxPower}=="100mA"
ATTRS{bNumConfigurations}=="1"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bcdDevice}=="0300"
ATTRS{bmAttributes}=="80"
ATTRS{busnum}=="3"
ATTRS{configuration}==""
ATTRS{devnum}=="2"
ATTRS{devpath}=="2"
ATTRS{idProduct}=="2303"
ATTRS{idVendor}=="067b"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Prolific Technology Inc."
ATTRS{maxchild}=="0"
ATTRS{product}=="USB-Serial Controller"
ATTRS{quirks}=="0x0"
ATTRS{removable}=="removable"
ATTRS{speed}=="12"
ATTRS{urbnum}=="22"
ATTRS{version}==" 1.10"
looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3':
KERNELS=="usb3"
SUBSYSTEMS=="usb"
DRIVERS=="usb"
ATTRS{authorized}=="1"
ATTRS{authorized_default}=="1"
ATTRS{avoid_reset_quirk}=="0"
ATTRS{bConfigurationValue}=="1"
ATTRS{bDeviceClass}=="09"
ATTRS{bDeviceProtocol}=="01"
ATTRS{bDeviceSubClass}=="00"
ATTRS{bMaxPacketSize0}=="64"
ATTRS{bMaxPower}=="0mA"
ATTRS{bNumConfigurations}=="1"
ATTRS{bNumInterfaces}==" 1"
ATTRS{bcdDevice}=="0404"
ATTRS{bmAttributes}=="e0"
ATTRS{busnum}=="3"
ATTRS{configuration}==""
ATTRS{devnum}=="1"
ATTRS{devpath}=="0"
ATTRS{idProduct}=="0002"
ATTRS{idVendor}=="1d6b"
ATTRS{interface_authorized_default}=="1"
ATTRS{ltm_capable}=="no"
ATTRS{manufacturer}=="Linux 4.4.0-81-generic xhci-hcd"
ATTRS{maxchild}=="10"
ATTRS{product}=="xHCI Host Controller"
ATTRS{quirks}=="0x0"
ATTRS{removable}=="unknown"
ATTRS{serial}=="0000:00:14.0"
ATTRS{speed}=="480"
ATTRS{urbnum}=="75"
ATTRS{version}==" 2.00"
looking at parent device '/devices/pci0000:00/0000:00:14.0':
KERNELS=="0000:00:14.0"
SUBSYSTEMS=="pci"
DRIVERS=="xhci_hcd"
ATTRS{broken_parity_status}=="0"
ATTRS{class}=="0x0c0330"
ATTRS{consistent_dma_mask_bits}=="64"
ATTRS{d3cold_allowed}=="1"
ATTRS{device}=="0x8c31"
ATTRS{dma_mask_bits}=="64"
ATTRS{driver_override}=="(null)"
ATTRS{enable}=="1"
ATTRS{irq}=="26"
ATTRS{local_cpulist}=="0-1"
ATTRS{local_cpus}=="3"
ATTRS{msi_bus}=="1"
ATTRS{numa_node}=="-1"
ATTRS{subsystem_device}=="0x8c31"
ATTRS{subsystem_vendor}=="0x8086"
ATTRS{vendor}=="0x8086"
looking at parent device '/devices/pci0000:00':
KERNELS=="pci0000:00"
SUBSYSTEMS==""
DRIVERS==""
然后,新开一个终端,插入同样的设备,假如系统默认命名为/dev/ttyUSB1,同样的方式查看详细信息(这里不粘贴了)。
1、我们可以看到之前我们用于绑定串口的参数: ATTRS{idProduct},ATTRS{idVendor},当然现在他们已经不能满足我们的需求了。
2、然后我们来对比他们存在差异的地方,我们看到在第三段有差异:KERNELS=="3-2:1.0",SUBSYSTEMS=="usb"(这只是/dev/ttyUSB0的)。
3、这一段最上面有:looking at parent device '/devices/pci0000:00/0000:00:14.0/usb3/3-2/3-2:1.0': 。在这里我们可以看到父级关系,在其中有:pci... ,既是这个usb硬件端口是连在pci总线上的(我想应该没有人会没事去拔pci上的设备吧^_^)
4、这里需要注意的一点是不要跨级(跨段:即looking at parent....不能混用)。KERNEL 所在的段可以与单个KERNELS所在的段的属性结合,但是2个KERNELS所在的段属性结合将会导致命令无效。
修改之前的文件/etc/udev/rules.d/10-local.rules,注释掉我们前面定义的规则。
ACTION=="add",SUBSYSTEMS=="usb",KERNELS=="3-2:1.0",SYMLINK+="Mytest0"
#ACTION=="add",ATTRS{idVendor}=="067b",ATTRS{idProduct}=="2303",SYMLINK+="MyArduino"
#ACTION=="add",ATTRS{idVendor}=="2341",ATTRS{idProduct}=="0042",SYMLINK+="MyACM0"
然后重启查看效果 :
$ ls -l /dev/M* lrwxrwxrwx 1 root root 7 6月 22 11:24 /dev/Mytest0 -> ttyUSB1
成功完成绑定。
b.串口设备权限
可插拔的串口设备所有者和属组一般分别为root、dialout。因此普通用户要使用串口设备读写是需要root权限的。
而且我们使用的ros-kinetic的robot_upstart包执行launch文件时使用的是安装这个包的用户的权限(无视属组权限),而我们的ros-kinetic是在普通用户下安装的,所以robot_upstart包也应该装在普通用户下(官网也不建议ros安装在root用户下,至于装root下会出什么问题试过才知道,不建议)。
因此,完成开机自启并使用串口,我们需要让我们登录的普通用户拥有串口读写权限。
这里我们还是用到udev管理串口设备文件。
新建一个文件,注意不要重名:
$ sudo gedit /etc/udev/rules.d/50-usb-serial.rules
在打开的文件中写入:
KERNEL=="ttyUSB*",OWNER="<yourusername>",GROUP="root",MODE="0666" KERNEL=="ttyACM*",OWNER="<yourusername>",GROUP="root",MODE="0666"
######替换<yourusername>为你的用户
根据需要,通过这两行我们将/dev下的所有以ttyUSB及ttyACM开头的设备文件的所有者和属组分别修改为用户和root。
重启。
查看效果
$ ls -l /dev/ttyUSB* /dev/ttyACM*
应该会有类似的输出:
crw-rw-rw- 1 <yourusername> root 166, 0 4月 11 10:32 /dev/ttyACM0
crw-rw-rw- 1 <yourusername> root 188, 0 4月 11 10:32 /dev/ttyUSB0
现在可以愉快的使用串口设备了。
为什么我们的普通用户能访问/dev/MyArduino和/dev/MyPL0呢?他们的所有者和属组都是root呀!这里我认为在使用超链接文件时权限是由超链接指向的具体设备文件权限决定。