多个I2C设备的并行(缓冲)读出,python 3

时间:2019-04-12 21:53:14

标签: python-3.x multiprocessing i2c buffering ftdi

为了进行人体平衡的实验测量,我想连接并读出多个I2C传感器(陀螺仪/磁力/加速度计,such as this one)。

我设法将它们连接起来(libftdi + python3.7)并可以从单个寄存器读取。

但是,我要求(大约)同步或时间记录来自多个设备和寄存器的数据。 我该如何实现?

(编辑:一个不错的解决方案是固定长度的并行缓冲区,每个I2C设备/寄存器一个,并在后台填充并存储在触发后)。

背景

(1)我不了解I2C的ICL时钟如何工作。我知道可以设置一个读取频率,例如100Hz。我可以在任意时间点阅读,并且传感器值似乎在变化,但可能并非一直都在变化。如何精确控制读数的时间?

(2)还是仅作为解决方案的一部分? 我一直在寻找缓冲解决方案,并发现了bytearrayio.BytesIO。但是我不知道如何只读取新值。大多数指南都涉及文件存储,但是我不希望流式传输到文件(数据不大)。我还使用asyncio(从字面上)“读了一点”到异步执行中。 但是,我的尝试(以下)并不理想,因为要存储精确的测量时间点将需要大量开销。还有其他限制,请参见下文。

(3)我的问题被放大了,因为到现在为止,我只能从I2C读取单个寄存器,即,我必须循环读取9次才能获得9DOF数据。我了解到有多种通过python访问I2C的解决方案,我正在使用FT232H breakout受支持的by many of those [*]。其中一些一次查询多个字节,可能涉及一些缓冲区。但是,使它起作用的唯一方法是使用libftdi并将I2C部分从Adafruit_GPIO移植到python3。所以我还不能再现并行字节查询。 (如何精确)libftdi是否可以进行此类查询?也许可以扩展?

起点:

我的第一个直觉是对multiprocessing和队列进行操作。但是,当有多个线程或进程时,如果我没有正确地进行ICL同步,它们将漂移(请参阅1)。另外,队列似乎被填充,但是如果阅读速度足够快,我可以使用后进先出和冲洗功能。

然后我发现了asyncio并进行了第一次尝试。 然后,我尝试使用基于io.BytesIO的类似于缓冲区的连接。但是我还没有学会如何真正填充,读取和刷新缓冲区,所以我的方法可能很笨拙。

这里是问题的模拟,创建随机字节并对其进行处理。

import asyncio as AIO
import io as IO
import numpy as NP


# a sender object that keeps spitting out data
class Sender(IO.BytesIO):
    def __init__(self, label):
        super(Sender, self).__init__()
        self.label = label

    async def GetGoing(self):
        await self.PutStuffIn()

    async def PutStuffIn(self):
        while True:
            rnd = NP.random.bytes(1)
            print (self.label, 'sending', rnd)
            self.write(rnd)
            await AIO.sleep(0.01)



### a receiving object that collects data
class Receiver(object):
    def __init__(self, senders):
        self.streams = senders

    async def GetReceiving(self):
        await self.ReadStuffOut()

    async def ReadStuffOut(self):
        pointers = {stream.label: 0 for stream in self.streams}
        while True:
            await AIO.sleep(0.02)
            for stream in self.streams:
                data = stream.getvalue()
                print (stream.label, 'received', data[pointers[stream.label]:])
                pointers[stream.label] = stream.tell()


### main process
async def Main():
    # create multiple senders and a receiver
    senders = [Sender(1), Sender(2), Sender(3)]
    read = Receiver(senders)

    # execute sender and receiver in parallel
    await AIO.wait( [ \
        send.GetGoing() \
        for send in senders] \
        +[ read.GetReceiving() \
        ] )


### mission control
if __name__ == "__main__":
    loop = AIO.get_event_loop()
    loop.run_until_complete(Main())


期望:

如上所述,这种作品,但是:

  • 使用io.BytesIO.getvalue()似乎总是可以获取整个缓冲区,并且它没有被清空:我想我已经创建了一个列表,而不是真正的缓冲区?

  • 对于asyncio,执行是不确定的,因此我无法预分配固定大小的缓冲区。我之所以仅使用它是因为它的速度是因为我想比I2C时钟更快地采样,因此它可能是错误的轨道。另一方面,这似乎是让多个发件人准并行工作的好方法。

  • (未显示),我想了解有关并行I2C寄存器访问的深层结构以及它是否可以在设备之间使用的更多信息。

在此先感谢您的提示和指导!

顺便说一句,我几乎不识字C,但是(乐于学习)也会喜欢这种语言的代码示例。

[*]我使用的是FT232H分组接口,而不是我的odroid,因为在我呈现的内容之上,将通过DAQ获取测力板数据。因此,这也必须并行化,这可以通过多处理来实现。

0 个答案:

没有答案