blog

使用 Modbus 进行样机开发

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

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

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

从 pymodbus.client.sync 将 ModbusSerialClient 作为 ModbusClient 导入
导入结构
导入时间
导入日期时间
导入命令行解析

参数

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

parser = argparse.ArgumentParser(
    description="Modbus 数据记录仪"
)
parser.add_argument('port', help="用于连接探头的 COM 端口")
parser.add_argument('-f', '--file', help="数据存储文件的名称(默认数据.csv)", default="data.csv")
parser.add_argument('-a', '--address', help="探头地址(默认 240)", default=240, type=int)
parser.add_argument('-r', "--rate", help="以秒为单位的轮询率(默认 1 秒)", default=1, type=float)
parser.add_argument('-l', '--length', help="以小时为单位的数据记录时间长度(默认 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” 
安装 pymodbus。其他的库应该已经包含在 python 3 包中。
通过命令提示符导航到存储 Python 脚本的目录并键入 
“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 在线研讨会。

 

Add new comment