ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

深入解析开源软PLC框架Beremiz:从IEC 61131-3到运行时原理

深入解析开源软PLC框架Beremiz:从IEC 61131-3到运行时原理 做工业自动化的朋友应该都听过Beremiz这个名字。如果你还没接触过我简单说一句Beremiz 是一个开源的、遵循 IEC 61131-3 标准的 PLC 编程软件也就是软 PLC 工具链。它不仅能写梯形图LD、功能块图FBD、顺序功能图SFC、结构化文本ST和指令表IL还自带运行时Runtime能把写好的逻辑直接编译成 C 代码并跑起来。这个项目在开源工控圈子里算是很有分量的一个“框架级”存在。它解决的问题很直接很多商业 PLC 软件绑定自家硬件想换平台、想学习标准、想做一些定制化的控制器方案成本高、门槛也高。Beremiz 把“编程环境”和“运行环境”整个开源出来你可以在树莓派上跑一个软 PLC也可以在 x86 工控机上搭一套自己的控制系统甚至拿它的编译器内核去做二次开发。这篇文章我想从一个实际用过的角度把 Beremiz 的框架掰开揉碎讲一讲从组件构成到编译链路再到底层运行原理最后聊一些扩展思路和踩坑经验。不管是刚开始接触开源 PLC 的工程师还是已经在用 Beremiz 但想更深入理解它内部机制的人这篇文章都值得你看完。1. Beremiz 项目概览它到底是个什么“框架”1.1 项目起源与核心定位Beremiz 这个项目说起来已经有十几年历史了最开始是几位对 IEC 61131-3 标准有浓厚兴趣的开发者发起的开源项目。它的名字没有特别复杂的含义就是这个项目的代号。整个工具链基于 Python 编写 IDE 部分运行时部分用 C 语言实现是一个典型的“上位机 下位机”架构。从定位上看Beremiz 做了三件核心的事作为 PLC 编程 IDE支持 IEC 61131-3 的多种编程语言提供项目管理、代码编辑、编译下载、在线调试、变量监控等一整套开发环境。作为编译器工具链内部集成了 MatIEC 编译器把 IEC 61131-3 的程序编译成 C 代码然后调用系统的 C 编译器生成可执行文件。作为运行时框架提供了一套跨平台的 PLC Runtime负责调度、输入输出映射、通讯协议处理并能通过串口、TCP/IP 等接口与上位机通信。所以“框架”这个词用在这里很准确。Beremiz 不只是一个画梯形图的软件它更像是一整套“软 PLC 解决方案框架”。你用它可以组成一个完整的工业控制器系统。1.2 它能解决哪些实际痛点商业 PLC 编程软件我们都很熟悉比如用某个厂家的 IDE程序写好了想换一个品牌的 PLC 就得重新学一套软件而且很多高级功能都被锁定在特定硬件里。Beremiz 的价值就在于把“PLC 编程”从“特定硬件”里解放出来。我在实际项目里拿它做过几类事情在树莓派上跑一个软 PLC通过 GPIO 和 Modbus TCP 控制一套小型实验室设备。开发过程跟用商业 PLC 差不多但硬件成本低很多。利用它的编译内核研究 IEC 61131-3 标准 ST 语言到 C 代码的映射方式为公司内部的控制器设计做参考。在一个上位机系统里把 Beremiz Runtime 作为后台任务运行通过 Modbus 协议与上位机界面通信实现“可视化 逻辑控制”分离的方案。如果你的需求是快速搭建一套灵活、可定制的控制逻辑系统而不是被某个商业生态“锁死”Beremiz 是非常值得花时间研究的项目。1.3 与商业 PLC IDE 的差别对比我自己做项目时Beremiz 和常用的商业 IDE 都用过。这里不是要分高下但两者的设计哲学确实有明显差异。对比维度商业 PLC IDEBeremiz硬件绑定通常绑定自家控制器或专用授权完全开源可移植到多种平台编程语言各家对 IEC 61131-3 有不同实现完整支持标准语言风格严谨底层可扩展性基本不开放只能使用默认功能开放源码可改编译器和运行时技术支持厂商提供商业支持靠社区、邮件列表和源码自研成本软件授权费用高完全免费生态依赖自行维护这种差异决定了 Beremiz 特别适合两类人一类是学习型用户想深入理解 PLC 编程语言的底层本质另一类是方案型用户需要基于标准做定制控制器系统。2. 框架级拆解从图形界面到硬件输出的完整链路2.1 整体架构分层很多人第一次打开 Beremiz 的源码会被目录结构吓一跳感觉模块特别多。其实它整体逻辑非常清晰核心可以分成下面几层上层PLCOpenEditor——基于 wxPython 的图形编辑环境是用户直接使用的 IDE。中间层项目模型与 PLCopen XML——项目以 PLCopen XML 作为标准交换格式工程树、变量表、程序组织单元POU都映射成 XML 结构。编译层MatIEC 编译器——解析 PLCopen XML生成 C 代码。系统构建层——调用系统 C 编译器通常是 gcc将生成的 C 代码编译成目标机可执行文件。运行层PLC Runtime——运行在目标设备上负责循环扫描、任务调度、IO 刷新、通讯处理。配置层——通过项目的配置对话框生成 runtime 配置文件定义硬件映射、任务周期和通讯参数。整个架构最精妙的一点是把“PLC 编程语言”和“具体硬件”解耦了。写逻辑的工程师只关心 IEC 61131-3 语言硬件工程师只需要按照 runtime 的接口去适配板卡两边互不干扰。2.2 PLCOpenEditor基于 wxPython 的图形化前端PLCOpenEditor 是 Beremiz 的图形界面部分项目中也叫 PLCOpenEditor它基于 wxPython 开发所以在 Windows 和 Linux 上都有比较好的跨平台表现。界面主要包含几个区域项目树展示 PLC 工程下的 POU、变量表、任务配置、通讯配置等。编辑区针对不同语言打开不同编辑器。ST 语言就是文本编辑器LD、FBD 语言则有图形化的连线编辑界面。变量表窗口用于定义全局变量、直接表示变量比如 %IX0.0 这种 IO 映射和常量。消息输出区显示编译信息、错误提示、调试输出等。前端的工作流是用户编辑工程 - 生成或更新 PLCopen XML - 交给编译器编译 - 生成 C 代码 - 编译链接 - 生成可执行文件。整个流程对用户来说是无缝的界面操作体验跟普通桌面软件没有太大区别。不过说实话PLCOpenEditor 的图形编辑体验跟商业 IDE 比还是有一点差距特别是梯形图、功能块图这种图形语言操作流畅度和交互细节会差一些。如果你主要用 ST 语言或 LD 语言做逻辑控制那完全够用如果想做非常复杂的图形化编程可能需要心里有预期。2.3 PLCopen XML整个工具链的“通用语言”PLCopen 是一个国际组织制定了很多与 PLC 编程相关的标准。Beremiz 项目采用 PLCopen XML 作为项目的存储格式和交换格式这意味着一个工程文件本质上就是一个符合 PLCopen 规范的 XML 文档。这个选择有几个实际好处标准化理论上其它支持 PLCopen XML 的工具也能打开 Beremiz 的工程文件虽然实际兼容性没有想象中完美。可读性XML 是纯文本格式出问题的时候可以直接打开看甚至手动修改某些节点。可生成因为工程是 XML所以完全可以通过脚本或程序自动生成 PLC 工程。这一点对于批量生成控制程序特别有用。我举个实际例子有一次需要为十几台设备生成结构相同但参数不同的控制程序我直接写了一个 Python 脚本去生成 PLCopen XML 文件省去了大量重复性工作。这在商业 PLC 软件里是做不到的。2.4 MatIEC 编译器把 ST 语言翻译成 C 代码的核心引擎MatIEC 是 Beremiz 的编译引擎它的主要职能是把 IEC 61131-3 标准语言编译成 C 语言。具体工作流程是这样的读取 PLCopen XML 工程文件解析 POU、变量表、任务等信息。进行语义检查比如变量类型是否匹配、功能块调用是否正确等。生成 C 代码框架包括程序入口、任务循环、变量初始化和 IO 映射。输出若干 .c / .h 文件然后交给系统 C 编译器进行编译链接。这个环节最关键的一步是 ST 语言的语义转化为 C 语言。比如一个 ST 程序段motor : (start_btn OR motor) AND NOT stop_btn;MatIEC 会分析变量类型、操作符优先级、功能块调用关系后生成类似于下面的 C 代码PLC_BOOL motor (PLC_BOOL)(((start_btn || motor) (!stop_btn)));当然实际生成的 C 代码会复杂得多它还要处理功能块实例的状态保存、任务调度、输入输出刷新等。从学习角度看MatIEC 是理解“高级语言如何映射为低层语言”的绝佳教材。我记得第一次把一段 ST 程序编译成 C 之后仔细去查看生成的代码才真正理解信号上升沿检测这类问题在底层是怎么处理的。2.5 PLC Runtime运行时调度与硬件抽象层PLC Runtime 是最终运行在目标设备上的部分。它不是一个简单的 main 函数跑死循环而是有严格任务调度机制的“软控制器核心”。一个典型 Runtime 包含以下模块planner任务规划器管理多少个周期性任务、各自周期是多少毫秒。mainplcPLC 主循环逻辑负责调用用户程序执行 IO 刷新。loc本地输入输出访问模块比如直接读取某 GPIO 的状态。modbus内置 Modbus 从站协议栈支持 Modbus TCP 和 RTU。debugger运行调试接口支持在线修改变量值、断点、单步等。Runtime 启动后会先完成全局变量初始化然后进入循环扫描阶段。每个扫描周期内Runtime 按照配置调用用户逻辑并在周期结束时刷新输出信号。因为 Runtime 本身是 C 语言写的所以理论上可以移植到任何支持 C 编译的微处理器上。Beremiz 官方源码里已经包含了不少平台的移植示例常见的有树莓派、BeagleBone、x86 Linux、Windows 等。3. 完整实操用 Beremiz 从零搭建一个软 PLC 控制逻辑3.1 环境准备与安装Linux 下的推荐方案由于 Beremiz 对 Linux 的支持更完整我建议优先在 Linux 环境使用特别是 Ubuntu 或 Debian 系版本。安装依赖时最省心的做法是直接用系统的包管理器。以下是 Ubuntu 上常见的依赖项sudo apt update sudo apt install python3 python3-wxgtk4.0 python3-serial python3-lxml python3-pyvisa python3-pytest sudo apt install gcc make依赖装齐后Beremiz 可以通过源码启动或者使用 pip 安装git clone https://github.com/beremiz/beremiz.git cd beremiz pip install -r requirements.txt python3 ./Beremiz.py启动界面后你就能看到项目向导了。我第一次启动的时候还有点小激动因为一个完整的 IEC 61131-3 开发环境就这么免费跑起来了。3.2 创建一个新工程ST 语言实现启保停控制假设我们要做一个简单但很经典的控制逻辑电机的启动、保持、停止逻辑启保停。在 Beremiz 里操作流程大致如下第一步新建工程。打开 Beremiz 后选择新建工程指定工程名和存放路径。它会自动生成一个.xml后缀的工程文件这就是 PLCopen XML 格式的工程文件。第二步创建程序组织单元POU。在项目树里右键添加 POU语言选择结构化文本ST。给它起个名字比如MotorControl。第三步编写 ST 代码。在 ST 编辑器里输入以下逻辑PROGRAM MotorControl VAR start_btn AT %IX0.0 : BOOL; stop_btn AT %IX0.1 : BOOL; motor AT %QX0.0 : BOOL; END_VAR motor : (start_btn OR motor) AND NOT stop_btn;这段代码的含义是当启动按钮按下时电机启动并自保持停止按钮按下时电机停止。AT %IX0.0这种语法表示直接映射到 PLC 的物理输入输出地址。Beremiz 支持这种直接地址表示方式方便与真实硬件接线对应。第四步配置任务。在项目树中打开任务配置添加一个循环任务周期设置成 10ms 或 20ms并把MotorControl这个 POU 分配给这个任务。这样 PLC 运行时才会按照固定周期反复调用这段逻辑。第五步编译。点击编译按钮MatIEC 会生成 C 代码然后调用 gcc 生成可执行文件。编译如果出错消息输出区会明确提示是哪一行、什么类型的问题。3.3 配置目标平台与下载运行编译成功只是第一步要想在真实设备上跑起来你得连接运行时设备。Beremiz 支持两种模式一种是把 Runtime 跑在本地 PC 上通过本地回环连接另一种是通过以太网连接远程设备比如树莓派。在工程配置里设定好目标设备的 IP 和端口默认端口一般是 102 或 502具体要看 Runtime 的配置。连接成功后就可以把编译好的可执行文件下载到 Runtime 上启动运行。我一般会先在本地把一个软件模拟 Runtime 跑起来验证逻辑和监控变量都没问题后再下载到树莓派等真实环境。这样做的好处是可以快速迭代不占用硬件资源。3.4 在线调试与变量监控的实战操作运行起来之后Beremiz 的在线调试功能非常实用。你可以连接运行中的 PLC Runtime查看变量的实时值、强制变量、甚至暂停运行。操作步骤大致是点击连接按钮IDE 与 Runtime 建立调试通道。打开监控窗口添加motor、start_btn、stop_btn等需要观察的变量。点击运行实时刷新查看变量状态。需要测试时直接强制某个输入变量为 True观察输出是否按预期变化。这个调试通道走的是 TCP/IP 协议底层实现了一套类似调试器的协议栈。如果你对通讯协议有兴趣这部分源码也值得研究但平时使用完全不需要关心这些细节。在我调试启保停逻辑时最常见的情况是物理按钮接线接反了或者接触不良导致输入变量始终为 False。这种问题在 Beremiz 监控界面里一眼就能看出来——变量值不变化基本就是硬件层问题根本不需要去猜程序 bug。4. 框架的高级玩法扩展通讯协议与二次开发4.1 增加自定义通讯协议Beremiz Runtime 自带了 Modbus 从站协议栈对绝大多数工业应用来说已经够用了。但如果你需要自定义协议框架也给了足够的扩展空间。一种常见做法是在 Runtime 层增加一个通讯服务线程通过 Runtime 预留的接口读写 PLC 变量。比如在目标机的 C 代码中可以直接操作变量表结构体。Beremiz 工程生成的核心全局变量都会放在一个PLC_Globals结构体里。你的自定义通讯模块只需要包含对应的头文件就能访问所有全局变量。这种自由度是商业 PLC 完全不具备的。不过有个前提就是你要对 C 语言和 Runtime 的代码结构足够熟悉。我的经验是先用官方源码树里的runtime/目录理清模块分工再动手改代码能省大量时间。4.2 利用 Python 实现自动化和测试扩展Beremiz 的 IDE 是 Python 写的这意味着你可以通过 Python 脚本做很多自动化操作。比如批量生成工程、批量修改变量、自动化测试逻辑。我分享一个实际用过的场景当时需要验证一系列逻辑点的布尔组合是否正确。我直接用 Python 写了段脚本将不同的输入组合写入运行时变量读取输出结果自动判断是否与预期一致。整个过程比手动在界面上点按监控快了一个数量级。这个思路的底层原理就是 Beremiz 提供了对 PLCopen XML 的解析能力和运行时变量的访问能力。掌握这两点之后相当于拿到了整个工具链的“自动化接口”。4.3 基于 Beremiz 框架构建私有上位机系统在不少场合我们需要把 PLC 的“逻辑引擎”嵌入到自己的系统里比如实验室自动化设备、数据采集控制一体化装置。Beremiz Runtime 很适合做这种事情的执行核心。一个典型的组合方式是逻辑层用 Beremiz 编写核心控制逻辑处理保护、联锁、状态机等。通讯层Runtime 自带 Modbus TCP 从站向外部提供变量读写接口。上层界面用 Python、Node-RED、可视化组态软件或自己开发的客户端通过 Modbus 协议与 Runtime 交互。这个方案让我彻底摆脱了“必须买某家 PLC 某家组态软件”的绑定系统架构变得透明、可控、低成本。如果团队里有懂标准工业协议的人整个系统能非常高效地搭起来。5. 常见问题与避坑实录5.1 高频错误速查表用 Beremiz 的过程中我遇到过很多问题。下面这些是最常见、也最消耗意志力的类型错误现象可能原因解决办法编译无错误但运行时没有输出任务配置里没有绑定 POU或者输出映射地址写错检查任务配置和直接地址变量%QX连接 Runtime 超时目标设备 IP 端口错误或防火墙拦截先 ping 通设备再确认端口和 Runtime 是否启动图形编辑器打开 LD 工程卡顿工程图片段过多拆分工程、减少单页元素数量中文注释保存后乱码编码格式不统一统一使用 UTF-8 编码避免中文路径编译时报错缺少 gcc 相关库编译工具链不完整安装 build-essential检查 make 和 gcc5.2 几个很隐蔽的坑除了明面上的报错还有一些不易察觉的坑我在实际使用中踩过很多次这里拿几个典型出来说第一个坑%QW 地址和 Modbus 寄存器偏址之间的转换关系。如果你一直搞混 Modbus 寄存器编号和%QW地址容易在通信调试时找不到变量。实际上 Runtime 的 Modbus 映射是从寄存器 0 开始但很多组态软件界面往往把地址从 0 或 1 开始显示最终结果会错位。做通讯对接之前一定要先在 Runtime 的实现源码里确认偏移规则。第二个坑任务周期太短导致 CPU 占用飙升。如果是 1ms 的任务在一个性能一般的树莓派上跑起来可能会把 CPU 吃满还会拖慢通讯响应。一般来说逻辑控制用 10ms 就够了IO 快速处理才需要降低周期。项目初期别为了“性能”盲目设小周期合理测算实际需求更容易让系统稳定。第三个坑直接映射变量时地址越界。有些老工程师习惯写%IX100.0但实际硬件只有 16 路输入。Beremiz 编译时有些情况不会报错运行后得到的却是未定义值很难排查。建议先在项目配置里定义好硬件 IO 点数再使用直接地址映射。第四个坑运行时版本和 IDE 版本不匹配。Beremiz 更新迭代很快老版本的 Runtime 可能不认识新版本的编译产物会报一堆诡异错误。遇到这种问题先检查两者的版本号。5.3 性能调优与稳定性心得如果你已经在用 Beremiz 做真实项目那稳定性肯定是第一位的。我在实践中总结了一套比较有效的排错和优化顺序先稳定编译链路。确保同样的工程在任何机器上都能编译出一致结果。再固定 Runtime 环境。尽量使用相同版本、相同编译选项的 Runtime。然后在 IDE 里反复做在线调试把变量监控、强制、断点的流程跑熟。最后才考虑性能优化。大多数“卡顿”来自通讯层或任务周期配置优先检查这两处。另外有一点我很深的体会Beremiz 的调试能力虽然够用但和大型商业 IDE 的“固件级”调试还是没法比。遇到 Runtime 自身行为异常时只能靠日志输出和加打印信息来排查。所以建议把所有运行时状态信息先写好循环日志能大幅减少疑难杂症的排查时间。6. Beremiz 框架的后续扩展想象Beremiz 的框架设计决定了它很适合被扩展成更复杂的自动化平台。比如把它的编译器内核封装成一个服务供云端批量生成控制代码或者把 Runtime 部署到容器里配合边缘计算网关做远程控制。我甚至见过有人把 Beremiz 和 OPC UA 协议栈整合做了一个开源的 OPC UA 服务器方案。从“框架”的视角来看Beremiz 真正留下的是一个分层的、可替换核心组件的软 PLC 实现思路而不是某个特定功能点。理解了这套思路无论以后是继续用 Beremiz还是基于其它平台自研控制器都会有非常扎实的基础。整个项目本身就是一本活的工程教材值得反复研读。
返回列表