使用Python和PyQt5实现Modbus TCP协议下的量程切换功能

news/2024/12/12 10:29:55/

使用Python和PyQt5实现Modbus TCP协议下的量程切换功能

在工业自动化系统中,设备的量程切换是一个常见的需求。本文将介绍如何使用Python和PyQt5开发一个图形用户界面(GUI)应用程序,以通过Modbus TCP协议向设备发送特定的指令,实现量程的切换(从大量程到小量程,反之亦然)。

一、需求概述

根据您的需求,我们需要实现以下功能:

  1. 切换指令
    • 大量程指令
      [0x01, 0x00, 0x00, 0x00, 0x04, 0x06, 0x01, 0x10, 0x00, 0xC8, 0x00, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02]
      
    • 小量程指令
      [0x01, 0x00, 0x00, 0x00, 0x04, 0x06, 0x01, 0x10, 0x00, 0xC8, 0x00, 0x02, 0x04, 0x00, 0x01, 0x00, 0x01]
      
  2. Modbus TCP服务器配置
    • IP地址:192.168.0.150
    • 端口:6789
  3. 开发工具
    • 编程语言:Python
    • GUI框架:PyQt5

我们将通过发送上述字节序列的方式,向指定的Modbus TCP服务器发送指令,实现量程的切换。

二、技术实现方案

为了满足需求,我们将采取以下步骤:

  1. 建立GUI界面:使用PyQt5创建一个简单的界面,包含两个按钮:“设置大量程”和“设置小量程”。
  2. 发送Modbus TCP指令:使用Python的socket库,通过TCP连接向指定的服务器发送相应的指令。
  3. 异步处理:为了确保GUI的响应性,我们将使用多线程或异步编程,防止发送指令时界面卡顿。
  4. 反馈机制:在发送指令后,向用户显示成功或失败的信息。

三、详细实现步骤

3.1 安装必要的库

确保已安装PyQt5库。如果尚未安装,可以使用以下命令进行安装:

pip install PyQt5

3.2 编写Python代码

以下是完整的Python代码示例,使用PyQt5创建GUI,并通过TCP发送Modbus指令:

python">import sys
import socket
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, QVBoxLayout, QLabel, QMessageBox
)
from PyQt5.QtCore import Qt, QThread, pyqtSignalclass ModbusThread(QThread):# 定义信号,用于向主线程发送消息finished = pyqtSignal(str)def __init__(self, command, ip, port):super().__init__()self.command = commandself.ip = ipself.port = portdef run(self):try:# 创建TCP/IP套接字with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:# 设置连接超时时间为5秒sock.settimeout(5)# 连接到服务器sock.connect((self.ip, self.port))# 发送指令sock.sendall(bytearray(self.command))# 接收响应(根据具体设备的响应而定,此处假设响应长度为8字节)response = sock.recv(1024)# 可以根据需要解析响应,这里仅简单地返回成功信息self.finished.emit("指令发送成功,收到响应:" + response.hex())except socket.timeout:self.finished.emit("连接超时,请检查服务器是否可达。")except socket.error as e:self.finished.emit(f"Socket错误: {e}")except Exception as e:self.finished.emit(f"发生错误: {e}")class ModbusApp(QWidget):def __init__(self):super().__init__()self.initUI()# 配置Modbus服务器的IP和端口self.modbus_ip = '192.168.0.150'self.modbus_port = 6789# 定义指令self.large_scale_command = [0x01, 0x00, 0x00, 0x00, 0x04, 0x06, 0x01, 0x10, 0x00, 0xC8, 0x00, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02]self.small_scale_command = [0x01, 0x00, 0x00, 0x00, 0x04, 0x06, 0x01, 0x10, 0x00, 0xC8, 0x00, 0x02, 0x04, 0x00, 0x01, 0x00, 0x01]def initUI(self):self.setWindowTitle('Modbus TCP量程切换')self.setGeometry(100, 100, 300, 200)layout = QVBoxLayout()self.label = QLabel('请选择要设置的量程模式:', self)self.label.setAlignment(Qt.AlignCenter)layout.addWidget(self.label)self.large_scale_btn = QPushButton('设置大量程', self)self.large_scale_btn.clicked.connect(self.set_large_scale)layout.addWidget(self.large_scale_btn)self.small_scale_btn = QPushButton('设置小量程', self)self.small_scale_btn.clicked.connect(self.set_small_scale)layout.addWidget(self.small_scale_btn)self.status_label = QLabel('', self)self.status_label.setAlignment(Qt.AlignCenter)layout.addWidget(self.status_label)self.setLayout(layout)def set_large_scale(self):self.status_label.setText('正在发送大量程指令...')self.send_command(self.large_scale_command)def set_small_scale(self):self.status_label.setText('正在发送小量程指令...')self.send_command(self.small_scale_command)def send_command(self, command):# 创建并启动Modbus线程self.thread = ModbusThread(command, self.modbus_ip, self.modbus_port)self.thread.finished.connect(self.on_finished)self.thread.start()def on_finished(self, message):# 更新状态标签self.status_label.setText(message)# 弹出消息框QMessageBox.information(self, '信息', message)def main():app = QApplication(sys.argv)window = ModbusApp()window.show()sys.exit(app.exec_())if __name__ == '__main__':main()

3.3 代码解析

3.3.1 模块导入
python">import sys
import socket
from PyQt5.QtWidgets import (QApplication, QWidget, QPushButton, QVBoxLayout, QLabel, QMessageBox
)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
  • sys:用于系统相关的功能,如退出应用。
  • socket:用于建立TCP连接和发送接收数据。
  • PyQt5.QtWidgets:用于创建GUI组件。
  • PyQt5.QtCore:用于多线程和信号通信。
3.3.2 创建ModbusThread类
python">class ModbusThread(QThread):# 定义信号,用于向主线程发送消息finished = pyqtSignal(str)def __init__(self, command, ip, port):super().__init__()self.command = commandself.ip = ipself.port = portdef run(self):try:# 创建TCP/IP套接字with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:# 设置连接超时时间为5秒sock.settimeout(5)# 连接到服务器sock.connect((self.ip, self.port))# 发送指令sock.sendall(bytearray(self.command))# 接收响应(根据具体设备的响应而定,此处假设响应长度为1024字节)response = sock.recv(1024)# 可以根据需要解析响应,这里仅简单地返回成功信息self.finished.emit("指令发送成功,收到响应:" + response.hex())except socket.timeout:self.finished.emit("连接超时,请检查服务器是否可达。")except socket.error as e:self.finished.emit(f"Socket错误: {e}")except Exception as e:self.finished.emit(f"发生错误: {e}")
  • ModbusThread:继承自QThread,用于在子线程中执行发送指令的操作,避免阻塞主线程。
  • 信号:定义finished信号,用于将操作结果传递回主线程。
  • run方法:执行发送指令的具体逻辑,包括建立连接、发送指令、接收响应,并通过信号传递结果。
3.3.3 创建ModbusApp类
python">class ModbusApp(QWidget):def __init__(self):super().__init__()self.initUI()# 配置Modbus服务器的IP和端口self.modbus_ip = '192.168.0.150'self.modbus_port = 6789# 定义指令self.large_scale_command = [0x01, 0x00, 0x00, 0x00, 0x04, 0x06, 0x01, 0x10, 0x00, 0xC8, 0x00, 0x02, 0x04, 0x00, 0x02, 0x00, 0x02]self.small_scale_command = [0x01, 0x00, 0x00, 0x00, 0x04, 0x06, 0x01, 0x10, 0x00, 0xC8, 0x00, 0x02, 0x04, 0x00, 0x01, 0x00, 0x01]
  • 初始化:设置服务器的IP和端口,以及定义切换量程所需的指令。
3.3.4 初始化GUI界面
python">    def initUI(self):self.setWindowTitle('Modbus TCP量程切换')self.setGeometry(100, 100, 300, 200)layout = QVBoxLayout()self.label = QLabel('请选择要设置的量程模式:', self)self.label.setAlignment(Qt.AlignCenter)layout.addWidget(self.label)self.large_scale_btn = QPushButton('设置大量程', self)self.large_scale_btn.clicked.connect(self.set_large_scale)layout.addWidget(self.large_scale_btn)self.small_scale_btn = QPushButton('设置小量程', self)self.small_scale_btn.clicked.connect(self.set_small_scale)layout.addWidget(self.small_scale_btn)self.status_label = QLabel('', self)self.status_label.setAlignment(Qt.AlignCenter)layout.addWidget(self.status_label)self.setLayout(layout)
  • 窗口标题和大小:设置窗口的标题和初始大小。
  • 布局:使用垂直布局(QVBoxLayout)组织组件。
  • 组件
    • 标签:提示用户选择量程模式。
    • 按钮:两个按钮分别用于设置大量程和小量程。
    • 状态标签:显示操作结果。
3.3.5 定义按钮点击事件
python">    def set_large_scale(self):self.status_label.setText('正在发送大量程指令...')self.send_command(self.large_scale_command)def set_small_scale(self):self.status_label.setText('正在发送小量程指令...')self.send_command(self.small_scale_command)
  • set_large_scaleset_small_scale:分别对应“设置大量程”和“设置小量程”按钮的点击事件,更新状态标签并调用send_command方法发送指令。
3.3.6 发送指令的方法
python">    def send_command(self, command):# 创建并启动Modbus线程self.thread = ModbusThread(command, self.modbus_ip, self.modbus_port)self.thread.finished.connect(self.on_finished)self.thread.start()def on_finished(self, message):# 更新状态标签self.status_label.setText(message)# 弹出消息框QMessageBox.information(self, '信息', message)
  • send_command:创建一个ModbusThread线程,传递指令、IP和端口,连接信号,并启动线程。
  • on_finished:接收线程发送的信号,更新状态标签并弹出消息框显示操作结果。
3.3.7 主函数
python">def main():app = QApplication(sys.argv)window = ModbusApp()window.show()sys.exit(app.exec_())if __name__ == '__main__':main()
  • main函数:初始化并运行PyQt5应用程序。

3.4 运行代码

将上述代码保存为modbus_switch.py,然后在终端或命令提示符中运行:

python modbus_switch.py

四、代码运行效果

运行程序后,您将看到一个简单的窗口,包含以下组件:

  1. 标签:提示用户选择量程模式。
  2. “设置大量程”按钮:点击后,程序将发送大量程指令。
  3. “设置小量程”按钮:点击后,程序将发送小量程指令。
  4. 状态标签:显示当前操作的状态信息。
  5. 消息框:在指令发送完成后,弹出消息框显示操作结果。

运行结果

在这里插入图片描述
点击切换大量程:
在这里插入图片描述
在这里插入图片描述
点击切换小量程:
在这里插入图片描述
在这里插入图片描述
与网络串口助手收的结果一致:
在这里插入图片描述

五、注意事项

  1. 指令正确性:确保发送的指令与设备的协议规范一致。根据您提供的指令,程序将发送特定的字节序列。如果设备有特定的响应格式,您可能需要根据实际情况解析响应。
  2. 网络配置:确保运行该程序的计算机与Modbus TCP服务器在同一网络或能够相互访问。检查防火墙设置,确保端口6789未被阻塞。
  3. 错误处理:程序中已包含基本的错误处理,如连接超时和Socket错误。根据需要,您可以扩展错误处理逻辑。
  4. 多线程:使用子线程发送指令,确保GUI的响应性。如果发送指令的时间较长,考虑进一步优化线程管理。
  5. 安全性:在生产环境中,考虑使用加密和身份验证机制,确保通信的安全性。

六、扩展功能建议

  1. 指令验证:在发送指令前,添加对指令格式和内容的验证,确保指令的合法性。
  2. 日志记录:添加日志功能,记录发送的指令和接收的响应,便于后续分析和故障排查。
  3. 配置选项:将Modbus服务器的IP和端口、指令等配置项外部化(如使用配置文件),提高程序的灵活性。
  4. 高级响应解析:根据设备的响应协议,解析并显示更多详细的信息,如错误码、执行状态等。
  5. 用户认证:在GUI中添加用户认证功能,确保只有授权用户可以操作量程切换。

七、结语

通过本文的介绍,您可以使用Python和PyQt5开发一个简单而有效的Modbus TCP量程切换工具。该工具通过发送特定的Modbus指令,实现设备量程的切换,并提供友好的用户界面和基本的错误处理。根据实际需求,您可以进一步扩展和优化该工具,以满足更复杂的应用场景。

如果在开发过程中遇到问题,建议参考以下资源:

  • PyQt5官方文档
  • Python socket库文档
  • Modbus协议规范

http://www.ppmy.cn/news/1554468.html

相关文章

海选女主角

Description 光头强虽然很喜欢教书,但是迫于生活压力,不得不想办法在业余时间挣点外快以养家糊口。 “做什么比较挣钱呢?筛沙子没力气,看大门又不够帅...”光头强老师很是无奈。 “冯小刚比你还难看,现在多有钱呀&a…

MindSearch深度解析实践

任务要求:在 官方的MindSearch页面 复制Spaces应用到自己的Spaces下,Space 名称中需要包含 MindSearch 关键词,请在必要的步骤以及成功的对话测试结果当中 1.在github codespace中配置环境 conda create -n mindsearch python3.10 -y conda…

Ps:时间轴面板 - 面板控制菜单(视频时间轴)

Ps菜单:窗口/时间轴 Window/Timeline 使用“创建帧动画”和“创建视频时间轴”时,“时间轴”面板控制菜单提供了完全不同的选项。 以下对“创建视频时间轴”模式下的面板控制菜单进行详细说明。 ◆ ◆ ◆ 面板控制菜单说明 转到 Go To 用于定位播放头在…

3D 生成重建020-Gaussian Grouping在场景中分割并编辑一切

3D 生成重建020-Gaussian Grouping在场景中分割并编辑一切 文章目录 0 论文工作1 方法2 实验结果 0 论文工作 最近提出的高斯Splatting方法实现了高质量的实时三维场景新视角合成。然而,它仅仅关注外观和几何建模,缺乏细粒度的物体级场景理解。为了解决…

aippt:AI 智能生成 PPT 的开源项目

aippt:AI 智能生成 PPT 的开源项目 在现代办公和学习中,PPT(PowerPoint Presentation)是一种非常重要的展示工具。然而,制作一份高质量的PPT往往需要花费大量的时间和精力。为了解决这一问题,aippt项目应运…

nmap详解

Nmap(Network Mapper)是一个开放源代码的网络探测和安全审核的工具。由于它的功能强大,被广泛应用于网络安全领域。以下是Nmap的一些主要功能及其在实战中的应用举例。 Nmap的主要功能: 端口扫描:检测目标主机上开放…

【golang】 WaitGroup使用注意事项

注意1:使用指针 当把WaitGroup作为参数传递给函数时,如果传递的是变量本身(值传递),会发生复制。在 Go 语言中,这种复制可能会导致意外的行为。因为每个WaitGroup副本都有自己独立的计数器。下面的代码如果…

初识Linux · 线程池

目录 前言: thread pool成员变量分析 接口编写 前言: 前文我们介绍了基于线程同步和互斥两种关系的一种模型->生产消费模型,那么之前在学习进程的时候我们已经编写过了进程池,同理,学习线程的时候我们也要编写线…