Автоматический запуск программ на Raspberry Pi

Существует множество способов автоматического запуска программ на Raspberry Pi при загрузке или входе в систему. Есть cron, init, Gnome Scheduler и другие. Однако последняя версия Raspbian включает ещё один инструмент, называемый systemd.

systemd

systemd — это набор приложений, используемых для управления операционной системой. Мне он нравится тем, что можно настроить «сервис» (вашу программу), которым systemd будет автоматически управлять за вас. Так, например, если ваша программа аварийно завершится, systemd может перезапустить её. Это особенно полезно, если ваш Raspberry Pi используется для мониторинга чего-либо или записи измерений, и вы не хотите пропустить ни одного значения, или если вы используете робота на базе Raspberry Pi в соревновании, и аварийное завершение управляющей программы означало бы потерю очков!

Настройка

В этом примере мы будем запускать Python-скрипт каждый раз при загрузке вашего Raspberry Pi. Этот скрипт используется для управления роботом, у которого нет экрана или клавиатурного ввода, поэтому автоматический запуск управляющей программы при загрузке Raspberry Pi просто необходим. Я поместил скрипт в домашнюю директорию пользователя pi:

/home/pi/DriveRobot.py

systemd использует конфигурационные файлы, называемые «unit-файлами», чтобы знать, что делать. Давайте создадим один для нашего робота. Откройте окно терминала и введите следующее:

sudo nano /lib/systemd/system/driverobot.service

Теперь введите следующее:

[Unit]
Description=DriveRobot Service
After=multi-user.target

[Service]
Type=idle
User=pi
ExecStart=/usr/bin/python3 /home/pi/DriveRobot.py
Restart=always
RestartSec=0

[Install]
WantedBy=multi-user.target

В этом unit-файле три секции:

  • Секция [Unit] содержит два значения:

    • Имя сервиса (Description).

    • Когда в процессе загрузки сервис должен быть запущен (After). В данном случае он будет запущен после завершения процесса multi-user в systemd — то есть на этапе, когда учётные записи пользователей доступны системе. Это происходит до загрузки рабочего стола Raspbian, поэтому если ваш Raspberry Pi загружается в режиме рабочего стола и вы хотите, чтобы ваша программа отображала пользовательский интерфейс на рабочем столе, вам нужно изменить это значение на graphical.target.

  • Секция [Service] определяет, что будет запущено и что делать, если ваша программа аварийно завершится или выйдет.

    • Параметр Type со значением idle указывает systemd дождаться завершения всех остальных сервисов. Это делается для того, чтобы не замедлять загрузку.

    • User определяет, под каким пользователем будет запущена программа. В данном случае это стандартный пользователь pi.

    • ExecStart — это исполняемый файл для запуска. В данном случае python3, запускающий скрипт DriveRobot.py. Обратите внимание, что необходимо указывать полный путь как к программе, которую вы запускаете (python3), так и к скрипту.

    • Restart со значением always указывает systemd отслеживать запущенный процесс, и если он остановится, systemd перезапустит его.

    • RestartSec указывает systemd ждать 0 секунд перед перезапуском программы, если она завершилась.

  • Последняя секция, [Install], содержит директиву WantedBy. Она указывает, что сервис driverobot будет нежёстко привязан к сервису multi-user — он будет запущен после успешного старта сервиса multi-user.

После сохранения файла необходимо изменить права доступа unit-файла командой:

sudo chmod 644 /lib/systemd/system/driverobot.service

Это сделает его доступным для чтения всем, а для записи — только владельцу.

Настройка systemd

Теперь, когда вы создали unit-файл, необходимо сообщить systemd о нём и включить его, чтобы сервис driverobot запускался каждый раз при загрузке Raspberry Pi. Сделайте это с помощью:

sudo systemctl daemon-reload
sudo systemctl enable driverobot.service

После чего вы можете перезагрузить ваш Raspberry Pi.

Проверка статуса сервиса driverobot

После завершения перезагрузки вашего Raspberry Pi ваш скрипт должен уже работать. Вы можете проверить это с помощью команды systemctl:

sudo systemctl status driverobot.service

Она должна вернуть что-то вроде этого:

Вывод команды systemctl status

Тестирование «аварийного завершения»

Полезно проверить, будет ли systemd обрабатывать аварийное завершение кода. Чтобы сымитировать это, нужно «убить» процесс python, выполняющий ваш скрипт. Чтобы узнать идентификатор процесса, выполните следующее:

ps -ax | grep driverobot

Эта команда должна вернуть две строки — одну для процесса python3 и одну для только что выполненного grep. Идентификатор процесса (pid) — это первое число в строке.

Получение идентификатора процесса (pid)

Чтобы остановить ваш код, выполните следующее:

kill -9 xxx

Где xxx — это идентификатор процесса, который вы только что нашли.

Теперь проверьте, был ли ваш код перезапущен, выполнив это снова:

ps -ax | grep driverobot
Проверка перезапуска сервиса

Если systemd корректно выполнил свою работу, вы должны увидеть процесс python3, который всё ещё работает, но на этот раз с другим идентификатором процесса.

Заключение

Теперь у вас есть возможность запускать ваш код или любую программу каждый раз при загрузке вашего Raspberry Pi и поддерживать её работу всё время!