Обновить

Как перестать гадать, что сегодня /dev/ttyUSB0: стабильная работа с USB в Linux Ubuntu

Уровень сложностиСредний
Время на прочтение5 мин
Охват и читатели15K
Всего голосов 37: ↑35 и ↓2+39
Комментарии33

Комментарии 33

Раз уж весь процесс "привязывания" заключается в создании симлинков, почему нельзя сразу открывать в софте по /dev/*/by-path/* вместо /dev/cam_left и иже с ними (к тому же, как я понимаю, все равно не сильно стандартные) - и не городить лишний конфиг, скрипт и юнит systemd?

Причин тому несколько: читаемость ссылок в коде, удобство использования стандартных пакетов для лидаров в ROS2 (конечно, переопределить параметры запуска, можно, а зачем?)

а почему просто не создать симлинки навсегда?

Спрашивать у работающих с железом, зачем лишний костыль - это смело :)

Подключать новые USB-устройства после запуска мы, конечно же, не будем.

Лично для меня идентификация только по by-path не кажется удобной, так как при наличии большого количество устройств не очень-то поймёшь, куда какой воткнул.

Зато, для примера, ESP32-С3 замечательно идентифицируются по серийному номеру, что позволяет давать произвольные имена устройствам.

Bus 001 Device 015: ID 303a:1001 Espressif USB JTAG/serial debug unit
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               2.00
  bDeviceClass          239 Miscellaneous Device
  bDeviceSubClass         2 [unknown]
  bDeviceProtocol         1 Interface Association
  bMaxPacketSize0        64
  idVendor           0x303a Espressif
  idProduct          0x1001 USB JTAG/serial debug unit
  bcdDevice            1.01
  iManufacturer           1 Espressif
  iProduct                2 USB JTAG/serial debug unit
  iSerial                 3 80:65:99:2D:19:64

На всякий случай, приведу пример использования. Создаем файл /etc/udev/rules.d/91-esp32.rules с содержимым:

  ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", ATTRS{serial}=="80:65:99:2D:19:64", SYMLINK+="gate_control_dev_1"

Перезагружаем правила udev

sudo udevadm control --reload-rules

Подключаем ESP32-C3 с серийным номером, указанным выше и видим симлинк /dev/gate_control_dev_1

В случае отсутствия серийного номера, как для CH340, действительно приходится ориентироваться на by-path. Но для этого тоже достаточно udev. Например:

ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7522", DEVPATH=="*/usb1/1-3/1-3:1.0/*", SYMLINK+="ch340_on_USB3-2"
ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7522", DEVPATH=="*/usb1/1-4/1-4.4/1-4.4.3/1-4.4.3:1.0/*", SYMLINK+="ch340_on_USB3HUB-6"
ACTION=="add", SUBSYSTEM=="tty", ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7522", DEVPATH=="*/usb1/1-4/1-4.4/1-4.4.4/1-4.4.4:1.0/*", SYMLINK+="ch340_on_USB3HUB-7"

Тут первая строка - для встроенного в мой ноут второго порта USB3.0. Вторая - для шестого порта внешнего семипортового USB3.0 хаба. Третья - для седьмого порта того же хаба.

Идентификация по серийному номеру (или, например, MAC-адресу) имеет один существенный недостаток - надо настраивать для каждого экземпляра устройства.

Т.е. если вы делаете девайс с тремя сетевыми платами, серийно делаете, хотя бы по 100 штук в месяц - вас задолбает привязка по МАС-адресу каждой платы в каждом девайсе.

А ещё при ремонте - плату заменил, меняй правила в udev. А меняет - местный персонал, который открутить-прикрутить может, а вот прописать правило в udev - нет.

Это как минимум чрезвычайно неудобно.

--------------------

Можно конечно скрипт написать, типа "вставьте кабель/нажмите/где лампочка зажглась скажите" - который бы позволял более-менее автоматизировать привязку по серийнику. Но всё равно неудобно.

неудобно

Это субъективно и зависит от контекста. При этом я специально указал, как при помощи того же самого udev делать идентификацию не только по serial, но и по devpath. Вы возражаете против свободы выбора?

by-path удобно, когда у тебя устройства распаяны на плате и никто их местами менять не будет.
У меня так для разных арм девайсов наборы udev правил написаны и все ок.

Именно поэтому я и написал, как использовать udev для by-path

Увидел сообщение и согласен с ним. Просто use-case'ом решил поделиться.

Я же изначально писал, что "для меня идентификация ТОЛЬКО по by-path не кажется удобной", что никак не обозначает, что я не пользуюсь идентификацией по by-path, когда это востребовано. То есть, я указал, что есть случаи, когда идентификация по серийному номеру удобней, чем по by-path. Поэтому ограничиваться только идентификацией по by-path я не хочу.

По by_path без привязки к серийнику появляется возможность быстро заменить модуль в полях или соревнованиях, не залезая в консоль, или проводя там меньше времени

И как из этого следует, что удобна идентификация ТОЛЬКО по by-path?

Тем, что by-path гарантирует, что на определённом порту датчик/актуатор будет правильно определён, даже если у него нет явных идентов по USB, и робототехническая логика подхватит устройство правильно.

Удобство для быстрого ремонта. Достаточно заменить засбоивший датчик/актуатор, без необходимости прописывать

При этом не защищает от ошибок, например, в случае, если подключили камеру туда, где должен быть лидар. Там уже дополнительный механизм нужен

Прочитайте, что сами написали. А теперь ответьте на заданный вопрос ещё раз внимательно прочитав на что отвечаете и не пропустив слово ТОЛЬКО

Или Вы действительно ярый противник свободы выбора и апологет "золотого молотка"?

Подождите, что имеете в виду под ТОЛЬКО?

Я вижу несколько способов идентификации устройств (прописание алиасов, как в случае с by-path, в расчет не беру)

  • VID/PID: очень широко, притом, если свои делать, либо дорого, либо есть риск на чужие VID/PID нарваться, если совместимость с другими девайсами отбрасываем. А использовать общие VID/PID приводит к случаю как с USB/UART: непонятно, что за устройство

  • По сериийному номеру: можем отличать разные экземпляры, но роботу надо прописать серийник устройства, чтобы он правильно с девайсом работал. Усложняет ремонт в полях. С другой стороны, если работать с однотипными девайсами, то так можно один от другого отличать в программе, и притом, ни с кем не перепутать

  • По строками Vendor/Model: годится для флешеров, например, или для программ настройки девайсов. Если использовать только их, то есть риск перепутать передние и задние лидары, например

Или что имеете в виду? Комбинации, которые дадут возможность однозначно идентифицировать девайсы?

Если чего-то не хватает, просто задайте уточняющий вопрос.

Если лишь бы перейти на личности, то я базар сворачиваю

Подождите, что имеете в виду под ТОЛЬКО?

Ровно то, что обозначает семантика этого слова в русском языке: "Выражает ограничение, выделение из множества, единственно, исключительно." (Толковый словарь Ожегова).

Я за свободу выбора и мне не удобно ограничивать себя только одним способом идентификации устройств по USB. Поэтому "для примера" я описал вариант идентификации по серийному номеру средствами udev. Так же, для примера, я ниже описал и вариант идентификации по by-path тоже средствами udev. Что Вам, по неведомым мне причинам, сильно не понравилось.

По сериийному номеру: можем отличать разные экземпляры, но роботу надо прописать серийник устройства, чтобы он правильно с девайсом работал.

Кто же мешает роботу определять по by-path, а инженеру при обслуживании этого робота - по серийному номеру? Особенно, если таких роботов много и у них должны быть разные прошивки каких-то МК.

Или что имеете в виду?

Я имею в виду, что "золотого молотка" не существует и ограничивать себя только одним способом решения задачи, по меньшей мере, неразумно. Всё очень просто. Я не подгоняю задачи под один "золотой молоток", а выбираю наиболее подходящий способ решения для каждой конкретной задачи.

Погодите, где именно я топлю против udev и топлю за мифический золотой молоток? Я только ЗА udev, но это только одно из средств.

Я топил против жёсткого прописания уникальных идентификаторов для каждого девайса прямо в конфиг-файлы udev, иначе это усложняет замену устройств.

Это в контексте робототехники, где важно иметь возможность быстро заменить девайсину, и так, чтобы другой инженер тоже смог это сделать.

Инженеру по ремонту проще понять из инструкции, что ЭТОТ датчик втыкать ТОЛЬКО в этот порт, а то работать не будет, а то еще и в конфиги лезть.

Для самоделок пофиг, Вы, возможно, и скорректируете и не видите ничего сложного. А что если сыну поручить? Коллеге?

где именно я топлю за мифический золотой молоток?

Уже здесь:

против жёсткого прописания уникальных идентификаторов для каждого девайса прямо в конфиг-файлы udev

Так как свобода выбора для Вас граничит с преступлением.

А если имеете в виду, что ТОЛЬКО по by-path устройства идентифицировать не получится, потому что к порту может быть подключено что угодно, то да, упустил этот момент. Тогда один из вариантов: by-path + VID/PID. Потому как серийник нового устройства надо прописывать, а на это не каждый способен, да и не всегда есть такая возможность

Потому как серийник нового устройства надо прописывать, а на это не каждый способен, да и не всегда есть такая возможность

Опять зависит от задачи. А прописывать ATTRS{serial} ничуть не сложнее, чем прописывать DEVPATH.

Спасибо. Честно говоря мне эта мысль не приходила в голову. У меня сейчас 6 серийных устройств, все время в них путаюсь.

Практический вопрос: если исключить переходники с одинаковыми VID/PID и добавить подключение устройств не в те порты + переезд на другой вычислитель, то насколько такой подход удобнее предварительного программного опроса и последующего изменения путей в конфигурации перед запуском робота?
Зачем вы лидар в нижней части расположили?

С программным опросом сложность возникла как раз с лидером: он при получении "странных", с его точки зрения пакетов просто переставал работать до перезагрузки. А так, в процессе эксплуатации робота особо ничего переключать-то и не нужно (еще повторюсь: я занимаюсь образовательной робототехникой с школьниками).

По поводу лидара снизу: чтобы видеть низкие препятствия и защитить сам лидер, при этом сохранить полный обзор.

Я у себя в канале рассказываю про этот и другие проекты. Если интересно, добро пожаловать!

Сложности случайно не с rplidar? Самые беспроблемные по опыту: lslidar n10, LD19 и COIN-D4. На последний встречается драйвер только под ROS2, если нужен ROS1, то придется переделывать. Зато у него есть программное включение и отключение двигателя.

А почему бы не использовать аппаратные UART на RPi и ESP?

Можно и так, однако еще и камеры есть, и количество UART аппаратных может не хватать.

Я бы наверное решал задачу через libusb. Раз lsusb знает что куда подключено, значит решение у задачи есть.

Вот из моего makefile (нужно отделить FTDI232 от CH340, CP210x):

# Фильтрация из всех имеющихся /dev/ttyUSB* только того, который FTDI.
ttys		:= $(wildcard /dev/ttyUSB*)
BOOTPORT 	?= $(foreach tty,$(ttys),$(shell udevadm info -q symlink -n $(tty) | sed -n 's%.*FTDI.*%$(tty)%p'))

А зачем именно make? Все равно внутри shell

Ну мне нужен Makefile.
А если просто bash, то:

BOOTPORT=''
for tty in $(ls /dev/ttyUSB*); do
  BOOTPORT+="$(udevadm info -q symlink -n $tty | sed -n 's%.*FTDI.*%$tty%p')"
done

Наверно, по серийнику тоже можно отфильтровать вместо '.*FTDI.*'.

А что такое /dev/serial/by-id/ и можно ли его использовать как серебряную пулю (вот тут рекомендуют)? И, если кто понимает как образуется ID_PORT - расскажите пожалуйста на примерах!

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации