当前位置:首页 > 微信算帐机器人定制 > 正文内容

微信算帐机器人定制 CODESYS 应用实践 — 上下位机闭环

admin1个月前 (09-16)微信算帐机器人定制54



这是工业自动化中非常典型的架构:上位机(PC/HMI/SCADA)负责监控、参数下发、数据可视化;下位机(PLC/控制器运行 CODESYS Runtime)负责实时逻辑控制、PID 闭环、运动控制。两者通过工业通信协议构成完整闭环。下面从架构到代码实现完整讲透。


---

一、架构总览


┌──────────────────────────────────────────────────────────┐

│ 上位机 (上位) │

│ │

│ ┌─────────┐ ┌──────────┐ ┌──────────────────┐ │

│ │ CODESYS │ │ HMI / │ │ SCADA / Python │ │

│ │ IDE │ │ WebVisu │ │ / 上位机软件 │ │

│ │ (开发调试)│ │ (可视化) │ │ (数据采集监控) │ │

│ └────┬────┘ └────┬─────┘ └────────┬─────────┘ │

│ │ │ │ │

│ └──────────────┼───────────────────┘ │

│ │ │

└───────────────────────┼───────────────────────────────────┘

 │

 通信协议层

 ┌──────────┼──────────┐

 │ │ │

 OPC UA Modbus TCP EtherCAT

 (语义化) (简单通用) (实时总线)

 │ │ │

┌───────────┼──────────┼──────────┼────────────────────────┐

│ │ │ │ 下位机 (下位) │

│ ▼ ▼ ▼ │

│ ┌──────────────────────────────┐ │

│ │ CODESYS Runtime │ │

│ │ (IEC 61131-3 运行时) │ │

│ │ │ │

│ │ ┌──────────────────────┐ │ │

│ │ │ PLC 逻辑 (ST/LD/FBD) │ │ │

│ │ │ PID 闭环控制 │ │ │

│ │ │ 运动控制 (MC) │ │ │

│ │ └──────────────────────┘ │ │

│ │ │ │

│ │ ┌──────────────────────┐ │ │

│ │ │ I/O 驱动 │ │ │

│ │ │ EtherCAT Master │ │ │

│ │ │ Modbus TCP/Ser │ │ │

│ │ │ OPC UA Server │ │ │

│ │ └──────────────────────┘ │ │

│ └──────────────────────────────┘ │

│ │ │

│ ┌─────────┴──────────┐ │

│ │ 现场设备 │ │

│ │ 传感器/执行器/电机 │ │

│ └────────────────────┘ │

└──────────────────────────────────────────────────────────┘


---

二、CODESYS 是什么


| 维度 | 说明 |

|------|------|

| 全称 | Controller Development System |

| 开发方 | 德国 3S(CODESYS)软件集团 |

| 标准 | 遵循 IEC 61131-3 国际标准 |

| 编程语言 | LD(梯形图)、FBD(功能块图)、ST(结构化文本)、SFC(顺序功能图)、IL(指令表)、CFC(连续功能图) |

| 核心能力 | PLC 逻辑 + 运动控制 + HMI 可视化 + 安全控制 + Web 远程监控 + 冗余 |

| 硬件独立性 | 同一套软件可编程不同厂商的 PLC/控制器 |

| 架构 | IDE(开发环境)+ Runtime(运行时,部署在目标硬件上) |


---

三、上下位机角色划分


| 维度 | 上位机 | 下位机 |

|------|--------|--------|

| 硬件 | PC / 工业平板 / 触摸屏 | PLC / 运动控制器 / 嵌入式控制器 / 工业 PC |

| 软件 | CODESYS IDE / HMI 软件 / SCADA / Python | CODESYS Runtime |

| 职责 | 开发调试、参数下发、数据可视化、历史存储、报警管理 | 实时逻辑控制、PID 闭环、运动控制、I/O 采集 |

| 实时性 | 秒级 / 百毫秒级 | 毫秒级 / 微秒级 |

| 通信角色 | OPC UA Client / Modbus Master | OPC UA Server / Modbus Slave |


---

四、通信协议选择


| 协议 | 特点 | 适用场景 | CODESYS 支持 |

|------|------|----------|:---:|

| OPC UA | 语义化信息模型、带类型/时间戳/质量码、跨厂商标准 | 大量带语义 tag、工业互联网、MES/SCADA 对接 | ✅ 内置 Server |

| Modbus TCP | 简单、寄存器地址、无类型语义 | 简单数据交换、老旧设备兼容 | ✅ Master/Slave |

| EtherCAT | 实时总线、微秒级周期 | 伺服运动控制、高速 I/O | ✅ Master |

| CANopen | CAN 总线、设备协议 | 工程机械、车辆 | ✅ Master/Slave |

| PROFINET | 西门子生态 | 西门子设备对接 | ✅ 需授权 |

| EtherNet/IP | 罗克韦尔生态 | AB 设备对接 | ✅ Scanner/Adapter |


选型建议:


需要语义化 tag 管理?

├── 是 → OPC UA(PLC 做 Server,上位机做 Client)

└── 否 → 需要实时运动控制?

 ├── 是 → EtherCAT(伺服/IO 模块)

 └── 否 → Modbus TCP(简单够用)


---

五、实战:OPC UA 上下位机闭环

5.1 下位机(CODESYS PLC)配置


Step 1:创建工程


CODESYS IDE → File → New Project

→ Device: CODESYS Control Win V3 (或对应硬件)

→ PLC PRJ → 添加 POU


Step 2:开启 OPC UA Server


在设备树中添加 OPC UA Server:


Device → 右键 → Add Device → Fieldbus → OPC UA → OPC UA Server


Step 3:定义变量(ST 语言)


// ── 全局变量表 ──

{attribute 'OPC.UA.DA' := '1'} // 暴露给 OPC UA

VAR_GLOBAL

 // 上位机下发的设定值

 fSetTemp : REAL := 25.0; // 目标温度

 fSetPressure : REAL := 1.5; // 目标压力

 bStart : BOOL := FALSE; // 启动信号

 bStop : BOOL := FALSE; // 停止信号


 // 上位机读取的反馈值

 fActTemp : REAL := 0.0; // 实际温度

 fActPressure : REAL := 0.0; // 实际压力

 fActRPM : REAL := 0.0; // 实际转速

 iRunStatus : INT := 0; // 运行状态码

 sAlarmMsg : STRING(80); // 报警信息

END_VAR


Step 4:PID 闭环控制(ST 语言)


// ── PID 温度闭环控制 ──

FUNCTIONBLOCK FBTempControl

VAR_INPUT

 fSetpoint : REAL; // 目标温度

 fActual : REAL; // 实际温度(传感器采集)

 bEnable : BOOL; // 使能

 bAuto : BOOL; // 自动/手动模式

 fManualOut : REAL; // 手动输出(0~100%)

END_VAR

VAR_OUTPUT

 fOutput : REAL; // 输出(0~100%,控制加热器 PWM)

END_VAR

VAR

 pidTemp : FB_PID; // CODESYS 内置 PID 功能块

 fError : REAL;

END_VAR


// PID 参数

pidTemp(

 KP := 2.0, // 比例系数

 TN := 10.0, // 积分时间(秒)

 TV := 2.0, // 微分时间(秒)

 SET_POINT := fSetpoint,

 ACTUAL := fActual,

 AUTO := bAuto,

 MANUAL := fManualOut,

 Y => fOutput // 输出 0~100%

);


IF NOT bEnable THEN

 fOutput := 0.0;

END_IF


Step 5:主程序


PROGRAM PLC_PRG

VAR

 fbTemp1 : FB_TempControl;

 fbPress1: FB_PressureControl;

 iState : INT := 0; // 状态机

END_VAR


// ── 状态机 ──

CASE iState OF

 0: // 待机

 IF bStart THEN

 iState := 10;

 bStart := FALSE;

 END_IF


 10: // 运行 - 温度闭环

 fbTemp1(

 fSetpoint := fSetTemp,

 fActual := fActTemp,

 bEnable := TRUE,

 bAuto := TRUE,

 fManualOut := 0.0

 );


 // 压力闭环

 fbPress1(

 fSetpoint := fSetPressure,

 fActual := fActPressure,

 bEnable := TRUE,

 bAuto := TRUE,

 fManualOut := 0.0

 );


 // 状态反馈

 iRunStatus := 10;


 IF bStop THEN

 iState := 20;

 bStop := FALSE;

 END_IF


 20: // 停止

 fbTemp1(bEnable := FALSE);

 fbPress1(bEnable := FALSE);

 iRunStatus := 20;

 iState := 0;

END_CASE


// ── 报警检测 ──

IF fActTemp > 80.0 THEN

 sAlarmMsg := '温度超限!';

 iState := 20;

ELSIF fActPressure > 5.0 THEN

 sAlarmMsg := '压力超限!';

 iState := 20;

ELSE

 sAlarmMsg := '';

END_IF


Step 6:下载到下位机


Online → Login → Download

→ PLC 开始运行,OPC UA Server 在端口 4840 监听

5.2 上位机(Python OPC UA Client)


from opcua import Client

import time

连接下位机 OPC UA Server

client = Client("opc.tcp://192.168.1.100:4840")

client.connect()

── 获取变量节点 ──

方式 A:通过 NodeID 直接获取

nodesettemp = client.getnode("ns=4;s=Application.PLCPRG.fSetTemp")

nodeacttemp = client.getnode("ns=4;s=Application.PLCPRG.fActTemp")

nodestart = client.getnode("ns=4;s=Application.PLC_PRG.bStart")

nodestatus = client.getnode("ns=4;s=Application.PLC_PRG.iRunStatus")

nodealarm = client.getnode("ns=4;s=Application.PLC_PRG.sAlarmMsg")

── 下发设定值 ──

nodesettemp.set_value(25.0) # 设置目标温度

nodestart.setvalue(True) # 启动

── 订阅反馈值(变化时回调)──

def ontempchanged(node, val, data):

 print(f"[反馈] 实际温度: {val:.1f}°C")


def onalarmchanged(node, val, data):

 if val:

 print(f"[报警] {val}")


sub = client.create_subscription(500, handler=None) # 500ms

sub.subscribedatachange(nodeacttemp, ontempchanged)

sub.subscribedatachange(nodealarm, onalarm_changed)

── 主循环:监控 + 记录 ──

while True:

 status = nodestatus.getvalue()

 temp = nodeacttemp.get_value()

 print(f"[状态] {status} | 温度 {temp:.1f}°C")

 time.sleep(1)

5.3 上位机(CODESYS WebVisu 可视化)


如果用 CODESYS 自带的 WebVisu,不需要额外软件:

工程中添加 Visualization Manager

添加 Visualization 对象

拖拽控件:

文本框绑定 fActTemp(显示实际温度)

输入框绑定 fSetTemp(下发目标温度)

按钮绑定 bStart / bStop

指示灯绑定 iRunStatus

报警条绑定 sAlarmMsg

WebVisu → 启动 Web Server

浏览器打开 http://<PLC_IP>:8080


---

六、实战:Modbus TCP 上下位机闭环

6.1 下位机配置


Device → 右键 → Add Device → Fieldbus → Modbus → Modbus TCP Slave Device

→ 配置 IP: 192.168.1.100, Port: 502

→ 添加 Modbus Channel:

Holding Register 0: fSetTemp (REAL, 2 registers)

Holding Register 2: fActTemp (REAL, 2 registers)

Coil 0: bStart

Coil 1: bStop

6.2 上位机(Python Modbus Client)


from pymodbus.client import ModbusTcpClient


client = ModbusTcpClient("192.168.1.100", port=502)

client.connect()

写设定值(REAL 占 2 个寄存器)

import struct

temp_bytes = struct.pack('>f', 25.0)

regval = struct.unpack('>HH', tempbytes)

client.writeregisters(0, list(regval))

启动

client.write_coil(0, True)

读实际温度

result = client.readholdingregisters(2, 2)

raw = struct.pack('>HH', result.registers[0], result.registers[1])

act_temp = struct.unpack('>f', raw)[0]

print(f"实际温度: {act_temp:.1f}°C")


client.close()


---

七、PID 闭环控制完整实现


CODESYS 提供 FBPID(或 CTRLPID)功能块,也可以手写:


// ── 手写位置式 PID ──

FUNCTIONBLOCK FBPID_Custom

VAR_INPUT

 fSetpoint : REAL; // 设定值

 fActual : REAL; // 实际值

 fKp : REAL := 2.0; // 比例

 fKi : REAL := 0.1; // 积分

 fKd : REAL := 0.5; // 微分

 fOutMin : REAL := 0.0; // 输出下限

 fOutMax : REAL := 100.0; // 输出上限

 tCycle : TIME := T#100ms; // 控制周期

END_VAR

VAR_OUTPUT

 fOutput : REAL; // 输出

END_VAR

VAR

 fError : REAL;

 fLastError: REAL;

 fIntegral : REAL;

 fDeriv : REAL;

 ton : TON; // 定时器

END_VAR


// 周期触发

ton(PT := tCycle, IN := TRUE);

IF ton.Q THEN

 ton(IN := FALSE);


 // PID 计算

 fError := fSetpoint - fActual;

 fIntegral := fIntegral + fError * TIMETOREAL(tCycle);

 fDeriv := (fError - fLastError) / TIMETOREAL(tCycle);


 fOutput := fKp fError + fKi fIntegral + fKd * fDeriv;


 // 输出限幅

 fOutput := LIMIT(fOutMin, fOutput, fOutMax);


 // 抗积分饱和

 IF fOutput >= fOutMax AND fError > 0 THEN

 fIntegral := fIntegral - fError * TIMETOREAL(tCycle);

 ELSIF fOutput <= fOutMin AND fError < 0 THEN

 fIntegral := fIntegral - fError * TIMETOREAL(tCycle);

 END_IF


 fLastError := fError;

END_IF


---

八、通信协议对比


| 维度 | OPC UA | Modbus TCP | EtherCAT |

|------|--------|------------|----------|

| 语义化 | ✅ 带名字/类型/时间戳 | ❌ 只有寄存器地址 | ❌ 过程数据映射 |

| 类型安全 | ✅ 强类型 | ❌ 需手动解析 | ✅ ESI 描述 |

| 订阅模式 | ✅ 变化通知 | ❌ 轮询 | ✅ 周期同步 |

| 实时性 | 毫秒级 | 十毫秒级 | 微秒级 |

| 配置复杂度 | 中 | 低 | 高 |

| 跨厂商 | ✅ 标准 | ✅ 标准 | ✅ 标准 |

| 适用 | 上位机 ↔ PLC | 简单数据交换 | PLC ↔ 伺服/IO |


---

九、典型部署形态

形态 1:CODESYS 软PLC(PC-based)


工业 PC(运行 CODESYS Control for Linux/Windows)

├── 上位机:同一 PC 或远程 PC 上的 WebVisu/SCADA

├── 下位机:CODESYS Runtime(软 PLC)

├── 通信:本地内存共享 / OPC UA

└── I/O:EtherCAT 总线连接远程 IO 模块

形态 2:CODESYS + 独立 PLC


上位机 PC(CODESYS IDE + WebVisu)

 ↕ OPC UA / Modbus TCP

下位机 PLC(汇川 AC 系列 / 倍福 CX / Wago PFC 等)

 ↕ EtherCAT / Modbus

现场设备(伺服/传感器/执行器)

形态 3:HMI 一体化(HMI 即 PLC)


威纶通 cMT X / 倍福 CP 系列

├── HMI(触摸屏可视化)

├── PLC(CODESYS Runtime 内嵌)

└── 远程 IO(EtherCAT/Modbus)


---

十、调试与排坑


| 问题 | 原因 | 解法 |

|------|------|------|

| OPC UA 连不上 | 端口未开放/防火墙 | 检查 4840 端口、关闭防火墙或加白名单 |

| 变量在 OPC UA 中看不到 | 未加 {attribute 'OPC.UA.DA'} | 在变量声明前加属性标记 |

| Modbus 读到乱码 | 字节序不对 | 尝试 Big-endian / Little-endian / Word Swap |

| PID 输出震荡 | Kp 太大或周期太短 | 降 Kp、增大积分时间、调大控制周期 |

| EtherCAT 通信超时 | 拓扑/线缆/从站配置 | 检查拓扑顺序、线缆质量、ENI 文件 |

| WebVisu 打不开 | Web Server 未启动 | 工程中添加 WebVisu 模块,下载后访问 8080 |

| 下位机重启后参数丢失 | 变量未持久化 | 变量加 PERSISTENT 或 RETAIN 关键字 |


参数持久化:


VAR_GLOBAL PERSISTENT

 fSetTemp : REAL := 25.0; // 重启后保持上次值

 fSetPressure : REAL := 1.5;

END_VAR


---

十一、完整闭环数据流


上位机设定值 ──OPC UA/Modbus──► 下位机 PLC

 │

 ▼

 PID 闭环计算

 │

 ▼

 PWM/模拟量输出 ──► 加热器/电机/阀门

 │

 ▼

 传感器采集实际值

 │

 ▼

实际值反馈 ◄──OPC UA/Modbus── 下位机 PLC ──► 上位机显示/记录/报警


核心就一条链:上位机下发设定值 → 下位机 PID 闭环 → 输出到执行器 → 传感器采集反馈 → 上位机监控显示。CODESYS 的优势在于 PLC 逻辑、PID 控制、HMI 可视化、通信协议全部在一个平台里完成,不需要拼凑多个软件。


相关文章

微信算帐机器人定制 .NET 那边曲折得多,核心在于 "没有官方标准" 导致的军阀混战

Java 日志的历史比 .NET 那边曲折得多,核心在于 "没有官方标准" 导致的军阀混战。一条时间线讲清楚:---时间线:一部"接口战争"史第一阶段:蛮荒时代...

微信算帐机器人定制 用餐厅和盘子理解栈和堆

用餐厅和盘子理解栈和堆我们可以把整个内存想象成一家餐厅,‌栈就是门口专门摞盘子的固定置物架,堆就是餐厅里散放的所有餐桌‌,用这个生活化的场景就能把栈和堆的核心区别讲得明明白白。🥣 栈:门口的盘子置物架...

微信算帐机器人定制 大坐标、镜像与弦高:.NET CSG 库的工程笔记

这是OpenCSG.NET几何建模库在工业级场景落地时,针对三个高频踩坑点沉淀的实战工程经验,解决了传统.NET CSG库在大尺度工业建模场景下普遍存在的精度漂移、镜像拓扑失效、曲线离散失真三大核心问...

微信算帐机器人定制 典型的压力面试题,它真正考的不是“你能不能被替代”

这是一道典型的压力面试题,我先调用面试辅导能力,给你一套能直接上考场作答的完整思路。这是一道典型的压力面试题,它真正考的不是“你能不能被替代”,而是四个更底层的东西。我把解题逻辑、要避开的雷、以及一段...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。