【systemd】プログラム自動起動の設定時にハマったこと(ユーザ指定・Pythonパス指定・ウィンドウ表示)

2020.11.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

カフェチームの山本です。

カフェでは、店舗の開店/閉店時に機器の電源をON/OFFしています。そのために、Systemdを利用して、OS起動時に自動でプログラムを実行しています。

今回は、自動でプログラムを実行する際にハマった点とその解決方法についてまとめます。以下では、まず最終的な実装について書き、その後(一番最初に実装したスクリプトと)ハマった点と解決している設定の該当箇所について書きます。

(掲載の都合上、一部文字を置き換えております(大文字の箇所)。お手数おかけしますが、適宜読み替えていただきますよう、お願いいたします。)

最終的な実装

最終的に以下のようなスクリプトを実装し、systemdに登録(sudo systemctl enable jetson_launch_program)しました。

(1)プログラム実行スクリプト(/FOLDER_TO_PROGRAM/launch_tracking_program.sh)

cd `dirname $0`

PYTHONPATH=/usr/local/lib \
DISPLAY=:0 \
python3 PROGRAM.py \
--ARGUMENT0 \
--ARGUMENT1

(2)プログラム起動スクリプト(/home/USER/launch_jetson_program.sh)

sleep 10

sh /FOLDER_TO_PROGRAM/launch_tracking_program.sh

(3)Systemd登録用ファイル(/etc/systemd/system/launch_jetson_program.service)

[Unit]
Description=service to lanuch skeleton detection program on jetson

[Service]
WorkingDirectory=/home/USER/
ExecStart=/bin/sh /home/USER/launch_jetson_program.sh
User=USER

[Install]
WantedBy=default.target

(最初の実装)

最初、以下のようなスクリプトを実装し、launch_jetson_program.serviceをsystemdに登録することで、自動で起動すると考えました。しかし、後述のエラーがでて実行できませんでした。

プログラム実行スクリプト(/FOLDER_TO_PROGRAM/launch_tracking_program.sh)

まず、自動起動したいスクリプトは以下の通りでした。PROGRAM.pyでは、RealSenseというカメラから映像を取得し、画像認識をした結果をOpenCVを利用して別ウィンドウに表示します。

python3 PROGRAM.py \
--ARGUMENT0 \
--ARGUMENT1

ターミナルを開いてshで実行(sh launch_tracking_program.sh)すれば、通常通り動作する状態でした。

Systemd登録用ファイル(/etc/systemd/system/launch_jetson_program.service)

以下の内容でファイルを作成、systemdに登録しました。

[Unit]
Description=service to lanuch skeleton detection program on jetson

[Service]
ExecStart=sh /FOLDER_TO_PROGRAM/launch_jetson_program.sh

[Install]
WantedBy=default.target

ハマりポイント(エラー)

ログ(journalctl -u launch_jetson_program)に出力されるエラーを見ながら対処していきました。

shが見つからない

まず、service起動時にshが見つからないというエラーが出ました。調べると、これはshがフルパスで指定されていないことが原因であったため、以下のように変更しました

  • (3):ExecStart=sh → ExecStart=/bin/sh

実行スクリプトが見つからない

スクリプトファイルが見つからないという旨のエラーが出ました。これに対処するため、以下を追加しました。

  • (3):WorkingDirectory=/home/USER/

プログラム(PROGRAM.py)が見つからない

実行されるディレクトリが異なるため、プログラム実行スクリプトにcd dirname $0を追加し、ワーキングディレクトリを変えるようにしました。

  • (1):cd dirname $0

Pythonのライブラリが見つからない

(全ユーザではなく)特定ユーザにインストールしたライブラリを使用していたため、ライブラリが見つからないというエラーがでました。そのため、実行するユーザを設定しました。

  • (3):User=USER

また、実行ユーザを変更したことで、別のライブラリが見つからなくなってしまったため、実行スクリプトにpythonライブラリへのパスを追加しました。

  • (1):PYTHONPATH=/usr/local/lib

RealSenseから映像が取得できない

上記でプログラムを開始することはできたのですが、カメラとして使用しているRealSenseデバイスから映像を取得できないというエラーになりました。何回か実行していると、OSが起動してから少し時間がたった後であれば、このエラーにならないことがわかりました。

実行スクリプト(1)に待つ処理を入れることも考えられましたが、通常の起動で不便になるため、サービスから実行する専用のスクリプト(2)を用意し、そこでスリープ処理をいれるようにしました。

  • (2):sleep 10
  • (3):ExecStart=/bin/sh /home/USER/launch_jetson_program.sh

ディスプレイが開けない(別ウィンドウに表示できない)

上記で、撮影した画像の認識処理まではうまくいったものの、ディスプレイに表示する際にエラーになりました。これは、サービスのプログラムがバックグランドで動いており、ディスプレイを認識できないことが原因だったため、ディスプレイ設定をプログラム実行前にはさみました。

(1):DISPLAY=:0

まとめ

Ubuntuでsytemdを利用することで、OS起動時にプログラムを自動実行できました。サービスやプログラムにおいて、いくつかエラーになる箇所がありましたが、適切に設定することで目的通りの動作ができました。

あまりこういった処理に詳しくないため、おかしな箇所などあるかもしれません。ご指摘いただければ幸いです。