PiZero W连接到两个外围设备(GPIO和USB):如何同时从两个外围设备连续读取?

时间:2019-10-21 18:21:15

标签: python raspberry-pi raspberry-pi-zero

我有一个覆盆子pizero W,它通过GPIO引脚连接到流量计,并通过USB连接到条形码扫描仪。我有python脚本,当检测到GPIO输入时,该脚本使用回调函数来发出警报。该python脚本需要在pizero上连续运行,以便识别流量计何时激活并处理输入。

问题是我还通过USB将条形码扫描仪连接到pizero。我希望pizero也能识别出何时扫描条形码并也处理该输入。

然后,pizero应该发送一条消息,其中包含来自流量计的信息和来自条形码扫描仪的信息。

有没有办法在相同的python脚本中执行此操作?如何同时从两个输入进行pizero侦听和处理?将其分成两个不同的脚本是否更容易实现,如果可以,我是否可以同时运行它们并以某种方式统一它们在第三个连续运行的脚本中提供的信息?

谢谢!

每个评论有一些澄清(感谢您的输入):

  • 流量计的输入引脚为GPIO 17,这是SPI连接
  • 还连接了5V电源和接地引脚。

该脚本需要在系统启动时运行。我将看看systemctl,直到被提及之前我才听说过。

未安装流量计时,Pi通常会将正在扫描的条形码识别为键盘输入(即一系列数字后跟换行符)。

当我发送包含流量计和条形码信息的消息时,我需要从python发送一个JSON对象,该对象既包含信息,又包含接收信息的时间戳。

此JSON对象将通过wifi发送到具有与pizero相同的家庭网络上的静态ip的树莓派服务器。 raspberry pi服务器可以访问Django数据库,该数据库应将JSON对象信息合并到数据库中。

2 个答案:

答案 0 :(得分:1)

更新后的答案

我为条形码阅读器添加了一些代码。我这样做是为了使条形码读取器花费可变的时间,最多花费5秒来读取数据,而流量计花费恒定的0.5秒,以便您可以看到不同的线程以彼此独立的速率进行传输。

#!/usr/bin/env python3

from threading import Lock
import threading
import time
from random import seed
from random import random

# Dummy function to read SPI as I don't have anything attached
def readSPI():
    # Take 0.5s to read
    time.sleep(0.5)
    readSPI.static += 1
    return readSPI.static
readSPI.static=0

class FlowMeter(threading.Thread):
    def __init__(self):
        super(FlowMeter, self).__init__()
        # Create a mutex
        self.mutex = Lock()
        self.currentReading = 0

    def run(self):
        # Continuously read flowmeter and safely update self.currentReading
        while True:
            value = readSPI()
            self.mutex.acquire()
            self.currentReading = value
            self.mutex.release()

    def read(self):
        # Main calls this to get latest reading, we just grab it from internal variable
        self.mutex.acquire()
        value = self.currentReading
        self.mutex.release()
        return value

# Dummy function to read Barcode as I don't have anything attached
def readBarcode():
    # Take variable time, 0..5 seconds, to read
    time.sleep(random()*5)
    result = "BC" + str(int(random()*1000))
    return result

class BarcodeReader(threading.Thread):
    def __init__(self):
        super(BarcodeReader, self).__init__()
        # Create a mutex
        self.mutex = Lock()
        self.currentReading = 0

    def run(self):
        # Continuously read barcode and safely update self.currentReading
        while True:
            value = readBarcode()
            self.mutex.acquire()
            self.currentReading = value
            self.mutex.release()

    def read(self):
        # Main calls this to get latest reading, we just grab it from internal variable
        self.mutex.acquire()
        value = self.currentReading
        self.mutex.release()
        return value

if __name__ == '__main__':

    # Generate repeatable random numbers
    seed(42)

    # Instantiate and start flow meter manager thread
    fmThread = FlowMeter()
    fmThread.daemon = True
    fmThread.start()

    # Instantiate and start barcode reader thread
    bcThread = BarcodeReader()
    bcThread.daemon = True
    bcThread.start()

    # Now you can do other things in main, but always get access to latest readings
    for i in range(20):
        fmReading = fmThread.read()
        bcReading = bcThread.read()
        print(f"Main: i = {i} FlowMeter reading = {fmReading}, Barcode={bcReading}")
        time.sleep(1)

示例输出

Main: i = 0 FlowMeter reading = 0, Barcode=0
Main: i = 1 FlowMeter reading = 1, Barcode=0
Main: i = 2 FlowMeter reading = 3, Barcode=0
Main: i = 3 FlowMeter reading = 5, Barcode=0
Main: i = 4 FlowMeter reading = 7, Barcode=BC25
Main: i = 5 FlowMeter reading = 9, Barcode=BC223
Main: i = 6 FlowMeter reading = 11, Barcode=BC223
Main: i = 7 FlowMeter reading = 13, Barcode=BC223
Main: i = 8 FlowMeter reading = 15, Barcode=BC223
Main: i = 9 FlowMeter reading = 17, Barcode=BC676
Main: i = 10 FlowMeter reading = 19, Barcode=BC676
Main: i = 11 FlowMeter reading = 21, Barcode=BC676
Main: i = 12 FlowMeter reading = 23, Barcode=BC676
Main: i = 13 FlowMeter reading = 25, Barcode=BC86
Main: i = 14 FlowMeter reading = 27, Barcode=BC86
Main: i = 15 FlowMeter reading = 29, Barcode=BC29
Main: i = 16 FlowMeter reading = 31, Barcode=BC505
Main: i = 17 FlowMeter reading = 33, Barcode=BC198
Main: i = 18 FlowMeter reading = 35, Barcode=BC198
Main: i = 19 FlowMeter reading = 37, Barcode=BC198

原始答案

我建议您查看systemdsystemctl,以在每次系统启动时启动应用程序-例如here

关于同时监视两件事,我建议您使用Python的 threading 模块。这是一个简单的示例,我创建了一个threading子类化的对象,该对象通过不断读取流量计并将当前值保存在主程序可以随时读取的变量中来管理您的流量计。您可以启动另一个类似的程序来管理您的条形码读取器,然后并行运行它们。我不想这样做,并且会使您的代码重复一遍。

#!/usr/bin/env python3

from threading import Lock
import threading
import time

# Dummy function to read SPI as I don't have anything attached
def readSPI():
    readSPI.static += 1
    return readSPI.static
readSPI.static=0

class FlowMeter(threading.Thread):
    def __init__(self):
        super(FlowMeter, self).__init__()
        # Create a mutex
        self.mutex = Lock()
        self.currentReading = 0

    def run(self):
        # Continuously read flowmeter and safely update self.currentReading
        while True:
            value = readSPI()
            self.mutex.acquire()
            self.currentReading = value
            self.mutex.release()
            time.sleep(0.01)

    def read(self):
        # Main calls this to get latest reading, we just grab it from internal variable
        self.mutex.acquire()
        value = self.currentReading
        self.mutex.release()
        return value

if __name__ == '__main__':

    # Instantiate and start flow meter manager thread
    fmThread = FlowMeter()
    fmThread.start()

    # Now you can do other things in main, but always get access to latest reading
    for i in range(100000):
        fmReading = fmThread.read()
        print(f"Main: i = {i} FlowMeter reading = {fmReading}")
        time.sleep(1)

您可以考虑使用logging来协调和统一调试和日志记录消息-请参见here

您可以查看events,以使其他线程知道某些事情达到临界水平时需要做的事情-例如here

答案 1 :(得分:1)

另一个也许更简单的选择是使用 Redis Redis 是一种高性能的内存中数据结构服务器。在Raspberry Pi,Mac,Linux Windows或其他计算机上安装很简单。它使您可以在网络上任意数量的客户端之间共享原子整数,字符串,列表,哈希,队列,集合和有序集合。

因此,概念可能是有一个单独的程序来监视流量计,并根据需要将电流读数填充到Redis中。然后,另一个独立的程序读取条形码,并根据需要将其填充到 Redis 中。最后,有一个控制程序,可能在您网络上的其他任何地方都可以随意获取两个值。

请注意,您可以在Raspberry Pi或任何其他计算机上运行 Redis 服务器。

因此,这是流量计程序-只需将host更改为运行Redis的机器的IP地址:

#!/usr/bin/env python3

import redis
import time

host='localhost'
port=6379

# Connect to Redis
r = redis.Redis(host,port)

reading = 0
while True:
   # Generate synthetic reading that just increases every 500ms
   reading +=1 
   # Stuff reading into Redis as "fmReading"
   r.set("fmReading",reading)
   time.sleep(0.5)

这是条形码读取程序:

#!/usr/bin/env python3

import redis
import time
from random import random, seed

host='localhost'
port=6379

# Connect to local Redis server
r = redis.Redis(host,port)

# Generate repeatable random numbers
seed(42)

while True:
   # Synthesize barcode and change every 2 seconds
   barcode = "BC" + str(int((random()*1000)))
   # Stuff barcode into Redis as "barcode"
   r.set("barcode",barcode)
   time.sleep(2)

这是主控制程序:

#!/usr/bin/env python3

import redis
import time

host='localhost'
port=6379

# Connect to Redis server
r = redis.Redis(host,port)

while True:
   # Grab latest flowmeter reading and barcode
   fmReading = r.get("fmReading")
   barcode   = r.get("barcode")
   print(f"Main: fmReading={fmReading}, barcode={barcode}")
   time.sleep(1)

示例输出

Main: fmReading=b'10', barcode=b'BC676'
Main: fmReading=b'12', barcode=b'BC892'
Main: fmReading=b'14', barcode=b'BC892'
Main: fmReading=b'16', barcode=b'BC86'
Main: fmReading=b'18', barcode=b'BC86'
Main: fmReading=b'20', barcode=b'BC421'
Main: fmReading=b'22', barcode=b'BC421'
Main: fmReading=b'24', barcode=b'BC29'

请注意,为了进行调试,您还可以使用命令行界面从网络上的任何计算机 Redis 获取所有读数,例如在终端中:

redis-cli get barcode
"BC775"

如果您想在用PHP编写的Web浏览器中显示值,您也可以使用与Redis的PHP绑定来获取值-非常方便!

当然,您可以调整程序以发送每个读数的时间戳-可能使用Redis 哈希而不是简单的键。您也可以使用Redis LPUSH BRPOP 在程序之间实现队列发送消息。

关键字:Redis,列表,队列,哈希,Raspberry Pi