Pymodbus - 在树莓派 pi3 的 UART 上通过 rs485 读取电能表的输入寄存器 [英] Pymodbus - Read input register of Energy meter over rs485 on uart of raspberry pi3

查看:318
本文介绍了Pymodbus - 在树莓派 pi3 的 UART 上通过 rs485 读取电能表的输入寄存器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个电能表,我正在尝试通过 RS485 从 raspberry pi uart 上的电表中检索电压、频率值

我的树莓派和rs485的连接如下Rs485 DI - 树莓派的 TxRs485 R0 - 树莓派的 RxRs485 DE/RE -Pin 7 of raspberry pi

我的代码如下:

<块引用>导入序列将 RPi.GPIO 导入为 GPIO

从 pymodbus.client.sync 导入 ModbusSerialClient 作为 ModbusClient
从 pymodbus.register_read_message 导入 ReadInputRegistersResponse

从 pymodbus.register_read_message 导入 ReadInputRegistersRequest

导入日志

logging.basicConfig() 日志 = logging.getLogger()log.setLevel(logging.DEBUG)

GPIO.setmode(GPIO.BOARD) GPIO.setup(7,GPIO.OUT,initial=GPIO.LOW)

client= ModbusClient(method = 'rtu', port='/dev/ttyS0',stopbits = 1,timeout =0.3, bytesize = 8, parity = 'N', baudrate = '9600')

connection = client.connect()

打印连接"打印连接

而 1:

volt=0频率=0如果连接:尝试:电压1= client.read_input_registers(0x000,4,unit=0x03)印刷电压1除了:打印错误:没有收到消息"客户端关闭()

我收到的输出如下

DEBUG:pymodbus.transaction:当前交易状态 - TRANSACTION_COMPLETE调试:pymodbus.transaction:运行事务 4调试:pymodbus.transaction:发送:0x3 0x4 0x0 0x0 0x0 0x4 0xf0 0x2b调试:pymodbus.framer.rtu_framer:将状态更改为空闲 - 最后一帧结束 - 无,当前时间戳 - 1557304284.88调试:pymodbus.client.sync:新交易状态发送"调试:pymodbus.transaction:将交易状态从发送"更改为等待回复"调试:pymodbus.transaction:将交易状态从等待回复"更改为处理回复"调试:pymodbus.transaction:RECV:0x7b 0x20 0x31 0x20 0x31 0x20 0x32 0x36 0x2e 0x33 0x35 0x20 0x31调试:pymodbus.transaction:将交易状态从处理回复"更改为交易完成"Modbus 错误:[输入/输出] 未收到来自远程单元的响应/无法解码响应调试:pymodbus.transaction:当前交易状态 - TRANSACTION_COMPLETE调试:pymodbus.transaction:运行事务 5调试:pymodbus.transaction:清除当前帧:- 0x7b 0x20 0x31 0x20 0x31 0x20 0x32 0x36 0x2e 0x33 0x35 0x20 0x31调试:pymodbus.framer.rtu_framer:重置帧 - 缓冲区中的当前帧 - 0x7b 0x20 0x31 0x20 0x31 0x20 0x32 0x36 0x2e 0x33 0x35 0x20 0x31调试:pymodbus.transaction:发送:0x3 0x4 0x0 0x0 0x0 0x4 0xf0 0x2b调试:pymodbus.framer.rtu_framer:将状态更改为空闲 - 最后一帧结束 - 无,当前时间戳 - 1557304284.98调试:pymodbus.client.sync:新交易状态发送"警告:pymodbus.client.sync:发送前清理接收缓冲区:0x37 0x2e 0x35 0x35 0x20 0x33调试:pymodbus.transaction:将交易状态从发送"更改为等待回复"DEBUG:pymodbus.transaction:Incomplete message received, Expected 13 bytes Received 7 bytes !!!!调试:pymodbus.transaction:将交易状态从等待回复"更改为处理回复"调试:pymodbus.transaction:RECV:0x2e 0x30 0x36 0x20 0x7d 0xd 0xa调试:pymodbus.transaction:将交易状态从处理回复"更改为交易完成"Modbus 错误:[输入/输出] 未收到来自远程单元的响应/无法解码响应

解决方案

如果我没有弄错,那么您正确定义了 GPIO 引脚,但从未将其切换为高电平和低电平.为了能够在您的 RS485 芯片上驱动 DE/~RE 信号,您应该在写入总线之前将 GPIO 拉高,然后立即拉低,以便能够从仪表中读取答案.

不幸的是,我担心开箱即用的 pyModbus 无法实现您的尝试.你可以看看这个链接:

在蓝色中,您可以看到来自 Pi 的 UART(连接器上的第 8 针)的 TX,在黄色中是您应该连接到 RS485 芯片的 DE/~RE(第 11 针,GPIO17).如您所见,从 Modbus 数据帧结束到总线空闲以供从站应答之间有 0.6 毫秒的延迟.在我使用的速度 (9600 bps) 下,符合 Modbus 规范所需的最小延迟约为 3 毫秒(3.5 个字符),因此在大多数情况下应该没问题.

唯一悬而未决的是将所有这些 GPIO 函数添加到 pylibmodbus 包装器中,但这应该很容易.我计划很快在我的袖珍芯片计算机上使用 Python 中的这个库作为 Modbus 手持式测试仪,因此如果您或其他任何人设法找到时间,我将非常乐意测试它.

一旦我有更多时间,我将尝试将 libmodbus 与我的 FTDI 串行端口一起使用,并进行几次示波器捕获以比较硬件与软件信号.

我忘了提到我对 test.c 所做的唯一更改是:

第 13 行:#define UART_PORT "/dev/serial0"

第 14 行:#define BAUD_RATE 9600

第一个是我的 Pi 上嵌入式串行端口的名称,第二个是我一直用于测试目的的速度.

软件与硬件信号

正如承诺的那样,我已经测试了使用 libmodbus 提出的解决方案,但我没有使用 Raspberry Pi 上的嵌入式 UART,而是将它与我​​的 FTDI USB 适配器一起使用,以比较释放总线所需的时间.

您可以看到 TXEN(品红色轨迹)如何在停止位后大约 250 微秒变低,而 Pi 上的 GPIO(蓝色)所用的时间与上面捕获的时间大致相同(500-600微秒).

因此,在进行更广泛的测试之前,我的结论是 libmodbus 在没有可用 TX 启用信号的 UART 方面做得很好.我认为应该可以在大多数情况下进行可靠的 Modbus 通信.

I have one energy meter and i am trying to retrieve voltage, freq values from meter on raspberry pi uart over RS485

My connections for raspberry pi and rs485 are as follows Rs485 DI - Tx of raspberry pi Rs485 R0 - Rx of raspberry pi Rs485 DE/RE -Pin 7 of raspberry pi

my code is as follows:

import serial import RPi.GPIO as GPIO

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
from pymodbus.register_read_message import ReadInputRegistersResponse

from pymodbus.register_read_message import ReadInputRegistersRequest

import logging

logging.basicConfig() log = logging.getLogger() log.setLevel(logging.DEBUG)

GPIO.setmode(GPIO.BOARD) GPIO.setup(7,GPIO.OUT,initial=GPIO.LOW)

client= ModbusClient(method = 'rtu', port='/dev/ttyS0',stopbits = 1,timeout =0.3, bytesize = 8, parity = 'N', baudrate = '9600')

connection = client.connect()

print "Connection" print connection

while 1:

volt=0     

freq=0   

if connection:  

    try:  

        voltage1= client.read_input_registers(0x000,4,unit=0x03)  
        print voltage1

    except:
        print "Error: No message Received"

client.close()

And i am receiving the output as follows

DEBUG:pymodbus.transaction:Current transaction state - TRANSACTION_COMPLETE
DEBUG:pymodbus.transaction:Running transaction 4
DEBUG:pymodbus.transaction:SEND: 0x3 0x4 0x0 0x0 0x0 0x4 0xf0 0x2b
DEBUG:pymodbus.framer.rtu_framer:Changing state to IDLE - Last Frame End - None, Current Time stamp - 1557304284.88
DEBUG:pymodbus.client.sync:New Transaction state 'SENDING'
DEBUG:pymodbus.transaction:Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG:pymodbus.transaction:Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG:pymodbus.transaction:RECV: 0x7b 0x20 0x31 0x20 0x31 0x20 0x32 0x36 0x2e 0x33 0x35 0x20 0x31
DEBUG:pymodbus.transaction:Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response
DEBUG:pymodbus.transaction:Current transaction state - TRANSACTION_COMPLETE
DEBUG:pymodbus.transaction:Running transaction 5
DEBUG:pymodbus.transaction:Clearing current Frame : - 0x7b 0x20 0x31 0x20 0x31 0x20 0x32 0x36 0x2e 0x33 0x35 0x20 0x31
DEBUG:pymodbus.framer.rtu_framer:Resetting frame - Current Frame in buffer - 0x7b 0x20 0x31 0x20 0x31 0x20 0x32 0x36 0x2e 0x33 0x35 0x20 0x31
DEBUG:pymodbus.transaction:SEND: 0x3 0x4 0x0 0x0 0x0 0x4 0xf0 0x2b
DEBUG:pymodbus.framer.rtu_framer:Changing state to IDLE - Last Frame End - None, Current Time stamp - 1557304284.98
DEBUG:pymodbus.client.sync:New Transaction state 'SENDING'
WARNING:pymodbus.client.sync:Cleanup recv buffer before send: 0x37 0x2e 0x35 0x35 0x20 0x33
DEBUG:pymodbus.transaction:Changing transaction state from 'SENDING' to 'WAITING FOR REPLY'
DEBUG:pymodbus.transaction:Incomplete message received, Expected 13 bytes Recieved 7 bytes !!!!
DEBUG:pymodbus.transaction:Changing transaction state from 'WAITING FOR REPLY' to 'PROCESSING REPLY'
DEBUG:pymodbus.transaction:RECV: 0x2e 0x30 0x36 0x20 0x7d 0xd 0xa
DEBUG:pymodbus.transaction:Changing transaction state from 'PROCESSING REPLY' to 'TRANSACTION_COMPLETE'
Modbus Error: [Input/Output] No Response received from the remote unit/Unable to decode response

解决方案

If I'm not getting it wrong, you're defining your GPIO pin correctly but you're never toggling it high and low. To be able to drive the DE/~RE signal on your RS485 chip you should take the GPIO high before you write on the bus and low right after to be able to read the answer from your meter.

Unfortunately, I'm afraid what you're trying to do is not possible with pyModbus out of the box. You can take a look at this link:

https://github.com/riptideio/pymodbus/issues/33

You might be able to tweak pyModbus and use the RTS alternative functions on your Pi (see here: https://github.com/mholling/rpirtscts), but I don't think this path will get you very far reliability wise.

As I wrote here: RS485: Inappropriate ioctl for device, you might be better off going for a hardware solution. If you can't get new hardware you could always try the 555 timer solution, at least as a temporary fix.

Good luck, and be sure to post your progress or any further ideas.

EDIT: Solution using libmodbus instead

The suggestion to use libmodbus was very successful. Follow these steps if you want to try it (tested with Raspberry Pi 3B):

1) Clone libmodbus fork with GPIO support to your Pi:

git clone https://github.com/dhruvvyas90/libmodbus

2) Configure, compile and install libmodbus library (same commands as for the main repo):

./autogen.sh && ./configure --prefix=/usr && make && sudo make install

3) Go to rpi-test folder and compile the example:

gcc -o test -I/usr/include/modbus test.c -lmodbus

4) Run test, you will need to change permissions or sudo it: sudo ./test

What you get is actually much better than I expected and probably good enough for most Modbus hardware:

In blue, you see the TX from the Pi's UART (pin number 8 on the connector) and in yellow you get your DE/~RE (pin number 11, GPIO17) that you should connect to your RS485 chip. As you can see there is a delay of 0.6 ms from the end of the Modbus data frame until the bus is free for the slave to answer. At the speed I was using (9600 bps) the minimum delay you need to comply with the Modbus specification is around 3 ms (3.5 chars), so it should be fine for most situations.

The only thing pending would be to add all these GPIO functions to the pylibmodbus wrapper but that should be quite easy. I'm planning to use this library from Python real soon in the field with my Pocket Chip computer to work as a Modbus handheld tester so if you or anybody else manage to find the time I'd be more than glad to test it.

As soon as I have more time I'll try libmodbus together with my FTDI serial port and take a couple of scope captures to compare hardware vs. software signaling.

I forgot to mention that the only changes I made to the test.c were:

Line 13: #define UART_PORT "/dev/serial0"

Line 14: #define BAUD_RATE 9600

The first one just to the name of the embedded serial port on my Pi and the second one is the speed I always use for testing purposes.

EDIT: Software vs. Hardware signalling

As promised I have tested the solution proposed with libmodbus but instead of the embedded UART on the Raspberry Pi I made it work together with my FTDI USB adaptor to compare the time it takes to release the bus.

You can see how the TXEN (magenta trace) manages to go low about 250 microseconds after the stop bit while the GPIO on the Pi (in blue) takes more or less the same time as in the capture above (500-600 microseconds).

So pending more extensive testing, my conclusion is libmodbus does a great job for UARTs where you don't have a TX enable signal available. I think it should be possible to have reliable Modbus communication for most scenarios.

这篇关于Pymodbus - 在树莓派 pi3 的 UART 上通过 rs485 读取电能表的输入寄存器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆