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



对于人体平衡的实验测量,我想连接并读出多个I2C传感器(陀螺仪/磁力/加速度计,例如这个)。

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

但是,我要求来自多个设备和寄存器的数据(大约)同步或时间记录。 我怎样才能做到这一点?

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

背景:

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

(2)还是时钟只是解决方案的一部分? 我一直在寻找缓冲解决方案,并找到了bytearrays和io.BytesIO。但我不知道如何只阅读新值。大多数指南都提到文件存储,但我宁愿不流式传输到文件(数据不大)。我还"读了一点"(字面意思)异步执行,使用 asyncio。 但是,我的尝试(如下)并不理想,因为它需要大量的开销来存储测量的精确时间点。还有其他限制,见下文。

(3)我的问题被放大了,因为到目前为止,我只能从I2C读取单个寄存器,即我必须循环读取9次才能获得9DOF数据。我了解到有多种解决方案可以通过python访问I2C,我正在使用FT232H突破[*],其中许多都支持。其中一些一次查询多个字节,可能涉及一些缓冲区。然而,我让它工作的唯一方法是使用 libftdi 并将 I2C 部分从 Adafruit_GPIO 移植到 python3。所以我还无法重现并行字节查询。(具体如何)libftdi 能够进行此类查询吗?也许这可以扩展?

起点:

我的第一个直觉是用multiprocessing和队列做一些事情。但是,当有多个线程或进程时,如果我没有正确进行 ICL 同步,它们就会漂移(请参阅 1)。此外,队列似乎已填满 fifo,但如果以足够的速率阅读,我可以使用后进先出和刷新。

然后我发现了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分线,而不是我的机器人,因为在我介绍的内容之上,还将通过DAQ获取测力板数据。因此,这也必须并行化,这可以通过多处理来实现。

I2c 协议一次仅支持从一个设备进行串行数据传输。典型的多路复用器仅将主接口移至每个隔离通道,因此它们只能支持串行/顺序读取。为了并行读取多个 i2c 设备,每个相同的设备都应位于到处理器的物理隔离总线上。然后可以使用多线程并行读取每个设备,最后可以聚合所有数据。这将花费与仅从一个传感器读取数据所需的时间大致相同,但会产生更多数据。要在 pi 上做到这一点,可以使用额外的软件定义的 i2c 总线和多线程代码从中读取。否则,我不知道有任何硬件可以执行这样的功能。也许可以在硬件级别对FPGA进行编程以执行此操作。

相关内容

  • 没有找到相关文章