Run function in the background and clear a list - python

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()

Related

Arduino extract data from serial monitor

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);

Issues with filtering Tweepy streams

I am working on a project where my code needs to react when a Twitter user tweets #foo using #bar. I have followed the tutorial here https://docs.tweepy.org/en/latest/streaming_how_to.html and I have my code partially working. The issue is that it works when I tweet "#foo I like #bar" but I get no response when I tweet "#foo #bar" (see my code below). Has anyone else had this issue?
import tweepy
import threading
import random
import board
import neopixel
import random
import colorsys
import numpy as np
import time
from adafruit_servokit import ServoKit
import busio
import adafruit_pca9685
from scipy.interpolate import interp1d
i2c = busio.I2C(board.SCL, board.SDA)
hat = adafruit_pca9685.PCA9685(i2c)
# Set channels to the number of servo channels on your kit.
# 8 for FeatherWing, 16 for Shield/HAT/Bonnet.
kit = ServoKit(channels=16, frequency=50)
pixel_pin = board.D18
num_pixels = 300
ORDER = neopixel.GRB
pixels = neopixel.NeoPixel(
pixel_pin, num_pixels, brightness=0.2, auto_write=False, pixel_order=ORDER
)
access_token = "1345547423154888706-VibtuSn31Aeu4e827GKaZmEnCVxsj7"
access_token_secret = "VfciVdPUW5STkVePYewyMTEWYo5rXhgOOHqyLFW5vk7tU"
consumer_key = "jrJFgRGHTg8MH8gcwgUMiL9lO"
consumer_secret = "UXOCkkEj1Y2eDzqzfKtqnC8K0IvsrdtzBe2sprIwDkqrLTHQes"
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
auth.set_access_token(access_token, access_token_secret)
api = tweepy.API(auth)
# for tweet in tweepy.Cursor(api.search, q="#PerotMuseum", rpp=100).items():
# inCaps = tweet.text.upper()
# if not "RT " in inCaps:
# if "#FOSSILFRIDAY" in inCaps:
# print(tweet.user.name+":")
# print(tweet.text.encode(encoding='UTF-8',errors='strict'))
# #print("\n")
#
class Listener(tweepy.StreamListener):
def __init__(self):
super(Listener,self).__init__()
def on_status(self, status):
inCaps = status.text.upper()
if not "RT " in inCaps:
print("========== "+status.user.name+" ==========")
print(status.text+"\n")
t_end = time.time() + 12
t1 = threading.Thread(target=marquee, args=(10, pickColor(), t_end,))
t2 = threading.Thread(target=loop, args=(t_end,))
# t2 = threading.Thread(target=wave, args=())
t1.start()
t2.start()
t1.join()
t2.join()
motorDefault()
detachServos()
pixels.fill((0,0,0))
pixels.show()
def on_error(self, status_code):
print(status_code)
return False
def SMOOTHERSTEP(x):
# return((x) * (x) * (x) * ((x) * ((x) * 6 - 15) + 10))
return np.sin(x * 3.1415 / 2);
def interp(start, stop, t, totsteps):
v = t / totsteps
v = SMOOTHERSTEP(v)
val = (start * v) + (stop * (1 - v))
# print (val)
return val
def pickColor():
h = random.random()
color = colorsys.hsv_to_rgb(h, 1, 1)
color = np.multiply(color, 255)
color = np.floor(color).astype(int)
return(color)
def loop(t_end):
steps = 130
step = 0.0
steps = steps/4
while time.time() < t_end:
# marquee(10, color, int(step))
if step < steps:
i = step
kit.servo[0].angle = interp(130, 95, i, steps)
kit.servo[1].angle = interp(180, 30, i, steps)
kit.servo[2].angle = interp(110, 140, i, steps)
kit.servo[3].angle = interp(120, 90, i, steps)
step+=1
elif step < steps * 2:
i = step - steps
kit.servo[0].angle = interp(95, 130, i, steps)
kit.servo[1].angle = interp(30, 180, i, steps)
kit.servo[2].angle = interp(140, 110, i, steps)
kit.servo[3].angle = interp(90, 120, i, steps)
step+=1
elif step < steps * 3:
i = step - steps * 2
kit.servo[0].angle = interp(130, 95, i, steps)
kit.servo[1].angle = interp(60, 30, i, steps)
kit.servo[2].angle = interp(110, 140, i, steps)
kit.servo[3].angle = interp(60, 90, i, steps)
step+=1
elif step < steps * 4:
i = step - steps * 3
kit.servo[0].angle = interp(95, 130, i, steps)
kit.servo[1].angle = interp(30, 60, i, steps)
kit.servo[2].angle = interp(140, 110, i, steps)
kit.servo[3].angle = interp(90, 60, i, steps)
step+=1
else:
step = 0
def marquee(width, color, t_end):
t = 0
while time.time() < t_end:
i = (t%width)
while i < num_pixels:
for x in range(int(width/2)):
pixels[int(i-x)] = color
i+=width
pixels.show()
pixels.fill((0,0,0))
t+=1
pixels.fill((0,0,0))
pixels.show()
# def marquee(width, color, step):
# for i in range(num_pixels):
# if(i % width < width/2):
# if(i + step < num_pixels):
# pixels[i+step] = color
# else:
# pixels[i+step-num_pixels] = color
# pixels.show()
# pixels.fill((0,0,0))
def wave():
kit.servo[1].angle = 180#30 right arm
time.sleep(2)
kit.servo[1].angle = 160#30 right arm
time.sleep(.25)
kit.servo[1].angle = 180#30 right arm
time.sleep(.25)
kit.servo[1].angle = 160#30 right arm
time.sleep(.25)
kit.servo[1].angle = 180#30 right arm
time.sleep(.25)
kit.servo[1].angle = 30#30 right arm
def detachServos():
for i in range(16):
channel = hat.channels.__getitem__(i)
channel.duty_cycle = 0
def motorDefault():
kit.servo[0].angle = 100#90 skull
kit.servo[1].angle = 30#30 right arm
kit.servo[2].angle = 140#150 left arm
kit.servo[3].angle = 90#90 head
time.sleep(.5)
try:
marquee(10, pickColor(), time.time() + 3)
myStreamListener = Listener()
myStream = tweepy.Stream(auth = api.auth, listener=myStreamListener)
myStream.filter(track=['#Foo', '#Bar'], languages=['en'])
except:
motorDefault()
detachServos()
print("something went wrong")
I figured it out. By filtering only English results it was excluding tweets that include only hashtags and handles. I assume this is because hashtags and handles are excluded in language calculations because they can be in any language and not necessarily reflect the language of the tweet itself.
so the solution was changing this:
myStream.filter(track=['#Foo', '#Bar'], languages=['en'])
to this:
myStream.filter(track=['#Foo', '#Bar'])

Index Error, countdown calendar not working

Can you help me with my code?
I wanted an if-else statement, that if there is no description for the festival is given, it displays there is no info about that particular festival. But for that, I would have to do if not(event[2]) but for that, it shows
Traceback (most recent call last):
File "C:\Users\kanav_i4cko4c\Downloads\My first tkinter program.py", line 52, in <module>
if (event[2]):
IndexError: list index out of range
Here is the source code for festivals.txt
Diwali,5/11/21
Christmas,25/12/21
Here is the source code for the main program
from tkinter import Tk, Canvas, simpledialog, messagebox
from datetime import date, datetime
# function get_events is to get the celebration events
def get_events():
list_events = []
with open('festivals.txt') as file:
for line in file:
line1 = line.rstrip('\n')
global current_event
current_event = line1.split(',')
print('Check 0')
print(current_event)
current_event[1] = datetime.strptime(current_event[1], '%d/%m/%y').date()
list_events.append(current_event)
return list_events
def days_between_dates(date1, date2):
time_between = str(date1 - date2)
number_of_days = time_between.split(' ')
return number_of_days[0]
# End of Functions
# -----------------------------------------------------------------------------------------------
# Main program starts here
root = Tk()
root.title('Calendar')
c = Canvas(root, width=2000, height=800, bg='dark blue')
c.pack()
c.create_text(100, 50, anchor='w', fill='white', font=' Times 40 bold underline',
text='My Countdown Calendar')
c.create_rectangle(30, 10, 60, 1000,
outline="#fb0", fill="#fb0")
events = get_events()
today = date.today()
# Make a dictionary for the festivals
vertical_space = 100
events.sort(key=lambda x: x[1])
horizontal_space = 100
for event in events:
event_name = event[0]
days_until = days_between_dates(event[1], today)
if (event[2]):
display = 'It is %s days until %s. %s = %s' % (days_until, event_name, event_name,event[2])
else:
display = 'It is %s days until %s. There is no info on %s' % (days_until, event_name, event_name)
if (int(days_until) <= 50):
text_col = '#c11a2b'
else:
text_col = 'SkyBlue1'
c.create_text(100, vertical_space, anchor='w', fill=text_col,
font='Calibri 28 bold', text=display)
vertical_space = vertical_space + 30
horizontal_space = horizontal_space + 40
When you evaluate event[2] it attempts to retrieve the 3rd item in the list which isn't there so python raises an exception.
One solution could be by initializing your list with default values:
event = [None for i in range(3)]
This way there is a None value at event[2] which can be evaluated by your if statement.
Another solution could be to simply check whether the list contains less than 3 items:
if len(event) <= 2:
# do something

Multithreading in tkinter using window.after

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.

Python Script for Art Museum Installation intermittently locks up, Removing Thermal Camera Sensor read function seems to work?

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.

Categories