首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用Threading.Timer精确地每隔0.05秒从Modbus服务器读取数据?

如何使用Threading.Timer精确地每隔0.05秒从Modbus服务器读取数据?
EN

Stack Overflow用户
提问于 2021-01-19 12:03:26
回答 1查看 181关注 0票数 0

我想实现什么?

  • 每隔0.05秒准确地从Modbus服务器读取数据。

更大的图景是,我正在创建一个PyQt5应用程序,通过它我想保存并绘制Modbus数据。因此,稍后我可以使用它们进行PID自整定。PID自动调谐器要求测量数据的精度至少为0.05秒.而且,数据点需要像这样分布:M wait 0.05s then M wait 0.05s then M,而不是M wait 0.08s then M wait 0.03s then M(M = measure data)

到目前为止我尝试了什么?

  • I尝试实现Threading.Timer每隔0.05秒读取一次数据。

  • 问题是定时器的精度太低了。

这是我测试Threading.Timer 精度:的代码

代码语言:javascript
复制
from threading import Timer
import timeit

starttime = timeit.default_timer()

def f():
    Timer(0.05, f).start()

    global starttime

    print("The time difference is :", timeit.default_timer() - starttime)
    starttime = timeit.default_timer()

    #Here I would read the data

f() 

代码产生的输出:

代码语言:javascript
复制
...
The time difference is : 0.07623
The time difference is : 0.07707
The time difference is : 0.07684
The time difference is : 0.07557
...

如果我要这样精确地读取数据的话,

  • 。从长远来看,这将造成巨大的时间差。

  • 理想的情况下,代码将读取每一个0.05s,也就是20每秒读取的数据。但是有了这样的精度,它将平均读取每个0.07s的数据,并将其解释为0.07s

  • ,每秒钟的时差是0.07 * 20 - 0.05 * 20 = 0.4 seconds,这是不可接受的,因为在一分钟之后,时差将是24秒。

如何提高Threading.Timer对象的精度?或者我应该使用哪些其他方法/工具?

其他信息:

我已经测量了使用以下代码从Modbus读取一个值需要多长时间:

代码语言:javascript
复制
from pyModbusTCP.client import ModbusClient
import timeit

c = ModbusClient("localhost")
c.open()

for i in range(0,10):
    starttime = timeit.default_timer()
    data_now = c.read_holding_registers(0, 1)
    print("Reading 1 register takes:", timeit.default_timer() - starttime)

输出:

代码语言:javascript
复制
...
Reading 1 register takes: 0.000297100
Reading 1 register takes: 0.000307600
Reading 1 register takes: 0.000271699
...

我正在使用的:

  • Windows 10
  • Python3.7 (32位verison)
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-01-19 12:28:27

你太过分了。做个FPS锁。如果阅读所需时间超过0.05,则必须向后重新计算(notimplemented)。如果你测量得很快,根据你想要的0.05s重新计算并等待那个时间。使用这种方法,您可以达到精确的0.05s间隔。如果读取注册表所用的时间超过您的工作时间,它将无法工作。

这是带有FPS锁的工作示例。没什么花哨的。设置精度以创建假读取延迟。为你的钱包设定时间(我设定了1s,你想要0.05s)

代码语言:javascript
复制
import time
import random

def time_keeper(lost_by_reading,period=1):
    if lost_by_reading>period:
        pass # a problem because reading takes longer than period
    elif lost_by_reading<period:
        time.sleep(period-lost_by_reading)


def mock_register_reading(precision=1000):
    rand_sleep = random.randint(0,10)/precision
    time.sleep(rand_sleep)


_measure = time.time()

period = 1

for i in range(1000):

    start = time.time()
    mock_register_reading()

    ## just for log
    print('measured after',time.time()-_measure, ', ERROR: ',period-(time.time()-_measure))
    _measure = time.time()
    ### end

    finish = time.time()
    reading_time = finish-start
    time_keeper(reading_time,period = period)

备注:我建议您不要对modbus使用线程。根据我自己的经验,modbus和线程并不是朋友,例如,通过线程读取寄存器只会导致灾难(以防万一你会有办法让线程每0.5读一次)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65791146

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档