简体   繁体   English

如何以高频读取和累积传感器值,而无需不断写入磁盘(RPi 2 b+、MCP3304、Python)

[英]How to read & accumulate sensor values at high frequency, without constantly writing to disk (RPi 2 b+, MCP3304, Python)

I am attempting to use a Raspberry Pi 2 Model B+ to read analog data on IR intensity from a photodiode via an MCP3304 (5v VDD) at a rate of ~ 10kHz three times in a row (0.1 ms between readings, or a rate of 10 ksps) once every second based on an external stimulus, average those values, then write them to a text file along with the current datetime.我正在尝试使用Raspberry Pi 2 B+ 型通过MCP3304 (5v VDD)以 ~ 10kHz 的速率连续三次(读数之间为 0.1 ms,或 10 ksps) 基于外部刺激每秒一次,对这些值求平均值,然后将它们与当前日期时间一起写入文本文件。 The photodiode is simply reading out data to an amplifier, which then feeds into the MCP3304, which, via SPI, feeds data into the RPi.光电二极管只是将数据读出到放大器,然后放大器馈入 MCP3304,MCP3304 通过 SPI 将数据馈入 RPi。 (In essence: RPi receives a digital input, triggering three consecutive samples from the photodiode via an MCP3304 and in-line signal amplifier. Those three samples are stored in memory, averaged, then written to disk along with a datetime stamp to an existing CSV text file.) This is all on Python 2.7. (本质上:RPi 接收数字输入,通过 MCP3304 和在线信号放大器触发来自光电二极管的三个连续样本。这三个样本存储在内存中,取平均值,然后与日期时间戳一起写入磁盘到现有的 CSV文本文件。)这一切都在 Python 2.7 上。

As it stands, I'm getting a sampling of < 1kHz with the below code ( SensorRead() ).就目前而言,我使用以下代码( SensorRead() )获得 < 1kHz 的采样。 I am very new to Python (and playing with sensors & RPis, for that matter!), and think the way I've setup my class to take three separate, consecutive ADC samples and possibly my setup for writing to disk may be slowing me down.我对 Python 非常陌生(并且在这方面使用传感器和 RPis!),并且认为我设置我的课程以获取三个单独的连续 ADC 样本的方式以及可能我的写入磁盘设置可能会减慢我的速度下来。 However, I can't quite seem to find a better way.但是,我似乎无法找到更好的方法。 Edit1: I've done a good bit of research on max sampling rates via Python from the RPi GPIO, and it appears to be well above the ADC's restriction at ~ 1MHz or ~ 1000 ksps (eg 1 , 2 ).编辑 1:我通过 Python 从 RPi GPIO 对最大采样率进行了大量研究,它似乎远高于 ADC 对 ~ 1MHz 或 ~ 1000 ksps(例如12 )的限制。 Edit2: Perhaps the ADC max sample rate of 100 ksps actually refers to how many bits can be read rather than how many full 12-bit samples can be taken per second? Edit2:也许 100 ksps 的 ADC 最大采样率实际上是指可以读取多少位而不是每秒可以获取多少个完整的 12 位样本?

Yup.是的。 This was it.就是这样。 The MCP3304 can do 100ksps, but the Python read rate is closer to 30ksps, which, when split between the 24-bits read by the MCP3304 per iteration, is closer to 1ksps MCP3304 可以达到 100ksps,但 Python 读取速率接近 30ksps,当在 MCP3304 每次迭代读取的 24 位之间拆分时,接近 1ksps



My two questions:我的两个问题:
1) Are there any better ways of getting closer to the full 100 ksps advertised in the MCP3304 spec sheet? 1) 是否有更好的方法来接近 MCP3304 规格表中宣传的完整 100 ksps? This link suggests calling WiringPi every time I want to take a single sample may cause some considerable latency. 此链接建议每次我想获取单个样本时调用 WiringPi 可能会导致一些相当大的延迟。

and

2) is it possible, with a beginner/moderate level of Python skill for me to do all of this sampling and per-second averaging in the memory, and only write to disk, say, once every minute? 2) 有没有可能,对于初学者/中等水平的 Python 技能,我可以在内存中进行所有这些采样和每秒平均,并且只写入磁盘,例如,每分钟一次? Edit: could you please point me in the direction of some related links/resources?编辑:您能否指出一些相关链接/资源的方向?

Thanks!谢谢!

Note 1: the code is "Threaded" because there are some other functions running simultaneously.注 1:代码是“线程化的”,因为还有一些其他功能同时运行。 Note 2: I am also, simultaneously reading a differential channel on the ADC, hence the "differential = True" in the MCP3304 command注 2:我也在同时读取 ADC 上的差分通道,因此 MCP3304 命令中的“差分 = 真”

'''
FILENAME = "~/output_file_location/and/name.txt"
adc_channel_pd = pin of the ADC from which analog signal is taken
stimulus_in_pin = the the pin that receives the alert to begin sampling
stimulus_LED_alert_pin = pin that goes "high" to illuminate an LED every time the stimulus_in_pin is triggered
Vref = the reference voltage for the ADC (3.3v; VDD = 5V)

'''

# import packages
import wiringpi2 as wiringpi
import time
from gpiozero import MCP3304
import threading
import datetime

# Define important objects
Vref = 3.3
adc_channel_pd = 7
stimulus_in_pin = 32
stimulus_LED_alert_pin = 16

# establish GPIO reading structure
wiringpi.wiringPiSetupPhys()

# set appropriate pin inputs and outputs (0 = input, 1 = output)
wiringpi.pinMode(stimulus_in_pin, 0)
wiringpi.pinMode(stimulus_LED_alert_pin, 1)

# create a class to take 3 PD readings, then average them, immediately upon stimulus
class SensorRead(threading.Thread):
    def __init__(self):
        super(SensorRead, self).__init__()
        self.daemon = True
        self.start()
    def run(self):
        for i in itertools.count():
            if (wiringpi.digitalRead(stimulus_in_pin) == True):
                val_ir_1 = MCP3304(adc_channel_pd, True).value * Vref)
                val_ir_2 = MCP3304(adc_channel_pd, True).value * Vref)
                val_ir_3 = MCP3304(adc_channel_pd, True).value * Vref)
                voltage_ir = round(  (float( (sum([val_ir_1,val_ir_2,val_ir_3])) / 3)) , 9)
                dt_ir = '%s' % datetime.datetime.now()
                f = open(FILENAME, "a")
                f.write("IR Sensor," + dt_ir + "," + str(voltage_ir) + "\n")    
                f.close()
                # print to terminal so I can verify output in real time
                print "IR Sensor:", dt_ir,",",voltage_ir
                # blink ir light on board for visual verification of stimulus in real time
                wiringpi.digitalWrite(stimulus_LED_alert_pin, 1)
                time.sleep(0.5)
                wiringpi.digitalWrite(stimulus_LED_alert_pin, 0)
                # sleep to avoid noise post LED firings
                time.sleep(0.5)

# run class
SensorRead()

Edit: I ended up getting some great results with Cython, as demonstrated in this test-code I wrote to quantify how fast I could read my ADC .编辑:我最终用 Cython 得到了一些很好的结果,正如我编写的这个测试代码所示,以量化我读取 ADC 的速度 I also ended up writing my own function to read from the MCP3304-- which I'll link to once it's all clean-- that I was able to further optimize in Cython.我还最终编写了自己的函数来从 MCP3304 中读取数据——一旦一切都干净了,我将链接到它——我能够在 Cython 中进一步优化。

One point about your question.关于你的问题的一点。 Three samples in a second is a rate of 3Hz not 100kHz.每秒三个样本是 3Hz 而非 100kHz 的速率。 Sounds to me like what you want is three samples 10us apart.在我看来,您想要的是三个相距 10us 的样本。

1) 10us sample period on MCP3304 using Pi running Linux? 1) 使用运行 Linux 的 Pi 在 MCP3304 上的 10us 采样周期? Quite possibly not.很可能不是。 Do some searching.做一些搜索。 See for example https://raspberrypi.stackexchange.com/questions/45386/microphone-via-spi where one answer says they achieved 33us (33ksps) using C code and avoiding the SPI driver.例如,参见https://raspberrypi.stackexchange.com/questions/45386/microphone-via-spi ,其中一个答案说他们使用 C 代码实现了 33us(33ksps)并避免了 SPI 驱动程序。 Also I suspect you will find Linux process switching and other threads getting in the way and affecting the sample rate particularly if they are also reading the ADC.此外,我怀疑您会发现 Linux 进程切换和其他线程妨碍并影响采样率,特别是如果它们也在读取 ADC。 This may be more likely if you have a dedicated non-Linux processor to read the ADC, programmed in C or assembly language, feeding the three samples to the Pi.如果您有一个专用的非 Linux 处理器来读取 ADC,用 C 或汇编语言编程,将三个样本提供给 Pi,那么这可能更有可能。 Easier if you use a parallel ADC, ie not using SPI-like serial comms.如果您使用并行 ADC,即不使用类似 SPI 的串行通信,则更容易。 See also http://www.hertaville.com/interfacing-an-spi-adc-mcp3008-chip-to-the-raspberry-pi-using-c.html and https://www.raspberrypi.org/forums/viewtopic.php?f=93&t=83069另见http://www.hertaville.com/interface-an-spi-adc-mcp3008-chip-to-the-raspberry-pi-using-c.htmlhttps://www.raspberrypi.org/forums/ viewtopic.php?f=93&t=83069

2) While the sampling at 10us period using the MCP3304 is difficult-to-impossible on Pi, the averaging and writing is definitely possible. 2) 虽然使用 MCP3304 以 10us 周期采样在 Pi 上是难以实现的,但求平均值和写入绝对是可能的。

I have a solution for your problem, though: if literally all you're going to do with the three samples is to average them, why not add an old-fashioned low-pass analog filter before the input pin and then just take one sample.不过,我有一个解决您的问题的方法:如果实际上您对三个样本所做的只是对它们求平均值,为什么不在输入引脚之前添加一个老式低通模拟滤波器,然后只取一个样本. Hey presto, no need for hardish-realtime ADCing, no need to worry about other processes, or kernel interrupts! Hey presto,无需硬实时 ADC,无需担心其他进程或内核中断!

We have recently benchmarked PIGPIO and RPi.GPIO with regards to the accuracy of reading inputs at different frequencies.我们最近针对不同频率下读取输入的准确性对 PIGPIO 和 RPi.GPIO 进行了基准测试。 The test was performed on a Raspberry Pi 3b.该测试是在 Raspberry Pi 3b 上进行的。

I would suggest to use the PIGPIO for better results.我建议使用 PIGPIO 以获得更好的结果。 On our test The max read frequency on that library with a read accuracy above 99% was 20 KHz, compared to 5KHz on the Rpi.GPIO library在我们的测试中,读取精度高于 99% 的库的最大读取频率为 20 KHz,而 Rpi.GPIO 库的最大读取频率为 5KHz

You can find the exact test setup and the complete results on this this post: https://atman-iot.com/blog/raspberry-pi-benchmark/您可以在此帖子中找到确切的测试设置和完整结果: https : //atman-iot.com/blog/raspberry-pi-benchmark/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 尝试通过SPI(MCP3304,MCP3204或MCP3008)在RPi 2 b +上读取带有Cython的ADC吗? - Trying to read an ADC with Cython on an RPi 2 b+ via SPI (MCP3304, MCP3204, or MCP3008)? 从 python 中的传感器读取值 - Read values from a sensor in python Python 使用 MCP3008 采样频率 - Python using MCP3008 sample frequency 如何更改将mcp3008读取并显示降雨传感器数据的wxpython程序更改为软件spi? - How to change my wxpython program that read and display rain sensor data from mcp3008 to software spi? 如何在不写入磁盘的情况下在python进程之间共享数据 - How to share data between python processes without writing to disk 如何在另一个目录中运行 python 脚本,而不将脚本写入磁盘? - How to run python scripts in another directory, without writing scripts to disk? 如何在不写入磁盘的情况下解压缩? - How to unzip without writing to disk? Python,RPi + MCP3008 + 2xForce敏感电阻-正方形 - Python, RPi + MCP3008 + 2xForce Sensitive Resistor - Square 如何使用 Python Pillow 更改图像格式而不将其写入磁盘 - How to change image format without writing it to disk using Python Pillow 将Perl哈希写入磁盘以供Python读取 - Writing a Perl hash to disk to be read by Python
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM