我是Python的新手,希望有人能为我指出正确的方向,关于我的代码中的逻辑问题。
该程序运行良好,行为,据我所能理解,正如我所期望的。但是现在,当killswitch按钮被按下时(我可以在输出中看到按钮被按下,并且killswitch变量被设置为True),线程继续工作而不停止。当按钮被按下时,我希望kill_processes方法运行。为什么线程不能优雅地死去,程序不能像我希望的那样结束?我错过了什么?
# Source: rplcd.readthedocs.io/en/stable/getting_started.html
# https://www.circuitbasics.com/raspberry-pi-lcd-set-up-and-programming-in-python/
# LCD R Pi
# RS GPIO 26 (pin 37)
# E GPIO 19 (35)
# DB4 GPIO 13 (33)
# DB5 GPIO 6 (31)
# DB6 GPIO 5 (29)
# DB7 GPIO 11 / SCLK (23)
# WPSE311/DHT11 GPIO 24 (18)
# Relay Fog GPIO 21 (40)
# Relay Oxy GPIO 20 (38)
# Relay LED GPIO 16 (36)
# Button Killsw. GPIO 12 (32)
# Imports--- [ToDo: How to import settings from a configuration file?]
import adafruit_dht, board, digitalio, threading
import adafruit_character_lcd.character_lcd as characterlcd
import RPi.GPIO as GPIO
from time import sleep, perf_counter
from gpiozero import CPUTemperature
from datetime import datetime
# Compatible with all versions of RPI as of Jan. 2019
# v1 - v3B+
lcd_rs = digitalio.DigitalInOut(board.D26)
lcd_en = digitalio.DigitalInOut(board.D19)
lcd_d4 = digitalio.DigitalInOut(board.D13)
lcd_d5 = digitalio.DigitalInOut(board.D6)
lcd_d6 = digitalio.DigitalInOut(board.D5)
lcd_d7 = digitalio.DigitalInOut(board.D11)
# Define LCD column and row size for 16x2 LCD.
lcd_columns = 16
lcd_rows = 2
# Initialise the lcd class---
lcd = characterlcd.Character_LCD_Mono(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6,
lcd_d7, lcd_columns, lcd_rows)
# Init sensors---
dhtDevice_nutrient_mist = adafruit_dht.DHT11(board.D24, use_pulseio=False)
#dhtDevice_xx = adafruit_dht.DHT22(board.Dxx, use_pulseio=False)
#dhtDevice = adafruit_dht.DHT11(board.D24, use_pulseio=False)
# Define relays
relay_fogger = 21 #digitalio.DigitalInOut(board.D21) #- Why does this not work?
relay_oxygen = 20 #digitalio.DigitalInOut(board.D20) #- Why does this not work?
relay_led = 16 #digitalio.DigitalInOut(board.D16) #- Why does this not work?
# Init relays---
GPIO.setwarnings(False)
GPIO.setup(relay_fogger, GPIO.OUT)
GPIO.setup(relay_oxygen, GPIO.OUT)
GPIO.setup(relay_led, GPIO.OUT)
# Define liquid nutrient temperature probe
liquid_nutrients_probe = 16 #digitalio.DigitalInOut(board.D16) - Why does this not work?
# Define the killswitch push button
GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
# Global variables---
killswitch = False
# Fogger bucket vars
temp_nutrient_solution = 0
temp_nutrient_mist = 0
humidity_nutrient_mist = 0
fogger_on_seconds = 2700 #45 min
fogger_off_seconds = 900 #15 min
sleep_fogger = False
# Grow bucket vars
temp_roots = 0
humidity_roots = 0
# Oxygen bucket vars
sleep_oxygen = False
# Rapsberry Pi internal temperature
rpi_internal_temp = 0
# Methods---
def get_temp_nutrient_solution(killswitch): # Temp för näringsväska. KLAR för TEST
"""Measure the temperature of the nutrient solution where the ultrasonic fogger is."""
while not killswitch:
global temp_nutrient_solution
temp_nutrient_solution = 22
#lcd.message = datetime.now().strftime('%b %d %H:%M:%S\n')
#lcd.message = "Dummy temp liquid solution:/n {:.1f}C".format(temp_nutrient_solution)
# For development process
print(
"T: {:.1f} C / {:.1f} F".format(
temp_nutrient_solution, c2f(temp_nutrient_mist)
)
)
sleep(1)
def get_temp_humidity_nutrient_mist(killswitch): # Temp och fuktighet för ånga. KLAR för TEST
"""Measure the tmeperature and humidity of the nutrient mist where the ultrasonic fogger is."""
while not killswitch:
try:
# Update global temp value and humidity once per second
global temp_nutrient_mist
global humidity_nutrient_mist
temp_nutrient_mist = dhtDevice_nutrient_mist.temperature
humidity_nutrient_mist = dhtDevice_nutrient_mist.humidity
# For development process
print(
"T: {:.1f} C / {:.1f} F Humidity: {}% ".format(
temp_nutrient_mist, c2f(temp_nutrient_mist), humidity_nutrient_mist
)
)
except RuntimeError as error:
# Errors happen fairly often, DHT's are hard to read, just keep going
print(error.args[0])
sleep(1) # sleep(1) for DHT11 and sleep(2) for DHT22
pass
except Exception as error:
dhtDevice.exit()
kill_processes() # Förbättra denna här så att den ska visa vilken DHT-enhet som har fått error
raise error
sleep(1)
def relay_fogger_control(killswitch, sleep_fogger): # Fogger av eller på
"""Fogger on for 45 min and off for 15. Perpetual mode unless kill_processes() is activated"""
while not killswitch or sleep_fogger:
GPIO.output(relay_fogger, GPIO.HIGH)
sleep(1)
#sleep(fogger_on_seconds)
GPIO.output(relay_fogger, GPIO.LOW)
sleep(1)
#sleep(fogger_off_seconds)
def relay_heatLED_control(killswitch): # Värmelampa LED av eller på
"""Heat LED controller. When is it too hot for the crops? Sleep interval? Perpetual mode unless kill_processes() is activated"""
while not killswitch:
GPIO.output(relay_led, GPIO.HIGH)
sleep(3)
#sleep(fogger_on_seconds)
GPIO.output(relay_led, GPIO.LOW)
sleep(3)
#sleep(fogger_off_seconds)
def relay_oxygen_control(killswitch, sleep_oxygen): # Syremaskin av eller på
"""Oxygen maker. Perpetual mode unless kill_processes() is activated"""
while not killswitch or sleep_oxygen:
GPIO.output(relay_oxygen, GPIO.HIGH)
sleep(5)
#sleep(fogger_on_seconds)
GPIO.output(relay_oxygen, GPIO.LOW)
#sleep(fogger_off_seconds)
sleep(5)
def kill_processes(): # Döda alla processer
"""ToDo: A button must be pressed which gracefully kills all processes preparing for shutdown."""
# Power off machines
GPIO.output(relay_fogger, GPIO.LOW)
GPIO.output(relay_led, GPIO.LOW)
GPIO.output(relay_oxygen, GPIO.LOW)
# Joined the threads / stop the threads after killswitch is true
t1.join()
t2.join()
t3.join()
t4.join()
t5.join()
#t6.join()
reset_clear_lcd()
# Stop message and GPIO clearing
lcd.message = 'Full stop.\r\nSafe to remove.'
GPIO.cleanup()
def reset_clear_lcd(): # Reset och rensa LCD
"""Move cursor to (0,0) and clear the screen"""
lcd.home()
lcd.clear()
def get_rpi_temp(): # Reset och rensa LCD
"""Move cursor to (0,0) and clear the screen"""
global rpi_internal_temp
cpu = CPUTemperature()
rpi_internal_temp = cpu.temperature
def c2f(temperature_c):
"""Convert Celsius to Fahrenheit"""
return temperature_c * (9 / 5) + 32
def lcd_display_data_controller(killswitch): # LCD display data controller
"""Display various measurments and data on the small LCD. Switch every four seconds."""
while not killswitch:
reset_clear_lcd()
# Raspberry Pi internal temperature
lcd.message = (
"R Pi (int. temp): \n{:.1f}C/{:.1f}F ".format(
rpi_internal_temp, c2f(rpi_internal_temp)
)
)
sleep(5)
reset_clear_lcd()
# Nutrient liquid temperature
lcd.message = (
"F1: {:.1f}C/{:.1f}F ".format(
temp_nutrient_solution, c2f(temp_nutrient_solution)
)
)
sleep(5)
reset_clear_lcd()
# Nutrient mist temperature and humidity
lcd.message = (
"F2: {:.1f}C/{:.1f}F \nHumidity: {}% ".format(
temp_nutrient_mist, c2f(temp_nutrient_mist), humidity_nutrient_mist
)
)
sleep(5)
reset_clear_lcd()
# Root temperature and humidity
lcd.message = (
"R1: {:.1f}C/{:.1f}F \nHumidity: {}% ".format(
temp_roots, c2f(temp_roots), humidity_roots
)
)
sleep(5)
reset_clear_lcd()
def button_callback(channel):
global killswitch
print("Button was pushed!")
killswitch = True
# Init the button
GPIO.add_event_detect(12, GPIO.RISING, callback=button_callback)
# Create the threads
#tx = threading.Thread(target=xx, args=(killswitch,sleep_fogger,))
t1 = threading.Thread(target=get_temp_nutrient_solution, args=(killswitch,))
t2 = threading.Thread(target=get_temp_humidity_nutrient_mist, args=(killswitch,))
t3 = threading.Thread(target=relay_fogger_control, args=(killswitch,sleep_fogger,))
t4 = threading.Thread(target=lcd_display_data_controller, args=(killswitch,))
t5 = threading.Thread(target=get_rpi_temp)
#t6 = threading.Thread(target=killswitch_button)
# Start the threads
t1.start()
t2.start()
t3.start()
t4.start()
t5.start()
#t6.start()
# Code main process---
while not killswitch:
sleep(1)
# Graceful exit
kill_processes()
1条答案
按热度按时间vtwuwzda1#
可以不将kill开关作为参数传递,而是将其视为方法内部的全局参数。我在想,既然它是一个布尔型(基本类型),它是通过值传递的(复制的,值只是来自
False
,它是从全局定义分离的),而不是通过引用传递的。也许你所需要做的就是删除传递函数的参数(并从线程启动调用中删除它们),并将每个方法中的变量标记为全局变量,如:
global killSwitch
看起来您在
button_callback
方法中这样做了,但在其他方法中没有。你可以在这里看到例子:Python creating a shared variable between threads
希望这能帮上忙。