Black Lives Matter - Action and Equality. ... Adafruit is open and shipping.

Kill a bash script running as root from a python script?
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Kill a bash script running as root from a python script?

by JC_LaFleur on Fri Jun 26, 2020 3:22 pm

Not sure if this is the best place to ask this question, but I've been looking all over Stack Exchange and other forums for the past week and still haven't found a working solution for this.
Once I get this all working, I'd love to post it to the Adafruit projects page ;-)

I need to gracefully kill a bash script from inside a python script, and so far I can't make it work.

I am running a python3 script at startup (it runs as root). In that script I call a bash script to also start (it also runs as root).
The python script is running a stepper motor, the bash script is running a timelapse series with the Pi camera.
The goal is to create a sunrise to sunset panoramic timelapse video. I need both scripts to run in parallel in order to control frame rates and panning speed independently from each other.
What I'm trying to accomplish is:
On boot, automatically start the motor panning, and start the camera taking pictures.
Once the stepper motor has completed it's pan, then gracefully kill the bash script that is running the camera. (this is what I'm having problems with)
Then have the motor return to it's starting position.
Then shut down the Pi, which will be turned on again using a WittyPi 3 Mini the next morning at sunrise to start the process over again.
(Eventually this project will be running on a solar panel with a small battery "buffer")

Here is the python script I'm using... please note the 2 (of many) solutions I've attempted to use to kill the bash script are REMed out as I could get neither of them to work... the script was still running after the python script ended.
Code: Select all | TOGGLE FULL SIZE

from adafruit_motorkit import MotorKit
from adafruit_motor import stepper
from time import sleep
import subprocess
from subprocess import call
#import psutil
#import os, signal

kit = MotorKit()

# this starts the script
#subprocess.Popen(['/bin/bash', './'])

#this is the slow east to west pan while pics are taken during timelapse using 5V 28BYJ-48 1:64 gear ratio stepper motor
for j in range(22400):
    for i in range(1):
        kit.stepper1.onestep(direction=stepper.FORWARD, style=stepper.MICROSTEP)
#set time between motor steps
    sleep(2.41)   #timing for 270 degree (22400 steps) 15 hour pan with 16 microstepping

# this kills the script to stop taking pictures (didn't work)
#for proc in psutil.process_iter():
    # check whether the process name matches
#    if == PROCNAME:
#        proc.kill()

#this kills the script to stop taking pictures (didn't work)
#def check_kill_process(timelapse):
#    for line in os.popen("ps ax | grep " + pstring + " | grep -v grep"):
#        fields = line.split()
#        pid = fields[0]
#        os.kill(int(pid), signal.SIGKILL)

#this returns the stepper motor to starting position
for i in range(1400):
   kit.stepper1.onestep(direction=stepper.BACKWARD, style=stepper.DOUBLE)

#this shuts down the pi to wait for next reboot via the wittypi3 power controller
call("sudo nohup shutdown -h now", shell=True)

So far I have everything working except being able to gracefully kill the script before the Pi shuts down :-(
Any help or suggestions would be appreciated.

I've attached a picture of the setup... Raspberry Pi ZeroW with 32GB SD card running latest RasPiOS Lite, WittyPi 3 Mini to control on/off schedule and conserve battery power between solar charges, Adafruit DC & Stepper Motor Bonnet for Raspberry Pi running a 5V 28BYJ-48 1:64 gear ratio stepper motor. 8MP Arducam camera board with 170 degree wide angle lens.
The camera is mounted in a project box I was using for another timelapse project. Eventually I will put all the eletronics, camera. and stepper motor in another weatherproof enclosure so I can run this camera out in the field rain or shine... I want to take panoramic timelapse videos of our Monsoon season storms :-)
Thanks to anyone who can point me in the right direction :-)
A panning timelapse camera.jpg
A panning timelapse camera.jpg (55.33 KiB) Viewed 34 times

Posts: 27
Joined: Thu May 28, 2020 10:29 pm

Re: Kill a bash script running as root from a python script?

by JC_LaFleur on Fri Jun 26, 2020 6:26 pm

Ok... finally found the answer on another forum...
Code: Select all | TOGGLE FULL SIZE
proc = subprocess.Popen(['/bin/bash', './'])
# do things

Simple, elegant, awesome! :-)
Apparently I was over-complicating things, which is what I figured :-P

Posts: 27
Joined: Thu May 28, 2020 10:29 pm

Re: Kill a bash script running as root from a python script?

by JC_LaFleur on Fri Jun 26, 2020 8:49 pm

By the way, here is the bash script that I am using to run timelapse sequences on the Pi.
I do not know who wrote this script. :-(
I wish I did so I could give them credit because it's a really great script for running timelapse sequences! :-)
I have modified the script to include most of the camera settings to give greater control and consistency for shooting timelapse images in broader lighting conditions.
This script is nice because:
- It is designed to run indefinitely until you power-off the Pi or kill the script by some other means.
- It will power down the camera module in between shots to conserve power if you are running the Pi from a battery and your interval is greater than 2-3 seconds.
- It has a GPIO setting for connecting a push button to do a graceful system shutdown.
- It has a GPIO setting to connect an external LED to show when the camera is busy (the V2 camera has no built-in LED)
- It automatically creates the image directory for you if it doesn't already exist (/home/pi/timelapse)
- It uses a file naming scheme that will allow you to stop the script, and then start it up again so the next sequence of image files will not overwrite any previous images already in the image directory.

This script will NOT automatically compile your image sequences into a video file, that is better done externally on a more powerful computer/laptop with ffmpeg or other video editing applications.

ENJOY! :-)

Code: Select all | TOGGLE FULL SIZE

# Timelapse script, because timelapse options in raspistill don't power
# down the camera between captures. Script also provides a camera busy LED
# (v2 cameras don't include one) and a system halt button.
# 'gpio' command requires WiringPi: sudo apt-get install wiringpi
# Limitations: if DEST is FAT32 filesystem, max of 65535 files in directory;
# if DEST is ext4 filesystem, may have performance issues above 10K files.
# For intervals <2 sec, better just to use raspistill's timelapse feature.

# Configurable stuff...
INTERVAL=5   #Time between image captures in seconds
WIDTH=1640   #Image width in pixels
HEIGHT=1232   #Image height in pixels
QUALITY=30   #JPEG compression image quality (0 to 100)
DRC=high   #Dynamic Range Compression (off, low, med, high)
ISO=800   #Set ISO (100 to 800)
SHUTTER=6000   #Set shutter speed in microseconds (1000000 = 1 second)
AWB=fluorescent   #auto,sun,cloud,shade,tungsten,fluorescent,incandescent,flash,horizon
EXPOSURE=fixedfps   #auto,night,nightpreview,backlight,spotlight,sports,snow,beach,verylong,fixedfps,fireworks
METERING=matrix   #average,spot,backlit,matrix
EV=-1   #Set EV exposure compensation (-10 to 10)
BRIGHTNESS=47   #Set image brightness (0 to 100)
CONTRAST=1   #Set image contrast (-100 to 100)
SHARPNESS=70   #Set image sharpness (-100 to 100)
SATURATION=10   #Set image color saturation (-100 to 100)
DEST=/home/pi/timelapse   #Destination directory (MUST NOT CONTAIN NUMBERS)
prevtime=0   #Time of last capture (0 = do 1st image immediately)
#HALT=21   #Halt button GPIO pin (other end to GND)
#LED=5   #Status LED pin (v2 Pi cam lacks built-in LED)

#gpio -g mode $HALT up  # Initialize GPIO states
#gpio -g mode $LED  out

mkdir -p $DEST         # Create destination directory (if not present)

# Find index of last image (if any) in directory, start at this + 1
FRAME=$(($(find $DEST -name "*.jpg" -printf %f\\n | sed 's/^[^1-9]*//g' | sort -rn | head -1 | sed 's/[^0-9]//g') + 1))

while :         # Forever
   while : # Until next image capture time
      currenttime=$(date +%s)
      if [ $(($currenttime-$prevtime)) -ge $INTERVAL ]; then
         break # Time for next image cap
      # Check for halt button -- hold >= 2 sec
#      while [ $(gpio -g read $HALT) -eq 0 ]; do
#         if [ $(($(date +%s)-currenttime)) -ge 2 ]; then
#            gpio -g write $LED 1
#            shutdown -h now
#         fi
#      done

   OUTFILE=`printf "$DEST/$PREFIX%05d.jpg" $FRAME`
#     echo $OUTFILE
#   gpio -g write $LED 1
   raspistill -n -w $WIDTH -h $HEIGHT -q $QUALITY -th none -drc $DRC -ISO $ISO -ss $SHUTTER -awb $AWB -ex $EXPOSURE -mm $METERING -ev $EV -br $BRIGHTNESS -co $CONTRAST -sh $SHARPNESS -sa $SATURATION -t 2000 -o $OUTFILE
#   gpio -g write $LED 0
   FRAME=$(($FRAME + 1)) # Increment image counter
   prevtime=$currenttime # Save image cap time

Posts: 27
Joined: Thu May 28, 2020 10:29 pm

Please be positive and constructive with your questions and comments.