No Linux, como identificar vários Arduinos conectados via USB?

17

Se eu tiver vários Arduinos conectados via USB a um computador Linux, e eles aparecerem como

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

Como posso identificar qual é o Arduino sem conectar a eles via conexão serial ? Existe um número de série ou um ID exclusivo no Arduino?

Obrigado pelo seu tempo.

Situação: Uno R3, Mega, Leonardo com / ttyACM [1,2,3]

Saída lsusb com dispositivos na ordem mencionada acima:

...
Barramento 001 Dispositivo 011: ID 2341: 0043
Dispositivo 0013 do barramento 001: ID 2341: 8036
...
Barramento 001 Dispositivo 014: ID 2341: 0042

lsusb -d vendor: dispositivo -vvv mostra para cada um

Uno

Barramento 001 Dispositivo 014: ID 2341: 0042
Descritor de dispositivo:
  bComprimento 18
  bDescriptorType 1
  bcdUSB 1.10
  Comunicações do 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
  Descritor de configuração:
    bComprimento 9
    bDescriptorType 2
    wTotalLength 62
    bNumInterfaces 2
    bConfigurationValue 1
    iConfiguration 0
    bmAttributes 0xc0
      Auto-alimentado
    MaxPower 100mA
    Descritor de Interface:
      bComprimento 9
      bDescriptorType 4
      bInterfaceNumber 0
      bAlternateSetting 0
      bNumEndpoints 1
      Comunicações bInterfaceClass 2
      Resumo de bInterfaceSubClass 2 (modem)
      bInterfaceProtocol 1 comandos AT (v.25ter)
      iInterface 0
      Cabeçalho do CDC:
        bcdCDC 10.01
      CDC ACM:
        bmCapabilities 0x06
          envia pausa
          codificação de linha e estado serial
      União CDC:
        bMasterInterface 0
        bSlaveInterface 1
      Descritor de ponto final:
        bComprimento 7
        bDescriptorType 5
        bEndpointAddress 0x82 EP 2 IN
        bmAttributes 3
          Interrupção do tipo de transferência
          Tipo de sincronização Nenhum
          Dados do tipo de uso
        wMaxPacketSize 0x0008 1x 8 bytes
        bInterval 255
    Descritor de Interface:
      bComprimento 9
      bDescriptorType 4
      bInterfaceNumber 1
      bAlternateSetting 0
      bNumEndpoints 2
      Dados do CDC do bInterfaceClass 10
      bInterfaceSubClass 0 Não utilizado
      bInterfaceProtocol 0
      iInterface 0
      Descritor de ponto final:
        bComprimento 7
        bDescriptorType 5
        bEndpointAddress 0x04 EP 4 OUT
        bmAttributes 2
          Tipo de transferência em massa
          Tipo de sincronização Nenhum
          Dados do tipo de uso
        wMaxPacketSize 0x0040 1x 64 bytes
        bInterval 1
      Descritor de ponto final:
        bComprimento 7
        bDescriptorType 5
        bEndpointAddress 0x83 EP 3 IN
        bmAttributes 2
          Tipo de transferência em massa
          Tipo de sincronização Nenhum
          Dados do tipo de uso
        wMaxPacketSize 0x0040 1x 64 bytes
        bInterval 1
Status do dispositivo: 0x0000
  (Alimentado por barramento)

Leonardo:

Dispositivo 0013 do barramento 001: ID 2341: 8036
Descritor de dispositivo:
  bComprimento 18
  bDescriptorType 1
  bcdUSB 2.00
  bDeviceClass 0 (definido no nível da interface)
  bDeviceSubClass 0
  bDeviceProtocol 0
  bMaxPacketSize0 64
  idVendor 0x2341
  idProduct 0x8036
  bcdDevice 1.00
  iManufacturer 1 Arduino LLC
  iProduct 2 Arduino Leonardo
  iSerial 0
  bNumConfigurations 1
  Descritor de configuração:
    bComprimento 9
    bDescriptorType 2
    wTotalLength 100
    bNumInterfaces 3
    bConfigurationValue 1
    iConfiguration 0
    bmAttributes 0x80
      (Alimentado por barramento)
    MaxPower 500mA
    Associação de interface:
      bComprimento 8
      bDescriptorType 11
      bFirstInterface 0
      bInterfaceCount 2
      Comunicações bFunctionClass 2
      Resumo de bFunctionSubClass 2 (modem)
      bFunctionProtocol 1 comandos AT (v.25ter)
      iFunction 0
    Descritor de Interface:
      bComprimento 9
      bDescriptorType 4
      bInterfaceNumber 0
      bAlternateSetting 0
      bNumEndpoints 1
      Comunicações bInterfaceClass 2
      Resumo de bInterfaceSubClass 2 (modem)
      bInterfaceProtocol 0 Nenhum
      iInterface 0
      Cabeçalho do CDC:
        bcdCDC 1.10
      Gerenciamento de chamadas do CDC:
        bmCapabilities 0x01
          gerenciamento de chamadas
        bDataInterface 1
      CDC ACM:
        bmCapabilities 0x06
          envia pausa
          codificação de linha e estado serial
      União CDC:
        bMasterInterface 0
        bSlaveInterface 1
      Descritor de ponto final:
        bComprimento 7
        bDescriptorType 5
        bEndpointAddress 0x81 EP 1 IN
        bmAttributes 3
          Interrupção do tipo de transferência
          Tipo de sincronização Nenhum
          Dados do tipo de uso
        wMaxPacketSize 0x0040 1x 64 bytes
        bInterval 0
      Descritor de ponto final:
        bComprimento 7
        bDescriptorType 5
        bEndpointAddress 0x83 EP 3 IN
        bmAttributes 2
          Tipo de transferência em massa
          Tipo de sincronização Nenhum
          Dados do tipo de uso
        wMaxPacketSize 0x0040 1x 64 bytes
        bInterval 0
    Descritor de Interface:
      bComprimento 9
      bDescriptorType 4
      bInterfaceNumber 2
      bAlternateSetting 0
      bNumEndpoints 1
      Dispositivo de interface humana bInterfaceClass 3
      bInterfaceSubClass 0 Nenhuma subclasse
      bInterfaceProtocol 0 Nenhum
      iInterface 0
        Descritor de dispositivo HID:
          bComprimento 9
          bDescriptorType 33
          bcdHID 1.01
          bCountryCode 0 Não suportado
          bNumDescriptors 1
          Relatório bDescriptorType 34
          wDescriptorLength 101
          Descritor do relatório: (length is 101)
            Item (global): página de uso, dados = [0x01] 1
                            Controles genéricos de área de trabalho
            Item (local): uso, dados = [0x02] 2
                            Rato
            Item (Principal): Coleta, dados = [0x01] 1
                            Inscrição
            Item (local): uso, dados = [0x01] 1
                            Ponteiro
            Item (Principal): Coleta, dados = [0x00] 0
                            Fisica
            Item (global): ID do relatório, dados = [0x01] 1
            Item (Global): Página de Uso, dados = [0x09] 9
                            Botões
            Item (local): uso mínimo, dados = [0x01] 1
                            Botão 1 (Primário)
            Item (local): uso máximo, dados = [0x03] 3
                            Botão 3 (Terciário)
            Item (Global): Mínimo Lógico, dados = [0x00] 0
            Item (Global): Máximo Lógico, dados = [0x01] 1
            Item (Global): Contagem de Relatórios, dados = [0x03] 3
            Item (global): tamanho do relatório, dados = [0x01] 1
            Item (Principal): Entrada, dados = [0x02] 2
                            Variável de dados Absoluto No_Wrap Linear
                            Campo de bits não-volátil de estado preferencial
            Item (Global): contagem de relatórios, dados = [0x01] 1
            Item (Global): Tamanho do Relatório, dados = [0x05] 5
            Item (Principal): Entrada, dados = [0x03] 3
                            Variável constante Absoluto No_Wrap Linear
                            Campo de bits não-volátil de estado preferencial
            Item (global): página de uso, dados = [0x01] 1
                            Controles genéricos de área de trabalho
            Item (local): uso, dados = [0x30] 48
                            Direção-X
            Item (local): uso, dados = [0x31] 49
                            Direção-Y
            Item (local): uso, dados = [0x38] 56
                            Roda
            Item (Global): Mínimo Lógico, dados = [0x81] 129
            Item (Global): Máximo Lógico, dados = [0x7f] 127
            Item (global): tamanho do relatório, dados = [0x08] 8
            Item (Global): Contagem de Relatórios, dados = [0x03] 3
            Item (Principal): Entrada, dados = [0x06] 6
                            Variável de dados relativa No_Wrap linear
                            Campo de bits não-volátil de estado preferencial
            Item (Principal): Finalizar Coleta, dados = nenhum
            Item (Principal): Finalizar Coleta, dados = nenhum

            ......

      Descritor de ponto final:
        bComprimento 7
        bDescriptorType 5
        bEndpointAddress 0x84 EP 4 IN
        bmAttributes 3
          Interrupção do tipo de transferência
          Tipo de sincronização Nenhum
          Dados do tipo de uso
        wMaxPacketSize 0x0040 1x 64 bytes
        bInterval 1
Status do dispositivo: 0x0000
  (Alimentado por barramento)

E Mega256:

Barramento 001 Dispositivo 014: ID 2341: 0042
Descritor de dispositivo:
  bComprimento 18
  bDescriptorType 1
  bcdUSB 1.10
  Comunicações do 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
  Descritor de configuração:
    bComprimento 9
    bDescriptorType 2
    wTotalLength 62
    bNumInterfaces 2
    bConfigurationValue 1
    iConfiguration 0
    bmAttributes 0xc0
      Auto-alimentado
    MaxPower 100mA
    Descritor de Interface:
      bComprimento 9
      bDescriptorType 4
      bInterfaceNumber 0
      bAlternateSetting 0
      bNumEndpoints 1
      Comunicações bInterfaceClass 2
      Resumo de bInterfaceSubClass 2 (modem)
      bInterfaceProtocol 1 comandos AT (v.25ter)
      iInterface 0
      Cabeçalho do CDC:
        bcdCDC 10.01
      CDC ACM:
        bmCapabilities 0x06
          envia pausa
          codificação de linha e estado serial
      União CDC:
        bMasterInterface 0
        bSlaveInterface 1
      Descritor de ponto final:
        bComprimento 7
        bDescriptorType 5
        bEndpointAddress 0x82 EP 2 IN
        bmAttributes 3
          Interrupção do tipo de transferência
          Tipo de sincronização Nenhum
          Dados do tipo de uso
        wMaxPacketSize 0x0008 1x 8 bytes
        bInterval 255
    Descritor de Interface:
      bComprimento 9
      bDescriptorType 4
      bInterfaceNumber 1
      bAlternateSetting 0
      bNumEndpoints 2
      Dados do CDC do bInterfaceClass 10
      bInterfaceSubClass 0 Não utilizado
      bInterfaceProtocol 0
      iInterface 0
      Descritor de ponto final:
        bComprimento 7
        bDescriptorType 5
        bEndpointAddress 0x04 EP 4 OUT
        bmAttributes 2
          Tipo de transferência em massa
          Tipo de sincronização Nenhum
          Dados do tipo de uso
        wMaxPacketSize 0x0040 1x 64 bytes
        bInterval 1
      Descritor de ponto final:
        bComprimento 7
        bDescriptorType 5
        bEndpointAddress 0x83 EP 3 IN
        bmAttributes 2
          Tipo de transferência em massa
          Tipo de sincronização Nenhum
          Dados do tipo de uso
        wMaxPacketSize 0x0040 1x 64 bytes
        bInterval 1
Status do dispositivo: 0x0000
  (Alimentado por barramento)
vlad b.
fonte
lsusb -vvvdiz?
Ignacio Vazquez-Abrams
Você pode desconectar um e ver qual desaparece?
Anonymous Penguin
1
Na verdade não, eu quero fazer isso para um conjunto de sensores remotos movidos a energia solar que estará muito longe para alguém fazer isso quando reiniciar.
vlad b.
Ignacio Vasquez-Abrams - como posso mapear as informações de lsusb -vvv para / dev / ttyACM <x>? Existe algo na saída lsusb que eu possa analisar? Obrigado pela idéia!
vlad b.
Você tem outro Arduino com o qual você pode comparar a saída?
Ignacio Vazquez-Abrams

Respostas:

6

Supondo que sua distribuição esteja usando udev:

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

Você pode precisar de privilégios de root para executar isso (sudo / su). Ele exibirá uma lista de informações como esta:

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

Isto é para um Uno com firmware modificado no atmega16u2 (usb para serial). As linhas de interesse provavelmente são ID_MODEL_ID e ID_MODEL_FROM_DATABASE.

user2973
fonte
Obrigado. Estou usando o OpenWrt nesse caso com hotplug2 por padrão, mas tentarei mudar para o udev e testar isso.
vlad b.
5

Você pode adicionar um alias para cada um. Então você sabe qual é qual. Aqui está um bom tutorial sobre como configurar isso.

Aqui está um trecho que escrevi com base no tutorial. No exemplo abaixo, estou usando um adaptador USB para serial FTDI RS232RL, que acredito ser o que o Arduino também usa.

  1. Para atribuir um alias a um dispositivo USB-serial, precisamos encontrar algumas informações sobre o dispositivo
  2. Conecte o usb. Isso pressupõe que você já instalou os drivers para este uso, seja dispositivo e o dispositivo estará visível ao digitar:

lsusb

  1. Nós vamos precisar do seguinte a. A identificação do fornecedor b. O ID do produto c. O número de série do dispositivo
  2. Para fazer isso, é preciso um pouco de caça. Todos os seus dispositivos registram entradas em '/ var / log / messages'.

Portanto, podemos ler este arquivo e encontrar o USB correto:

grep "ftdi" /var/log/messages

Você também pode usar "usb"

  1. Esta é a localização de todas as mensagens marcadas com ftdi:

  2. Ao lado de ftdi_sio, há um número como 1-1.2. Este é o dispositivo USB

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

Ou você pode usar:

dmesg | grep "usb 1-1.3"
  1. Isso nos fornece todas as informações que precisamos:

Alias ​​do USB

  1. Agora, com a lista de números de série em mãos, vamos criar um conjunto de regras UDEV que criará um bom link simbólico para cada um desses dispositivos. As regras UDEV geralmente estão espalhadas em muitos arquivos em /etc/udev/rules.d. Crie um novo arquivo chamado 99-usb-serial.rules e insira as seguintes linhas:

Neste exemplo, meu apelido é chamado 'lcdbox'

SUBSYSTEM=="tty", ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6001", ATTRS{serial}=="A601ERJJ", SYMLINK+="lcdbox"
  1. SYMLINK é o nome do seu alias. Nesse caso, meu apelido é lcdbox.
  2. Salve o arquivo e digite

    sudo udevadm control --reload-rules

  3. Tipo

    ls –l / dev / lcdbox

lrwxrwxrwx 1 root root 7 de janeiro de 1970 / dev / lcdbox -> ttyUSB0

  1. Isso mostra que meu alias do lcdbox está mapeado para ttyUSB0
PhillyNJ
fonte
4

Isso é bem fácil! Você precisa personalizar o firmware dos chips ftdi e adicionar uma regra do udev:

Primeiro, obtenha ftdi_eepromvia apt-getou das fontes. Identifique seu dispositivo via lsusb e obtenha o ID:

lsusb

Dispositivo 005 do barramento 001: ID 0403: 6001 Future Technology Devices International, Ltd IC serial FT232 (UART)
....

Prepare uma configuração e certifique-se, que vendor_ide product_idcorresponder. Personalize as seqüências de caracteres na Stringsseção para obter um ID exclusivo para o seu dispositivo.

vendor_id = 0x0403 # ID do fornecedor
product_id = 0x6001 # ID do produto

max_power = 50 # consumo de energia: valor * 2 mA. Use 0 se self_powered = true.

###########
# Cordas #
########### 
manufacturer = "FTDI" # Fabricante
product = "Arduino Nano" # Produto
serial = "arduino1" # serial

###########
# Opções #
###########
self_powered = false # Desative isso para o barramento alimentado
remote_wakeup = false # Ative para o recurso de ativação remota
use_serial = true # Use a sequência do número de série

# Normalmente, não é necessário alterar um desses sinalizadores
# BM_type_chip = true # Fichas mais recentes são do tipo BM
in_is_isochronous = false # No terminal é isócrono
out_is_isochronous = false # O ponto final de saída é isócrono
suspend_pull_downs = false # Ative suspensões suspensas para obter menos energia
change_usb_version = false # Alterar versão do USB
usb_version = 0x0200 # Usado apenas quando change_usb_version está ativado

########
# Diversos #
########

filename = "eeprom.old" # Nome do arquivo, deixe em branco para ignorar a gravação do arquivo
cbus0 = RXLED #
cbus1 = TXLED #

Despejar o firmware ftdi atual:

ftdi_eeprom --read-eprom

Este comando cria ${pwd}/eeprom.old, que contém o firmware atual no ftdi. Faça backup desse arquivo antes de continuar , porque durante flash-eepromo arquivo é reescrito. Após o backup, atualize o ftdi:

ftdi_eeprom --flash-eeprom myconfig.conf

Agora, crie uma regra do udev, assim

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

no /etc/udev/rules.d/90-arduino-usb.rulese reinicie o udev.

service udev restart

Desconecte e reconecte seu dispositivo e tente

ls -lah /dev/arduino1

Onde arduino1é a seqüência definido em serialno exemplo acima .conf.

Veja também: Riscos de ftdi_eeprom? - TX sempre alto depois de piscar

ansi_lumen
fonte
3

Eu teria usado um script para criar um alias abaixo /dev/e também definir o grupo e os direitos com udevas outras respostas.

Mas se eu não tivesse, udeveu iria lsusbentrar grepou awkgostar lsusb|grep -e "idProduct".

De qualquer forma, com udevregras ou com lsusbe greppara identificar dispositivos USB, uso idVendor, idProducte iSerialem Device descriptorparte lsusbpara fazer a idenification adequada. O idVendoraviso indica que o fabricante idProductdeve identificar o produto do fabricante, mas às vezes eles usam o mesmo ID de produto para mais de um produto. Por fim, se necessário, iSerialdeve ser um ID exclusivo para cada exemplo desse produto.

Anders
fonte
3

No Ubuntu 16.04 (e talvez versões anteriores ou outros distribs também), você pode:

> ls /dev/serial/by-id

que é exibido (na minha caixa onde um UNO do Arduino está conectado):

usb-Arduino__www.arduino.cc__0043_A4139363931351318241-if00

Você pode identificar facilmente o ID do dispositivo 0043 (UNO) aqui.

Este arquivo é realmente um link para /dev/ttyACM0na minha caixa.

jfpoilpret
fonte
2

Você sempre pode imprimir algum tipo de identificação via serial na configuração de cancelamento (). Depois que determinada placa for conectada, ela enviará esse ID à sua interface USB (que você está ouvindo com algum tipo de aplicativo daemon na sua caixa Linux). Depois de receber o ID, você pode mapeá-lo para o caminho 'Arduino1': '/ dev / ttyACM0', 'Arduino2': '/ dev / ttyACM1', 'Arduino3': '/dev/ttyACM2'...etc

Esteja ciente de que, quando o dispositivo é desconectado, por algum motivo, ele pode alterar seu caminho físico; portanto, é necessário remapear todos eles. Nesse caso, pode ser bom escrever uma função separada ex: get_id () que você pode chamar a qualquer momento (não apenas na inicialização).

cyberbrain
fonte
1

Eu ficaria muito tentado a identificar outra maneira, como fazer com que o próprio esboço respondesse a um comando de identificação especial, apenas para evitar as estranhas maneiras de identificação de dispositivos do USB.

EternityForest
fonte