PLC技术资料
    codesys与python“牵手”
    发布者:  发布时间:2025/10/14 14:14:52

    codesysplc与python的socket“牵手”:开启工业控制无限可能

    关键词:codesys、python、socket 通信、raspberry pi、工业物联网、实时数据采集、跨语言集成

    微信公众号原文连接:

    https://mp.weixin.qq.com/s/0jwwybowub5lj0g26gvjsa

    csdn:

    https://blog.csdn.net/qq_36063437/article/details/153248117?fromshare=blogdetail&sharetype=blogdetail&sharerid=153248117&sharerefer=pc&sharesource=qq_36063437&sharefrom=from_link

    一、引言:让 plc 拥抱开放的编程世界

    传统工业里,plc 稳守固定逻辑,精准执行控制任务。在工业物联网与智能制造浪潮下,工程师有了新期待:让 plc 与 python 等现代高级编程语言联手,将 plc 的稳定可靠与 python 的开放多元完美融合,从而释放出无限潜能。

    本文将以一个精彩案例,展示 plc 程序通过 socket 请求,让树莓派上 python 服务器抓取实时天气数据并回传解析存储的奇妙过程,一起探索!

    二、系统总体架构与数据流

    系统由两个主要部分构成:

    模块平台功能描述
    codesys plc 程序树莓派上的 codesys runtime客户端。检测触发信号、建立tcp连接、发送命令、接收天气 json 数据、解析并输出到变量。
    python 服务端程序树莓派 / 其他主机服务器。监听tcp端口,接收plc命令,通过 http 从 weather.com.cn 获取实时天气数据,解析后返回 json 格式响应。

    三、codesys 端:实现 plc 调用外部服务的关键逻辑

    codesys中新建名为socket_fb的功能块(function block),在plc主循环中调用。

    3.1 功能块的引脚设计

    socket_fb功能块引脚示意图

    3.2 上升沿触发与一次通信周期

    代码示例:

    brisingedge := bsendtrigger and not btrigold;

    btrigold := bsendtrigger;

    plc 程序通过检测输入 bsendtrigger 的上升沿,触发一次完整的通信任务。这样可确保每次请求都是用户或外部事件驱动,不会连续触发导致网络阻塞。一旦触发在后续的程序中会依次执行以下命令:

    周期初始化,清空所有状态变量;

    创建 tcp socket;

    连接到服务器;

    发送命令;

    等待并接收应答;

    解析结果;

    关闭连接。

    这是一个典型的“事务式通信模式”,类似工业现场中“一次握手、一问一答”的数据采集流程。

    3.3 周期初始化

    代码示例:

    if brisingedge then

    bconnectok := false;

    bsendok := false;

    brecvok := false;

    bdone := false;

    srecvbuffer := '';

    ierrorcode := errors.err_ok;

    每次通讯开始前重置所有状态标志,清空接收缓冲区。

    3.4 socket 通信核心流程

    codesys 的 syssocket 库提供了底层网络访问能力:

    函数作用
    syssockcreate()创建 socket,返回句柄
    syssockconnect()与服务器建立 tcp 连接
    syssocksend()发送数据
    syssockrecv()接收数据
    syssockclose()关闭连接

    (1) 创建socket:

    代码示例:

    hsocket := syssockcreate(socket_af_inet, socket_stream, socket_ipproto_tcp, adr(iresult));

    codesys库syssockcreate文档

    创建一个新的 socket,并返回该 socket 的句柄(handle)。这个句柄以后会作为参数传给其他套接字相关函数,例如 syssockbind、syssockconnect、syssocklisten、syssockaccept、syssocksend、syssockrecv、syssockclose 等。

    参数:socket_af_inet, socket_stream, socket_ipproto_tcp是 codesys 系统库中定义的常量,初始值如下表所示。

    nametypeinitialcomment
    socket_af_inetint2addressfamily: dinternetwork: udp, tcp, etc.
    socket_streamdint1socket types: stream socket
    socket_ipproto_tcpdint6protocols: tcp

    (2)设置socket服务器地址

    代码示例:

    sockinetaddr_result := syssockinetaddr('127.0.0.1', adr(ipaddr));

    if sockinetaddr_result = errors.err_ok then

    addrserver.sin_family := socket_af_inet;

    addrserver.sin_port := syssockhtons(5678);

    addrserver.sin_addr.uladdr := ipaddr;

    这段代码的作用是:将字符串形式的 ip 地址 "127.0.0.1" 转换为可用于网络通信的数值格式,并在转换成功后,设置服务器地址结构 addrserver 的基本参数:指定使用 ipv4 协议、端口号为 5678,并将目标 ip 地址设为 127.0.0.1,为后续建立 socket 连接做准备。

    codesys库syssockinetaddr文档

    在使用syssockconnect 前,需要把目标 ip(字符串)转换为可写入地址结构的二进制值。所以,syssockinetaddr 通常是网络通信初始化步骤中的一环。syssockinetaddr 的作用就是:把 "点分十进制" 的 ip 地址(例如 '127.0.0.1')转成一个 32 位无符号整数(udint)形式。

    在实际测试中使用的‘127.0.0.1’通过syssockinetaddr转换结果是16777343。一个 ipv4 地址本质上是 4 个字节(共 32 位),把它转换为16进制按字节拼起来是0x7f000001。网络中数据是 big endian(高位在前),但大多数 plc/cpu(x86、arm)是 little endian(低位在前)。也就是说在内存中这 4 个字节的排列是反的:

    网络字节序(标准): 7f 00 00 01

    plc内存(小端表示): 01 00 00 7f

    0x0100007f = (1 × 256^3) + (0 × 256^2) + (0 × 256) + 127= 16777343

    codesys库sockaddress文档

    sockaddress 结构用于在 codesys 中描述一个完整的网络通信地址,它包含了建立或识别网络连接所需的全部信息——包括地址族(如 ipv4)、端口号以及目标或本地的 ip 地址。该结构在调用syssockconnect函数时作为参数使用,用来告诉系统“我要与哪个 ip、哪个端口进行通信”。其中端口号需要通过 syssockhtons() 转换为网络字节序,ip 地址通常由 syssockinetaddr() 生成。简单来说,sockaddress 就是 codesys 中 socket 通信的“地址卡片”。

    (3)建立socket连接

    代码示例:

    sockconnect_result := syssockconnect(hsocket, adr(addrserver), sizeof(addrserver));

    这段代码的作用是:通过已创建的 socket (hsocket),调用 syssockconnect() 函数,将其连接到由 addrserver 定义的远程服务器地址,并返回连接结果。

    codesys库syssockconnect文档

    syssockconnect是一个用于实现客户端连接socket服务器功能的功能块。使用时,需将传入socket句柄和包含服务器ip地址和端口号等信息的sockaddress结构等。函数执行后会返回一个rts_iec_result类型的值,用于指示连接操作是否成功,若返回0表示连接成功,可进行后续数据传输等操作,否则需根据返回值进行相应的错误处理。

    (4) 发送命令

    代码示例:

    ssendbuffer := 'fun1';

    if syssocksend(hsocket, adr(ssendbuffer), len(ssendbuffer), 0, adr(socksend_result)) >; 0 and socksend_result = errors.err_ok then

    bsendok := true;

    这段代码的作用是:plc通过已连接的socket发送字符串 “fun1”,并在确认发送成功后设置发送成功标志。

    codesys库syssocksend文档

    syssocksend 函数用于向已建立的 socket发送数据。hsocket 是先前创建并连接成功的 socket 句柄;adr(ssendbuffer) 提供发送缓冲区的内存地址;len(ssendbuffer) 指定要发送的数据长度;0 表示不使用额外的发送标志;adr(socksend_result) 用于接收运行时系统返回的错误码。函数返回成功发送的字节数。如果发送的字节数大于 0 且系统返回码 socksend_result 等于 errors.err_ok,则说明数据成功发出,于是程序将 bsendok 置为 true,表示发送完成。

    (5) 接收数据

    代码示例:

    direcvbytes := syssockrecv(hsocket, adr(byrecvbuffer), sizeof(byrecvbuffer), 0, adr(sockrecv_result));

    if direcvbytes >; 0 and sockrecv_result = errors.err_ok then

    if direcvbytes >; sizeof(srecvbuffer) - 1 then

    direcvbytes := sizeof(srecvbuffer) - 1;

    end_if

    sysmemcpy(adr(srecvbuffer), adr(byrecvbuffer), direcvbytes);

    srecvbuffer[direcvbytes] := byte#0;

    brecvok := true;

    这段代码的主要作用是:从一个已建立的 tcp socket (hsocket) 中接收数据并保存到接收缓冲区中 (srecvbuffer),并在成功接收后标记 brecvok := true。

    codesys库syssockrecv文档

    syssockrecv用于从 socket中接收数据。它通过指定的socket句柄 hsocket 从端口读取数据,并将接收到的字节写入由 pbybuffer 指向的接收缓冲区中,最大接收长度由 dibuffersize 限制。

    codesys库sysmemcpy文档

    sysmemcpy用于内存数据复制,其作用是将指定源地址 psrc 中的内容复制到目标地址 pdest,复制的字节数由参数 udicount 决定。

    实际运行状态监控

    网络传输底层不认识“字符串”,所有内容(包括文字、数字、图片)都要被转为字节流(byte stream)。byrecvbuffer 收到的就是这些 ascii/utf-8 字节,direcvbytes是接收到的字节数量。

    codesys监控byrecvbuffer

    byrecvbuffer接收到的字节数据前9个依次为:123,34,110,97,109,101,101,110,34。根据字符与字节(ascii / utf-8 编码)之间的关系,以上字节可转译为:{、"、n、a、m、e、e、n、"。

    字符十进制字节值十六进制含义
    {1230x7b左花括号
    }1250x7d右花括号
    "340x22双引号
    :580x3a冒号
    ,440x2c逗号
    空格320x20空格
    0–948–570x30–0x39数字字符
    a–z97–1220x61–0x7a小写字母

    标准 ascii 或 utf-8 编码

    文本的案例中接收到的完整字符串为:{"nameen": "baoshan", "temp": "23.9", "wde": "nw", "wse": "11km/h", "sd": "84%", "qy": "1015", "njd": "4km", "updatetime": "20:40", "rain": "0", "rain24h": "0", "aqi": "88", "aqi_pm25": "88", "weathere": "haze"},共211字节,与监控的direcvbytes值一致。

    (6) json 解析

    代码示例:

    s_nameen := getfieldvalue(srecvbuffer, 'nameen');

    function getfieldvalue : string

    ...

    spattern := concat(skey, '": "');

    istart := find(ssrc, spattern);

    ...

    getfieldvalue := left(stemp, iend - 1);

    这段代码的主要作用是:从 ssrc 字符串中查找以 skey 为字段名的键值对,并提取该键对应的字符串值。类似从 ... "name": "alice", ... 中提取 alice 的功能。

    虽然 plc 没有内置完整 json 解析器,但通过字符串查找函数即可实现简化版字段提取。这说明即便在嵌入式 plc 环境中,也可以通过基础字符串操作解析网络数据。解析完成后,plc 将天气各项指标写入输出变量,如:

    s_temp := getfieldvalue(srecvbuffer, 'temp');

    s_windspeed := getfieldvalue(srecvbuffer, 'wse');

    s_humidity := getfieldvalue(srecvbuffer, 'sd');

    s_weather := getfieldvalue(srecvbuffer, 'weathere');

    这些变量可用于显示在 hmi、记录数据库、或驱动后续控制逻辑。

    (7) 关闭socket

    syssockclose(hsocket);

    关闭已创建的套接字 hsocket,释放与该套接字相关的系统资源,结束该网络连接。

    四、python 端:codesys 的“外部智能助手”

    4.1 设计思路

    python 在此系统中扮演“中间件服务层”角色。plc 不直接访问互联网,而是请求 python 服务端,由 python 完成网络请求与数据解析任务,再将结果以简洁 json 返回。

    这既保证了:

    plc 稳定、安全(不直接暴露外网请求);

    python 灵活、强大(可访问任意 api 或算法)。

    这种设计模式是“plc + 外部语言”协同的典型结构。

    本文案例以python监听socket端口,接收来自plc的命令来执行获取当前天气数据的功能,并且将天气数据返还给plc进行解析。

    4.2 主要功能模块

    (1) 天气数据抓取

    代码示例:

    def get_weather_data():

    url = f"https://d1.weather.com.cn/sk_2d/101020300.html?_{int(time.time() * 1000)}"

    headers = {

    'referer': 'https://e.weather.com.cn/',

    'user-agent': 'mozilla/5.0'

    }

    response = requests.get(url, headers=headers, timeout=10)

    return parse_weather_data(response.text)

    这段代码的作用是:python 使用 requests 库访问气象网站,提取返回数据包中的 json 数据段。

    解析后得到标准字典对象,例如:

    {

    "nameen": "pudong",

    "temp": "26",

    "wde": "east",

    "wse": "3.4",

    "sd": "65%",

    "qy": "1012"

    }

    (2) 端口监听

    def handle_client(conn, addr):

    data = conn.recv(2048).decode('utf-8').strip()

    if data == "fun1":

    weather_data = format_weather_data(get_weather_data())

    reply = json.dumps(weather_data, ensure_ascii=false)

    conn.sendall(reply.encode('utf-8'))

    python 服务监听端口 5678,一旦接收到 "fun1",便执行天气抓取并回传 json。采用多线程模式,保证可以同时服务多个 plc 连接。

    4.3 codesys 与 python 的契约:数据格式 + 通信协议

    项目内容
    连接方式tcp
    端口号5678
    请求命令fun1
    返回格式utf-8 编码的 json 文本
    通信周期按 plc 触发(例如每 30 秒或人工触发)

    通过这种契约,plc不需要理解python,只需发命令并解析字符串即可。这正是 “codesys 调用 python” 的精髓:plc 不直接运行 python 代码,但通过 socket 请求 → python 执行 → 结果返回,实现了间接调用。

    五、实验结果与运行验证

    实验环境:

    硬件:raspberry pi 4b + 2gb ram

    操作系统:raspberry pi os (64-bit)

    codesys 版本:3.5 sp21

    python 版本:3.11

    网络:同机运行(127.0.0.1)

    运行效果:

    1. 启动 python 服务器:

    [服务器启动] 正在监听 127.0.0.1:5678

    树莓派python

    2. 在 codesys 中触发 bsendtrigger 上升沿:

    bconnectok = true

    bsendok = true

    brecvok = true

    s_temp = "26"

    s_windspeed = "3.4"

    s_humidity = "65%"

    bdone = true

    codesys在线监控

    3. codesys可视化界面显示:

    codesys可视化界面

    验证:通信成功,数据解析正确。

    六、codesys 与 python 协同的技术意义

    6.1 打破 plc 封闭边界

    传统 plc 依赖专有协议和有限的函数库,难以直接与云端 api 或第三方系统交互。通过 syssocket,codesys 实现了跨语言通信的“开放接口”,使 plc 能够访问:

    web 服务(restful api)

    本地算法服务(python、c/c++)

    数据库代理(通过 python、node.js 等)

    6.2 各取所长的架构优势

    模块优势角色定位
    codesys plc实时性强、控制逻辑稳定数据消费者、执行层
    python 程序网络与算法能力强数据提供者、智能层

    这是一种工业界常见的分层架构:plc 负责“控制”,python 负责“智能”。

    七、扩展应用方向

    (1)工业 iot 数据融合

    可将 python 改为接入 mqtt、modbus、opc ua 等接口,plc 作为订阅者。

    (2)ai 辅助控制

    python 端可运行机器学习模型,根据实时天气预测能耗或生产计划,再通过 socket 返回控制参数。

    (3)边缘计算节点

    树莓派同时运行 plc 与 python,形成“混合智能边缘设备”,既具实时性又具云连接能力。

    (4)云服务接口

    可替换天气 api 为任意 web 服务(设备管理、能源监控、物流状态等),实现 codesys 与云端系统的数据桥接。

    八、结语:codesys 与 python 的融合之路

    本文以“codesys 获取实时天气数据”为案例,完整展示了:

    l 如何在树莓派上运行 codesys runtime;

    l 如何用 iec 61131-3 语言建立socket通信;

    l 如何通过 python 服务器实现外部数据访问;

    l 以及两者协作实现“plc 调用 python”的机制。

    这不是简单的网络实验,而是一个工业控制新时代的缩影。plc 不再局限于封闭的逻辑循环,而是可以与 ai、云端、web 世界自由交互。python 也不只是桌面脚本,而能成为工业现场的“智慧补脑”。

    这种模式预示着未来工业控制系统的方向:控制逻辑与数据智能的融合,实时性与开放性的统一。

    版权声明PLC信息网转载作品均注明出处,本网未注明出处和转载的,是出于传递更多信息之目的,并不意味 着赞同其观点或证实其内容的真实性。如转载作品侵犯作者署名权,或有其他诸如版权、肖像权、知识产权等方面的伤害,并非本网故意为之,在接到相关权利人通知后将立即加以更正。联系电话:0571-87774297。
0571-87774297