在Linux中,如何识别通过USB连接的多个Arduino?


17

如果我有多个通过USB连接到Linux计算机的Arduino,它们显示为

  • / tty / ACM0
  • / tty / ACM1
  • / tty / ACM2

不通过串行连接将其连接的情况下,如何确定是哪个Arduino ?Arduino上有序列号或唯一ID吗?

感谢您的时间。

情况:Uno R3,Mega,Leonardo和/ ttyACM [1,2,3]

具有上述顺序的lsusb输出和设备:

...
总线001设备011:ID 2341:0043
总线001设备013:ID 2341:8036
...
总线001设备014:ID 2341:0042

lsusb -d供应商:device -vvv显示每个

宇野

总线001设备014:ID 2341:0042
设备描述符:
  长度18
  bDescriptorType 1
  bcdUSB 1.10
  bDeviceClass 2通信
  bDeviceSubClass 0
  bDeviceProtocol 0
  bMaxPacketSize0 8
  idVendor 0x2341
  idProduct 0x0042
  bcdDevice 0.01
  iManufacturer 1 Arduino(www.arduino.cc)
  iProduct 2
  iSerial 220 55330313735351910141
  bNumConfigurations 1
  配置描述符:
    b长度9
    bDescriptorType 2
    wTotalLength 62
    bNumInterfaces 2
    bConfigurationValue 1
    iConfiguration 0
    bmAttributes 0xc0
      自供电
    最大功率100mA
    接口描述符:
      b长度9
      bDescriptorType 4
      bInterfaceNumber 0
      bAlternateSetting 0
      bNumEndpoints 1
      bInterfaceClass 2通信
      bInterfaceSubClass 2抽象(调制解调器)
      bInterfaceProtocol 1 AT指令(v.25ter)
      iInterface 0
      CDC标头:
        bcdCDC 10.01
      CDC ACM:
        bmCapabilities 0x06
          发送中断
          线路编码和串行状态
      CDC联盟:
        bMasterInterface 0
        bSlaveInterface 1
      端点描述符:
        b长度7
        bDescriptorType 5
        bEndpointAddress 0x82 EP 2输入
        bmAttributes 3
          传输类型中断
          同步类型无
          使用类型数据
        wMaxPacketSize 0x0008 1x 8字节
        b间隔255
    接口描述符:
      b长度9
      bDescriptorType 4
      bInterfaceNumber 1
      bAlternateSetting 0
      bNumEndpoints 2
      bInterfaceClass 10 CDC数据
      bInterfaceSubClass 0未使用
      bInterfaceProtocol 0
      iInterface 0
      端点描述符:
        b长度7
        bDescriptorType 5
        bEndpointAddress 0x04 EP 4输出
        bmAttributes 2
          批量传输类型
          同步类型无
          使用类型数据
        wMaxPacketSize 0x0040 1x 64字节
        b间隔1
      端点描述符:
        b长度7
        bDescriptorType 5
        bEndpointAddress 0x83 EP 3输入
        bmAttributes 2
          批量传输类型
          同步类型无
          使用类型数据
        wMaxPacketSize 0x0040 1x 64字节
        b间隔1
设备状态:0x0000
  (总线供电)

莱昂纳多:

总线001设备013:ID 2341:8036
设备描述符:
  长度18
  bDescriptorType 1
  bcdUSB 2.00
  bDeviceClass 0(在接口级别定义)
  bDeviceSubClass 0
  bDeviceProtocol 0
  bMaxPacketSize0 64
  idVendor 0x2341
  idProduct 0x8036
  bcdDevice 1.00
  iManufacturer 1 Arduino LLC
  iProduct 2 Arduino莱昂纳多
  iSerial 0
  bNumConfigurations 1
  配置描述符:
    b长度9
    bDescriptorType 2
    wTotalLength 100
    bNumInterfaces 3
    bConfigurationValue 1
    iConfiguration 0
    bmAttributes 0x80
      (总线供电)
    最大功率500mA
    接口关联:
      b长度8
      bDescriptorType 11
      bFirstInterface 0
      bInterfaceCount 2
      bFunctionClass 2通信
      bFunctionSubClass 2抽象(调制解调器)
      bFunctionProtocol 1 AT指令(v.25ter)
      iFunction 0
    接口描述符:
      b长度9
      bDescriptorType 4
      bInterfaceNumber 0
      bAlternateSetting 0
      bNumEndpoints 1
      bInterfaceClass 2通信
      bInterfaceSubClass 2抽象(调制解调器)
      bInterfaceProtocol 0无
      iInterface 0
      CDC标头:
        bcdCDC 1.10
      CDC呼叫管理:
        bmCapabilities 0x01
          通话管理
        bDataInterface 1
      CDC ACM:
        bmCapabilities 0x06
          发送中断
          线路编码和串行状态
      CDC联盟:
        bMasterInterface 0
        bSlaveInterface 1
      端点描述符:
        b长度7
        bDescriptorType 5
        bEndpointAddress 0x81 EP 1输入
        bmAttributes 3
          传输类型中断
          同步类型无
          使用类型数据
        wMaxPacketSize 0x0040 1x 64字节
        b间隔0
      端点描述符:
        b长度7
        bDescriptorType 5
        bEndpointAddress 0x83 EP 3输入
        bmAttributes 2
          批量传输类型
          同步类型无
          使用类型数据
        wMaxPacketSize 0x0040 1x 64字节
        b间隔0
    接口描述符:
      b长度9
      bDescriptorType 4
      bInterfaceNumber 2
      bAlternateSetting 0
      bNumEndpoints 1
      bInterfaceClass 3人机界面设备
      bInterfaceSubClass 0没有子类
      bInterfaceProtocol 0无
      iInterface 0
        HID设备描述符:
          b长度9
          bDescriptorType 33
          bcdHID 1.01
          bCountryCode 0不支持
          bNumDescriptors 1
          bDescriptorType 34报告
          wDescriptorLength 101
          报告描述符:(长度为101)
            项(全局):使用情况页,数据= [0x01] 1
                            通用桌面控件
            项目(本地):用法,数据= [0x02] 2
                            鼠
            项目(主):集合,数据= [0x01] 1
                            应用
            项目(本地):使用情况,数据= [0x01] 1
                            指针
            项目(主):集合,数据= [0x00] 0
                            物理
            项目(全局):报表ID,数据= [0x01] 1
            项(全局):使用情况页,数据= [0x09] 9
                            纽扣
            项目(本地):最低使用量,数据= [0x01] 1
                            按钮1(主要)
            项(本地):使用率上限,数据= [0x03] 3
                            按钮3(第三级)
            项(全局):逻辑最小值,数据= [0x00] 0
            项(全局):逻辑最大值,数据= [0x01] 1
            项目(全局):报告计数,数据= [0x03] 3
            项目(全局):报告大小,数据= [0x01] 1
            项目(主):输入,数据= [0x02] 2
                            数据变量绝对No_Wrap线性
                            Preferred_State No_Null_Position非易失性位域
            项目(全局):报告计数,数据= [0x01] 1
            项目(全局):报告大小,数据= [0x05] 5
            项目(主):输入,数据= [0x03] 3
                            恒定变量绝对No_Wrap线性
                            Preferred_State No_Null_Position非易失性位域
            项(全局):使用情况页,数据= [0x01] 1
                            通用桌面控件
            项目(本地):使用情况,数据= [0x30] 48
                            X方向
            项目(本地):使用情况,数据= [0x31] 49
                            Y方向
            项目(本地):用法,数据= [0x38] 56
                            轮
            项(全局):逻辑最小值,数据= [0x81] 129
            项(全局):逻辑最大值,数据= [0x7f] 127
            项(全局):报告大小,数据= [0x08] 8
            项目(全局):报告计数,数据= [0x03] 3
            项目(主):输入,数据= [0x06] 6
                            数据变量相对No_Wrap线性
                            Preferred_State No_Null_Position非易失性位域
            项目(主要):结束收集,数据=无
            项目(主要):结束收集,数据=无

            ......

      端点描述符:
        b长度7
        bDescriptorType 5
        bEndpointAddress 0x84 EP 4输入
        bmAttributes 3
          传输类型中断
          同步类型无
          使用类型数据
        wMaxPacketSize 0x0040 1x 64字节
        b间隔1
设备状态:0x0000
  (总线供电)

和Mega256:

总线001设备014:ID 2341:0042
设备描述符:
  长度18
  bDescriptorType 1
  bcdUSB 1.10
  bDeviceClass 2通信
  bDeviceSubClass 0
  bDeviceProtocol 0
  bMaxPacketSize0 8
  idVendor 0x2341
  idProduct 0x0042
  bcdDevice 0.01
  iManufacturer 1 Arduino(www.arduino.cc)
  iProduct 2
  iSerial 220 55330313735351910141
  bNumConfigurations 1
  配置描述符:
    b长度9
    bDescriptorType 2
    wTotalLength 62
    bNumInterfaces 2
    bConfigurationValue 1
    iConfiguration 0
    bmAttributes 0xc0
      自供电
    最大功率100mA
    接口描述符:
      b长度9
      bDescriptorType 4
      bInterfaceNumber 0
      bAlternateSetting 0
      bNumEndpoints 1
      bInterfaceClass 2通信
      bInterfaceSubClass 2抽象(调制解调器)
      bInterfaceProtocol 1 AT指令(v.25ter)
      iInterface 0
      CDC标头:
        bcdCDC 10.01
      CDC ACM:
        bmCapabilities 0x06
          发送中断
          线路编码和串行状态
      CDC联盟:
        bMasterInterface 0
        bSlaveInterface 1
      端点描述符:
        b长度7
        bDescriptorType 5
        bEndpointAddress 0x82 EP 2输入
        bmAttributes 3
          传输类型中断
          同步类型无
          使用类型数据
        wMaxPacketSize 0x0008 1x 8字节
        b间隔255
    接口描述符:
      b长度9
      bDescriptorType 4
      bInterfaceNumber 1
      bAlternateSetting 0
      bNumEndpoints 2
      bInterfaceClass 10 CDC数据
      bInterfaceSubClass 0未使用
      bInterfaceProtocol 0
      iInterface 0
      端点描述符:
        b长度7
        bDescriptorType 5
        bEndpointAddress 0x04 EP 4输出
        bmAttributes 2
          批量传输类型
          同步类型无
          使用类型数据
        wMaxPacketSize 0x0040 1x 64字节
        b间隔1
      端点描述符:
        b长度7
        bDescriptorType 5
        bEndpointAddress 0x83 EP 3输入
        bmAttributes 2
          批量传输类型
          同步类型无
          使用类型数据
        wMaxPacketSize 0x0040 1x 64字节
        b间隔1
设备状态:0x0000
  (总线供电)

lsusb -vvv说什么
伊格纳西奥·巴斯克斯

您能拔掉一根插头,看看哪一根消失了吗?
匿名企鹅2014年

1
并非如此,我想对远程太阳能传感器阵列执行此操作,该传感器阵列在重新启动时将很远。
vlad b。

Ignacio Vasquez-Abrams-如何将信息从lsusb -vvv映射到/ dev / ttyACM <x>?我可以解析lsusb输出中的内容吗?谢谢你的主意!
vlad b。

您还有另一个可以与输出进行比较的Arduino吗?
伊格纳西奥·巴斯克斯

Answers:


6

假设您的发行版正在使用udev

udevadm info --query=all --name=/dev/ttyACM0

您可能需要root用户权限才能运行此命令(sudo / su)。它将输出如下信息列表:

P: /devices/pci0000:00/0000:00:1d.2/usb4/4-2/4-2:1.0/tty/ttyACM0
N: ttyACM0
S: serial/by-id/usb-Dean_Camera_LUFA_USB-RS232_Adapter_74133353537351403012-if00
S: serial/by-path/pci-0000:00:1d.2-usb-0:2:1.0
E: DEVLINKS=/dev/serial/by-id/usb-Dean_Camera_LUFA_USB-RS232_Adapter_74133353537351403012-if00 /dev/serial/by-path/pci-0000:00:1d.2-usb-0:2:1.0
E: DEVNAME=/dev/ttyACM0
E: DEVPATH=/devices/pci0000:00/0000:00:1d.2/usb4/4-2/4-2:1.0/tty/ttyACM0
E: ID_BUS=usb
E: ID_MM_CANDIDATE=1
E: ID_MODEL=LUFA_USB-RS232_Adapter
E: ID_MODEL_ENC=LUFA\x20USB-RS232\x20Adapter
E: ID_MODEL_FROM_DATABASE=Uno R3 (CDC ACM)
E: ID_MODEL_ID=0043
E: ID_PATH=pci-0000:00:1d.2-usb-0:2:1.0
E: ID_PATH_TAG=pci-0000_00_1d_2-usb-0_2_1_0
E: ID_REVISION=0001
E: ID_SERIAL=Dean_Camera_LUFA_USB-RS232_Adapter_74133353537351403012
E: ID_SERIAL_SHORT=74133353537351403012
E: ID_TYPE=generic
E: ID_USB_DRIVER=cdc_acm
E: ID_USB_INTERFACES=:020201:0a0000:
E: ID_USB_INTERFACE_NUM=00
E: ID_VENDOR=Dean_Camera
E: ID_VENDOR_ENC=Dean\x20Camera
E: ID_VENDOR_FROM_DATABASE=Arduino SA
E: ID_VENDOR_ID=2341
E: MAJOR=166
E: MINOR=0
E: SUBSYSTEM=tty
E: UDEV_LOG=3
E: USEC_INITIALIZED=751387324986

这是针对在atmega16u2(USB到串行)上修改了固件的Uno。感兴趣的行可能是ID_MODEL_ID和ID_MODEL_FROM_DATABASE。


谢谢。在这种情况下,我默认情况下将OpenWrt与hotplug2一起使用,但我将尝试切换至udev并对其进行测试。
vlad b。

5

您可以为每个别名添加一个别名。然后您知道哪个是哪个。这是一个很好的教程,说明如何进行设置。

这是我根据教程编写的一个片段。在下面的示例中,我使用的是FTDI RS232RL USB转串口适配器,我相信这也是Arduino所使用的适配器。

  1. 为了给USB串行设备分配别名,我们需要在该设备上找到一些信息
  2. 插入USB。假定您已经为此设备安装了驱动程序,并且在键入时可以看到该设备:

lsusb

  1. 我们将需要以下内容。供应商ID。产品编号c。设备序列号
  2. 要做到这一点,需要花费一些时间。您所有的设备都将日志条目记录在“ / var / log / messages”中。

因此,我们可以读取此文件并找到正确的USB:

grep "ftdi" /var/log/messages

您也可以使用“ usb”

  1. 这是找到所有带有ftdi标签的消息:

  2. 在ftdi_sio旁边,有一个类似1-1.2的数字。这是USB设备

grep "usb 1-1.2" /var/log/messages

或者您可以使用:

dmesg | grep "usb 1-1.3"
  1. 这为我们提供了所需的所有信息:

USB别名

  1. 现在,有了序列号列表,让我们创建一个UDEV规则集,它将为这些设备中的每一个提供良好的符号链接。UDEV规则通常分散在/etc/udev/rules.d中的许多文件中。创建一个名为99-usb-serial.rules的新文件,并将以下行放入其中:

在此示例中,我的别名称为“ lcdbox”

SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A601ERJJ", SYMLINK+="lcdbox"
  1. SYMLINK是您的别名的名称。在这种情况下,我的别名是lcdbox。
  2. 保存文件并输入

    sudo udevadm控制--reload-rules

  3. 类型

    ls –l / dev / lcdbox

lrwxrwxrwx 1根根1970年1月1日/ dev / lcdbox-> ttyUSB0

  1. 这表明我的lcdbox别名已映射到ttyUSB0

4

这很容易!您必须自定义ftdi芯片固件并添加udev规则:

首先,ftdi_eeprom通过apt-get来源获取。通过lsusb识别您的设备并获取ID:

lsusb

总线001设备005:ID 0403:6001未来技术设备国际有限公司FT232串行(UART)IC
....

准备一个配置,并确保,这vendor_idproduct_id匹配。自定义部分中的字符串Strings以获取设备的唯一ID。

vendor_id = 0x0403#供应商ID
product_id = 0x6001#产品ID

max_power = 50#最大 功耗:值* 2 mA。如果self_powered = true,请使用0。

###########
#字符串#
########### 
Manufacturer =“ FTDI”#制造商
product =“ Arduino Nano”#产品
serial =“ arduino1”#序列号

###########
#选项#
###########
self_powered = false#为总线供电将其关闭
remote_wakeup = false#启用此功能以实现远程唤醒功能
use_serial = true#使用序列号字符串

#通常情况下,不必更改这些标志之一
#BM_type_chip = true#较新的芯片均为BM类型
in_is_isochronous = false#端点是同步的
out_is_isochronous = false#输出端点是同步的
suspend_pull_downs = false#启用暂停下拉以降低功耗
change_usb_version = false#更改USB版本
usb_version = 0x0200#仅在启用change_usb_version时使用

########
#其他#
########

filename =“ eeprom.old”#文件名,保留为空可跳过文件写入
cbus0 = RXLED#
cbus1 = TXLED#

转储当前的ftdi固件:

ftdi_eeprom --read-eprom

此命令创建${pwd}/eeprom.old,其中包含ftdi上的当前固件。在继续操作之前,请备份此文件,因为在此过程中文件被重写。备份后,刷新ftdi:flash-eeprom

ftdi_eeprom --flash-eeprom myconfig.conf

现在,创建一个udev规则,如下所示

SUBSYSTEMS=="usb", ATTRS{idProduct}=="6001", ATTRS{idVendor}=="0403", SYMLINK+="$attr{serial}", OWNER="bananapi", GROUP="pi", MODE="0777"

/etc/udev/rules.d/90-arduino-usb.rules和重启的udev。

service udev restart

拔下并重新插入设备,然后尝试

ls -lah /dev/arduino1

上面arduino1定义的字符串在哪里?serial.conf

另请参阅:ftdi_eeprom的风险?-闪烁后TX始终为高


3

我本可以使用脚本在其下创建别名,/dev/udev像其他答案一样在其上设置组和权限。

但是如果没有的话,我udev会用管道lsusb插入grepawklsusb|grep -e "idProduct"

总之,用udev规则或lsusbgrep识别USB设备,使用idVendoridProductiSerialDevice descriptor部分lsusb进行正确idenification。该idVendor告诉你manufaturer,idProduct应向制造商indentify的产品,但有时它们使用相同的产品ID为多个产品。最后,如果需要,则iSerial对于该产品的每个示例,该ID应该是唯一的ID。


3

在Ubuntu 16.04(可能还有以前的版本或其他发行版)上,您可以执行以下操作:

> ls /dev/serial/by-id

显示(在我的与Arduino UNO相连的盒子上):

usb-Arduino__www.arduino.cc__0043_A4139363931351318241-if00

您可以在此处轻松找到设备ID 0043(UNO)。

该文件实际上是/dev/ttyACM0我框中的链接。


2

您始终可以在void setup()中通过串行方式进行某种id打印。连接了特定的板后,它将将此ID发送到您的USB接口(您正在Linux盒子上通过某种守护程序进行监听)。收到ID之后,您可以将其映射到路径'Arduino1':'/ dev / ttyACM0','Arduino2':'/ dev / ttyACM1','Arduino3':'/dev/ttyACM2'...etc

请注意,由于某种原因断开设备连接时,它可以更改其物理路径,因此您可能必须重新映射所有设备。对于这种情况,最好编写单独的函数ex:get_id(),您可以随时调用它(不仅在启动时)。


1

我非常想识别其他方式,例如让草图本身响应特殊的识别命令,只是为了避免USB识别设备的奇怪方式。


0

总览

  • ansi_lumen在回答中提到的一种方法是将ftdi芯片EEPROM闪存具有唯一的序列号,然后可以通过UDEV规则进行识别。

    但是事实证明,它不能在廉价的中国Arduino上使用,而FTDI不是FTDI,而是CH340G芯片,该芯片没有用于存储唯一ID的EEPROMCH340B应该可以)。

  • 这个 答案建议使用特殊脚本编写UDEV规则,该脚本要求Arduino通过串行发送其唯一ID。这样做的问题是您需要修改Arduino草图,并且总的来说这很复杂。

通过端口识别

因此,我发现最简单的方法是使用UDEV规则并通过usb端口(devpath)识别Arduino,因此将Arduino连接到同一端口(即使在嵌套的usb集线器中)也将创建永久名称。

TLDR设置:

改装版

  1. 查找Arduino idVendor和idProduct:

lsusb

您将获得如下内容:

...
Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 124: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 003 Device 123: ID 214b:7000  
Bus 003 Device 122: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 003 Device 121: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 003 Device 120: ID 1a40:0101 Terminus Technology Inc. Hub
...

通过连接/断开Arduino,找到它是哪一个(我已经连接了3个)。我们正在寻找其ID。在我的情况下,“ ... ID 1a86:7523 QinHeng ...”。所以idVendor = 1a86,idProduct = 7523

  1. 创建新的UDEV规则文件:

sudo nano /etc/udev/rules.d/99-usb-serial.rules

  1. 通过在复制的上一步中找到的内容修改idVendor和idProduct值,将其粘贴到我们创建的规则文件中:

SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", SYMLINK+="ttyUSB-arduino%s{/devpath}"

  1. 重新加载UDEV规则

sudo udevadm control --reload

  1. 重新插入Arduinos,现在它将具有唯一的名称。要测试它,请输入:

ls /dev/ttyUSB*


将输出:

/dev/ttyUSB1 /dev/ttyUSB3 /dev/ttyUSB-arduino2.1 /dev/ttyUSB-arduino2.4 /dev/ttyUSB2 /dev/ttyUSB4 /dev/ttyUSB-arduino2.2 /dev/ttyUSB-arduino3

如您所见,我们仍然像以前一样获得/ dev / ttyUSBx,它总是根据首先连接的那个而变化。但是,现在我们也有了/ dev / ttyUSB-arduino {port},它们对于相同的端口始终是相同的,并且仅适用于Arduino。分析“ ..arduino2.4”的含义:2表示笔记本电脑的第二个端口,4表示USB集线器上的第四个端口。

为了更好地查看它,请输入:

lsusb -t

输出:

...
/:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 480M
    |__ Port 1: Dev 5, If 0, Class=Human Interface Device, Driver=usbhid, 12M
    |__ Port 1: Dev 5, If 1, Class=Human Interface Device, Driver=usbhid, 12M
    |__ Port 2: Dev 84, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 1: Dev 85, If 0, Class=Vendor Specific Class, Driver=ch341, 12M
        |__ Port 2: Dev 86, If 0, Class=Vendor Specific Class, Driver=ch341, 12M
        |__ Port 3: Dev 87, If 0, Class=Hub, Driver=hub/4p, 480M
        |__ Port 4: Dev 88, If 0, Class=Vendor Specific Class, Driver=ch341, 12M
    |__ Port 3: Dev 89, If 0, Class=Vendor Specific Class, Driver=ch341, 12M
/:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/2p, 480M
    |__ Port 1: Dev 2, If 0, Class=Hub, Driver=hub/6p, 480M
...

通过连接/断开连接,您可以查看哪些设备在哪些端口上

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.