线程计时器-树莓派上的NoneType错误-将变量传递给另一个线程



我是初级python开发人员,主要是后台Django。我工作中的第一项任务是在树莓派上编写程序,将状态设置为LOW,5秒后设置为HIGH

似乎不是问题,但是。。。。我认为等待5秒更改为HIGH的正确方式不是通过time.sleep(),而是通过threading.Timer(我在stackoverflow上找到了它(。。。它将通过网络套接字连接,所以我认为一个线程必须侦听,另一个线程则必须更改状态

我的问题是一半是蟒蛇,一半是树人。。。这是我的代码:

import RPi.GPIO as GPIO
from threading import Timer
from time import sleep
pin = 22
GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT)
def set_high():
GPIO.output(pin, GPIO.HIGH)
def web_socket_loop():
GPIO.output(pin, GPIO.LOW)
t = Timer(5, set_high(GPIO))
t.start()

web_socket_loop()
GPIO.cleanup()

当我运行这个代码时,状态正在改变,但几秒钟后我也得到了一个错误:

Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.7/threading.py", line 1158, in run
self.function(*self.args, **self.kwargs)
TypeError: 'NoneType' object is not callable

我在堆栈上发现我必须这样做:(但它不能正常工作(:;/

t = Timer(5, set_high, args=[GPIO])

它确实修复了关于NoneType的错误。。。但我又犯了一个错误:

Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/local/lib/python3.7/threading.py", line 917, in _bootstrap_inner
self.run()
File "/usr/local/lib/python3.7/threading.py", line 1158, in run
self.function(*self.args, **self.kwargs)
RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)

我可能知道这个错误的原因,但不知道如何处理。我认为在另一个线程上RPi.GPIO没有配置(GPIO.setmode(GPIO.BCM), GPIO.setup(pin, GPIO.OUT))

这就是为什么我将GPIO作为变量传递给函数set_high(GPIO),而在另一个线程上没有它,它认为RPi没有配置。。。传递这个变量很酷,但是。。。我收到NoneType错误…;/

当我用Timer(5, set_high, args=[GPIO])尝试第二种方法时,NoneType错误消失,但发生了另一个错误(RuntimeError with info about pin setup(。。。这与我没有将GPIO传递给这样的函数时得到的错误相同

def set_high(#i_dont_pass_GPIO):
#things
pass

将GPIO变量传递给另一个线程的正确方法是什么?以便它能正确地识别这个变量并将引脚22设置为高电平。

或者你建议换一种方式试试?也许睡眠更好?但它将通过网络套接字连接,所以我认为一个必须倾听,另一个必须改变状态?

我感谢任何帮助!!

您的第一个问题和第三个问题实际上并不相关,因为您已经正确地解决了它们。

当您调用Timer(5, set_high(GPIO))时,它现在调用set_high(GPIO),并传递它返回的任何内容作为Timer要调用的目标函数。由于它在5秒后返回None,因此Timer会尝试将None作为函数调用,从而生成TypeError

修复正是你已经做的:

Timer(5, set_high, [GPIO])

现在,一旦你解决了这个问题,就要仔细思考你所要求的控制流程。

首先,你要这样做:

GPIO.setmode(GPIO.BCM)
GPIO.setup(pin, GPIO.OUT)

然后你调用web_socket_loop,它会这样做:

GPIO.output(pin, GPIO.LOW)

然后它创建并启动一个Timer,然后返回。你这样做:

GPIO.cleanup()

然后,5秒后,计时器关闭并调用set_high函数,该函数执行以下操作:

GPIO.output(pin, GPIO.HIGH)

清理GPIO后,无法将引脚设置为高电平。

错误消息有点误导:

RuntimeError: Please set pin numbering mode using GPIO.setmode(GPIO.BOARD) or GPIO.setmode(GPIO.BCM)

这是因为清理后的状态与初始化前的状态相同,所以它假设您的问题是还没有通过调用setmode来初始化。


你怎么能解决这个问题?你的主线不应该试图清理,直到你完成。

通常,主线程还有其他事情要做。这就是为什么要使用TimerThread或其他形式的并发。但当你这样做的时候,你需要给你的主线程一些方法来等待后台工作完成,或者你需要找到一些方法来把事情链接起来,这样cleanup只在最后一个线程使用GPIO完成之后发生。

当你添加处理通过websocket进行通信的代码时,你需要做其中一件事。但是,如果不知道如何组织代码,就不可能向您展示您应该做什么。

同时,除了等待5秒之外,您真的没有其他事情可做,所以您不需要任何并发;仅sleep:

def web_socket_loop():
GPIO.output(pin, GPIO.LOW)
time.sleep(5)
set_high(GPIO)

最新更新