I wrote a simple controller for my robot in Python and now I want to send the data over the serial monitor to the Arduino. I managed to send the values but now I want to know how I can extract the data from the monitor with the Arduino. My Python code:
import PySimpleGUI as sg
import serial
import time
import math
ArmLänge = 205
TextX = 10
TextY = 10
TextZ = 10
font = ("Courier New", 11)
sg.theme("DarkBlue3")
sg.set_options(font=font)
ser = serial.Serial("COM6")
ser.flushInput()
layout = [
[sg.Text("Forward Kinematics:", font=("Helvetica", 12)), sg.Text(" Inverse Kinematics:", font=("Helvetica", 12))],
[sg.Text("X"), sg.Slider((0, 360), orientation='horizontal', key='SLIDER_X'), sg.Text("X"),sg.InputText(size=(10, 10), key="InputX")],
[sg.Text("Y"), sg.Slider((0, 360), orientation='horizontal', key='SLIDER_Y'), sg.Text("Y"),sg.InputText(size=(10, 10), key="InputY")],
[sg.Text("Z"), sg.Slider((0, 360), orientation='horizontal', key='SLIDER_Z'), sg.Text("Z"),sg.InputText(size=(10, 10), key="InputZ")],
[sg.Push(), sg.Button('Exit'), sg.Button("Move")],
]
window = sg.Window("Controller", layout, finalize=True)
window['SLIDER_X'].bind('<ButtonRelease-1>', ' Release')
window['SLIDER_Y'].bind('<ButtonRelease-1>', ' Release')
window['SLIDER_Z'].bind('<ButtonRelease-1>', ' Release')
while True:
event, values = window.read()
if event in (sg.WINDOW_CLOSED, 'Exit'):
break
elif event == 'SLIDER_X Release':
print("X Value:", values["SLIDER_X"])
elif event == 'SLIDER_Y Release':
print("Y Value:", values["SLIDER_Y"])
elif event == 'SLIDER_Z Release':
print("Z Value:", values["SLIDER_Z"])
#elif event == "Move":
#print("IK X:", values['InputX'])
#print("IK Y:", values['InputY'])
#print("IK Z:", values['InputZ'])
valX = int(values["SLIDER_X"]/2)
valY = int(values["SLIDER_Y"]/2)
valZ = int(values["SLIDER_Z"]/2)
Data = [1,valX,valY,valZ]
print(Data)
ser.write(Data)
if values['InputX'] >= str(1):
x = float(values['InputX'])
y = float(values['InputY'])
z = float(values['InputZ'])
h = round(math.sqrt(x ** 2 + y ** 2))
joint2 = round(math.degrees(math.atan(y / x)))
joint3 = round(math.degrees(math.acos((h / 2) / (ArmLänge / 2))))
print("----Ergebnis:----")
print("Höhe:", h)
print("Joint2:", joint2,"°")
print("Joint3:", joint3,"°")
IKData = [2, h, joint2, joint3]
print(IKData)
ser.write(IKData)
window.close()
ser.close()
It may not be the best code but it works. I need to extract every number for example [1, 20, 45, 30]. How can I do that?
I am assuming that the data goes to Serial in this Format as String:
[1,valX,valY,valZ]
After reading the data from Serial and converting the data line to String with String() function, you can assign the values to desired variables using sscanf() function.
The function works like this -
sscanf(const char *str, const char *format, ...)
So, here it would work like this -
int data_val1, data_val2, data_val3;
sscanf(Your_SerialData_String, [1,%d,%d,%d], data_val1, data_val2, data_val3);
Related
GitHub for this project
I am building a financial trading profit/loss calculator. I have built the script to function in the command line interface (main_cli.py).
Now, I am trying to convert to a desktop GUI via PySimpleGUI, but am having difficulty with passing multiple user input values from PySimpleGUI (main_gui.py) to the calculator function (functions.py), to then output the result in the same PySimpleGUI window.
When I run the main_gui.py script, it still asks for user_input in the CLI.
Just pass values to your function, then convert all fields into your data for the function to calculate the result, and return it back to event loop to update the GUI.
Note: No any entry validation in the code.
import PySimpleGUI as sg
def calculate(values):
ticker = ticker_list[[values[("Ticker", i)] for i in range(len(tickers))].index(1)]
tick_size, contract_amount = tickers[ticker]
position = "Long" if values[("Position", 0)] else "Short"
purchase_price = float(values['Entry'])
selling_price = float(values['Exit'])
contract_size = float(values['Contract'])
tick_value = (((purchase_price - selling_price)*contract_size)/tick_size)
dollar_value = (tick_value*contract_amount)
if position == "Long":
tick_value = abs(tick_value)
dollar_value = abs(dollar_value)
return tick_value, dollar_value
tickers = {
'ES' : (0.25, 12.50),
'NQ' : (0.25, 5.00),
'RTY': (0.10, 5.00),
'YM' : (1.00, 5.00),
'GC' : (0.10, 10.00),
'CL' : (0.01, 10.00),
}
ticker_list = list(tickers.keys())
positions = ['Long', 'Short']
keys = {
'Entry':'Entry price',
'Exit':'Exit price',
'Contract':'Contract size',
}
sg.theme('Dark')
sg.set_options(font=('Helvetica', 10))
layout = [
[sg.Text("Ticker:", size=10)] + [sg.Radio(tick, "Radio 1", key=("Ticker", i)) for i, tick in enumerate(tickers)],
[sg.Text("Position:", size=10)] + [sg.Radio(pos, "Radio 2", key=("Position", i)) for i, pos in enumerate(positions)]] + [
[sg.Text(text, size=10), sg.InputText(size=10, expand_x=True, key=key)] for key, text in keys.items()] + [
[sg.Text("Result"), sg.Text(text_color="white", key="Output")],
[sg.Push(), sg.Button("Reset"), sg.Button("Calculate", button_color=('white', '#007339'))],
]
window = sg.Window('Futures Profit/Loss Calculator', layout=layout)
while True:
event, values = window.read()
print(event, values)
if event == sg.WIN_CLOSED:
break
elif event == "Calculate":
tick_value, dollar_value = calculate(values)
result = f"ticks: {tick_value} | profit/loss: ${dollar_value}"
window['Output'].update(result)
elif event == "Reset":
for key in keys:
window[key].update('')
window.close()
If this function take long time to finish the caluclation, you can call method window.perform_long_operation to run your function, Lambda expression can help to pass the arguments here, then update your GUI when the event '-FUNCTION COMPLETED-' generated, like
elif event == "Calculate":
window.perform_long_operation(lambda x=values:calculate(x), '-FUNCTION COMPLETED-')
elif event == '-FUNCTION COMPLETED-':
tick_value, dollar_value = values[event]
result = f"ticks: {tick_value} | profit/loss: ${dollar_value}"
window['Output'].update(result)
I have to make a program to teach children multipliers, this is the core code of the assignment.
#include <stdio.h>
#define MIN 1
#define MAXINDEX 10
#define MAXTABLE 10
#define STEP 1
void main(void)
{
int i,j ;
for (j = MIN; j <MAXTABLE; j += STEP) {
for (i = MIN; i <= MAXINDEX; i += STEP)
printf(“%3d * %3d = %3d\n”, i, j, i*j);
printf(“\n---------------\n\n”);
}
for (i = MIN; i <= MAXINDEX; i += STEP)
printf(“%3d * %3d = %3d\n”, i, MAXTABLE, i*MAXTABLE);
}
After I have to rewrite it to a next generation language so I designed to write it in python.
Like this
j=1
i=1
for j in range(1,11):
for i in range(1,11):
print('%3d * %3d =%3d' % (i, j, i *j))
if j!=10:
print("\n---------------\n")
else:
print("\n")
And after that I have to make a UI for it so this image is what I designed to do like this This is the design of me
Since I just study python for 3 days, so I try my best to write this:
import PySimpleGUI as sg
import os.path
def Corecode():
j=1
i=1
for j in range(1,11):
for i in range(1,11):
print('%3d * %3d =%3d' % (i, j, i *j))
if j!=10:
print("\n---------------\n")
else:
print("\n")
from PySimpleGUI.PySimpleGUI import R, Image, Multiline
showrobot_column = [
[sg.Image('E:\img\robot.png',size = (300,300))],
],
show_Textbox_selectbox = [
[sg.Multiline(size=(50,20),key='-def-')],
[sg.Listbox(values=['a','b','c','d'], enable_events=True, size=(50,20), key="")]
]
layout = [
[sg.Column(showrobot_column),
sg.VSeparator(),
sg.Column(show_Textbox_selectbox)
]
]
window = sg.Window("First Test",layout)
while True:
event, value = window.read()
if event == sg.WIN_CLOSED:
break
window.close()
I designed to make it like a robot is talking and let the children interact by buttonBut, but I find out I can't insert the image, and also I can't find a way to print the Multiplier table by the core code that on the front, so someone can help me to finish the code or tell me why the sg.image get error. TY
Try this,
import PySimpleGUI as sg
def corecode(base):
return ("\n"+"-"*13+"\n").join([f'{i+1:>2d} * {base:>2d} = {(i+1)*base:>3d}' for i in range(10)])
sg.theme('DarkBlue3')
sg.set_options(font=("Courier New", 12))
showrobot_column = [
[sg.Image('E:/img/robot.png', size = (300, 300))],
]
list_values = [f'{i+1:>2d}' for i in range(10)]
show_Textbox_selectbox = [
[sg.Multiline(size=(15, 20), expand_y=True, key='-MULTILINE-')],
[sg.Listbox(values=list_values, enable_events=True, size=(15, 10), key="-LISTBOX-")],
]
layout = [
[sg.Column(showrobot_column),
sg.VSeparator(),
sg.Column(show_Textbox_selectbox),],
]
window = sg.Window("First Test", layout, finalize=True)
multiline = window['-MULTILINE-']
multiline.update(value=corecode(1))
listbox = window['-LISTBOX-']
listbox.update(set_to_index=0)
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == '-LISTBOX-':
base = int(values[event][0])
multiline.update(value=corecode(base))
window.close()
This is a shameless small tweak to Jason's answer (choose his as it's correct).
Wanted to include a couple of capabilities that may be helpful to some. One is that almost all elements have an initial value that you can set in your layout instead of finalizing it and then setting them. It reduces code.
I'm also including a "Trinket" embedded in this answer as a test. This way you can run the example on this StackOverflow page.
import PySimpleGUI as sg
def corecode(base):
return ("\n"+"-"*13+"\n").join([f'{i+1:>2d} * {base:>2d} = {(i+1)*base:>3d}' for i in range(10)])
sg.theme('DarkBlue3')
list_values = [f'{i+1:>2d}' for i in range(10)]
show_Textbox_selectbox = [[sg.Multiline(default_text=corecode(1), size=(15, 20), expand_y=True, key='-MULTILINE-')],
[sg.Listbox(values=list_values, default_values=[list_values[0]], enable_events=True, size=(15, 10), key="-LISTBOX-")]]
layout = [
[sg.Image(sg.EMOJI_BASE64_HAPPY_THUMBS_UP), sg.VSeparator(), sg.Column(show_Textbox_selectbox)]
]
window = sg.Window("First Test", layout, font='Courier 12')
while True:
event, values = window.read()
if event == sg.WIN_CLOSED:
break
elif event == '-LISTBOX-':
base = int(values[event][0])
window['-MULTILINE-'].update(value=corecode(base))
window.close()
Here is a link to the Trinket should it not embed correctly - https://trinket.io/pygame/d59ef3b352
<iframe src="https://trinket.io/embed/pygame/d59ef3b352" width="100%" height="600" frameborder="0" marginwidth="0" marginheight="0" allowfullscreen></iframe>
I'm having a rough time trying to create threads inside a tkinter GUI. To give some background on what I would like the code to do. This is a GUI that when the log buttons are pressed (e.g. log_1). I'd like to send a continuous command to fire a laser and eventually (after I tackle the current problem) log the subsequent parameters.
However, my issue is that I have 5 lasers needing to be fired at the same time (or very close to) and the more lasers I have in the logging state ON the more the time delay between the lasers firing. I guess this is an issue because my: fire_all() function in conjunction with the window after(100, fire_all) is not a threaded process so having more lasers firing results in more of a time delay between the onset of the command to fire.
My code is below. Does anyone have any suggestions how to implement this properly?
# start the GUI
import tkinter as tk
window = tk.Tk()
def fire_astrum(dev): # N = 100 # no of points in stream array, pulse_count = int(1) # no of desired pulses in pulse train #command is command volatge
#dev,ana_out,ana_in,N,pulse_count,pulse_on,pulse_off,command
#dev = 'Dev1'
ana_out = 'ao0'
ana_in = "ai0:1"# for non consecutive channels use: "Dev0/ai0:Dev0/ai4"
N = 100
pulse_count = 10
pulse_on = 45
pulse_off = 15
command = 3.5
channel = dev +'/' + ana_out
tot = dev + "/" + ana_in
duty = pulse_on/(pulse_on+pulse_off) # duty cycle in %
array_on = int(N*duty) # on values in array
array_off = int(N-array_on) # off values in array
samples = np.append(command*np.ones(array_on),np.zeros(array_off)) # command is command voltage (IPROG), sets up stream array to send to NI box
curr = np.empty((2,pulse_count*len(samples))) # Empty arrays for IMON,VMON
error = np.uint32(np.empty((3,pulse_count*len(samples)))) # # Empty arrays for Digital inputs with pull-up resistors (READY, ERR1 & ERR2)
#sample_clock = '/'+dev+'/ai/SampleClock'
arm_laser(dev,'on') # Sends 5V to Astrum to arm laser diode
time.sleep(0.3) # wait for 300ms before data stream
with nidaqmx.Task() as writeTask, nidaqmx.Task() as readcurr, nidaqmx.Task(): # as digitalread:#, nidaqmx.Task() as readvolt:
writeTask.ao_channels.add_ao_voltage_chan(channel,units = Volts)
writeTask.ao_channels.all.ao_max = 4 # Hard clamp Limit to 4V to protect laser diode
writeTask.ao_channels.all.ao_min = 0 # Set baseline to 0V (ground loop protection)
readcurr.ai_channels.add_ai_voltage_chan(tot, units = Volts,terminal_config = TerminalConfiguration.RSE) # define differntial NRE connfig of channels
#print(read_curr.ai_term_cfg)
#digitalread.di_channels.add_di_chan(dev + '/port0/line0:2',line_grouping=LineGrouping.CHAN_PER_LINE)
#writeTask.triggers.start_trigger.cfg_dig_edge_start_trig('/' + dev +'/' + terminal) #Setting the trigger on the analog input
writeTask.timing.cfg_samp_clk_timing(rate=(array_on/N)*1/pulse_on*1000*N,sample_mode= nidaqmx.constants.AcquisitionType.FINITE , samps_per_chan= pulse_count*len(samples))
readcurr.timing.cfg_samp_clk_timing(rate=(array_on/N)*1/pulse_on*1000*N, sample_mode= nidaqmx.constants.AcquisitionType.FINITE , samps_per_chan= pulse_count*len(samples))
#digitalread.timing.cfg_samp_clk_timing(rate=(array_on/N)*1/pulse_on*1000*N, sample_mode= nidaqmx.constants.AcquisitionType.FINITE , samps_per_chan= pulse_count*len(samples))
reader_curr = AnalogMultiChannelReader(readcurr.in_stream)
#digital = DigitalMultiChannelReader(digitalread.in_stream)
writer = AnalogSingleChannelWriter(writeTask.out_stream, auto_start=True)
writer.write_many_sample(samples)
time_vec = np.linspace(0, (pulse_on+pulse_off)*pulse_count, num=len(curr[0]), endpoint=True)
reader_curr.read_many_sample(data = curr,number_of_samples_per_channel = pulse_count*len(samples), timeout = nidaqmx.constants.WAIT_INFINITELY)# read from DAQ
#digital.read_many_sample_port_uint32(data = error,number_of_samples_per_channel = pulse_count*len(samples), timeout = nidaqmx.constants.WAIT_INFINITELY)# read from DAQ
curr = np.around(curr, 6) # Round all values to 6 decimals to avoid overflow
error = np.around(error, 6) # Round all values to 6 decimals to avoid overflow
print("The channels linked to WriteTask are: ")
for i in writeTask.ao_channels:
print(i)
print("The channels linked to ReadTask are: ")
for j in readcurr.ai_channels:
print(j)
################# Astrum parameters #########################
imon = curr[0]
vmon = curr[1]
ready = error[0]
err1 = error[1]
err2 = error[2]
trigger = np.tile(samples,pulse_count)
###############################################################
arm_laser(dev,'off')
###############################################################
V = np.max(vmon)
I = np.max(imon)
#for j in range(9):
laser_1[6].config(text = V)
laser_1[7].config(text = I)
def log1():
if log_1.config('text')[-1] =='ON':
log_1.config(text='OFF', bg="red",activebackground="red",textvariable=0)
print(log_1.config('textvariable')[-1])
else:
log_1.config(text='ON', bg="green",activebackground="green",textvariable=1)
print(log_1.config('textvariable')[-1])
def log2():
if log_2.config('text')[-1] =='ON':
log_2.config(text='OFF', bg="red",activebackground="red",textvariable=0)
print(log_2.config('textvariable')[-1])
else:
log_2.config(text='ON', bg="green",activebackground="green",textvariable=1)
print(log_2.config('textvariable')[-1])
def log3():
if log_3.config('text')[-1] =='ON':
log_3.config(text='OFF', bg="red",activebackground="red",textvariable=0)
print(log_3.config('textvariable')[-1])
else:
log_3.config(text='ON', bg="green",activebackground="green",textvariable=1)
print(log_3.config('textvariable')[-1])
def log4():
if log_4.config('text')[-1] =='ON':
log_4.config(text='OFF', bg="red",activebackground="red",textvariable=0)
print(log_4.config('textvariable')[-1])
else:
log_4.config(text='ON', bg="green",activebackground="green",textvariable=1)
print(log_4.config('textvariable')[-1])
def log5():
if log_5.config('text')[-1] =='ON':
log_5.config(text='OFF', bg="red",activebackground="red",textvariable=0)
print(log_5.config('textvariable')[-1])
else:
log_5.config(text='ON', bg="green",activebackground="green",textvariable=1)
print(log_5.config('textvariable')[-1])
##### logging button lasers ###########
log_1 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log1, bg = "red")
log_1.grid(row = 2, column = 8)
log_2 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log2, bg = "red") #, onvalue=1, offvalue=0)
log_2.grid(row = 3, column = 8)
log_3 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log3, bg = "red") #, onvalue=1, offvalue=0)
log_3.grid(row = 4, column = 8)
log_4 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log4, bg = "red") #, onvalue=1, offvalue=0)
log_4.grid(row = 5, column = 8)
log_5 = tk.Button(top_frame, width=8 , bd=4, text = 'OFF', command = log5, bg = "red") #, onvalue=1, offvalue=0)
log_5.grid(row = 6, column = 8)
def fire_all():
#global a
a = str(log_1.config('textvariable')[-1])
b = str(log_2.config('textvariable')[-1])
c = str(log_3.config('textvariable')[-1])
d = str(log_4.config('textvariable')[-1])
e = str(log_5.config('textvariable')[-1])
if a == '1':
fire_astrum('Dev1')
if b == '1':
fire_astrum('Dev2')
if c == '1':
fire_astrum('Dev3')
if d == '1':
fire_astrum('Dev4')
if e == '1':
fire_astrum('Dev5')
# call this function again in 100 milliseconds
window.after(100, fire_all)
window.after(100, fire_all)
window.mainloop()
you can probably launch fire_astrum in a thread from fire_all.
maybe like this:
import threading
...
if a == '1':
threading.Thread(target=lambda dev='Dev1': fire_astrum(dev)).start()
...
It is unclear how long fire_astrum takes to complete; it also sleeps for 300ms; there is no telling the outcome when fired every 100ms, you'll have to try.
First time poster, long time reader! I'm new to python, but I do have experience with other languages, primarily php and javascript, etc - basic web languages. I've touched on OOP in PHP and have built some amazing web apps, but this is all new to me!
I am running a rpi 1 b+ with a LED matrix on it. I took the luma led example code for the silly clock and built in a few things that will add additional functionality, including a crypto ticker. I have a function to check the specified crypto prices and return a list. I am trying to run this function in the background every minute or so and then return a new set of data. The data is then parsed through the cryptoticker() function which then displays it. I realized it is not running in the background and stops after one run through. If I call the function not as a thread it freezes this poor, old rpi and everything waits for the function cryptocheck() to finish, so a background process is ideal.
I am having problems getting the background process to run repeatedly as a thread and attempts to clear the data variable seem to clear it everywhere - it processes the crypto feed once, then shows nothing if I clear it. Itf I dont clear it, then newest data never shows, and I dont want the data list to grow forever, I need to clear it once it has been used in the cryptoticker function
Here's the code (let me know what else I'll need to clarify, not sure if this is correctly posted)
#!/usr/bin/env python
import time
from datetime import datetime
from luma.led_matrix.device import max7219
from luma.core.interface.serial import spi, noop
from luma.core.render import canvas
from luma.core.legacy import text, show_message
from luma.core.legacy.font import proportional, CP437_FONT, TINY_FONT, SINCLAIR_FONT, LCD_FONT
from luma.core.virtual import viewport
import requests
import random
from bs4 import BeautifulSoup
import threading
from threading import Thread
import random
cryptos = [['BTC', 'bitcoin'], ['ETH', 'ethereum'], ['LINA', 'linear'], ['SXP', 'swipe'], ['TRADE', 'unitrade'], ['UNI', 'uniswap']]
data = []
showme = ''
run = 0
finishedPromise = 0
serial = spi(port=0, device=0, gpio=noop())
device = max7219(serial, cascaded=8 , block_orientation=-90, rotate=2, height=8, contrast=20)
def meetingReminderSoon():
meetMessage = "The meeting is starting soon || The meeting is starting soon || The meeting is starting soon || The meeting is starting soon || The meeting is starting soon"
show_message(device, meetMessage, fill="white", font=proportional(LCD_FONT), scroll_delay = 0.02)
def meetingReminderNow():
meetMessage = "MEETING IS STARTING NOW || MEETING IS STARTING NOW || MEETING IS STARTING NOW || MEETING IS STARTING NOW || MEETING IS STARTING NOW || MEETING IS STARTING NOW"
show_message(device, meetMessage, fill="white", font=proportional(LCD_FONT), scroll_delay = 0.02)
def randomPromise():
randomPixels()
randpromise = (random.choice(list(open('/home/pi/ftp/promises.txt'))))
randpromise = randpromise + ' || ' + randpromise
show_message(device, randpromise, fill="white", font=proportional(LCD_FONT), scroll_delay = 0.02)
randomPixels()
show_message(device, randpromise, fill="white", font=proportional(LCD_FONT), scroll_delay = 0.02)
finishedPromise = 1
return finishedPromise
def randomPixels():
runrand = 0
while runrand < 20:
with canvas(device) as draw:
for i in range(38):
x = random.randint(0, device.width)
y = random.randint(0, device.height)
# 'draw' is an ImageDraw object.
draw.point((x, y), fill="white")
time.sleep(0.0007)
runrand = runrand + 1
def cryptocheck():
global run
run = 1
data.clear()
while 1:
for i in cryptos:
url = 'https://coinmarketcap.com/currencies/' + i[1] + '/'
response = requests.get(url)
html = response.content
soup = BeautifulSoup(html, 'html.parser')
symbol = i[0]
price = soup.find('span' ,attrs={"class" : "cmc-details-panel-price__price"})
changeprice = soup.find('span' ,attrs={"class" : "cmc-details-panel-price__price-change"})
if price is not None:
price = price.text
else:
price = ''
if changeprice is not None:
changeprice = changeprice.text
changeprice = changeprice.replace('(','')
changeprice = changeprice.replace(')','')
changeprice = changeprice.replace(' ','')
else:
changeprice = ''
data.append((symbol, price, changeprice))
return data
run = 1
timer.sleep(120)
def cryptoticker():
randomPixels()
# build the message
showme = ''
for row in data:
for elem in row:
showme = showme + elem + ' '
showme = showme + '| '
if showme.endswith('| '):
showme = showme[:-4]
now = datetime.now()
dt_string = now.strftime("%-m/%-d/%y %-I:%M:%S")
showme = dt_string + ' || ' + showme + '|| ' + dt_string
show_message(device, showme, fill="white", font=proportional(LCD_FONT), scroll_delay = 0.02)
randomPixels()
show_message(device, showme, fill="white", font=proportional(LCD_FONT), scroll_delay = 0.02)
randomPixels()
show_message(device, showme, fill="white", font=proportional(LCD_FONT), scroll_delay = 0.02)
def minute_change(device):
'''When we reach a minute change, animate it.'''
hours = datetime.now().strftime('%I')
minutes = datetime.now().strftime('%M')
def helper(current_y):
with canvas(device) as draw:
text(draw, (16, 0), hours, fill="white", font=proportional(CP437_FONT))
text(draw, (31,0), ":", fill="white", font=proportional(TINY_FONT))
text(draw, (33, current_y), minutes, fill="white", font=proportional(CP437_FONT))
time.sleep(0.1)
for current_y in range(0, 9):
helper(current_y)
minutes = datetime.now().strftime('%M')
for current_y in range(9, 0, -1):
helper(current_y)
def animation(device, from_y, to_y):
'''Animate the whole thing, moving it into/out of the abyss.'''
hourstime = datetime.now().strftime('%I')
mintime = datetime.now().strftime('%M')
current_y = from_y
while current_y != to_y:
with canvas(device) as draw:
text(draw, (16, current_y), hourstime, fill="white", font=proportional(CP437_FONT))
text(draw, (31, current_y), ":", fill="white", font=proportional(TINY_FONT))
text(draw, (33, current_y), mintime, fill="white", font=proportional(CP437_FONT))
time.sleep(0.1)
current_y += 1 if to_y > from_y else -1
def main():
randomPixels()
serial = spi(port=0, device=0, gpio=noop())
device = max7219(serial, cascaded=8, block_orientation=-90, blocks_arranged_in_reverse_order=False, rotate=2)
device.contrast(16)
# The time ascends from the abyss...
animation(device, 9, 0)
toggle = False # Toggle the second indicator every second
while True:
toggle = not toggle
sec = datetime.now().second
min = datetime.now().minute
min = str(min)
now = datetime.now()
meetRemind = datetime.now().strftime('%H:%M')
dow = now.strftime("%a")
dow = dow.lower()
nomeeting = 'no'
if dow == 'sat' or dow == 'sun' or dow == 'mon':
nomeeting = 'yes'
if sec == 59:
# When we change minutes, animate the minute change
minute_change(device)
elif sec == 30:
# Half-way through each minute, display the complete date/time,
# animating the time display into and out of the abyss.
full_msg = now.strftime("%a %b %-d %-I:%M:%S %Y")
animation(device, 0, 9)
show_message(device, full_msg, fill="white", font=proportional(CP437_FONT))
animation(device, 9, 0)
elif meetRemind == '09:13' and nomeeting == 'no':
animation(device, 0, -1)
meetingReminderSoon()
elif meetRemind == '09:15' and nomeeting == 'no':
animation(device, 0, -1)
meetingReminderNow()
elif min.endswith('1'):
animation(device, 0, -1)
cryptoticker()
finishedPromise = 0
elif min.endswith('3') and sec < 10:
animation(device, 0, -1)
randomPromise()
elif min.endswith('5'):
animation(device, 0, -1)
cryptoticker()
finishedPromise = 0
elif min.endswith('8') and sec < 10:
animation(device, 0, -1)
randomPromise()
else:
# Do the following twice a second (so the seconds' indicator blips).
# I'd optimize if I had to - but what's the point?
# Even my Raspberry PI2 can do this at 4% of a single one of the 4 cores!
hours = datetime.now().strftime('%I')
minutes = datetime.now().strftime('%M')
with canvas(device) as draw:
text(draw, (16, 0), hours, fill="white", font=proportional(CP437_FONT))
text(draw, (31, 0), ":" if toggle else " ", fill="white", font=proportional(TINY_FONT))
text(draw, (33, 0), minutes, fill="white", font=proportional(CP437_FONT))
time.sleep(0.5)
if __name__ == "__main__":
t1 = threading.Thread(target=cryptocheck)
t1.start()
t1.join()
main()
I have a python script for an installation in an art museum that is meant to run continuously playing sounds, driving an LED matrix, and sensing people via OpennCV and a thermal camera.
Each of the parts of the script work and all of them work together but randomly the script locks up and I need to restart it. I want to script to not lock up so no one has to reset it during the exhibition.
I have the code running on a spare Raspberry Pi and a spare LED matrix and it continues to cycle through fine. The only changes that I made were commenting out the start of a thread to check the IR sensor and a call to a function to get the max temp from the sensor.
To be clear, if I leave these bits of code in the script runs fine 1 -3 or sometimes 10 times. But it seems to lock up in the first "state" when IRcount = 0
I am stuck. Any help is greatly appreciated.
```
#!/usr/bin/python
import glob
import queue
import sys
import pygame
import cv2
import random
import math
import colorsys
import time
from rpi_ws281x import *
from PIL import Image
import numpy as np
import threading
global thresh
sys.path.insert(0, "/home/pi/irpython/build/lib.linux-armv7l-3.5")
import MLX90640 as mlx
currentTime = int(round(time.time() * 1000))
InflateWait = int(round(time.time() * 1000))
minTime = 6000
maxTime = 12000
lineHeight1 = 0
lineHue1 = float(random.randrange(1,360))/255
# IR Functions
# Function to just grab the Max Temp detected. If over threshold then start
# the sequence, if not stay in state 0
def maxTemp():
mlx.setup(8) #set frame rate of MLX90640
f = mlx.get_frame()
mlx.cleanup()
# get max and min temps from sensor
# v_min = min(f)
v_max = int(max(f))
return v_max
# Function to detect individual people's heat blob group of pixels
# run in a thread only at the end of the script
def irCounter():
img = Image.new( 'L', (24,32), "black") # make IR image
mlx.setup(8) #set frame rate of MLX90640
f = mlx.get_frame()
mlx.cleanup()
for x in range(24):
row = []
for y in range(32):
val = f[32 * (23-x) + y]
row.append(val)
img.putpixel((x, y), (int(val)))
# convert raw temp data to numpy array
imgIR = np.array(img)
# increase the 24x32 px image to 240x320px for ease of seeing
bigIR = cv2.resize(depth_uint8, dsize=(240,320), interpolation=cv2.INTER_CUBIC)
# Use a bilateral filter to blur while hopefully retaining edges
brightBlurIR = cv2.bilateralFilter(bigIR,9,150,150)
# Threshold the image to black and white
retval, threshIR = cv2.threshold(brightBlurIR, 26, 255, cv2.THRESH_BINARY)
# Define kernal for erosion and dilation and closing operations
kernel = np.ones((5,5),np.uint8)
erosionIR = cv2.erode(threshIR,kernel,iterations = 1)
dilationIR = cv2.dilate(erosionIR,kernel,iterations = 1)
closingIR = cv2.morphologyEx(dilationIR, cv2.MORPH_CLOSE, kernel)
# Detect countours
contours, hierarchy = cv2.findContours(closingIR, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
# Get the number of contours ( contours count when touching edge of image while blobs don't)
ncontours = str(len(contours))
# Show images in window during testing
cv2.imshow("Combined", closingIR)
cv2.waitKey(1)
#initialize pygame
pygame.init()
pygame.mixer.init()
pygame.mixer.set_num_channels(30)
print("pygame initialized")
# assign sound chennels for pygame
channel0 = pygame.mixer.Channel(0)
channel1 = pygame.mixer.Channel(1)
channel2 = pygame.mixer.Channel(2)
channel3 = pygame.mixer.Channel(3)
channel4 = pygame.mixer.Channel(4)
channel5 = pygame.mixer.Channel(5)
channel6 = pygame.mixer.Channel(6)
channel7 = pygame.mixer.Channel(7)
channel8 = pygame.mixer.Channel(8)
channel9 = pygame.mixer.Channel(9)
channel10 = pygame.mixer.Channel(10)
channel11 = pygame.mixer.Channel(11)
channel12 = pygame.mixer.Channel(12)
channel13 = pygame.mixer.Channel(13)
channel14 = pygame.mixer.Channel(14)
channel15 = pygame.mixer.Channel(15)
channel16 = pygame.mixer.Channel(16)
channel17 = pygame.mixer.Channel(17)
channel18 = pygame.mixer.Channel(18)
channel19 = pygame.mixer.Channel(19)
channel20 = pygame.mixer.Channel(20)
channel21 = pygame.mixer.Channel(21)
channel22 = pygame.mixer.Channel(22)
channel23 = pygame.mixer.Channel(23)
channel24 = pygame.mixer.Channel(24)
channel25 = pygame.mixer.Channel(25)
channel26 = pygame.mixer.Channel(26)
channel27 = pygame.mixer.Channel(27)
channel28 = pygame.mixer.Channel(28)
# load soundfiles
echoballs = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/echo balls FIX.ogg")
organbounce = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/ORGAN BOUNCE fix.ogg")
jar = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/jar whoop fix.ogg")
garland = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/GARLAND_fix.ogg")
dribble= pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/dribble.ogg")
cowbell = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/cowbell fix.ogg")
clackyballs = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/clacky balls boucne.ogg")
burpees = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/burpees_fix.ogg")
brokensynth = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/broken synth bounce.ogg")
woolballs = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/wool balls in jar FIX.ogg")
wiimoye = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/wiimoye_fix.ogg")
warpyorgan = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/warpy organ bounce#.2.ogg")
vibrate = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/vibrate fix.ogg")
turtlesbounce = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/turtles fix.ogg")
timer = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/timer.ogg")
tape = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/tape fix.ogg")
tambourine = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/TAMBOURINE.ogg")
springybounce = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/springy bounce.ogg")
smash3 = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/smash fix.ogg")
bristle2 = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/BRISTLE FIX.ogg")
blackkeys = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/black keys FIX.ogg")
zipper = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/zipper.ogg")
presatisfactionsweep = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/pre-satisfaction sweep .ogg")
satisfaction = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/SATISFACTION.ogg")
altsatisfaction = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/alt_satisfaction_trimmed.ogg")
solosatisfaction = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/SOLO_SATISFACTION.ogg")
print("sound files loaded")
# initializing sounds list
soundsList = [echoballs, organbounce, zipper, jar, garland, dribble, cowbell, clackyballs, burpees, brokensynth, woolballs,
wiimoye, warpyorgan, vibrate, turtlesbounce, timer, tambourine, springybounce, smash3, bristle2, blackkeys, zipper ]
IRcount = 0 # define initial state for main loop
pygame.display.set_mode((32, 8))
print("pygame dispaly open")
# LED strip configuration:
LED_COUNT = 256 # Number of LED pixels.
LED_PIN = 18 # GPIO pin connected to the pixels (18 uses PWM!).
#LED_PIN = 10 # GPIO pin connected to the pixels (10 uses SPI /dev/spidev0.0).
LED_FREQ_HZ = 800000 # LED signal frequency in hertz (usually 800khz)
LED_DMA = 10 # DMA channel to use for generating signal (try 10)
LED_BRIGHTNESS = 100 # Set to 0 for darkest and 255 for brightest
LED_INVERT = False # True to invert the signal (when using NPN transistor level shift)
LED_CHANNEL = 0 # set to '1' for GPIOs 13, 19, 41, 45 or 53
# Define functions which animate LEDs in various ways.
# PNG to LED function used to shuffle througfh folders of numbered PNGs exported
# from animations created
def pngToLED (strip, pngfile):
RGBimage = Image.open(pngfile).convert('RGB')
np_image = np.array(RGBimage)
colours = [Color(x[0],x[1],x[2]) for rows in np_image for x in rows]
colours2d = np.reshape(colours, (32, 8), order='F')
colours2d[1::2, :] = colours2d[1::2, ::-1]
pic = colours2d.flatten('C')
for i in range( 0, strip.numPixels(), 1 ):# iterate over all LEDs - range(start_value, end_value, step)
strip.setPixelColor(i, int(pic[ i ]))
strip.show()
def colorWipe(strip, color,wait_ms=10):
"""Wipe color across display a pixel at a time."""
for i in range(strip.numPixels()):
strip.setPixelColor(i, color)
strip.show()
time.sleep(1)
def theaterChase(strip, color, wait_ms, iterations=10):
"""Movie theater light style chaser animation."""
for j in range(iterations):
for q in range(3):
for i in range(0, strip.numPixels(), 3):
strip.setPixelColor(i+q, color)
strip.show()
time.sleep(wait_ms/1000.0)
for i in range(0, strip.numPixels(), 3):
strip.setPixelColor(i+q, 0)
def wheel(pos):
"""Generate rainbow colors across 0-255 positions."""
if pos < 85:
return Color(pos * 3, 255 - pos * 3, 0)
elif pos < 170:
pos -= 85
return Color(255 - pos * 3, 0, pos * 3)
else:
pos -= 170
return Color(0, pos * 3, 255 - pos * 3)
def rainbow(strip, wait_ms=20, iterations=1):
"""Draw rainbow that fades across all pixels at once."""
for j in range(256*iterations):
for i in range(strip.numPixels()):
strip.setPixelColor(i, wheel((i+j) & 255))
strip.show()
time.sleep(wait_ms/1000.0)
def rainbowCycle(strip, wait_ms=20, iterations=5):
"""Draw rainbow that uniformly distributes itself across all pixels."""
for j in range(256*iterations):
for i in range(strip.numPixels()):
strip.setPixelColor(i, wheel((int(i * 256 / strip.numPixels()) + j) & 255))
strip.show()
time.sleep(wait_ms/1000.0)
def theaterChaseRainbow(strip, wait_ms=90):
"""Rainbow movie theater light style chaser animation."""
for j in range(256):
for q in range(3):
for i in range(0, strip.numPixels(), 3):
strip.setPixelColor(i+q, wheel((i+j) % 255))
strip.show()
time.sleep(wait_ms/1000.0)
for i in range(0, strip.numPixels(), 3):
strip.setPixelColor(i+q, 0)
# Plasma LED Function from Root 42
def plasmaLED (plasmaTime):
h = 8
w = 32
out = [ Color( 0, 0, 0 ) for x in range( h * w ) ]
plasmaBright = 100.0
for x in range( h ):
for y in range( w ):
hue = (4.0 + math.sin( plasmaTime + x ) + math.sin( plasmaTime + y / 4.5 ) \
+ math.sin( x + y + plasmaTime ) + math.sin( math.sqrt( ( x + plasmaTime ) ** 2.0 + ( y + 1.5 * plasmaTime ) ** 2.0 ) / 4.0 ))/8
hsv = colorsys.hsv_to_rgb( hue , 1, 1 )
if y % 2 == 0: #even
out[ x + (h * y)] = Color( *[ int( round( c * plasmaBright ) ) for c in hsv ] )
else: #odd
out[ (y * h) + (h -1 -x) ] = Color( *[ int( round( c * plasmaBright ) ) for c in hsv ] )
for i in range( 0, strip.numPixels(), 1 ):# iterate over all LEDs - range(start_value, end_value, step)
strip.setPixelColor(i, out[ i ]) # set pixel to color in picture
strip.show()
# variables for plasma
plasmaTime = 5.0 # time
plasmaSpeed = 0.05 # speed of time
# thread for IRcounter function
class TempTask:
def __init__(self):
self.ir_temp = 0
self.lock = threading.Lock() #control concurrent access for safe multi thread access
self.thread = threading.Thread(target=self.update_temp)
def update_temp(self):
while True:
with self.lock:
self.ir_temp = irCounter()
time.sleep(0.1)
def start(self):
self.thread.start()
# Millis timer count function
def CheckTime( lastTime, wait):
if currentTime - lastTime >= wait:
lastTime += wait
return True
return False
# Main program logic follows:
if __name__ == '__main__':
# not currently starting the trhead because program is locking up without it
# want to figure out initial problem first
#start thread
#task = TempTask()
#task.start()
# Create NeoPixel object with appropriate configuration.
strip = Adafruit_NeoPixel(LED_COUNT, LED_PIN, LED_FREQ_HZ, LED_DMA, LED_INVERT, LED_BRIGHTNESS, LED_CHANNEL)
# Intialize the library (must be called once before other functions).
strip.begin()
print ('Press Ctrl-C to quit.')
try:
while True:
currentTime = int(round(time.time() * 1000))
if IRcount == 0:
#random solid color
colorWipe(strip, Color(random.randint(60,255), random.randint(60,255), random.randint(60,255)))
# use random.sample() to shuffle sounds list
shuffledSounds = random.sample(soundsList, len(soundsList))
if pygame.mixer.Channel(0).get_busy() == False: channel0.play(shuffledSounds[0],loops = -1)
thresh = 0
'''
# the threshold check below is the only thing I have taken out of
# Program on my test Raspberry Pi. It seems to not lock up without it
# not sure why this would be a problem.
thresh = int(maxTemp())
print (thresh)
if thresh >= 27:
InflateWait = int(round(time.time() * 1000))
print (thresh)
IRcount = 1
print("Threshold Temp Detected: Begin Sound Sequence")
else:
IRcount = 0
'''
if CheckTime(InflateWait,random.randint(minTime, maxTime)):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
print(IRcount)
elif IRcount == 1:
LEDimages = glob.glob("/home/pi/ruff-wavs/Crystal_Mirror/*.png")
for LEDimage in sorted(LEDimages):
pngToLED (strip, LEDimage)
if pygame.mixer.Channel(1).get_busy() == False:
channel1.play(shuffledSounds[1],loops = -1)
waitTime = random.randint(minTime, maxTime)
if CheckTime(InflateWait,waitTime):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
print(IRcount)
elif IRcount == 2:
LEDimages = glob.glob("/home/pi/ruff-wavs/Mercury_Loop/*.png")
for LEDimage in sorted(LEDimages):
pngToLED (strip, LEDimage)
if pygame.mixer.Channel(2).get_busy() == False:
channel2.play(shuffledSounds[2],loops = -1)
waitTime = random.randint(minTime, maxTime)
if CheckTime(InflateWait,waitTime):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
print(IRcount)
elif IRcount == 3:
LEDimages = glob.glob("/home/pi/ruff-wavs/Pink_Lava/*.png")
for LEDimage in sorted(LEDimages):
pngToLED (strip, LEDimage)
if pygame.mixer.Channel(3).get_busy() == False:
channel3.play(shuffledSounds[3],loops = -1)
waitTime = random.randint(minTime, maxTime)
if CheckTime(InflateWait,waitTime):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
print(IRcount)
elif IRcount == 4:
LEDimages = glob.glob("/home/pi/ruff-wavs/Horiz_Mosaic/*.png")
for LEDimage in sorted(LEDimages):
pngToLED (strip, LEDimage)
if pygame.mixer.Channel(4).get_busy() == False:
channel4.play(shuffledSounds[4],loops = -1)
waitTime = random.randint(minTime, maxTime)
if CheckTime(InflateWait,waitTime):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
print(IRcount)
elif IRcount == 5:
plasmaLED()
plasmaTime = plasmaTime + plasmaSpeed # increment plasma time
if pygame.mixer.Channel(5).get_busy() == False:
channel5.play(shuffledSounds[5],loops = -1)
waitTime = random.randint(minTime, maxTime)
if CheckTime(InflateWait,waitTime):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
print(IRcount)
elif IRcount == 6:
LEDimages = glob.glob("/home/pi/ruff-wavs/Radio_Loop/*.png")
for LEDimage in sorted(LEDimages):
pngToLED (strip, LEDimage)
if pygame.mixer.Channel(6).get_busy() == False:
channel6.play(shuffledSounds[6],loops = -1)
waitTime = random.randint(minTime, maxTime)
if CheckTime(InflateWait,waitTime):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
print(IRcount)
elif IRcount == 7:
LEDimages = glob.glob("/home/pi/ruff-wavs/Star_Loop/*.png")
for LEDimage in sorted(LEDimages):
pngToLED (strip, LEDimage)
if pygame.mixer.Channel(7).get_busy() == False:
channel7.play(shuffledSounds[7],loops = -1)
waitTime = random.randint(minTime, maxTime)
if CheckTime(InflateWait,waitTime):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
elif IRcount == 14:
plasmaLED()
plasmaTime = plasmaTime + plasmaSpeed # increment plasma time
if pygame.mixer.Channel(14).get_busy() == False:
channel14.play(shuffledSounds[14],loops = -1)
waitTime = random.randint(minTime, maxTime)
if CheckTime(InflateWait,waitTime):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
print(IRcount)
print (thresh)
elif IRcount == 15:
plasmaLED()
plasmaTime = plasmaTime + plasmaSpeed # increment plasma time
if pygame.mixer.Channel(15).get_busy() == False:
channel15.play(shuffledSounds[15],loops = -1)
waitTime = random.randint(minTime, maxTime)
if CheckTime(InflateWait,waitTime):
InflateWait = int(round(time.time() * 1000))
IRcount += 1
print(IRcount)
elif IRcount == 16:
# random color theater chase increment random ms to speed up with sounds
theaterChase(strip, Color(random.randint(1,255), random.randint(1,255), random.randint(1,255)), random.randint(40,50))
pygame.mixer.fadeout(45000)
if pygame.mixer.Channel(22).get_busy() == False:
channel22.play(presatisfactionsweep)
IRcount = 17
print(IRcount)
print("sweep end start")
elif IRcount == 18:
# random color theater chase increment random ms to speed up with sounds
theaterChase(strip, Color(random.randint(1,255), random.randint(1,255), random.randint(1,255)), random.randint(30,40))
if pygame.mixer.Channel(22).get_busy() == False:
pygame.mixer.stop()
channel23.play(satisfaction)
IRcount = 19
print(IRcount)
print("Play Satisfaction Sount")
elif IRcount == 19:
rainbowCycle(strip, 5)
if pygame.mixer.Channel(23).get_busy() == False: IRcount = 0
except KeyboardInterrupt:
colorWipe(strip, Color(0,0,0), 1)
pygame.mixer.stop()
pygame.quit()
```
Update 1 - Suspected Function(s)
When I left the script run overnight and came to the exhibit in the morning it would be stuck in the 1st state IRcount = 0 The only things that happen in that state is the maxTemp() function to get the max temp, the LED color wipe function to cycle colors.
When I would come in in the morning it would be stuck, playing a single sound from pygame, as it should, but it would not be cycling colors. I removed the maxTemp() from my test Pi and it has been working fine.
def maxTemp():
mlx.setup(8) #set frame rate of MLX90640
f = mlx.get_frame()
mlx.cleanup()
# get max and min temps from sensor
# v_min = min(f)
v_max = int(max(f))
return v_max
Update # 2
I thought that the thread might be the problem so I commented out the thread start call. That is why I made the simpler maxTemp() function to see if that would work better than the thread. So when I was using the max temp then the thread wasn't being called.
I don't understand threads very well. Is it possible to have the max temp variable update continuously and have the simple OpenCV numPy manipulations running continuously? That would be ideal. When I originally added the thread it seemed to stop after a few cycles.
I do not have a join on the thread. I know threads don't "restart" but do I need to call it again as the state machine starts again?
# not currently starting the thread because program is locking up without it
# want to figure out initial problem first
#start thread
#task = TempTask()
#task.start()
Update #3
I Uploaded new code that eliminated the duplicate functions. Everything is handled in the thread temp.task now. That seems to work fine. I also put the github suggestion of polling the thermal sensor if the image is a duplicate but that has not happened.
I left the program run over night and when I came in in the morning it was locked up. The SD card is set to read only mode. I ssh'd into the pi. I have my auto start python script in /etc/profile
It seems to start the script each time I log into ssh. When I logged in this morning to see if the pi was still up it game an out of memory error.
```
Traceback (most recent call last):
File "/home/pi/ruff-wavs/shufflewavdemo.py", line 210, in <module>
altsatisfaction = pygame.mixer.Sound("/home/pi/ruff-wavs/sounds/alt_satisfaction_trimmed.ogg")
pygame.error: Unable to open file '/home/pi/ruff-wavs/sounds/alt_satisfaction_trimmed.ogg'
OSError: [Errno 28] No space left on device
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/lib/python3.5/runpy.py", line 193, in _run_module_as_main
"__main__", mod_spec)
File "/usr/lib/python3.5/runpy.py", line 85, in _run_code
exec(code, run_globals)
File "/usr/local/lib/python3.5/dist-packages/virtualenvwrapper/hook_loader.py", line 223, in <module>
main()
File "/usr/local/lib/python3.5/dist-packages/virtualenvwrapper/hook_loader.py", line 145, in main
output.close()
OSError: [Errno 28] No space left on device
-bash: cannot create temp file for here-document: No space left on device
Could that be because it is in read only mode?
I used this script to switch from writable to read only and back.
[https://github.com/JasperE84/root-ro][1]
[1]: https://github.com/JasperE84/root-ro
I suspect the issue is that you're accessing the mlx device both in the main thread via maxTemp() as well as in the irCounter() thread. The fact that it works when you take out the maxTemp call, and that that call happens in the if IRcount == 0: state supports this.
I would add the maxTemp functionality to the irCounter thread, so that accessing it from only a single thread; and update a global variable (protected by a lock) with the maxTemp results if you need to retain this functionality.