The enclosed Python code for Raspberry Pi 4 runs separately each function without any problem countdown()
and RunThermalCam()
, but when running both functions concurrently the timers stop and camera image freeze. My understanding is camera is heavily processor usage so I used multiprocessing, but it gives the following error which I couldn't figure out. The code should first runs GUI then once "Start" button is hit, modules (PWM)
runs with countdown timers for each module along with thermal camera.
XIO: fatal IO error 25 (Inappropriate ioctl for device) on X server ":0"
after 1754 requests (1754 known processed) with 38 events remaining.
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python3: ../../src/xcb_io.c:269: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed.
Process ended with exit code -6.
import RPi.GPIO as GPIO
from adafruit_blinka import Enum, Lockable, agnostic
import csv, datetime
from tkinter import *
from tkinter.filedialog import asksaveasfile
import time,board,busio
import numpy as np
import adafruit_mlx90640
import matplotlib.pyplot as plt
import multiprocessing
def first():
print("first new time is up \n")
#stop module (1)
def second():
print("second new time is up \n")
#stop module (2)
def third():
print("third new time is up \n")
#stop module (3)
#Create interface#
root = Tk()
root.geometry("1024x600")
root.title("Countdown Timer")
def modules():
if (clockTime[0] == 0 or clockTime[0] == -1):
first()
if(clockTime[1] == 0 or clockTime[1] == -1):
second()
if(clockTime[2] == 0 or clockTime[2] == -1):
third()
#initialize timers lists
timers_number = 3
hrString=[0]*timers_number
minString=[0]*timers_number
secString=[0]*timers_number
totalSeconds = [0]*timers_number
totalMinutes = [0]*timers_number
totalHours = [0]*timers_number
for i in range(timers_number):
hrString[i] = StringVar()
hrString[i].set("00")
for i in range(timers_number):
minString[i] = StringVar()
minString[i].set("00")
for i in range(timers_number):
secString[i] = StringVar()
secString[i].set("00")
#Get User Input
hourTextBox1 = Entry(root, width=3, font=("Calibri", 20, ""),textvariable=hrString[0]).place(x=170, y=100)
minuteTextBox1 = Entry(root, width=3, font=("Calibri", 20, ""),textvariable=minString[0]).place(x=220, y=100)
secondTextBox1 = Entry(root, width=3, font=("Calibri", 20, ""),textvariable=secString[0]).place(x=270, y=100)
hourTextBox2 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=hrString[1]).place(x=170, y=180)
minuteTextBox2 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=minString[1]).place(x=220, y=180)
secondTextBox2 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=secString[1]).place(x=270, y=180)
hourTextBox3 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=hrString[2]).place(x=170, y=260)
minuteTextBox3 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=minString[2]).place(x=220, y=260)
secondTextBox3 = Entry(root, width=3, font=("Calibri", 20, ""), textvariable=secString[2]).place(x=270, y=260)
def RunThermalCam():
thermal_mapfile = str(datetime.datetime.now().date()) + '_' + str(datetime.datetime.now().time()).replace(':', '.')
thermal_mapfile = thermal_mapfile[:16] #limit thermal file name to 16 characters
i2c = busio.I2C(board.SCL, board.SDA, frequency=800000) # setup I2C
mlx = adafruit_mlx90640.MLX90640(i2c) # begin MLX90640 with I2C comm
mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_2_HZ # set refresh rate 2Hz
mlx_shape = (24,32)
print("Initialized")
# setup the figure for plotting
plt.ion() # enables interactive plotting
fig,ax = plt.subplots(figsize=(12,7))
therm1 = ax.imshow(np.zeros(mlx_shape),vmin=0,vmax=60) #start plot with zeros
cbar = fig.colorbar(therm1) # setup colorbar for temps
cbar.set_label('Temperature [$^{\circ}$C]',fontsize=14) # colorbar label
#frame = np.zeros((24*32,)) # setup array for storing all 768 temperatures
t_array = []
frame = [0] * 768
while True:
t1 = time.monotonic()
try:
mlx.getFrame(frame) # read MLX temperatures into frame var
data_array = (np.reshape(frame,mlx_shape)) # reshape to 24x32
therm1.set_data(np.fliplr(data_array)) # flip left to right
therm1.set_clim(vmin=np.min(data_array),vmax=np.max(data_array)) # set bounds
cbar.update_normal(therm1) # update colorbar range
plt.title(f"Max Temp: {np.max(data_array):.1f}C")
plt.pause(0.001) # required
t_array.append(time.monotonic()-t1)
print('Sample Rate: {0:2.1f}fps'.format(len(t_array)/np.sum(t_array)))
#except AttributeError:
# continue
except ValueError:
continue # if error, just read again
for h in range(24):
for w in range(32):
t = frame[h*32 + w]
frame = list(np.around(np.array(frame),1)) #round array elements to one decimal point
with open("/home/pi/MOC/Thermal_Camera/"+thermal_mapfile+".csv","a") as thermalfile:
writer = csv.writer(thermalfile,delimiter=" ")
writer.writerow([time.time(),frame])
def countdown():
for i in range (timers_number):
if(clockTime[i] > -1):
totalMinutes[i], totalSeconds[i] = divmod(clockTime[i], 60)
if(totalMinutes[i]>60):
totalHours[i], totalMinutes[i] = divmod(totalMinutes[i], 60)
hrString[i].set("{0:2d}".format(totalHours[i]))
minString[i].set("{0:2d}".format(totalMinutes[i]))
secString[i].set("{0:2d}".format(totalSeconds[i]))
if(clockTime[i] == 0): #time is up
hrString[i].set("00")
minString[i].set("00")
secString[i].set("00")
modules()
if(clockTime[i] != -1): #timer is paused
clockTime[i] -= 1
if(clockTime[i] != -1):
root.after(1000, countdown)
p1 = multiprocessing.Process(target = RunThermalCam)
p2 = multiprocessing.Process(target = countdown)
def starttimer():
#Start_modules()
global clockTime
clockTime = [0]*timers_number
try:
#global clockTime
for i in range (timers_number):
clockTime[i] = int(hrString[i].get())*3600 + int(minString[i].get())*60 + int(secString[i].get())
except:
print("Incorrect values")
countdown()
RunThermalCam()
#p1.start()
#p2.start()
#p1.join()
#p2.join()
def stop():
for i in range (timers_number):
clockTime[i] = 0
def pause():
for i in range (timers_number):
clockTime[i] = -1
modules()
def GUI():
setTimeButton = Button(root, text='START', bd='5', command=starttimer).place(x=200, y=500)
setTimeButton = Button(root, text='STOP', bd='5', command=stop).place(x=350, y=500)
setTimeButton = Button(root, text='PAUSE', bd='5', command=pause).place(x=500, y=500)
root.mainloop()
if __name__ == '__main__':
GUI()