处理 Python 中的最小 modbus 异常

Dealing with minimalmodbus exceptions in Python

我正在尝试创建一个小型家庭监控系统。我有一系列无线发射器,可以将测量数据传输到基站。我可以使用 Modbus RTU 查询该基站,以找出每个发射器的最新测量值。

为了存储测量值和可视化,我使用了 InfluxDB 和 Grafana。我在 Raspberry Pi 型号 3B+ 上拥有所有 运行ning,包括与基站的 RS-485 通信。

我选择使用 Python 从 Modbus RTU 读取数据,然后将其转发到 InfluxDB 进行存储,因为 Python 两者都有现成的库。但是,我正在努力使 Python 脚本稳定下来。不可避免地,我时不时地在 Modbus 传输中遇到 CRC 错误,当 minimalmodbus 库引发这些异常之一时,脚本似乎卡住了。

我不确定应该如何解决这个问题。

目前我正在使用 try-except-else 结构,但是因为我是 Python 的完全新手,所以我无法按照我想要的方式使用它。如果我丢失一个测量点也没关系。这意味着如果我收到 CRC 错误,我可以忘记该测量并继续进行,就像什么都没发生过一样。

我目前使用的代码(最小化)如下所示:

#!/user/bin/env python
import minimalmodbus
import time
from influxdb import InfluxDBClient

# influxdb stuff
influx = InfluxDBClient(host='localhost', port=8086)
influx.switch_database('dbname')

# minimalmodbus stuff
minimalmodbus.BAUDRATE = 9600
instrument = minimalmodbus.Instrument('/dev/ttyUSB0', 1)

errorcounter = 0
cyclecounter = 0

while True:

        try:

                sid1te = instrument.read_register(247, 1, 4)
                print "SID 1 TE:", sid1te

                influxquery = [
                        {"measurement": "sid1", "fields": { "te": sid1te}},
                        {"measurement": "system", "fields": { "errorcounter": errorcounter}},
                        {"measurement": "system", "fields": { "cyclecounter": cyclecounter}}
                ]

                print "InfluxDB query result:", influx.write_points(influxquery)

        except Exception as error:
                print "[!] Exception occurred: ", error
                errorcounter = errorcounter + 1

        else:
                print "[i] One cycle completed."
                cyclecounter = cyclecounter + 1

        time.sleep(30)

最终发生的事情是脚本可以像梦一样 运行 几个小时,然后,当传输中发生单个 CRC 错误时,它会进入一个永无止境的异常循环,如下所示:

[!] Exception occurred:  Checksum error in rtu mode: '\xeb\xf9' instead of 'p\x97' . The response is: '\x7f\x01\x04\x02\x00\xeb\xf9' (plain response: '\x7f\x01\x04\x02\x00\xeb\xf9')
[!] Exception occurred:  Checksum error in rtu mode: '\xeb\xf9' instead of 'p\x97' . The response is: '\x7f\x01\x04\x02\x00\xeb\xf9' (plain response: '\x7f\x01\x04\x02\x00\xeb\xf9')
[!] Exception occurred:  Checksum error in rtu mode: '\xeb\xf9' instead of 'p\x97' . The response is: '\x7f\x01\x04\x02\x00\xeb\xf9' (plain response: '\x7f\x01\x04\x02\x00\xeb\xf9')
[!] Exception occurred:  Checksum error in rtu mode: '\xeb\xf9' instead of 'p\x97' . The response is: '\x7f\x01\x04\x02\x00\xeb\xf9' (plain response: '\x7f\x01\x04\x02\x00\xeb\xf9')
[!] Exception occurred:  Checksum error in rtu mode: '\xeb\xf9' instead of 'p\x97' . The response is: '\x7f\x01\x04\x02\x00\xeb\xf9' (plain response: '\x7f\x01\x04\x02\x00\xeb\xf9')
[!] Exception occurred:  Checksum error in rtu mode: '\xeb\xf9' instead of 'p\x97' . The response is: '\x7f\x01\x04\x02\x00\xeb\xf9' (plain response: '\x7f\x01\x04\x02\x00\xeb\xf9')

当我使用 CTRL-C 退出时,脚本实际上看起来在睡眠命令中:

^CTraceback (most recent call last):
  File "temp.py", line 92, in <module>
    time.sleep(30)
KeyboardInterrupt

所以我很困惑,如果它实际上在程序循环中,为什​​么它不向控制台输出正常的打印命令。

在实际脚本中,我有三打 instrument.read_register 调用,所以我不确定我是否应该创建一个独特的函数来处理 per-read_register 调用中的异常或什么?在过去的一周里,我尝试了这段代码的六种变体,但由于脚本陷入异常循环,我在 Grafana 中获得的数据非常糟糕。

有什么建议吗?

我现在发布了一个新版本的 MinimalModbus,它在串行总线上进行任何通信之前默认刷新输入和输出串行缓冲区,以清除任何旧错误。请试一试。

免责声明:我是 MinimalModbus 的维护者。

我尝试使用不同的 USB/RS-485 转换器以及不同的 Modbus RTU 设备。同样的问题仍然存在。我 99% 确信问题出在 Linux 串口处理上。我不确定 how/why,但它有时会给出 pyserial/minimalmodbus 不完整的字节序列,导致 minimalmodbus 评估错误的序列作为响应。示例是 minimalmodbus 抱怨 0x11 响应太短,然后 minimalmodbus 立即抱怨 0x03 0x06 0xAE 0x41 0x56 0x52 0x43 0x40 0x49 0xAD 在 CRC 中有错误。实际上,如果将这两条消息作为一条消息接收,那将是一个完全有效的响应。

我不知道如何解决这个问题,但我很确定这个问题比 Python 级别更深。

编辑:这不是 hardware/Linux 问题,而是 Python/pyserial/minimalmodbus 问题。我一起破解了一个 Python 脚本,该脚本执行外部 C 语言 Modbus RTU 查询程序并解析输出。 100% 的时间都像魅力一样工作,现在已经一个多星期了。