使用 Modbus 进行样机开发

程序员在笔记本屏幕上编写 python 代码、java 脚本、html 代码
Alex Pohjanpelto
Alex Pohjanpelto
Published:
工业制造和工艺
工业测量
生命科学

您是在进行样机开发,还是在寻找一种经济型方式,保障应用中的温湿度测量质量?您是否了解关于 Python 等编程语言的一些基本知识?如果您了解,那么我想要向您展示如何仅通过一个 HMP110 探头、一条 USB 服务电缆 (219690) 和一台安装了 Python 3 的计算机来轻松地长时间记录数据。我将带您了解该代码的各个方面,但如果您对解释内容不感兴趣,您可以直接跳到本文的末尾,获取完整的代码。另外需要说明的是,这只是一个用于演示 Modbus 通信的示例脚本。

在介绍代码之前,让我们首先了解一下我们将用到的库,其中重要的是 pymodbus。我们使用该库来通过 Modbus RTU 与探头建立通信,具体操作是从 pymodbus.client.sync 导入 ModbusSerialClient。我们使用struct库将字位处理为不同的变量类型,使用time库更改轮询率,使用datetime库获得读取数据的时间和日期,此外,我们导入 argparse库,将参数从命令行传递至代码。

from pymodbus.client.sync import ModbusSerialClient as ModbusClient
import struct
import time
import datetime
import argparse

参数

为了有助提高代码的灵活性,我添加了一些参数。 使用上述参数可让我们无需更改代码,便能从命令行轻松更改变量值。我认为可能会有所帮助的参数有通信端口、数据存储文件的名称、探头的地址、轮询频率和数据记录长度。

parser = argparse.ArgumentParser(
    description="Modbus data logger"
)
parser.add_argument('port', help="The COM port where the probe is attached")
parser.add_argument('-f', '--file', help="The file name to store the data (default data.csv)", default="data.csv")
parser.add_argument('-a', '--address', help="The address of the probe (default 240)", default=240, type=int)
parser.add_argument('-r', "--rate", help="The poll rate in seconds (default 1)", default=1, type=float)
parser.add_argument('-l', '--length', help="The length of time in hours to data log (default 9999999)", type=float, default=9999999)
args = parser.parse_args()

Modbus 连接

我们首先需要初始化新的串行 Modbus 客户端,此客户端应已根据探头进行正确设置。本示例中的参数集必须包括通信方式、通信端口、响应超时、波特率、停止位和奇偶校验。Modbus RTU 的通信方式为“rtu”,端口取决于您的计算机,因此我将在以下部分说明如何识别正确的端口。由于其他参数由探头的设置决定,因此您需要参考探头的数据表,获取恰当的值。一般情况下,针对维萨拉探头,波特率应为 19200,停止位为 2,无奇偶校验。

probe = ModbusClient(method='rtu', port=args.port, timeout=1, baudrate=19200, stopbits=2, parity='N')

 

读取保持寄存器

现在我们来创建一个函数以读取探头的保持寄存器。我们要调用上一节中创建的 Modbus 客户端实例的 read_holding_registers() 方法来读取寄存器。我们需要指定保持寄存器的起始地址、寄存器的数量和探头的从属地址。我们会从寄存器收到低字节序格式的 16 位字数据,之后,我们必须将其转换为 32 位浮点值。 

def holding_registers_data():
    try:        
        registers = probe.read_holding_registers(address=0,count=10, unit=args.address).registers
            except Exception as e:
        print(e)
        return False, None, None, None
    try:
        rh = data_from_register(registers, 1)
        t = data_from_register(registers, 3)  
        dp = data_from_register(registers,9)   
       
    except Exception as e:
        print(e)
        return False, None, None, None
        return True, rh, t, dp
 

将寄存器的值转换为 32 位的值

寄存器的值以 16 位整数的形式存储,我们需要将其转换为 32 位浮点格式。为此,我创建了一个函数,它可以获取寄存器的值和寄存器索引,并返回索引数据的 32 位浮点值。我们采用模块结构来执行此转换

def data_from_register(registers, i):
    return struct.unpack('!f', bytes.fromhex('{0:04x}'.format(registers[i]) + '{0:04x}'.format(registers[i-1])))[0]

 

记录数据

鉴于我们已经可以读取保持寄存器并将寄存器的值转换为 32 位浮点值,我们需要创建一个可将这些值存储在 .csv 文件中的函数。为此,我创建了一个名为 data_logger() 的函数。它可以调用函数 holding_registers_data(),并以日期时间、相对湿度、温度、露点的格式将获取的数据附加到文件中。

def data_logger():
    probe.connect()
    successful, rh, t, dp = holding_registers_data()
    if (successful):
        dt = datetime.datetime.now()
        
        try:
            with open(args.file, "a") as f:
                line = f"{dt},{rh},{t},{dp}\n"
                print(line)
                f.write(line)   
        except Exception as e:
            print(e)
        probe.close()
        time.sleep(args.rate)
        
    else:
        probe.close()
        time.sleep(0.5)
 

 

确定探头的通信端口

首先,确保您的探头能正确连接到计算机。 
 

Windows
在 Windows 操作系统中,您可以在“设备管理器”下找到设备的 COM 端口。要打开“设备管理器”窗口,请打开屏幕左下方的“开始”菜单,然后输入“设备管理器”。它会显示在搜索结果中,单击该图标或按下键盘上的 Enter 键便可打开该窗口。单击“端口(COM 和 LPT)”旁边的箭头以展开端口。您会看到被列为“Vaisala USB Device”的一个设备,它的旁边列出了 COM 端口名称,在我们的示例中应为 COM6。

Image
Determining the communication port of the probe

Linux 
在 Linux 中,您可以通过在终端键入命令“dmesg | grep tty”来确定通信端口。在所有返回的语句中,会有一个类似于“'cp210x converter now attached to ttyUSBn ”的语句,其中 ttyUSBn 便是端口。

运行代码

要运行脚本,您必须安装所有的库。如果需要,可以使用 pip 命令 

pip3 install -U pymodbus 
to install pymodbus. The other libraries should already come with the python 3 package.
In a command prompt, navigate to the directory where they python script is stored and type 
    python Modbus_RTU -h 

以获得有关参数的操作。命令提示符中应显示此过程。下方是输出内容的屏幕截图。

Image
Terminal

 

 

 

 

 

通信端口是必需参数,其他参数均具备默认值,您可以根据自己的偏好进行更改。通信端口参数不需要标识符,可以放在文件名称之后的任意位置。但其他可选参数需要标识符。
 以下是以长格式和短格式显示的典型命令示例:

    Python .\Modbus_RTU  --file datalog.csv --address 240 --rate 10 --length 48 COM6
    Python .\Modbus_RTU -f datalog.csv -a 240 -r 10 -l 48 COM6 
 

 

下载完整代码观看 Modbus 101 在线研讨会。