1

Raspberry Pi chạy chương trình khi khởi động

tu-dong-chay-chuong-trinh-raspberry

Raspberry Pi đã trở nên quá phổ biến với các bạn trong nghề, nhưng như hầu hết các máy tính khác, chức năng của nó chỉ hoạt động khi có đầu vào từ người dùng. Nghĩa là, khi khởi động máy tính, nó sẽ chỉ chờ đến khi người dùng chạy chương trình. Vấn đề đó sẽ được giải quyết trong bài viết, thông qua các phương thức để Raspberry Pi chạy chương trình khi khởi động.

Bạn nên đọc:

Giả sử chúng ta có 2 chương trình đã lập trình trước:

  • Một là chương trình có chức năng chớp tắt LED mà ko có giao diện, chương trình có thể chạy với lệnh python blink.py
  • Hai là chương trình hiển thị đồ hồ số trên màn hình HDMI, chương trình có thể chạy với lệnh python clock.py

Có 3 cách phổ biến để chạy chương trình khi khởi động:

  • rc.local – Có lẽ đây là cách dễ nhất và đơn giản nhất để chương trình của bạn chạy khi khởi động. Nhược điểm là các tác vụ bắt đầu với rc.local được thực thi trước khi hệ thống X Window khởi động, có nghĩa là bạn sẽ không thể chạy chương trình có giao diện (GUI).
  • autostart – Được sử dụng để tự động chạy các chương trình của bạn khi LXDE (graphical desktop environment) bắt đầu. Nó phức tạp hơn so với rc.local, nhưng nó cho phép bạn chạy các chương trình có giao diện.
  • systemd – Là cách mới và phổ biến để tự động khởi động các chương trình trong Linux. Đây là phức tạp nhất trong ba cách, nhưng nó cho phép bạn chạy chương trình trước khi LXDE bắt đầu, đợi cho đến khi chương trình của bạn có quyền truy cập vào các tiến trình khác (ví dụ: network, graphical desktop) hoặc đơn giản là khởi động lại chương trình của bạn nhiều lần cho đến khi nó thành công.

Cách 1: rc.local

Chạy chương trình của bạn bằng rc.local là cách dễ làm nhất, nhưng nó được thự thì trước khi X window chạy nên bạn sẽ không thể tương tác giao diện GUI. Cách này chỉ nên dùng cho chương trình không có giao diện.

Khi hệ điều hành Linux khởi động trên Raspberry Pi của bạn, nó sẽ trải qua một loạt các trạng thái – runlevel . Bất cứ khi nào runlevel thay đổi, các tập lệnh run control (rc) khác nhau sẽ được thực thi để chạy hay dừng các dịch vụ hệ thống. Nếu bạn muốn tìm hiểu thêm về các tập lệnh rc, hãy xem bài viết này, nhưng ở đây chúng ta chỉ quan tâm rc.local.

Tập lệnh rc.local được thực thi sau khi tất cả các dịch vụ hệ thống bình thường đã được khởi động (bao gồm cả kết nối mạng, nếu được bật) và ngay trước khi hệ thống chuyển sang multiuser runlevel (thường khi chạy tới đây bạn sẽ thấy yêu cầu đăng nhập).

Sửa rc.local

Bạn cần quyền root để có thể sửa file này:

sudo nano /etc/rc.local

Thêm lệnh chạy chương trình trước dòng exit 0:

python /home/pi/blink.py &

Chú ý: thêm kí tự & tại cuối lệnh để chương trình được tách ra và thực thi trong một tiến trình khác, nếu không có kí tự này, rc.local sẽ chờ đến khi chương trình của bạn kết thúc, và nếu chương trình của bạn có vòng lặp vô hạn, bạn sẽ không bao giờ thấy lời mời đăng nhập.

raspberry-startup

Chú ý: bạn nên dùng đường dẫn tuyệt đối của chương trình để rc.local có thể tìm thấy.

Lưu lại để kết thúc.

Kiểm tra bằng cách khởi động lại:

sudo reboot

Bạn sẽ thấy Raspberry Pi chạy chương trình khi khởi động!

Cách 2: autostart

Nếu cần truy xuất các thành phần của X Window (ví dụ: tạo một giao diện điều khiển hay chơi game), bạn cần chờ đến khi X server  khởi tao xong. Một cách để thực hiện điều này là dùng autostart.

Sau khi X server được khởi động (trong trường hợp này là LXDE-pi), nó sẽ thực thi các lệnh trong file autostart, file này được đặt tại /home/pi/.config/lxsession/LXDE-pi/autostart  đối với Raspberry Pi. Chú ý rằng nếu bạn tạo một user khác pi, đường dẫn sẽ khác. Trong trường hợp hệ thống không tìm thấy file autostart  nó sẽ thực hiện các lệnh trong file /etc/xdg/lxsession/LXDE-pi/autostart.

Ngoài việc chạy các lệnh trong autostart, Linux cũng sẽ tìm kiếm và thực thi các tập lệnh trong file .desktop được đặt trong /home/pi/.config/autostart. Cách dễ nhất để thực thi các chương trình GUI khi khởi động là tạo một tập lệnh .desktop này.

Tạo một file .desktop

Bạn sẽ không dùng quyền root trong khi chỉnh sửa autostart hoặc tạo file .desktop.

Mở terminal, thực thi lệnh sau để tạo thư mục autostart nếu chưa tồn tại và sửa file .desktop:

mkdir /home/pi/.config/autostart 
nano /home/pi/.config/autostart/clock.desktop

Copy đoạn code sau, sửa Name  và Exec  phù hợp:

[Desktop Entry] 
Type=Application 
Name=Clock 
Exec=/usr/bin/python3 /home/pi/clock.py
raspberry-startup

Lưu và khởi động lại:

sudo reboot

Chú ý: đảm bảo rằng bạn đã cấu hình Pi tự động đăng nhập desktop ( cấu hình trong raspi-config). Bạn sẽ thấy Raspberry Pi chạy chương trình khi khởi động!

Cách 3: systemd

systemd là một cách được ưa chộng để chạy chương trình khi khởi động, nhưng nó cũng là một các phức tạp. Với systemd bạn có thể yêu cầu cho Linux khởi động một số chương trình nhất định trước khi bắt đầu. Cho nên, đây là một công cụ rất mạnh mẽ để khởi động một kịch bản hay một ứng dụng.

systemd là một bộ công cụ tương đối mới trong thế giới Linux và một trong những mục đích dự định của nó là quản lý các quy trình hệ thống sau khi khởi động. Khi được phát hành, systemd có ý nghĩa là thay thế công cụ init.d để khởi chạy các chương trình. Kể từ năm 2015, hầu hết các bản phân phối Linux chính đều có systemd, lưu ý rằng, init.d có thể không còn được dùng nhiều nữa và systemd sẽ là tương lại.

systemd khá phức tạp để hướng dẫn hết, trong bài này chúng ta chỉ tập chung vào những điều cơ bản để chạy được một chương trình trong lúc khỏi động. Nếu bạn muốn tìm hiểu sâu về thế giới systemd hãy đọc bài này.

Tạo một file Unit

File Unit là một file văn bản cung cấp thông tin cho systemd về service, device, mount point,… Chúng ta cần tạo một file Unit để khởi động một chương trình như một service (một tiến trình chạy nền). Dưới đây là hai file Unit cho hai chương trình ví dụ: chương trình blink.py có thể chạy trước khi hệ thống giao điện được khởi chạy, chương trình clock.py sẽ chỉ chạy sau khi hệ thống giao diện đã chạy xong.

Unit (Không giao diện)

Tạo một file .service trong thư mục systemd:

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

Nhập đoạn văn bản sau vào file:

[Unit] 
Description=Blink my LED 
After=multi-user.target 

[Service] 
ExecStart=/usr/bin/python3 /home/pi/blink.py 

[Install] 
WantedBy=multi-user.target

Bạn có thể sửa Description  tùy ý.

After  chỉ rằng khi nào chương trình được chạy.

multi-user.target là một trạng thaí hệ thống tại đó quyền điều khiển được trao cho người dùng nhưng trước khi hệ thống X Window được chạy. Điều đó có nghĩa là chương trình của bạn sẽ chạy ngay cả khi không đăng nhập! Bạn có thể thay đổi nó, tùy thuộc vào service (tiến trình) nào cần kích hoạt trước khi chạy chương trình của bạn (ví dụ như: network.target nếu cần kết nối mạng). Xem thêm về targetđây.

ExecStart là lệnh (hoặc các lệnh) được sử dụng để bắt đầu chương trình. Lưu ý rằng, bạn phải sử dụng các đường dẫn tuyệt đối tới vị trí của chương trình.

WantedBy trong phần [Install] chỉ định một target mà chương trình của bạn sẽ nằm trong đó. Trong ví dụ này, chúng ta muốn chương trình chạy khi multi-user.target được chạy (cụ thể là ngay sau nó, dựa vào After ).

raspberry-startup

Sau đó lưu lại.

Để hệ thống ghi nhận mỗi lần thay đổi bạn cần dùng lệnh sau:

sudo systemctl daemon-reload

Sau đó, chúng ta muốn systemd tự động chạy chương trình trong khi khởi động, nhập: 

sudo systemctl enable blink.service

Khởi động lại Pi với sudo reboot để kiểm chứng kết quả.

Unit (Có giao diện)

Tạo một file .service trong thư mục systemd:

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

Nhập đoạn văn bản sau:

[Unit] 
Description=Start Clock 

[Service] 
Environment=DISPLAY=:0 
Environment=XAUTHORITY=/home/pi/.Xauthority 
ExecStart=/usr/bin/python3 /home/pi/clock.py 
Restart=always 
RestartSec=10s 
KillMode=process 
TimeoutSec=infinity 

[Install] 
WantedBy=graphical.target

Description đoạn text mô tả bất kỳ.

Trong Service , chúng ta chỉ định một số biến môi trường. Chúng ta muốn kết nối với màn hình chính (giả sử chỉ có một màn hình được kết nối với Pi), vì vậy chúng ta đặt DISPLAY bằng :0 và chúng ta nói với ứng dụng của mình nơi tìm thông tin đăng nhập cần thiết để sử dụng hệ thống X Window  với XAUTHORITY. ExecStart là lệnh chúng ta muốn chạy.

Có một vấn đề là, chúng ta không thể biết chính xác khi nào hệ thống X Window sẽ khởi động và chúng ta cũng không cần thiết phải yêu cầu người dùng đăng nhập. Để giải quyết, chúng ta sẽ buộc chương trình khởi động lại (Restart) cứ sau 10 giây (RestartSec) nếu nó bị lỗi hay thoát. KillMode yêu cầu systemd hủy bỏ mọi tiến trình liên quan đến chương trình của chúng ta nếu nó khởi động không thành công và TimeoutSec=infinity có nghĩa là chúng ta không bao giờ muốn ngừng việc khởi động lại.

raspberry-startup

Sau đó lưu lại.

Để hệ thống ghi nhận mỗi lần thay đổi bạn cần dùng lệnh sau:

sudo systemctl daemon-reload

Sau đó, chúng ta muốn systemd tự động chạy chương trình trong khi khởi động, nhập: 

sudo systemctl enable clock.service

Khởi động lại Pi với sudo reboot để kiểm chứng kết quả.

Những cách khác

Trong Linux, thường có nhiều hơn một cách để hoàn thành một nhiệm vụ. Hướng dẫn này chỉ cho bạn ba phương pháp khác nhau để bắt đầu các chương trình (hoặc tập lệnh) khi khởi động. Tất cả ba được mặc định với Raspbian, có nghĩa là nó sẽ hoạt động với phiên bản Raspbian đầy đủ. Nếu bạn sử dụng một hệ điều hành khác (như Raspbian Lite), chỉ có một số phương pháp khả dụng, vì vậy hãy chọn những phương pháp phù hợp với bạn!

Nếu trong ba cách trên không phù hợp với bạn, bạn có thể tìm hiểu thêm:

  • SysVinit là một phương thức cũ để chạy các chương trình khi khởi động
  • crontab được sử dụng để lên lịch các tác vụ chạy thường xuyên.

Chúc các bạn thành công!

thanhbinh89

One Comment

Trả lời

Email của bạn sẽ không được hiển thị công khai.