小说python操作PLC

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

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

Python作为当前最火的语言,在AI、云计算等诸多方面都能看到它的身影,当然在工业控制中,也不能少了它。

这里,就小说一把如何使用Python构建PC与PLC的通信,也算show一把Python在工控领域的风采。

Snap7简介

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

本次接触到的是西门子S7系列的PLC,通信方式都为网络型的,而Snap7正是一个开源的、32/64位的、多平台的以太网通讯库:

  • 支持多硬件体系结构(i386/x86_64、ARM/ARM64、Sun Sparc、Mips)
  • 支持多系统(Windows、Linux、BSD、Solaris)
  • 支持多语言(C/C++、Phyton、Node.js、Pascal、C#、VB)

官网为: http://snap7.sourceforge.net/

Python对其进行了封装,具体可以参见:

https://github.com/gijzelaerr/python-snap7

开发环境搭建

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

Python的安装这里就不再赘述,环境搭建主要就是Snap7和python-snap7两个库的安装。

1

安装Snap7

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

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

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

$ sudo -s
$ add-apt-repository ppa:gijzelaar/snap7
$ apt-get update
$ apt-get install libsnap71 libsnap7-dev

2

安装python-snap7

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

$ pip install python-snap7

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

import snap7
client = snap7.client.Client()
client.connect('192.168.0.1', 0, 1)
client.disconnect()

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

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

读写PLC

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

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

1

python-snap7读写分析

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

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))

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

区域地址什么东西,PLC能提供的是如下信息:

PLC程序员的眼里只有I、M、Q、DB,

python程序员,现在慌了一比,这是what?

如何才能看到PLC程序员眼里的美丽风景,就得多看一眼PLC了。

2

PLC数据存储和地址

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

PLC的数据存储通过tag的形式与存储区间关联,分为输入(I)、输出(O)、位存储(M)和数据块(DB),程序在访问对应(I/O)tag时,是通过访问CPU的Process Image Out,对相应地址进行操作,具体对应关系如下:

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

areas = ADict({
   'PE': 0x81,  #input
   'PA': 0x82,  #output
   'MK': 0x83,  #bit memory
   'DB': 0x84,  #DB
   'CT': 0x1C,  #counters
   'TM': 0x1D,  #Timers
})

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

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

实战

经过上面的精心准备,下面就来一波实战。

通过读写PLC的M10.1、MW201来具体看看如何读写PLC。

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'\x01')
    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'\x00\x0C')
    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'\x00\x03')
    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)

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

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

最后给出一段视频,python操作PLC来个跑马灯。

视频内容

原文发布于微信公众号 - chafezhou(gh_5b8f0c59b682)

原文发表时间:2018-07-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏全华班

基于PHP爬虫的博客小程序

小程序后端是基于 Wext-server-thinkphp3.2 实现的数据爬虫,使用 ThinkPHP3.2 框架开发。Wext-server-thinkph...

2601
来自专栏嵌入式程序猿

赶快来更新你的bootloader吧

不知大家是否还记得在之前给大家介绍过NXP的kinetis bootloader1.2版本的, 嵌入式工程师必须会的技能:玩转bootloader 时隔一年多,...

3729
来自专栏FreeBuf

美国邮政服务网站漏洞可暴露6000万用户数据,现已修复

美国邮政服务系统刚刚修复了一个严重的网站漏洞,该漏洞使得拥有usps.com帐户的任何人都可查看和修改约6000万用户的账户详情。

1163
来自专栏更流畅、简洁的软件开发方式

论程序的成长—— 你写的代码有生命力吗?

做了五年多的程序员了,回过头来看了看以前发的一些帖子,颇有一番感想。 我最得意的就是对数据访问的处理方法(我的数据访问层),倒不是说他有多么的强大、多么的完善,...

2046
来自专栏java架构师

学习 WCF (1)--基础篇

  Windows Communication Foundation (WCF)是一个面向服务编程的综合分层架构。该架构的顶层称为服务模型层(Service M...

2719
来自专栏游戏杂谈

移动APP的IM后台架构浅析

IM(InstantMessaging 即时通讯)作为一项基础功能,很多APP都有,比如:手机QQ、微信、易信、钉钉、飞信、旺旺、咚咚、陌陌等。而IM如同我们日...

2892
来自专栏架构师小秘圈

日订单50万级分布式事务

作者:伈情,喜玩Java、Python、Golang!热爱架构设计、SOA、微服务、高并发、分布式、性能优化、DevOps、大数据、消息队列等....!在互联网...

6617
来自专栏腾讯架构师的专栏

多核处理器下数据库系统日志管理器优化技术探讨

传统数据库的设计假设磁盘为主要存储设备,其性能取决于基于I/O代价模型的优化。然而,当前数据库运行的平台已逐渐转移到由多核处理器、大内存和以闪存为代表的低延迟存...

2281
来自专栏腾讯NEXT学位

webpack 4 测试版 —— 现在让我们先一睹为快吧!

3435
来自专栏SDNLAB

分层安全用于通用客户端设备(uCPE)部署的准则

1455

扫码关注云+社区