树莓派程序自启动



前言

记录之前使用过的几种树莓派程序自启动的相关操作。

树莓派程序自启动的几种方法

1)将程序置于rc.local下

  这里假设在树莓派的 /home/pi/SIM8200_for_RPI/Goonline/ 路径下存在一个 simcom-cm 的可执行文件。并且我需要这个可执行文件每次开机都自动启动。

  • 设置开机启动,打开树莓派开机配置脚本
sudo nano /etc/rc.local
  • 将启动命令加入倒数第二行,注意是你的运行文件的绝对路径,也就是exit 0的上一行
sudo /home/pi/SIM8200_for_RPI/Goonline/simcom-cm &
  • 注意一定要添加"&" 后台运行,否则可能会出现系统不能启动的情况

    系统启动后,可通过ps命令查看进程是否存在。

ps -ef |grep simcom

示例
从图片中可以看到程序已正常启动。

2)通过.conifg文件夹下新建 *.desktop文件

  这个方式不用修改 rc.local 文件。机制上类似于 Windows 的“开始”菜单中的“启动”菜单。方法如下:
在 /home/pi/.config 下创建一个文件夹,名称为 autostart,并在该文件夹下创建一个xxx.desktop文件(文件名以.desktop结尾,前面可以自定义,这里假设为my.desktop)

cd ~/.config
sudo mkdir autostart
cd  autostart
sudo nano my.desktop

文件内容如下:

[Desktop Entry]
Type=Application
Exec=/home/pi/Desktop/Release/qm2

3)树莓派用服务器方式设置开机启动

这种方法主要是设置程序在初始化进程完成前就启动设置的脚本程序。实现步骤如下:

  1. 准备需要运行的python脚本
    这里以一个简单树莓派控制LED灯闪烁为例,程序写好后还需增加权限
#!/usr/bin/env python
 
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO.setup(21,GPIO.OUT)
#休眠20s等待系统初始化
time.sleep(20)
while True:
 try:
   GPIO.output(21,True)
   time.sleep(1)
   GPIO.output(21,False)
   time.sleep(1)
 except (KeyboardInterrupt, SystemExit):
   GPIO.close()
   print "exit"
给你的py文件增加权限
chmod 777  /home/pi/script/ledblink.py
  1. 编辑开机启动脚本,保存脚本为/etc/init.d/ledblink文件
#!/bin/bash
#/etc/init.d/ledblink
 
###BEGIN INIT INFO
#Provides: embbnux
#Required-Start: $remote_fs $syslog
#Required-Stop: $remote_fs $syslog
#Default-Start: 2 3 4 5
#Default-Stop: 0 1 6
#Short-Description: ledblink initscript
#Description: This service is used to manage a led
###END INIT INFO
 
case "$1" in
   start)
       echo "Starting LED Blink"
       nohup python3 /home/pi/script/ledblink.py &
       ;;
   stop)
       echo "Stopping ledblink"
       #killall ledblink.py
       kill $(ps aux | grep -m 1 'python /home/pi/script/ledblink.py' | awk '{ print $2 }')
       ;;
   *)
       echo "Usage: service ledblink start|stop"
       exit 1
       ;;
esac
exit 0
  1. 设置python脚本开机启动
sudo service ledblink start #启动
sudo service ledblink stop #停止

最后设置开机启动就好了
sudo update-rc.d ledblink defaults
这样就完工了,重启树莓派就会发现led自己闪烁了,停止用sudo service ledblink stop就行。

  因为这个开机自启是在机器还没完成初始化进程的时候就启动的,所以在你的python程序的开头最好加入一个time.sleep函数休眠20秒,强迫程序在系统初始化成功后进行运行。不然可能会因为系统还没准备好你的程序就强行运行而导致启动失败。

4)利用crontab -e定时查询(能实现自检)

  自检:指的是当程序因意外“挂”掉后,能重新启动。
  该方法的基本思路是用crontab设置定时执行python脚本查询程序执行状态,并根据程序状态执行相应的脚本启动程序。这样即使程序因意外停止,也会在定时任务到时后重新启动。

---- crontab简述 ----

  crontab命令常见于Unix和类Unix的操作系统之中,用于设置周期性被执行的指令。该命令从标准输入设备读取指令,并将其存放于“crontab”文件中,以供之后读取和执行。该词来源于希腊语 chronos(χρνο),原意是时间。通常,crontab储存的指令被守护进程激活, crond常常在后台运行,每一分钟检查是否有预定的作业需要执行。这类作业一般称为cron jobs。------------来自百度百科
  详细的crontab操作可以参考这篇博文,这里不在赘述。https://www.cnblogs.com/peida/archive/2013/01/08/2850483.html

------操作步骤------

  这里设置为按分钟检测,每隔一分钟系统就会调用一次checkiotprog.py脚本。
  输入 crontab -e 编辑crontab任务在文件末尾添加如下内容:

* * * * * python3 /home/pi/test20210702/bin/checkiotprog.py

  python脚本内容如下(iotprog.sh是我需要执行的脚本文件,需确定文件有可执行的权限):

import os
import psutil
import sys
import time
import logging
import shlex
import subprocess

# 创建一个logger
logger = logging.getLogger('checkproc_logger')
logger.setLevel(logging.INFO)
 
# 创建一个handler,用于写入日志文件
fh = logging.FileHandler('/home/pi/test20210702/log/checkproc.log')
fh.setLevel(logging.INFO)
 
# 定义handler的输出格式
formatter = logging.Formatter('[%(asctime)s][%(thread)d][%(filename)s][line: %(lineno)d][%(levelname)s] ## %(message)s')
fh.setFormatter(formatter)
 
# 给logger添加handler
logger.addHandler(fh)

def check_process(name_):
    pl = psutil.pids()
    for pid in pl:
        if psutil.Process(pid).name() == name_:
        	#程序正在运行,不做处理
            logger.info('iotprog found, continue...')
            return True
    #程序未运行
    logger.info('iotprog not found, start iotprog...')
    return False
        
if (check_process('iotprog')) == False:
    #os.system("/etc/init.d/iotmgr start")
    _cmd="/home/pi/test20210702/bin/iotprog.sh start"
    _cwd="/home/pi/test20210702/src"
    subprocess.Popen(args=_cmd,shell=True,close_fds=True,cwd=_cwd, universal_newlines=True, stderr=subprocess.PIPE,stdout=subprocess.PIPE).communicate()
    logger.info('start iotprog ok...')

  脚本文件如下所示:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          iotprog
# Should-Start:      console-screen kbd acpid dbus hal consolekit
# Required-Start:    $local_fs $remote_fs x11-common
# Required-Stop:     $local_fs $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: iotprog
# Description:       Debian init script for the Light Display Manager
### END INIT INFO
#
# Author:       Yves-Alexis Perez <corsac@debian.org> using gdm script from 
#               Ryan Murray <rmurray@debian.org>
#
set -e

PATH=/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/home/pi/test20210702/src/iotprog

test -x $DAEMON || exit 0

if [ -r /etc/default/locale ]; then
  . /etc/default/locale
  export LANG LANGUAGE
fi

. /lib/lsb/init-functions


case "$1" in
  start)
        log_daemon_msg "Starting iotprog..."
        start-stop-daemon --start --quiet --pidfile /home/pi/test20210702/src/iotprog.pid --name lightdm --exec $DAEMON -b|| echo -n " already running"
        log_end_msg $?
  ;;
  stop)
        log_daemon_msg "Stopping iotprog..."
        kill -9 $(ps aux | grep -m 1 'iotprog' |grep -v grep | awk '{ print $2 }')
  ;;
  *)
        echo "Usage: /etc/init.d/iotprog {start|stop|restart|reload|force-reload|status}"
        exit 1
  ;;
esac

exit 0

  脚本文件用于执行/home/pi/test20210702/src/路径下的 iotprog 可执行文件(即我需要自启动的程序)。脚本中提到 start-stop-daemon是linux系统中的进程启停工具。

本文参考了以下文章,链接如下:
https://www.jianshu.com/p/1a160067d8fd
https://shumeipai.nxez.com/2017/05/17/raspberry-pi-service-python-script-start-on-boot.html