Скетч ночной подсветки аквариума собирался идеально: ноль ошибок, зелёная полоса, вдох — и тут avrdude выдал ser_open(): can't open device /dev/ttyUSB0: Permission denied. Ubuntu, второй год на ноутбуке, я же администратор — какие ещё права? Ошибка повторялась с четырьмя разными скетчами подряд — значит, дело было не в коде. Кнопку загрузки я нажал ещё четыре раза с тем же результатом, потом запустил среду через sudo — загрузка прошла, и я месяц жил с запуском из терминала, считая это ценой Linux. Ценой оказалась моя беспечность: sketchbook потихоньку оброс файлами, принадлежащими root, и однажды среда из-под обычного пользователя перестала их сохранять.
Permission denied — не про Linux, а про то, что USB-порт — разделяемый ресурс, у которого есть владелец и группа. Порты плат система отдаёт группе dialout, и обычный пользователь в ней не состоит — по умолчанию в ней люди не состоят вовсе. Лечится одной командой и одним выходом из сеанса, а рядом лежат ещё три грабли: AppImage без libfuse2, brltty, отбирающий CH340, и ModemManager, пробующий новое устройство как модем. Все четыре я собрал за два года на трёх дистрибутивах, и все решаются за вечер, без перепрошивки чего-либо, кроме собственных привычек.
Порядок здесь такой: ставим среду легальным способом, добавляем пользователя в dialout, при надобности пишем правило udev — и порт оживает навсегда, без sudo в каждом запуске. Windows-половина этой истории, с драйверами и SmartScreen, разобрана в уроке про установку на Windows; на Linux драйвер CH340 уже в ядре — тут воюют только права. Проверить результат можно в симуляторе ниже: там порт открыт всегда.
Как ставится среда: AppImage, Flatpak и что не брать
Arduino IDE 2 под Linux идёт в четырёх обличьях. AppImage с официальной страницы — один файл, который после chmod +x запускается двойным щелчком; на Ubuntu 22.04 и новее для него может понадобиться пакет libfuse2, иначе файл молча не откроется — ни окна, ни ошибки. ZIP-архив — почти то же, но с установочным скриптом install.sh, раскладывающим ярлыки. Flatpak с Flathub — самый независимый от дистрибутива путь, с одной оговоркой: песочница иногда просит отдельного разрешения на доступ к USB.
Чего я не делаю: sudo apt install arduino. Пакет arduino в репозиториях Ubuntu и родни — это классическая IDE первой линейки, отставшая на годы: новичок, поставивший её по привычке, получает интерфейс десятилетней давности и ищет в нём кнопки из уроков. Snap-сборка из Ubuntu Software встречается и живёт, но истории с закрытыми портами в песочнице я видел своими глазами, поэтому она третья в моём списке.
Моё правило: AppImage, если среда нужна одному пользователю; Flatpak, если систему хочется держать чистой; и ни один способ не требует sudo при каждом запуске. Если загрузка работает только из-под sudo, вы решаете не ту проблему — настоящая ждёт в группе dialout.
Где бы среда ни жила, ваши скетчи она складывает в домашней папке: sketchbook — это ~/Arduino, и библиотеки из менеджера ложатся рядом, в ~/Arduino/libraries — разбор путей и версий в уроке про библиотеки. Заметьте, как это связано с прошлой ошибкой: на свежих системах sudo сбрасывает HOME, и под root скетчбук — уже /root/Arduino, то есть «исчезнувшие» скетчи просто лежали не там. Права на порт и права на файлы — одна история с двумя финалами, и оба лечатся отказом от sudo.
| Способ | Чем хорош | Что ловить |
|---|---|---|
| AppImage | один файл с официальной страницы, без установки | на свежих Ubuntu нужен libfuse2, иначе молчит |
| Flatpak | не зависит от дистрибутива, обновления сами | песочница может спросить доступ к USB |
| Пакет apt | знакомая команда | это Arduino 1.0.5 из прошлого, не тот интерфейс |
dialout: одна команда вместо sudo на каждый запуск
Сначала смотрим правду о порте. Воткните плату и выполните ls -l /dev/ttyUSB0. Ответ вида crw-rw---- 1 root dialout говорит всё: устройство принадлежит root, читать и писать его могут только root и члены группы dialout. Плата на чипе CH340 объявится как ttyUSB0; официальная Uno с её ATmega16U2 и большинство плат ESP32 — как ttyACM0. Имена разные, группа одна: dialout, меняется только имя файла в вопросе.
Проверьте себя командой groups и ищите в списке dialout. Нет её — добавляйтесь: sudo usermod -aG dialout $USER. И главное, о чём пишут все инструкции, а выполняют единицы: нужно выйти из сеанса и войти заново. Не «перезапустить окно среды», не «переподключить плату» — именно выйти: список групп привязывается к сеансу в момент входа. Терминал, открытый до перелогина, тоже держит старый список — закройте все окна, от среды до консоли. Я потерял на этом вечер, перезапуская всё, кроме собственного сеанса.
Если порт всё ещё капризничает, диагностика начинается с ядра: dmesg | tail сразу после подключения платы. Строка ch341 converter now attached to ttyUSB0 — это про CH340, и она означает, что с ядром всё хорошо и вопрос остался только в правах. Отдельный жанр — «порт занят»: устройство живо, открыть его нельзя, потому что его уже держит кто-то другой. Первый подозреваемый — монитор порта, мы разбирали его в уроке про монитор: закрытое окно монитора освобождает порт мгновенно.
Когда dialout встал на место, дальше всё как на Windows: выберите плату и порт в списке сверху и залейте мигалку — ритуал первой загрузки до зерна разобран в уроке про первый скетч в IDE, а саму мигалку мы собирали в уроке про светодиод. Разница одна: если порт после подключения в списке не появился, не спешите переустанавливать среду — проверьте groups: в девяти случаях из десяти перелогин так и не случился.
# кем объявилась плата и кому принадлежитls -l /dev/ttyUSB0 # есть ли я в группе dialoutgroups # добавиться в группу, затем ВЫЙТИ из сеанса и войти зановоsudo usermod -aG dialout $USER # проверка после перелогина: в списке должно появиться dialoutgroups # что ядро подумало о плате в момент подключенияdmesg | tailПравила udev: когда dialout мало
Dialout закрывает девять случаев из десяти, но остаются два отдельных жанра. Первый — brltty: сервис поддержки брайлевских дисплеев, который в Ubuntu 22.04 по умолчанию считает CH340 своим и через полминуты после подключения отбирает его у системы: порт появляется и исчезает, dmesg честно называет brltty. Если брайлевского дисплея у вас нет — а он есть не у всех, — лечение одно: sudo apt remove brltty. Второй жанр — ModemManager, который первые секунды после втыкания пробует опросить новое устройство как модем; обычно он отходит сам, но в скриптах и автовыгрузках успевает мешать.
Правило udev закрывает оба жанра одним файлом. Создаём /etc/udev/rules.d/99-arduino.rules: для чипов WCH (идентификаторы 1a86:7523 у CH340, 1a86:5523 у CH341) и для плат Arduino (vendor 2341) — права на чтение и запись для всех и запрет модем-менеджеру. Идентификаторы своей платы удобнее всего подсмотреть в lsusb при воткнутой плате: строка вида ID 1a86:7523 — это CH340, и ровно эти четыре цифры идут в ATTRS правила. Затем sudo udevadm control --reload-rules && sudo udevadm trigger — и переподключить плату. После этого порт работает без группы вовсе: MODE=0666 раздаёт права каждому пользователю машины.
Мнение с границей: на домашнем ноутбуке MODE=0666 — честная сделка, заодно снимающая вопросы с дистрибутивами, где dialout зовётся иначе — uucp в Arch, например. На многопользовательской машине порт должен оставаться достоянием группы: 0666 открывает его и тем, кому он не нужен. Если после trigger права не изменились, проверьте банальное: файл должен лежать в /etc/udev/rules.d и носить суффикс .rules — правило с другим именем молча игнорируется. А chmod 666 /dev/ttyUSB0 без udev я решением не считаю: права живут ровно до первого переподключения платы.
# /etc/udev/rules.d/99-arduino.rulesATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="5523", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1"ATTRS{idVendor}=="2341", ENV{ID_MM_DEVICE_IGNORE}="1" # применить правила и переподключить платуsudo udevadm control --reload-rulessudo udevadm trigger- Выполните groups до и после usermod с перелогином: разница — одно слово dialout, а поведение порта меняется целиком.
- Сделайте ls -l /dev/ttyUSB0 до правки udev и после: сравните права crw-rw---- и объясните для себя, откуда они теперь берутся — из группы или из MODE=0666.
- Воткните плату, выполните dmesg | tail: найдите строку с ch341 или cdc_acm — так ядро знакомит вас с платой, и её стоит уметь находить с первого раза.
- Временно переименуйте правило udev в 99-arduino.rules.bak и убедитесь, что перелогин с dialout по-прежнему даёт доступ: правило — надстройка, не фундамент.
- Запустите симулятор и ускорьте мигание: в плоттере ряды blinks= и uptime= должны остаться честными — если ряды поплыли, верните пары имя=значение на место.
- Permission denied — это права: порт принадлежит root:dialout, а вы в dialout не входите; sudo при запуске IDE — обход, который потом портит файлы sketchbook
- sudo usermod -aG dialout $USER плюс выход из сеанса и новый вход: список групп читается в момент входа, перезапуск окна не помогает
- CH340 объявляется как ttyUSB0, официальные Uno и ESP32 — как ttyACM0; группа у обеих одна и та же
- udev-правило с MODE=0666 и ID_MM_DEVICE_IGNORE закрывает brltty и ModemManager; на многопользовательской машине остаётесь в dialout
- dmesg | tail — первое место диагностики: строка ch341 converter now attached to ttyUSB0 означает, что ядро плату видит, и вопрос только в правах
- 1. Загрузка падает с can't open device /dev/ttyUSB0: Permission denied. Первое действие?
- 2. usermod выполнили, окно среды перезапустили — снова Permission denied. Что забыто?
- 3. Через полминуты после подключения порт исчезает, dmesg упоминает brltty. Что происходит?
- 4. Правило udev с MODE=0666 для CH340 написано. В чём его цена?
Частые вопросы по теме урока
- Загрузка падает с can't open device /dev/ttyUSB0: Permission denied. Первое действие?
- Порт принадлежит root:dialout, и пользователь должен войти в группу — проверяется тем же ls -l по колонке группы. Запуск через sudo маскирует проблему и заодно перекидывает sketchbook на root. Добавить себя в dialout: sudo usermod -aG dialout $USER, затем выйти из сеанса и войти
- usermod выполнили, окно среды перезапустили — снова Permission denied. Что забыто?
- Членство в группах привязывается к сеансу в момент входа. Перезапуск окна IDE не пересчитывает группы — нужен именно перелогин. Перевоткнуть плату десять раз подряд
- Через полминуты после подключения порт исчезает, dmesg упоминает brltty. Что происходит?
- brltty в Ubuntu 22.04 считает CH340 своим устройством и забирает его у системы. Для тех, у кого брайлевского дисплея нет, решение — sudo apt remove brltty. Сервис брайлевских дисплеев отбирает CH340; если дисплея нет, пакет удаляют
- Правило udev с MODE=0666 для CH340 написано. В чём его цена?
- MODE=0666 раздаёт права всем локальным пользователям. На домашней машине это удобная сделка, в офисе или классе портом должны владеть члены группы. На многопользовательской машине порт открыт каждому пользователю — там уместнее группа dialout