Python错误逻辑2

cgvd09ve  于 2023-06-28  发布在  Python
关注(0)|答案(1)|浏览(160)

我是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()
vtwuwzda

vtwuwzda1#

可以不将kill开关作为参数传递,而是将其视为方法内部的全局参数。我在想,既然它是一个布尔型(基本类型),它是通过值传递的(复制的,值只是来自False,它是从全局定义分离的),而不是通过引用传递的。
也许你所需要做的就是删除传递函数的参数(并从线程启动调用中删除它们),并将每个方法中的变量标记为全局变量,如:global killSwitch
看起来您在button_callback方法中这样做了,但在其他方法中没有。
你可以在这里看到例子:Python creating a shared variable between threads
希望这能帮上忙。

相关问题