当前位置: 首页 > article >正文

python基于ModBusTCP服务端的业务实现特定的client

python实现ModBusTCP协议的client是一件简单的事情,只要通过pymodbus、pyModbusTCP等模块都可以实现,本文采用pymodbus。但要基于ModBusTCP服务端的业务实现特定的client,那得看看服务端是否复杂。前面系列文章,我们学习了对服务端的简单交互,便是得力于服务端简单的业务流程,本文将实现有点复杂的业务流程。

一、业务描述

我们将使用python脚本来实现一个ModBusTCP client,他能够触发设备进行拍照,然后读取拍照情况。

1、ModBusTCP服务端交互流程

大概类似如下交互时序,其中PLC将用我们的脚本代替。

2、控制

根据上述业务,服务器需要有寄存器存储客户端写入的控制位,存储顺序如下。

3、状态

根据上述业务,服务器需要有寄存器存储状态位,让客户端来读取,存储顺序如下。

4、结果

根据上述业务,服务器需要有寄存器存储结果,让客户端来读取,存储顺序如下。

5、 地址空间

(1)控制

类型:HoldingRegisters、Coils

起始地址与寄存器数量:自定义

(2)状态

类型:HoldingRegisters、DiscreteInputs、InputRegisters

起始地址与寄存器数量:自定义

(3)结果

类型:HoldingRegisters、InputRegisters

起始地址与寄存器数量:自定义

二、程序整体设计

class myModBusTCPclient(object):

    def __init__(self, obj):
        self.obj = obj

    # 状态读取后转成二进制,分别对应TriggerReady等状态
    def custom_binary(self, num, length=16, ByteSwap=0):
        # 将整数转换为二进制字符串
        binary_str = bin(num)[2:]
        # 计算需要补充的零的个数
        zeros_to_add = length - len(binary_str)
        # 构造符合规则的二进制字符串
        result_str = '0' * zeros_to_add + binary_str
        # 翻转二进制,如01转为10,方便后续取值
        result_str = result_str[::-1]
        if ByteSwap==0:
            return result_str
        elif ByteSwap==1:  # 需要字节交换时
            return result_str[8:] + result_str[:8]
        else:
            raise ValueError("ByteSwap 的值错误!")

    # 控制写之前先将TriggerEnable等二进制控制位转成数值
    def custom_num(self, binary, length=16, ByteSwap=0):
        assert len(binary) == length, "输入的二进制长度不正确!"
        binary = binary[::-1]  # 翻转二进制,如01转为10,方便后续取值
        if ByteSwap==0:
            return int(binary, 2)
        elif ByteSwap==1:  # 需要字节交换时
            return int(binary[8:] + binary[:8], 2)
        else:
            raise ValueError("ByteSwap 的值错误!")

    def ctrl(self, addrtype="HoldingRegisters", ByteSwap=0, binary="0000000000000000", address=0, slave=1):
        if addrtype=="HoldingRegisters":
            value = self.custom_num(binary[0:16], ByteSwap=ByteSwap)
            self.obj.write_registers(address, value, slave=slave)
        elif addrtype=="Coils":
            ...
        else:
            raise ValueError("ctrl_addrtype的值错误!")

    def status(self, addrtype="HoldingRegisters", ByteSwap=0, reg_addr=2, reg_nb=2, slave=1):
        if addrtype=="HoldingRegisters":
            value = self.obj.read_holding_registers(reg_addr, reg_nb, slave=slave)
            value_list = [value.registers[i] for i in range(reg_nb)]  # 整型列表
            print("status HoldingRegisters:", value_list)
            print([self.custom_binary(i, ByteSwap=ByteSwap) for i in value_list])
            return [self.custom_binary(i, ByteSwap=ByteSwap) for i in value_list]
        elif addrtype=="InputRegisters":
            ...
        elif addrtype=="DiscreteInputs":
            ...
        else:
            raise ValueError("status_addrtype的值错误!")

    def plc_out(self, addrtype="HoldingRegisters", ByteSwap=0):
        if addrtype=="HoldingRegisters":
            ...
        elif addrtype=="InputRegisters":
            ...
        else:
            raise ValueError("plc_out_addrtype的值错误!")

if __name__ == "__main__":
    # Modbus TCP服务器的IP地址和端口号
    server_ip = "192.168.1.196"
    port = 502
    station = 1

    # 创建Modbus TCP客户端
    MDclient = ModbusTcpClient(server_ip, port)
    if MDclient.connect():
        myclient = myModBusTCPclient(MDclient)
        myclient.ctrl(ByteSwap=1, binary="1100000000000000")
        time.sleep(1)
        myclient.status(ByteSwap=1)

1、程序结构

上述代码定义了一个名为 myModBusTCPclient 的类,用于与 Modbus TCP 服务器进行通信。下面是对程序结构的分析:

构造函数 __init__

接收一个参数 obj,表示 Modbus TCP 客户端对象。将这个对象存储在实例变量 self.obj 中。

custom_binary 方法:

将给定的整数 num 转换为指定长度 length 的二进制字符串。可选参数 ByteSwap 用于指定是否进行字节交换。如果 ByteSwap 为 1,则进行字节交换,否则不进行。返回构造好的二进制字符串。

custom_num 方法:

接收一个二进制字符串 binary,根据给定的长度 length 和是否进行字节交换 ByteSwap 将其转换为整数。返回转换得到的整数。

ctrl 方法:

根据给定的地址类型 addrtype(默认是 "HoldingRegisters")、是否进行字节交换 ByteSwap、二进制字符串 binary、Modbus 地址 address 和从站号 slave,向 Modbus 服务器写入数据。如果地址类型是 "HoldingRegisters",则使用 write_registers 方法写入寄存器。

status 方法:

根据给定的地址类型 addrtype、是否进行字节交换 ByteSwap、寄存器地址 reg_addr、寄存器数量 reg_nb 和从站号 slave,从 Modbus 服务器读取数据。如果地址类型是 "HoldingRegisters",则使用 read_holding_registers 方法读取寄存器。

plc_out 方法:

根据给定的地址类型 addrtype 和是否进行字节交换 ByteSwap,执行一些 Modbus 操作。具体操作需要根据地址类型的不同进行扩展。

if __name__ == "__main__": 部分:

在脚本独立运行时进行的操作。创建了一个 Modbus TCP 客户端对象 MDclient。通过 myModBusTCPclient 类创建了一个自定义的客户端对象 myclient。调用了 ctrl 方法,向 Modbus 服务器写入数据。等待了一秒钟。调用了 status 方法,从 Modbus 服务器读取数据。

2、不同地址空间的请求

在ModbusTCP中,对于不同的寄存器,请求方式是不一样的,因此需要根据服务端的设置相应更改。

为了满足业务,需要对原有的pymodbus进行封装改造。

为了满足大端序和小端序,需要加入字节交换的操作。

三、程序实现


http://www.kler.cn/news/161056.html

相关文章:

  • 反钓鱼防盗号,共筑校园安全防线!Coremail出席CERNET学术年会
  • 案例054:基于微信的追星小程序
  • 代码随想录算法训练营第四十二天 _ 动态规划_01背包问题、416.分割等和子集。
  • 医院有HIS系统,为什么还要开发预约挂号小程序?数据如何互通?
  • 前端笔记(三)CSS 盒子模型
  • ★538. 把二叉搜索树转换为累加树
  • PHP使用HTTP代码示例模板
  • gpt3、gpt2与gpt1区别
  • 深入理解 Java 虚拟机(JVM)从入门到精通
  • 使用GPT-4V解决Pycharm设置问题
  • 西工大计算机学院计算机系统基础实验一(函数编写11~14)
  • Java程序员,你掌握了多线程吗?
  • 【运维面试100问】(七)ceph基础题面试
  • 「神印王座」萝莉女神小六打劫,白送10万功勋点,王原原恋人登场
  • 掌汇云 | 全场景数据追踪,多维了解用户偏好,提高运营效率
  • python入门级简易教程
  • C语言二叉树的基本概念(一)
  • 猫头虎分享ubuntu20.04下VSCode无法输入中文解决方法
  • ProEasy机器人案例:电池边包胶
  • IoT DC3 是一个基于 Spring Cloud 全开源物联网平台 linux docker部署傻瓜化步骤
  • 图解系列--HTTPS,认证
  • Linux AMH服务器管理面板本地安装与远程访问
  • C++ Primer Plus第十五章笔记
  • 第4节:Vue3 布尔属性
  • H5: 按钮的点击热区
  • 解析操作系统是如何启动起来的?
  • Django 模板引擎 (四)
  • 分享5款在各自领域遥遥领先的软件
  • 【IEEE独立出版】2024第四届神经网络、信息与通信工程国际学术会议(NNICE 2024)
  • 从cot到agent的survey视频笔记