记录数据并同时检查条件的最有效方法?

时间:2014-05-31 02:53:41

标签: python multithreading raspberry-pi

我正在尝试为rapspbery pi编写一个python代码来控制一个非常特殊的设备,它是一个杠杆(在其末端有一个旋转编码器)和几个LED。 基本上一个将杠杆拉到特定的位置范围,当正确完成时,LED将打开,表示您处于目标位置。 杠杆可以在一定范围的编码器计数内移动,您仍然可以成功完成试验。 我的问题是,记录杠杆位置数据的最佳方法是什么,同时能够检查杠杆是否位于正确的位置范围内?

我已经为这个程序的简单版本编写了软件,它只使用开关而不是旋转编码器作为杠杆。编码器的优势在于我可以非常精确地测量杠杆位置,从而获得更多数据!我可以想办法记录数据,唯一的问题是它会很慢。我正在考虑使用嵌套while循环,其中循环将检查并记录杠杆的位置,但是我担心这可能会选择具有非常低的采样率。

我也在考虑使用线程来实现这个目标,但我不知道如何使用线程来做到这一点,因为我之前从未使用过它们。

我已经拥有与编码器本身连接的软件和硬件,我能够获得非常好的杠杆位置数据,但我希望能够在同一时间记录尽可能多的这些数据点时间仍然可以检查杠杆是否在正确的位置范围内。

如果你能告诉我一个简单的代码,我真的很感激,我应该能够将它实现到我的代码中。

以下是我目前正在考虑编写代码的一个简单示例:

minCorrectPos = 100
maxCorrectPos = 200
timeToHoldLever = 5.0 #Seconds

while True:
    currentPos = encoder.readEncoderPos() #Function returns int
    writeToFile(str(currentPos)) #Records the data pos of the lever. I want this to happen as often as physically possible so as to lose the least amount of data.
    if currentPos < minCorrectPos or currentPos > maxCorrectPos:
        print 'Lever is out of range, wrong trial'
        writeData(timestamp)
    if time.time()-t_trialBegin > timeToHoldLever:
        print 'Lever has been held for enough time within correct range of positions. Rewarding person.'
        break
    #... 
    #Potentially checking for more things, like status of subject, whether he or she is still touching the lever, etc.

我不喜欢上面这段代码的原因是因为我担心我会丢失数据,因为树莓派可能无法快速轮询杠杆的位置,因为正在进行的while循环(慢速采样)率)。这就是为什么我认为线程可能是解决这个问题的正确方法,因为我将有一个单独的线程专门用于记录杠杆位置,给定主题拉动杠杆的名称。可悲的是,我需要帮助编写这种类型的代码。

1 个答案:

答案 0 :(得分:4)

我建议使用multiprocessing模块而不是线程,因为全局解释器锁(GIL)阻止Python同时执行线程,即使有多个内核也是如此。 multiprocessing模块避免了这种限制。

这是一个小例子,通过在父进程和子进程之间使用currentPos发送multiprocessing.Pipe,显示如何使用专用于将currentPos写入文件的子进程。

import multiprocessing as mp

def writeToFile(conn):
    with open(filename, "a") as f: # Just leave the file open for performance reasons.
        while True:
            currentPos = conn.recv()        
            f.write("{}\n".format(currentPos))

if __name__ == "__main__":
    parent_conn, child_conn = mp.Pipe()
    p = mp.Process(target=writeToFile, args=(child_conn,))
    p.start()
    while True:
        currentPos = encoder.readEncoderPos()
        parent_conn.send(currentPos)
        if currentPos < minCorrectPos or currentPos > maxCorrectPos:
            print 'Lever is out of range, wrong trial'
            writeData(timestamp)
        if time.time()-t_trialBegin > timeToHoldLever:
            print 'Lever has been held for enough time within correct range of positions. Rewarding pe'
            break

请注意,尽管我之前关于Python的声明没有很好地处理线程,但在这个特定示例中,与multiprocessing相比,它们的表现可能相当不错。这是因为子进程主要进行I / O操作,允许释放GIL。您可以尝试使用threading模块进行类似的实现,并比较性能。

此外,您可能希望writeToFile仅在收到N个f.write值后才实际执行currentPos。文件I / O很慢,因此执行更少,更大的写入可能会对您有更好的效果。