图解OpenPLC编程流程:从零开始的可视化实战教学
你是否曾被传统PLC高昂的学习成本劝退?是否想亲手搭建一个工业级控制系统,却苦于没有硬件支持?今天,我们就用树莓派 + OpenPLC,带你走完一条完整的“软PLC”开发之路——无需专业设备,也能体验真实的工业控制逻辑。
本文不堆术语、不讲空话,而是以图示+实操步骤+避坑指南的方式,手把手教你如何从创建项目到运行逻辑,再到远程监控,完整跑通一次OpenPLC编程流程。无论你是高校学生、电子爱好者,还是刚入行的自动化工程师,都能轻松上手。
为什么选择 OpenPLC?
在智能制造时代,PLC(可编程逻辑控制器)是工厂自动化的“大脑”。但市面上主流品牌如西门子、三菱等,不仅价格昂贵,还封闭生态,学习门槛极高。
而OpenPLC的出现,打破了这一局面:
- ✅ 完全开源免费
- ✅ 支持 IEC 61131-3 标准五大语言
- ✅ 可部署在树莓派、PC、STM32 等常见平台
- ✅ 内建 Modbus 和 Web HMI,开箱即用
更重要的是——它让“动手实践”变得触手可及。
我第一次在树莓派上点亮继电器时,那种“我真的在做工业控制”的感觉至今难忘。而这一切,只花了不到200元成本。
OpenPLC 是怎么工作的?一张图看懂核心架构
我们先来看这张简化版系统结构图:
[梯形图程序] ↓ (编译) [XML → C++ 代码] ↓ (运行) [OpenPLC Runtime 扫描执行] ↙ ↘ [%IX 输入读取] [%QX 输出写入] ↑ ↓ [传感器/按钮] [继电器/电机/灯] ↖ ↙ [Modbus TCP] ↓ [浏览器/Web HMI 或 SCADA]整个过程就像一场精密的“舞台剧”:
- 编剧:你在编辑器里画出梯形图或写结构化文本;
- 翻译:OpenPLC Editor 把你的逻辑转成 C++ 代码;
- 演出:运行时引擎每毫秒扫描一次输入→执行程序→更新输出;
- 观众互动:你可以通过网页实时查看变量状态,甚至强制修改。
接下来,我们就按这个流程一步步拆解。
第一步:搭建环境 & 创建项目
推荐配置(低成本入门方案)
| 组件 | 型号建议 | 备注 |
|---|---|---|
| 主控板 | 树莓派 3B+/4B 或 x86 PC | Linux 系统即可 |
| 操作系统 | Raspberry Pi OS Lite(64位) | 轻量无桌面更稳定 |
| 编程工具 | OpenPLC Editor v1.5+ | 官网下载:https://openplcproject.com |
安装完成后打开 OpenPLC Editor,点击File → New Project,弹出如下界面:
(示意图:新建项目窗口,包含名称、硬件平台、PLC类型选项)
关键设置项说明:
- Project Name:随便起个名字,比如
Motor_Control_Demo - Hardware Board:选
Raspberry Pi(若本地测试可选 Generic Linux) - PLC Type:保持默认
Standard PLC
点确定后,项目自动生成基础框架文件,包括:
-Program.st(主程序)
-Global Variables.xml(全局变量表)
- 默认 I/O 映射表
💡 小贴士:第一次使用建议勾选“Create example program”,会生成一个闪烁灯示例,方便快速验证环境是否正常。
第二步:编写你的第一个控制逻辑
我们来做个经典案例:电机启停控制(带自锁)
方案一:用梯形图绘制(图形化,适合新手)
切换到Diagram视图,你会看到类似下面的绘图区:
|--[ Start ]--+--[ Stop ]--|----( Motor )--| | | +--------( Motor )----------+操作步骤如下:
- 左侧元件库拖出一个常开触点,命名为
Start_Button - 并联一个名为
Motor_Run的常开触点(实现自锁) - 串联一个常闭触点
Stop_Button - 最后接上线圈
Motor_Run - 输出映射到
%QX0.0(第一个数字量输出)
保存为Main_Diagram.ld
🎯 关键理解:PLC不是“一次性执行”,而是每个周期都重新计算!所以必须靠“自锁”维持状态。
方案二:用结构化文本编写(ST语言,适合复杂逻辑)
如果你更习惯代码风格,可以改写为 ST:
(* 电机启停控制 - 结构化文本 *) PROGRAM MainProgram VAR Start_Button: BOOL := %IX0.0; // 对应 GPIO 输入 Stop_Button : BOOL := %IX0.1; Motor_Run : BOOL := FALSE; END_VAR // 自锁逻辑:启动信号触发或已运行,且未按下停止 Motor_Run := (Start_Button OR Motor_Run) AND NOT Stop_Button; // 输出驱动继电器 %QX0.0 := Motor_Run;两种方式生成的逻辑完全等效。你可以任选其一,也可以混合使用(同一个项目中多个POU共存)。
第三步:编译 → 生成可执行程序
点击顶部菜单栏的“Compile”按钮,会发生什么?
背后其实经历了一连串转换:
Ladder Diagram / ST Code ↓ XML Intermediate Format ↓ Auto-generated C++ Source (.cpp) ↓ g++ Compilation (with OpenPLC runtime lib) ↓ Binary Executable (main_program)编译成功后,会在项目目录下生成两个重要文件:
main_program:Linux 可执行二进制variables.csv:变量地址映射表
如果报错,请检查:
- 是否有语法错误(如未声明变量)
- 地址格式是否正确(应为%IXx.x,%QXx.x等)
⚠️ 常见坑点:Windows 用户注意路径斜杠方向!最好统一使用
/避免兼容问题。
第四步:部署到树莓派并运行
现在要把程序“烧”到目标设备上去。
方法一:SSH 上传(推荐)
假设你的树莓派 IP 是192.168.1.100,使用 SCP 命令传输:
scp main_program pi@192.168.1.100:/home/pi/openplc_exec/ scp variables.csv pi@192.168.1.100:/home/pi/openplc_exec/登录树莓派,进入目录并赋予执行权限:
ssh pi@192.168.1.100 cd /home/pi/openplc_exec chmod +x main_program然后运行启动脚本(需提前安装 OpenPLC Runtime):
sudo ./start_openplc.sh✅ 成功标志:终端显示
OpenPLC Runtime started successfully!并监听 502 端口(Modbus)和 8080 端口(Web HMI)
方法二:Docker 一键部署(高级用户推荐)
为了规避依赖冲突,官方提供了 Docker 镜像:
docker run -d --name openplc \ -p 502:502 -p 8080:8080 \ -v $(pwd)/main_program:/usr/local/openplc/runtime/main_program \ -v $(pwd)/variables.csv:/usr/local/openplc/webserver/variables.csv \ thiagoralves/openplc:v3一行命令搞定环境隔离与服务启动,再也不怕“在我电脑能跑”。
第五步:在线监控与调试
程序跑起来了,怎么知道它工作正常?
打开浏览器,访问:
http://192.168.1.100:8080你会看到 OpenPLC 内置的 Web HMI 页面:
(示意图:Web界面显示当前所有变量值,支持强制写入)
在这里你能看到:
-%IX0.0当前输入状态(模拟按钮按下)
-%QX0.0输出是否激活
- 可手动“强制”某个变量为 TRUE/FALSE,用于测试故障场景
这比串口打印日志直观多了!
如何与外部通信?Modbus 是关键桥梁
OpenPLC 默认启用 Modbus TCP 服务器模式,这意味着你可以用任何支持 Modbus 的客户端来读写数据。
Python 示例:远程读取电机状态
from pymodbus.client import ModbusTcpClient # 连接树莓派上的 OpenPLC client = ModbusTcpClient('192.168.1.100', port=502) client.connect() # 读取输出线圈状态(对应 %QX 寄存器) response = client.read_coils(address=0, count=1, slave=1) if not response.isError(): motor_running = response.bits[0] print(f"✅ 电机正在运行:" if motor_running else "⏸️ 电机已停止") else: print("❌ Modbus 通信失败") client.close()你还可以结合 Node-RED、Grafana 或自研 SCADA 系统,做出炫酷的数据看板。
新手常踩的三大“坑”,我都替你试过了
❌ 坑点1:程序写了但输出没反应?
原因分析:
- I/O 映射错误:误将%QX0.0写成了QX0.0(少百分号)
- 树莓派 GPIO 权限不足
- 继电器模块供电异常
解决方法:
- 检查variables.csv文件中的地址是否匹配
- 使用gpio read 0测试底层 GPIO 是否受控
- 用万用表测输出端是否有电压变化
❌ 坑点2:按钮按了没响应?
真相往往是:你忘了把物理输入接到正确的 GPIO 引脚!
OpenPLC 中%IX0.0默认对应树莓派的 GPIO 17(具体以core/board.h定义为准)。请务必核对:
| OpenPLC 地址 | 树莓派 BCM 编号 | 物理引脚 |
|---|---|---|
%IX0.0 | GPIO17 | Pin 11 |
%IX0.1 | GPIO18 | Pin 12 |
%QX0.0 | GPIO27 | Pin 13 |
建议贴一张引脚对照图在开发板旁边。
❌ 坑点3:网页打不开,提示连接拒绝?
排查清单:
- 防火墙是否放行 8080 和 502 端口?
- OpenPLC 服务是否真正启动?(ps aux | grep openplc)
- 是否用了错误的IP地址?(ifconfig查看真实局域网IP)
- Docker 容器是否正确暴露端口?
实战设计建议:写出可靠又易维护的PLC程序
别以为开源就等于“随便写”。真正的工程思维体现在细节中。
✅ 命名规范 > 地址记忆
与其记住%IX0.0是门传感器,不如定义符号名:
VAR_GLOBAL Door_Sensor : BOOL; // 仓库大门限位开关 Alarm_Light : BOOL; // 报警灯输出 Conveyor_Timer : TON; // 传送带延时启停 END_VAR这样别人一眼就能看懂逻辑意图。
✅ 分层设计:主程序只调度,功能块封装细节
不要把所有逻辑塞进一个 POU。推荐分层结构:
MainProgram (组织流程) ↓ Conveyor_Control_FB (传送带控制) ↓ Motor_Start_Stop_FB (电机启停)每个功能块独立测试,复用性极强。
✅ 安全第一:避免无限循环、加入超时保护
切记:PLC 程序不能阻塞!
错误示范:
WHILE TRUE DO END_WHILE; // 会导致扫描周期卡死!正确做法:使用定时器判断异常:
Conveyor_Timer(IN := Start_Cmd, PT := T#5S); IF NOT Conveyor_Timer.Q THEN Fault_Alarm := TRUE; // 启动超时报警 END_IF;它能用在哪里?这些真实场景值得参考
| 应用场景 | 实现方式 | 案例价值 |
|---|---|---|
| 教学实验平台 | 学生动手编程+LED模拟产线 | 零成本实训 |
| 小型自动化设备 | 控制步进电机+传感器反馈 | 替代商用PLC节省成本 |
| 智慧农业温室 | 监测温湿度+自动通风灌溉 | 边缘智能控制 |
| 机电一体化课程设计 | 结合机械臂+视觉识别 | 多学科融合实践 |
一位职校老师告诉我,他们用 OpenPLC 带学生做了整条模拟流水线,成本不到原方案的1/5,教学效果反而更好。
写在最后:掌握 OpenPLC,不只是学会一个工具
当你第一次看着自己写的梯形图,真的驱动了一个继电器、点亮了一盏灯、启动了一台电机……那种成就感,是任何仿真软件都无法替代的。
OpenPLC 不只是一个开源项目,它是通往工业4.0的一扇门。在这里,你不需要昂贵的授权许可,也不需要复杂的组态软件。你需要的,只是一颗愿意动手的心。
未来,随着边缘计算、IIoT 和 AI 的融合,OpenPLC 也正在进化:
- 支持 MQTT 协议接入云平台
- 集成 Python 脚本扩展能力
- 实验性支持 OPC UA
- 与 TensorFlow Lite 联动实现预测性维护
技术的边界,永远由探索者定义。
如果你正打算迈出工业自动化的第一步,不妨今晚就下载 OpenPLC Editor,试着画出你的第一条梯形图。
也许下一个改变生产的创意,就诞生于你的书桌之上。
👉动手资源包
- 下载地址: https://openplcproject.com
- GitHub 仓库: https://github.com/thiagoralves/OpenPLC_Runtime
- 社区论坛: https://forum.openplcproject.com
有什么问题欢迎留言交流,我会持续分享更多实战技巧。