gordon77
Posts: 4902
Joined: Sun Aug 05, 2012 3:12 pm

Why does this lock up / crash the Pi ?

Sat May 09, 2020 10:57 am

This script takes pictures with the PI Camera using raspistill as a subprocess, and you can set the shutter speed.

But after a while and longer shutter speeds it crashes the Pi, anyone identify why ?

I stop and restart the subprocess with a new shutter speed, and verify a valid jpg file, hopefully to determine its complete before loading.

Thanks

Code: Select all

#!/usr/bin/env python3
import os
import pygame, sys
import time
import shutil
import subprocess, glob
import signal
import tkinter as tk
from PIL import ImageTk, Image


class MainApplication(tk.Frame):
    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, self.master)
        self.ss = 100000
        if os.path.exists('/run/shm/test.jpg'):
            os.rename('/run/shm/test.jpg', '/run/shm/oldtest.jpg')
        rpistr = "raspistill -w 640 -h 480 -t 0 -tl 0 -bm -n -o /run/shm/test.jpg -ex off -ss " + str(self.ss)
        self.p = subprocess.Popen(rpistr, shell=True, preexec_fn=os.setsid)
        time.sleep(1)
        self.dataure_gui()
        self.create_frames()
        self.create_buttons()
        
    def dataure_gui(self):
        self.master.title('Shutter Speed Selection')
        self.master.geometry('640x520')
        self.master.resizable(0, 0)

    def create_frames(self):
        self.Frame10 = tk.Frame(width=800, height=600)
        self.Frame10.grid_propagate(0)
        self.Frame10.grid(row=0, column=0)

    def create_buttons(self):

        self.B1 = tk.Button(self.Frame10, text='SS_Down',  command = self.SS_Down)       
        self.B1.grid(row=0, column=0)
        self.SS = tk.Label(self.Frame10, text = str(int(self.ss/1000)) + " mS")
        self.SS.grid(row=0, column=1)
        self.B2 = tk.Button(self.Frame10, text=' SS_Up ',command = self.SS_Up)       
        self.B2.grid(row=0, column=2)
        self.B3 = tk.Button(self.Frame10, text='EXIT',command = self.Exit)       
        self.B3.grid(row=0, column=3)
        self.load = Image.open("/run/shm/test.jpg")
        self.renderc = ImageTk.PhotoImage(self.load)
        self.img = tk.Label(self.Frame10, image = self.renderc)
        self.img.grid(row = 1, column = 0, columnspan = 4, rowspan = 5, pady = 2)
        self.Display()

    def Display(self):
        if os.path.exists('/run/shm/test.jpg'):
            try:
                self.load = Image.open("/run/shm/test.jpg") 
                self.load.verify() 
                self.load = Image.open("/run/shm/test.jpg")
                self.renderc = ImageTk.PhotoImage(self.load)
                self.img.config(image = self.renderc)
            except (IOError, SyntaxError) as e:
                print('Bad file:', filename)
        self.after(200, self.Display)

    def SS_Down(self):
        self.ss -= 100000
        if self.ss < 100000:
            self.ss = 100000
        self.Restart()

    def SS_Up(self):
        self.ss += 100000
        if self.ss > 6000000:
            self.ss = 6000000
        self.Restart()

    def Restart(self):
        self.SS.config(text = str(int(self.ss/1000)) + " mS")
        os.killpg(self.p.pid, signal.SIGTERM)
        if os.path.exists('/run/shm/test.jpg'):
            os.rename('/run/shm/test.jpg', '/run/shm/oldtest.jpg')
        rpistr = "raspistill -w 640 -h 480 -t 0 -tl 0 -bm -n -o /run/shm/test.jpg -ex off -ss " + str(self.ss)
        self.p = subprocess.Popen(rpistr, shell=True, preexec_fn=os.setsid)

    def Exit(self):
        os.killpg(self.p.pid, signal.SIGTERM)
        self.master.destroy()

if __name__ == '__main__':
    
    root = tk.Tk()
    main_app =  MainApplication(root)
    root.mainloop()

User avatar
DougieLawson
Posts: 38447
Joined: Sun Jun 16, 2013 11:19 pm
Location: A small cave in deepest darkest Basingstoke, UK
Contact: Website Twitter

Re: Why does this lock up / crash the Pi ?

Sat May 09, 2020 11:49 am

Why are you spawning raspistill rather than using the python picamera module?
Are you sure you've terminated all of those spawned processes when each one is done capturing your new image?
Note: Any requirement to use a crystal ball or mind reading will result in me ignoring your question.

I'll do your homework for you for a suitable fee.

Any DMs sent on Twitter will be answered next month.
All non-medical doctors are on my foes list.

gordon77
Posts: 4902
Joined: Sun Aug 05, 2012 3:12 pm

Re: Why does this lock up / crash the Pi ?

Sat May 09, 2020 11:53 am

There is only one subprocess running at a time and yes it's terminated as required.

I've added 2 steps to ensure the subprocess is stopped, and restarted. Still crashes.

Code: Select all

#!/usr/bin/env python3
import os
import pygame, sys
import time
import shutil
import subprocess, glob
import signal
import tkinter as tk
from PIL import ImageTk, Image


class MainApplication(tk.Frame):
    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, self.master)
        self.ss = 100000
        if os.path.exists('/run/shm/test.jpg'):
            os.rename('/run/shm/test.jpg', '/run/shm/oldtest.jpg')
        rpistr = "raspistill -w 640 -h 480 -t 0 -tl 0 -bm -n -o /run/shm/test.jpg -ex off -ss " + str(self.ss)
        self.p = subprocess.Popen(rpistr, shell=True, preexec_fn=os.setsid)
        time.sleep(1)
        self.dataure_gui()
        self.create_frames()
        self.create_buttons()
        
    def dataure_gui(self):
        self.master.title('Shutter Speed Selection')
        self.master.geometry('640x520')
        self.master.resizable(0, 0)

    def create_frames(self):
        self.Frame10 = tk.Frame(width=800, height=600)
        self.Frame10.grid_propagate(0)
        self.Frame10.grid(row=0, column=0)

    def create_buttons(self):

        self.B1 = tk.Button(self.Frame10, text='SS_Down',  command = self.SS_Down)       
        self.B1.grid(row=0, column=0)
        self.SS = tk.Label(self.Frame10, text = str(int(self.ss/1000)) + " mS")
        self.SS.grid(row=0, column=1)
        self.B2 = tk.Button(self.Frame10, text=' SS_Up ',command = self.SS_Up)       
        self.B2.grid(row=0, column=2)
        self.B3 = tk.Button(self.Frame10, text='EXIT',command = self.Exit)       
        self.B3.grid(row=0, column=3)
        self.load = Image.open("/run/shm/test.jpg")
        self.renderc = ImageTk.PhotoImage(self.load)
        self.img = tk.Label(self.Frame10, image = self.renderc)
        self.img.grid(row = 1, column = 0, columnspan = 4, rowspan = 5, pady = 2)
        self.Display()

    def Display(self):
        if os.path.exists('/run/shm/test.jpg'):
            try:
                self.load = Image.open("/run/shm/test.jpg") 
                self.load.verify() 
                self.load = Image.open("/run/shm/test.jpg")
                self.renderc = ImageTk.PhotoImage(self.load)
                self.img.config(image = self.renderc)
            except (IOError, SyntaxError) as e:
                print('Bad file:', filename)
        self.after(200, self.Display)

    def SS_Down(self):
        self.ss -= 100000
        if self.ss < 100000:
            self.ss = 100000
        self.Restart()

    def SS_Up(self):
        self.ss += 100000
        if self.ss > 6000000:
            self.ss = 6000000
        self.Restart()

    def Restart(self):
        self.SS.config(text = str(int(self.ss/1000)) + " mS")
        os.killpg(self.p.pid, signal.SIGTERM)
        poll = self.p.poll()
        while poll == None: # subprocess still running
            time.sleep(.1)
            poll = self.p.poll()
        if os.path.exists('/run/shm/test.jpg'):
            os.rename('/run/shm/test.jpg', '/run/shm/oldtest.jpg')
        rpistr = "raspistill -w 640 -h 480 -t 0 -tl 0 -bm -n -o /run/shm/test.jpg -ex off -ss " + str(self.ss)
        self.p = subprocess.Popen(rpistr, shell=True, preexec_fn=os.setsid)
        poll = self.p.poll()
        while poll != None: # ensure subprocess running
            time.sleep(.1)
            poll = self.p.poll()

    def Exit(self):
        os.killpg(self.p.pid, signal.SIGTERM)
        self.master.destroy()

if __name__ == '__main__':
    
    root = tk.Tk()
    main_app =  MainApplication(root)
    root.mainloop()

gordon77
Posts: 4902
Joined: Sun Aug 05, 2012 3:12 pm

Re: Why does this lock up / crash the Pi ?

Fri May 22, 2020 1:58 pm

amazingadmin wrote:
Fri May 22, 2020 6:46 am
I recommend you to learn about https://rawpython.com/tkinter-label/ from this awesome tutorial.

Thanks, to learn what ?

Idahowalker
Posts: 464
Joined: Wed Jan 03, 2018 5:43 pm

Re: Why does this lock up / crash the Pi ?

Fri May 22, 2020 3:39 pm

Have you used task manager to confirm that all the processes are shutting down? You can, also, monitor memory use and CPU use vs time.

There are come CLI thingies that will give 'better' info of the happenings.
Without knowing why you are deleting my postings, I will not know how...

gordon77
Posts: 4902
Joined: Sun Aug 05, 2012 3:12 pm

Re: Why does this lock up / crash the Pi ?

Fri May 22, 2020 5:45 pm

Idahowalker wrote:
Fri May 22, 2020 3:39 pm
Have you used task manager to confirm that all the processes are shutting down? You can, also, monitor memory use and CPU use vs time.

There are come CLI thingies that will give 'better' info of the happenings.
Thanks, l'll look further for details

gordon77
Posts: 4902
Joined: Sun Aug 05, 2012 3:12 pm

Re: Why does this lock up / crash the Pi ?

Sat May 23, 2020 10:00 am

Idahowalker wrote:
Fri May 22, 2020 3:39 pm
Have you used task manager to confirm that all the processes are shutting down? You can, also, monitor memory use and CPU use vs time.

There are come CLI thingies that will give 'better' info of the happenings.
I have looked further at this, and modified the script so it stops the subprocess whenever I change a parameter, and I check with Task manager it has stopped, I then restart the subprocess. Still it crashes the Pi, with shutter times > 1 second usually.
No excess CPU / RAM use shown.

I can only assume its a raspistill issue ?

Code: Select all

#!/usr/bin/env python3
import os
import pygame, sys
import time
import shutil
import subprocess, glob
import signal
import tkinter as tk
from PIL import ImageTk, Image


class MainApplication(tk.Frame):
    def __init__(self, master):
        self.master = master
        tk.Frame.__init__(self, self.master)
        self.ss = 10000
        self.ISO = 0
        self.mode = 1
        self.Br = 50
        self.Co = 0
        self.modes =  ['off',  'auto', 'night', 'sports', 'verylong', 'fireworks']
        if os.path.exists('/run/shm/test.jpg'):
            os.rename('/run/shm/test.jpg', '/run/shm/oldtest.jpg')
        rpistr = "raspistill -w 640 -h 480 -t 0 -tl 0 -n -ISO 0 -o /run/shm/test.jpg -br " +  str(self.Br) + " -co " + str(self.Co) + " -ex " + self.modes[self.mode] + " -ss " + str(self.ss)
        self.p = subprocess.Popen(rpistr, shell=True, preexec_fn=os.setsid)
        time.sleep(2)
        self.dataure_gui()
        self.create_frames()
        self.create_buttons()
        
    def dataure_gui(self):
        self.master.title('Shutter Speed Selection')
        self.master.geometry('640x600')
        self.master.resizable(0, 0)

    def create_frames(self):
        self.Frame10 = tk.Frame(width=800, height=600)
        self.Frame10.grid_propagate(0)
        self.Frame10.grid(row=0, column=0)

    def create_buttons(self):

        self.B1 = tk.Button(self.Frame10, text='SS_Dn',  command = self.SS_Down,repeatdelay=100, repeatinterval=50)       
        self.B1.grid(row=0, column=0)
        self.SS = tk.Label(self.Frame10, text = str(int(self.ss/1000)) + " mS")
        self.SS.grid(row=0, column=1)
        self.B2 = tk.Button(self.Frame10, text=' SS_Up ',command = self.SS_Up,repeatdelay=100, repeatinterval=50)       
        self.B2.grid(row=0, column=2)
        self.B3 = tk.Button(self.Frame10, text='EXIT',command = self.Exit)       
        self.B3.grid(row=0, column=3)
        self.C1 = tk.Button(self.Frame10, text='ISO_Dn',  command = self.ISO_Down,repeatdelay=1000, repeatinterval=500)       
        self.C1.grid(row=1, column=0)
        self.CS = tk.Label(self.Frame10, text = str(self.ISO))
        self.CS.grid(row=1, column=1)
        self.C2 = tk.Button(self.Frame10, text=' ISO_Up ',command = self.ISO_Up,repeatdelay=1000, repeatinterval=500)       
        self.C2.grid(row=1, column=2)
        self.M1 = tk.Button(self.Frame10, text='Mode_Dn',  command = self.Mode_Down,repeatdelay=1000, repeatinterval=500)       
        self.M1.grid(row=1, column=3)
        self.MS = tk.Label(self.Frame10, text = self.modes[self.mode])
        self.MS.grid(row=1, column=4)
        self.M2 = tk.Button(self.Frame10, text=' Mode_Up ',command = self.Mode_Up,repeatdelay=1000, repeatinterval=500)       
        self.M2.grid(row=1, column=5)
        self.D1 = tk.Button(self.Frame10, text='Br_Dn',  command = self.Br_Down,repeatdelay=1000, repeatinterval=500)       
        self.D1.grid(row=2, column=0)
        self.DS = tk.Label(self.Frame10, text = str(self.Br))
        self.DS.grid(row=2, column=1)
        self.D2 = tk.Button(self.Frame10, text=' Br_Up ',command = self.Br_Up,repeatdelay=1000, repeatinterval=500)       
        self.D2.grid(row=2, column=2)
        self.E1 = tk.Button(self.Frame10, text='Co_Dn',  command = self.Co_Down,repeatdelay=1000, repeatinterval=500)       
        self.E1.grid(row=2, column=3)
        self.ES = tk.Label(self.Frame10, text = str(self.Co))
        self.ES.grid(row=2, column=4)
        self.E2 = tk.Button(self.Frame10, text=' Co_Up ',command = self.Co_Up,repeatdelay=1000, repeatinterval=500)       
        self.E2.grid(row=2, column=5)
        self.R1 = tk.Button(self.Frame10, text=' Retstart ',command = self.Restart)       
        self.R1.grid(row=2, column=6)
        self.load = Image.open("/run/shm/test.jpg")
        self.renderc = ImageTk.PhotoImage(self.load)
        self.img = tk.Label(self.Frame10, image = self.renderc)
        self.img.grid(row = 4, column = 0, columnspan = 8, rowspan = 5, pady = 2)
        self.Display()

    def Display(self):
        if os.path.exists('/run/shm/test.jpg'):
            try:
                self.load = Image.open("/run/shm/test.jpg") 
                self.load.verify() 
                self.load = Image.open("/run/shm/test.jpg")
                self.renderc = ImageTk.PhotoImage(self.load)
                self.img.config(image = self.renderc)
            except (IOError, SyntaxError) as e:
                print('Bad file:', filename)
        self.after(200, self.Display)

    def SS_Down(self):
        if self.ss < 20000:
            inc = 1000
        elif self.ss >= 20000 and self.ss <= 490000:
            inc = 10000
        elif self.ss > 490000 and self.ss <= 1000000:
            inc = 100000
        elif self.ss > 1000000:
            inc = 1000000
        self.ss -= inc
        if self.ss < 1000:
            self.ss = 1000
        self.SS.config(text = str(int(self.ss/1000)) + " mS")
        self.Stop()

    def SS_Up(self):
        if self.ss < 20000:
            inc = 1000
        elif self.ss >= 20000 and self.ss <= 490000:
            inc = 10000
        elif self.ss > 490000 and self.ss <= 1000000:
            inc = 100000
        elif self.ss > 1000000:
            inc = 1000000
        self.ss += inc
        if self.ss > 6000000:
            self.ss = 6000000
        self.SS.config(text = str(int(self.ss/1000)) + " mS")
        self.Stop()


    def ISO_Down(self):
        self.ISO -= 100
        if self.ISO < 0:
            self.ISO = 0
        self.CS.config(text = str(self.ISO))
        self.Stop()

    def ISO_Up(self):
        self.ISO += 100
        if self.ISO > 800:
            self.ISO = 800
        self.CS.config(text = str(self.ISO))
        self.Stop()

    def Mode_Down(self):
        self.mode -= 1
        if self.mode < 0:
            self.mode = 0
        self.MS.config(text = self.modes[self.mode])
        self.Stop()

    def Mode_Up(self):
        self.mode += 1
        if self.mode > 5:
            self.mode = 5
        self.MS.config(text = self.modes[self.mode])
        self.Stop()

    def Br_Down(self):
        self.Br -= 1
        if self.Br < 0:
            self.Br = 0
        self.DS.config(text = str(self.Br))
        self.Stop()

    def Br_Up(self):
        self.Br += 1
        if self.Br > 100:
            self.Br = 100
        self.DS.config(text = str(self.Br))
        self.Stop()

    def Co_Down(self):
        self.Co -= 1
        if self.Co < -50:
            self.Co = -50
        self.ES.config(text = str(self.Co))
        self.Stop()

    def Co_Up(self):
        self.Co += 1
        if self.Co > 50:
            self.Co = 50
        self.ES.config(text = str(self.Co))
        self.Stop()

    def Stop(self):
        poll = self.p.poll()
        if poll == None: # subprocess still running
            os.killpg(self.p.pid, signal.SIGTERM)
        poll = self.p.poll()
        while poll == None: # ensure subprocess stopped
            time.sleep(.1)
            poll = self.p.poll()
        self.R1.config(bg = "red")

    def Restart(self):
        self.SS.config(text = str(int(self.ss/1000)) + " mS")
        self.CS.config(text = str(self.ISO))
        self.MS.config(text = self.modes[self.mode])
        self.DS.config(text = str(self.Br))
        self.ES.config(text = str(self.Co))
        poll = self.p.poll()
        if poll == None: # subprocess running
            os.killpg(self.p.pid, signal.SIGTERM)
        poll = self.p.poll()
        while poll == None: # subprocess still running
            time.sleep(.1)
            poll = self.p.poll()
        if os.path.exists('/run/shm/test.jpg'):
            os.rename('/run/shm/test.jpg', '/run/shm/oldtest.jpg')
        rpistr = "raspistill -w 640 -h 480 -t 0 -tl 0 -bm -n -ISO " + str(self.ISO) + " -o /run/shm/test.jpg -br " +  str(self.Br) + " -co " + str(self.Co) + " -ex " + self.modes[self.mode] + " -ss " + str(self.ss)
        self.p = subprocess.Popen(rpistr, shell=True, preexec_fn=os.setsid)
        poll = self.p.poll()
        while poll != None: # ensure subprocess running
            time.sleep(.1)
            poll = self.p.poll()
        self.R1.config(bg = "light grey")

    def Exit(self):
        os.killpg(self.p.pid, signal.SIGTERM)
        self.master.destroy()

if __name__ == '__main__':
    
    root = tk.Tk()
    main_app =  MainApplication(root)
    root.mainloop()
Attachments
screen2.jpg
screen2.jpg (56.45 KiB) Viewed 167 times
screen1.jpg
screen1.jpg (61.13 KiB) Viewed 167 times

Idahowalker
Posts: 464
Joined: Wed Jan 03, 2018 5:43 pm

Re: Why does this lock up / crash the Pi ?

Sat May 23, 2020 10:53 am

WHen you write change a parameter, are you 'saying' that the sub process is running and you, in some way, send it a new thing do and then the sub process stops? Have you tried sending data to the sub process through a queue?
Without knowing why you are deleting my postings, I will not know how...

gordon77
Posts: 4902
Joined: Sun Aug 05, 2012 3:12 pm

Re: Why does this lock up / crash the Pi ?

Sat May 23, 2020 10:56 am

Idahowalker wrote:
Sat May 23, 2020 10:53 am
WHen you write change a parameter, are you 'saying' that the sub process is running and you, in some way, send it a new thing do and then the sub process stops? Have you tried sending data to the sub process through a queue?
The subprocess is running, I change the parameter value, then stop the process, and then restart it (another button) with new parameters.

example

Code: Select all

    def SS_Down(self):
        if self.ss < 20000:
            inc = 1000
        elif self.ss >= 20000 and self.ss <= 490000:
            inc = 10000
        elif self.ss > 490000 and self.ss <= 1000000:
            inc = 100000
        elif self.ss > 1000000:
            inc = 1000000
        self.ss -= inc
        if self.ss < 1000:
            self.ss = 1000
        self.SS.config(text = str(int(self.ss/1000)) + " mS")
        self.Stop()

Idahowalker
Posts: 464
Joined: Wed Jan 03, 2018 5:43 pm

Re: Why does this lock up / crash the Pi ?

Sat May 23, 2020 12:49 pm

I'd try to inject parameter, if possible, changes whiles the processes are running using a queue.
Without knowing why you are deleting my postings, I will not know how...

gordon77
Posts: 4902
Joined: Sun Aug 05, 2012 3:12 pm

Re: Why does this lock up / crash the Pi ?

Sat May 23, 2020 4:05 pm

Idahowalker wrote:
Sat May 23, 2020 12:49 pm
I'd try to inject parameter, if possible, changes whiles the processes are running using a queue.
Can you give me an idea how to do that ?

I tried starting the subprocess with..

self.p = subprocess.Popen(['raspistill','-w','640','-h','480','-t','0','-tl','0','-n','-ISO','0','-o','/run/shm/test.jpg'], preexec_fn=os.setsid, stdin=subprocess.PIPE)

which works OK

but how do I get different parameters to it when running ?

I tried self.p.stdin.write(b' -ss 1000000') but it didn't work

gordon77
Posts: 4902
Joined: Sun Aug 05, 2012 3:12 pm

Re: Why does this lock up / crash the Pi ?

Sun May 24, 2020 10:35 am

I tried using picamera, anyone know why cv2.setMouseCallback(winName,onmouse) won't work with it ?

Code: Select all

# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2

width = 640
height = 480
winName = "Frame"

def onmouse(event,x,y,flags,params):
  if event == cv2.EVENT_LBUTTONDOWN:
      print (x,y)

cv2.setMouseCallback(winName,onmouse)

# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (width, height)
camera.framerate = 30
rawCapture = PiRGBArray(camera, size=(width, height))
# allow the camera to warmup
time.sleep(1)
# capture frames from the camera
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
# grab the raw NumPy array representing the image, then initialize the timestamp
# and occupied/unoccupied text
    image = frame.array
    cv2.imshow(winName,image)
    key = cv2.waitKey(1) & 0xFF
    # clear the stream in preparation for the next frame
    rawCapture.truncate(0)
    # if the `q` key was pressed, break from the loop
    if key == ord("q"):
        break

Return to “Python”