python 网络通讯 plc_如何使用 Python 构建 PC 通信?

7dedb0460b9d517196c480e36d0a93df.jpg-article

88228cae16c05f0cf31bfc13693ce873.jpg-article

PLC (Programmable Logic

Controller)即可编程逻辑控制器,可以理解为一个微型计算机,广泛应用于工业控制领域中,包括楼宇智控、精密机床、汽车电子等等。

随着物联网的兴起,越来越多的传统工业设备需要和外界通信,但很多情况下,类似 PLC 的微控制器经常会由于自身硬件因素而无法与外界直接互联互通。PC 作为一个中介桥梁,为 PLC 与外界的沟通打开了一扇门。

而 Python 作为当前最火的语言,不仅在 AI、云计算等诸多方面都能看到它的身影,在工业控制中也不能少了它。本文就来分享下如何使用 Python 构建 PC 与 PLC 的通信,也算展示一把 Python 在工控领域的风采。

**

**

7e60a5fbfbb1f3c446bdc876739a4879.jpg-article

Snap7 简介

当前市场上主流的 PLC 通信方式为网络通信和串行通信。网络通信这块主要协议有 profinet,modbus-tcp 等,串行通信主要是基于 RS232/485 的 modbus。

本次接触到的是西门子 S7 系列的 PLC,通信方式都为网络型的,而 Snap7 (http://snap7.sourceforge.net/)正是一个开源的、32/64 位的、多平台的以太网通讯库:支持多硬件体系结构(i386/x86_64、ARM/ARM64、Sun Sparc、Mips);

支持多系统(Windows、Linux、BSD、Solaris);

支持多语言(C/C++、Phyton、Node.js、Pascal、C#、VB)。

**

e2f52b9c0b4b5b1718b25c768bea08fd.jpg-article**

开发环境搭建

**

**

这里主要从 Windows 和 Linux (Ubuntu)两个平台,说说如何搭建 Python 环境下的 Snap7 开发环境。Python 的安装这里就不再赘述

,环境搭建主要就是 Snap7 和 python-snap7 两个库的安装。

1、安装 Snap7

Windows 下,需要根据 Python 的结构版本 (32 位 /64 位),将下载的 Snap7 的发布库 copy 到对应的 Python 安装根目录下即可。

9b374e4468f08821ff37aca2fb264cd2.jpg-article

如上图所示,我的 Python 是 32bit,所以需要将 Snap7 中 Win32 目录下的文件 Copy 到 Python 的安装根目录下,如下图所示:

9959050eb41591bed8f45a28c00e98cc.jpg-article

53cafaa5acbfddcacf6572b1b6bb2a8b.jpg-article

Linux (Ubuntu)下安装相对简单些,按如下命令即可:

[code]

$ sudo -s

$ add-apt-repository ppa:gijzelaar/snap7

$ apt-get update

$ apt-get install libsnap71 libsnap7-dev

[/code]

2、安装 python-snap7

Snap7 的 Python 库安装就简单很多了,不管是 Windows 还是 Linux,直接 pip 安装即可。

[code]

$ pip install python-snap7

[/code]

经过上面两步,环境就算搭建好了。通过一个连接测试代码试试,判断下环境是否搭建正常。

[code]

import snap7

client = snap7.client.Client()

client.connect('192.168.0.1', 0, 1)

client.disconnect()

[/code]

如果是下图提示,则环境正常(192.168.0.1 的 PLC 不存在)。

1c2e3a9704a6ea0635242aff960c6b4a.jpg-article

如果是下图提示,则环境异常(snap7 库安装不正确)。

0f5bea6775458cac8d393b96da142400.jpg-article

**

4d9e09432ac9bfef94427592a29ec044.jpg-article**

读写 PLC

环境搭建正常后,在正式建立通信前 PLC 还需做些配置工作,主要是开发自身的读写权限。具体参照下图配置:

e8698e2afdb8a1bf50d1f22b9014e542.jpg-article

c0f02235e53c0cb551b540ff6750d62b.jpg-article

066855f5a93dbd7cd4d7b4543c2e8cb6.jpg-article

通过上述配置,PLC 可以正常通信了。

1、python-snap7 读写分析

结合 python-snap7 的文档 API 和源码分析,python-sna7 重要的两个方法是 read_area 和 write_area,通过这两个方法就能读和写 PLC 的对应存储地址。

[code]

def read_area(self, area, dbnumber, start, size):

"""This is the main function to read data from a PLC.

With it you can read DB, Inputs, Outputs, Merkers, Timers and Counters.

:param dbnumber: The DB number, only used when area= S7AreaDB

:param start: offset to start writing

:param size: number of units to read

"""

assert area in snap7.snap7types.areas.values()

wordlen = snap7.snap7types.S7WLByte

type_= snap7.snap7types.wordlen_to_ctypes[wordlen]

logger.debug("reading area: %s dbnumber: %s start: %s: amount %s: "

"wordlen: %s" % (area, dbnumber, start, size, wordlen))

data = (type_* size)()

result = self.library.Cli_ReadArea(self.pointer, area, dbnumber, start,

size, wordlen, byref(data))

check_error(result, context="client")

return bytearray(data)

@error_wrap

def write_area(self, area, dbnumber, start, data):

"""This is the main function to write data into a PLC. It's the

complementary function of Cli_ReadArea(), the parameters and their

meanings are the same. The only difference is that the data is

transferred from the buffer pointed by pUsrData into PLC.

:param dbnumber: The DB number, only used when area= S7AreaDB

:param start: offset to start writing

:param data: a bytearray containing the payload

"""

wordlen = snap7.snap7types.S7WLByte

type_= snap7.snap7types.wordlen_to_ctypes[wordlen]

size = len(data)

logger.debug("writing area: %s dbnumber: %s start: %s: size %s: "

"type: %s" % (area, dbnumber, start, size, type_))

cdata = (type_* len(data)).from_buffer_copy(data)

return self.library.Cli_WriteArea(self.pointer, area, dbnumber, start,

size, wordlen, byref(cdata))

[/code]

从参数可见,需要提供 PLC 的区域地址、起始地址、读和写的数据长度。PLC 能提供如下信息:

c6b0681fd8830a621cafd644d3db9dbf.jpg-article

2、PLC 数据存储和地址

通过阅读 PLC 的手册获取到如下信息:

083c86e95ff5fcbe939a0dd28b7d6f3d.jpg-article

PLC 的数据存储通过 Tag 的形式与存储区间关联,分为输入 (I)、输出 (O)、位存储 (M) 和数据块 (DB)。程序在访问对应 (I/O)tag 时,是通过访问 CPU 的 Process

Image Out 对相应地址进行操作的。具体对应关系如下:

593fe2c96c7036b38c5f69f1608f4521.jpg-article

到这里就能明白 python-snap7 中定义的 areas 地址是什么含义了。

[code]

areas = ADict({

'PE': 0x81, #input

'PA': 0x82, #output

'MK': 0x83, #bit memory

'DB': 0x84, #DB

'CT': 0x1C, #counters

'TM': 0x1D, #Timers

})

[/code]

现在离读写 PLC 还差最后一步,就是起始地址如何确定呢?

ffee30f08be4ce2c95450b8e67efd1b3.jpg-article

从上可见对于 M3.4,对应的就是 M(0x83),起始地址是 3,对应 bit 位是 4。

**

0d68ba688a8038d09ffe0c9496c5405d.jpg-article**

实战

经过上面的精心准备,下面就来一波实战。通过读写 PLC 的 M10.1、MW201 来具体看看如何读写 PLC。

[code]

import struct

import time

import snap7

def plc_connect(ip, rack=0, slot=1):

"""

连接初始化

:param ip:

:param rack: 通常为 0

:param slot: 根据 plc 安装,一般为 0 或 1

:return:

"""

client = snap7.client.Client()

client.connect(ip, rack, slot)

return client

def plc_con_close(client):

"""

连接关闭

:param client:

:return:

"""

client.disconnect()

def test_mk10_1(client):

"""

测试 M10.1

:return:

"""

area = snap7.snap7types.areas.MK

dbnumber = 0

amount = 1

start = 10

print(u' 初始值 ')

mk_data = client.read_area(area, dbnumber, start, amount)

print(struct.unpack('!c', mk_data))

print(u' 置 1')

client.write_area(area, dbnumber, start, b'')

print(u' 当前值 ')

mk_cur = client.read_area(area, dbnumber, start, amount)

print(struct.unpack('!c', mk_cur))

def test_mk_w201(client):

"""

测试 MW201, 数据类型为 word

:param client:

:return:

"""

area = snap7.snap7types.areas.MK

dbnumber = 0

amount = 2

start = 201

print(u' 初始值 ')

mk_data = client.read_area(area, dbnumber, start, amount)

print(struct.unpack('!h', mk_data))

print(u' 置 12')

client.write_area(area, dbnumber, start, b'')

print(u' 当前值 ')

mk_cur = client.read_area(area, dbnumber, start, amount)

print(struct.unpack('!h', mk_cur))

time.sleep(3)

print(u' 置 3')

client.write_area(area, dbnumber, start, b'')

print(u' 当前值 ')

mk_cur = client.read_area(area, dbnumber, start, amount)

print(struct.unpack('!h', mk_cur))

if__name__== "__main__":

client_fd = plc_connect('192.168.0.1')

test_mk10_1(client_fd)

test_mk10_1(client_fd)

plc_con_close(client_fd)

[/code]

从代码可见,MW201,根据 M 确定 area 为 MK,根据 W 确定数据 amount 为 2Btye,根据 201 确定 start 为 201,读出来的数据根据数据长度用 struct 进行 unpack,写数据对应 strcut 的 pack。

这里给出 PLC 变量类型和大小,这样对应确定读写的 amount。

e889b2994cfceb4814bf20322f6c6b7f.jpg-article

最后给出一段视频,Python 操作 PLC 来个跑马灯。声明:本文为作者投稿,原载于个人公众号 chafezhou,版权归作者所有。

6a9da5bfec53b5952978a90ab8478153.jpg-article

9fc25526c9d1e9bb51d72925c11d4194.jpg-article

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值