简介:本资源是一套基于西门子TIA Portal V16开发的自动化立体仓库控制系统完整工程代码,面向工业自动化初学者、PLC工程师及智能制造实训教学人员,解决Factory IO虚拟产线与S7-1500/1200系列PLC协同控制的实际落地问题。压缩包共39个文件(1.76MB),涵盖AP15_1主项目文件、PLC程序(.plf/.db)、HMI配置(.tvd/.tvx)、系统日志(.xml/.xsl)、图标资源(.png)及索引与分段数据(.idx/.segments_13c等),其中PLC逻辑、设备IO映射、OPC UA通信配置与Factory IO仿真接口均已预置并验证。已有2541人学习下载,资源可直接导入TIA Portal V16运行,配套Factory IO场景模型实现堆垛机定位、输送线启停、货位状态反馈等核心功能,特别适合用于课程设计、毕业实训或自动化运维能力进阶训练。
1. 这个项目到底在解决什么问题:Factory IO自动化立体仓库的定位
1.1 一个虚拟仓库能带给你什么
把一套自动化立体仓库的控制程序从零写到能稳定跑通,我试过最有效率的路径,就是用TIA Portal V16写逻辑,再接到Factory IO里做三维仿真。原因是真实设备动作慢、空间占用大、接线风险高,很多逻辑问题还没到设备层就被各种硬件干扰掩盖了。而在Factory IO里,你可以把所有I/O信号、设备动作、传感器状态都看得清清楚楚,逻辑错了马上就能在画面上暴露出来。
这个项目的核心不是“做一个立体仓库”,而是通过一套虚拟仓储设备,把PLC编程里最典型的状态机设计、任务调度、联锁保护、手动自动切换这几个关键能力全部串起来。Factory IO恰好给了这样一个接近真实设备的数字孪生环境:传送带能跑,堆垛机能动,货位能占能空,传感器会响应。你在TIA Portal V16里写的每一个Q点输出,都能在虚拟场景里驱动一个机械动作;虚拟场景里的每一个光电开关,也会作为一个I点反馈到你的程序里。
对刚入门西门子PLC的人来说,这套组合比看教材案例要直观得多。对已经在做真实项目的工程师来说,它也是一个很好的验证平台,尤其是在写大型物流输送线之前的工艺验证阶段,能提前把节拍、互锁和异常流程跑熟。
1.2 项目边界:控制对象到底有哪些
我以Factory IO场景库里的自动化立体仓库场景为例,控制对象包括上料台、出入库输送线、堆垛机、货架和气缸推杆等。不同版本的场景在细节上会有差别,比如堆垛机的X轴和Z轴运动方式、托盘到位传感器的安装位置,但整体控制逻辑是通用的。
自动化立体仓库的工艺循环大致是托盘从入库口进入,经输送线送到取货台,堆垛机把托盘抬升到指定货位;出库时堆垛机取走托盘,放到出库输送线,由输送线送出去。这个流程简单说就是“进库、存、取、出库”四个环节,但每个环节背后都有独立的传感器反馈和执行机构动作。
这套项目里,你真正要写代码的是三类逻辑:第一类是设备控制逻辑,比如传送带什么时候启动、什么时候停止;第二类是位置与状态逻辑,比如堆垛机现在在哪个货位、目标货位是哪里;第三类是任务调度逻辑,比如多个入库请求同时来的时候,程序按什么顺序处理。下面我会按这个顺序把整套代码的写法拆开讲。
2. 搭好虚拟现场:Factory IO场景与I/O地址的对应关系
2.1 示例I/O映射表
开始写代码之前,第一件事是列I/O映射表。Factory IO里的设备不会自动知道你的PLC变量叫什么,它只认地址。所以我习惯在TIA Portal V16里先把PLC变量表建好,再对照Factory IO场景里的信号列表,把每一个输入输出固定下来。
我常用的S7-1500配置下,I/O分配大致是这样:
| 信号含义 | 方向 | 地址 | 说明 |
|---|---|---|---|
| 入库口光电传感器 | 输入 | I0.0 | 检测托盘进入入库输送线 |
| 取货台就位传感器 | 输入 | I0.1 | 托盘到达堆垛机取货台 |
| 出库口光电传感器 | 输入 | I0.2 | 检测托盘到达出库口 |
| 堆垛机X轴零点 | 输入 | I0.3 | 堆垛机水平归零位 |
| 堆垛机Z轴零点 | 输入 | I0.4 | 堆垛机垂直归零位 |
| 启动按钮 | 输入 | I0.5 | 自动流程启动 |
| 停止按钮 | 输入 | I0.6 | 自动流程停止 |
| 自动/手动切换 | 输入 | I0.7 | 默认自动模式 |
| 故障复位按钮 | 输入 | I1.0 | 复位报警 |
| 入库输送线启动 | 输出 | Q0.0 | 控制入库传送带电机 |
| 出库输送线启动 | 输出 | Q0.1 | 控制出库传送带电机 |
| 堆垛机X轴正向移动 | 输出 | Q0.2 | 堆垛机向正方向运动 |
| 堆垛机X轴反向移动 | 输出 | Q0.3 | 堆垛机向负方向运动 |
| 堆垛机Z轴上升 | 输出 | Q0.4 | 提升机构上升 |
| 堆垛机Z轴下降 | 输出 | Q0.5 | 提升机构下降 |
| 取货台推杆伸出 | 输出 | Q0.6 | 将托盘推到堆垛机 |
| 取货台推杆缩回 | 输出 | Q0.7 | 推杆复位 |
| 运行指示灯 | 输出 | Q1.0 | 自动运行中点亮 |
| 故障指示灯 | 输出 | Q1.1 | 故障时点亮 |
实际项目中地址要根据你选的PLC模块和Factory IO场景里的信号顺序重新调整。关键是先把这张表打印出来放在手边,写代码时随时参照,别写到一半又回场景里去翻信号,那样容易漏。
2.2 建立符号表,而不是到处用绝对地址
不少初学者在TIA Portal里写程序时直接用“I0.0”“Q0.2”这样的绝对地址,程序短的时候没什么感觉,一旦上了立体仓库这种几十个信号的程序,后期维护会非常痛苦。我建议从一开始就在PLC变量表里给每个地址起一个能看懂的名字。
比如把I0.0命名为“Infeed_Sensor”,把Q0.0命名为“Infeed_Conveyor_Run”。这样交叉引用和程序段看起来一目了然,修改地址也只需要改变量表,不用满程序去替换。尤其是当Factory IO场景调整了信号顺序时,只要重新映射变量表,程序逻辑可以完全不改动。
在TIA Portal V16里,符号名的命名规则不区分大小写,但建议统一用“下划线分隔单词”的写法。命名时把“设备_位置_动作”三层信息都体现出来,比如“Stacker_X_Move_Forward”就比“sbj_a”这种东西强太多了。
2.3 传感器“初始态”在仿真环境里更敏感
Factory IO里传感器的初始状态并不是完全统一的,有的光电开关默认是检测到货物时输出1,有的在场景编辑时可能被配置成了反逻辑。这一点在真实设备上同样常见,但仿真环境里更容易被忽略。
我遇到过一种情况:入库口光电传感器在没有托盘时显示为1,程序里一启动就认为有货进来了,传送带空转。排查了半天,发现是Factory IO场景里该传感器的极性设置跟我的PLC程序假设相反。解决办法是写代码前,先手动在Factory IO画面上逐个触发传感器,确认它们是“有货=1”还是“无货=1”,再决定程序里的取反逻辑。这个步骤虽然基础,但能避免后面很多莫名其妙的误动作。
3. 程序结构从哪一层开始搭:OB/FB/FC/DB与状态机设计
3.1 分层:OB、FB、FC、DB怎么排
写TIA Portal程序最忌讳的就是把所有逻辑塞进OB1里堆积木。自动化立体仓库逻辑量很大,我在这个项目里用的结构是:
- OB1:负责调用各个功能块,按固定周期执行。
- FB_Conveyor:传送带控制,包含启动、停止、超时故障、手动干预。
- FB_Stacker:堆垛机控制,包含X轴/Z轴的移动、定位、联锁。
- FC_TaskDispatch:出入库任务调度,决定当前该执行哪个任务。
- FC_Manual:手动模式下的单步操作逻辑。
- DB_Config:全局参数,包括货位矩阵、速度参数、超时时间等。
- DB_BinStatus:货位占用状态,用数组描述。
- DB_Alarm:故障信息记录。
FC和FB的区别要注意:FB每次调用都要有背景数据块,能保存静态变量,适合描述设备这样的人工实体;FC不保存静态数据,适合做纯计算和任务分发。
立体仓库里的堆垛机是典型用FB描述的对象。X轴当前位置、Z轴当前位置、当前任务号、目标货位这些数据,全部做成FB的静态变量。这样不管你是从自动模式切到手动模式,还是在监控表里查看实时状态,都能从背景DB里直接看到这个设备的“记忆”。
3.2 货位矩阵与任务调度的SCL思路
立体仓库的存储区可以看成一张二维货位表,比如8列10层,那么我的库位上就有80个位置。如果代码里为每一个货位都写一段IF语句,那代码量会爆炸。正确的做法是用二维数组去描述货位。
在DB_Config里定义货位矩阵:
ARRAY[0..9, 0..7] OF INT数组元素的值用来表示货位状态:0代表空闲,1代表占用。同时,为了记录每个货位对应堆垛机的X和Z坐标,可以再建两个数组,分别存储列坐标和层坐标。这样调度程序只要遍历货位矩阵,找到第一个值为0的货位,就能通过坐标数组计算出这个货位的物理位置。
任务调度的核心是一个“任务表”。我用FC_TaskDispatch维护一个任务队列,每个任务包含任务号、任务类型(入库还是出库)、源位置、目标位置、执行状态。主程序每扫描周期检查任务表里有没有待执行的任务,如果有就调用FB_Stacker去执行。
这个设计的优势在于灵活扩展。后续如果要增加“双堆垛机协同”,只需要把任务表按照堆垛机编号拆分,再增加一个任务冲突处理。
3.3 状态机:为什么它是这套程序的骨架
自动化立体仓库的控制逻辑本质上是顺序逻辑:先做什么,再做什么,必须严格按照工艺顺序。如果用梯形图的常规自锁互锁去写,很容易出现条件交叉导致的动作紊乱。我在这里强烈建议用状态机写法,而且优先选择SCL语言。
以入库流程为例,我把它切成了十几个状态:
CASE #state OF 0: // 待机状态 IF #startCommand AND #infeedSensor THEN #state := 10; #taskType := 1; // 入库 END_IF; 10: // 启动入库输送 Q0_0 := TRUE; // 入库输送线运行 IF #takePosSensor THEN Q0_0 := FALSE; #state := 20; END_IF; 20: // 检查货位矩阵,分配目标货位 #targetBin := FC_FindEmptyBin(); #state := 30; 30: // 堆垛机移动到取货台 FB_Stacker.MoveTo(#takePosX, #takePosZ); IF FB_Stacker.Done THEN #state := 40; END_IF; 40: // 取货,推杆伸出 ... END_CASE;这种写法的最大好处是:任何时刻程序处于哪个阶段,一眼就能看出来。调试的时候,我在监控表里看这个状态值,马上知道设备卡在哪一步。状态转移的条件也高度集中,不容易出现两边同时满足的竞争情况。
在TIA Portal V16里,状态机用SCL写最合适。SCL的CASE语法本身就是为这种多分支场景设计的,比用梯形图排几十个网络要清晰得多。如果你想在一段梯形的环境里加入状态机,也可以用“等于比较+置位复位”的方式,但代码会明显臃肿。
4. 把程序“接”进Factory IO:TIA Portal V16与PLCSIM的联调方式
4.1 PLCSIM与Factory IO的连接方法
很多人以为Factory IO是直接跟TIA Portal通讯的,其实中间还隔着一个PLCSIM。TIA Portal V16负责把编译好的程序下载到虚拟PLC里,PLCSIM负责模拟这个PLC的运行,Factory IO再通过配套驱动去读写PLC的I/O地址。
以我常用的一套流程为例,在TIA Portal V16里新建项目,组态一台S7-1500 CPU,写好程序和变量表之后,点击“在线”菜单里的“仿真”按钮,启动PLCSIM。等PLCSIM的界面出现后,把项目下载进去,把CPU切到RUN状态。然后打开Factory IO,在“驱动”设置里选择“Siemens S7-PLCSIM”,点连接。这个时候Factory IO会开始循环读写TIA侧已经下载的PLC地址。
如果I/O地址分配和程序里的变量一致,画面上任何一个传感器动作,都会在PLC监控表里看到对应I点的变化;你在程序里修改Q点,画面上的电机也会跟着转。到这里,虚拟PLC和虚拟设备之间的“接线”就算完成了。
使用标准PLCSIM时,这个连接不需要设置IP地址,也不需要Profinet网络,因为PLCSIM和Factory IO通过本机进程通信。这是这个方法对新手最友好的地方。如果你用的是PLCSIM Advanced,反而要额外配置IP并处理网卡绑定,复杂度高不少,非必要不需要用。
4.2 联调启动顺序和信号交互细节
联调容易翻车的往往不是程序本身,而是启动顺序。我建议固定一个顺序:先编译程序,再启动PLCSIM,下载程序,切RUN,最后启动Factory IO并连接驱动。反过来操作的话,Factory IO可能找不到PLCSIM实例,或者驱动连接成功后PLC还处于STOP状态,画面上的设备纹丝不动。
还有一种情况是PLCSIM已经载入了旧版本的程序,而你后来改了程序但没再下载,Factory IO连上后跑的还是旧逻辑。这个坑我也踩过。所以在联调前,强制做一遍“编译-下载-切RUN”三连,不要带着怀疑调试。
下载到PLCSIM时,TIA会提示是否要停止PLC,一般选“是”。下载完成后记得把CPU切到RUN,并按“在线监视”按钮,这样能实时看到程序执行到哪一状态。联调时千万不要把PLCSIM窗口关掉,它一旦退出,Factory IO会瞬间失去PLC实例。
4.3 模拟量或脉冲量地址怎么处理
自动化立体仓库如果只做基础版,所有信号都可以做成数字量。但Factory IO的场景里,也可能出现需要模拟量的地方,比如传送带速度控制、堆垛机移动速度。如果用数字量,只能通过启动停止来控制速度,这比较粗糙。
这种情况下,我通常会在PLC里用一个INT型的地址往Factory IO里送速度值。比如控制传送带速度,可以定义MW100作为速度设定值,程序里把目标速度写入MW100,Factory IO读取这个地址作为电机速度参数。
如果你用的是S7-1500,要记得这些地址在PLC变量表里的数据类型要统一。Factory IO端如果期望0-100之间的整数,你就在程序里把范围掐好,避免出现负值或者超大值把虚拟场景搞出奇怪动作。模拟量转换的标准化指令在TIA里叫NORM_X和SCALE_X,但这里没必要那么复杂,直接限制范围再赋值就行。
5. 调试实录:我在这个仓库项目里踩过的坑和解决过程
5.1 信号脉冲太短,动作直接“丢”
立体仓库联调一开始,我遇到最典型的问题是:托盘明明已经通过传感器位置了,但程序里的传感器状态却没有被捕捉到。原因不是地址映射错,而是Factory IO里的传感器信号持续时间太短,可能只有100毫秒,而我的PLC扫描周期加上程序处理,很容易丢掉这个脉冲。
解决办法有两个方向。第一个方向是在程序里做脉冲捕捉,用上升沿指令把短脉冲锁存到中间位,后续逻辑使用这个中间位而不是直接读I点。第二个方向是在Factory IO场景属性里把传感器的信号保持时间延长一点,让PLC有足够的扫描周期去发现它。
我建议两个都做。程序里的脉冲锁存是设备逻辑的一部分,真实PLC也有硬件输入滤波和过程映像的问题。而调整仿真场景里的信号保持时间,只是为了演示方便,真实设备上你没法改传感器脉宽,所以主逻辑还是要靠程序处理。
5.2 双传感器重合区造成状态跳变
自动化立体仓库的进库输送线上,入库口传感器的检测范围和取货台传感器的检测范围可能有重叠区域。托盘经过这个区域时,两个传感器会同时为1。我第一版程序里,判断“到位”的条件是“取货台传感器=1”,判断“离开”的条件是“入库口传感器=0”。当托盘停在重叠区时,入库口和取货台都为1,程序就会同时认为“还没离开”和“已经到位”,状态机跳来跳去。
这个问题反映出顺序逻辑里一个很重要的原则:不要把状态判断建立在多个独立传感器组合的瞬时值上,而要用事件顺序去判断。我把状态转换改成了“必须由前一个状态经历过的条件触发”,而不是直接用传感器组合判断。同时,在入库口传感器变成0之后,启动一个短延时确认,确保托盘已经离开检测区域,再允许状态机进入下一步。
5.3 手动/自动切换时状态残留
这套项目里我同时做了手动和自动两种模式。调试发现,如果正在自动运行中途,突然切到手动,操作人员把堆垛机挪到了别的位置,再切回自动,原来状态机仍然保存着“正在去往A货位”的记忆,于是堆垛机可能从当前位置突然往A货位跑,非常危险。
安全逻辑必须在切换的瞬间生效。我在程序里加了一个“模式切换复位”功能:当自动/手动选择开关状态发生变化时,清除所有任务状态、状态机归0、所有输出复位、堆垛机进入待机。之后从手动模式切回自动时,程序必须重新收到一次启动命令,才允许进入自动流程。
如果你希望自动流程在手动干预后继续,那就要做更复杂的位置校正逻辑,先把堆垛机当前位置读取回来,重新计算任务。但在这个项目里,我的建议是优先保证安全性,切换模式后强制重新开始,别让程序带着旧状态继续执行。
5.4 交叉引用和监控表:定位问题的两个加速器
程序里变量多起来以后,想找一个信号“到底在哪些程序段里被用过”,手动翻阅是个噩梦。TIA Portal V16里有一个交叉引用功能,选中变量后右键打开“交叉引用”,它能列出该变量曾经出现过的所有位置,包括地址、程序块、网络号。查某一个输出为什么总被置位时,这个功能非常常用。
监控表则是我联调时最常用的调试窗口。把状态机的当前状态变量、任务号、目标货位、堆垛机坐标全部加入到监控表里,运行中盯着实时值看。动作不对时,先看状态,状态不对再看条件变量,一级一级倒推,通常几分钟就能定位到逻辑问题点。
这里再分享一个习惯:监控表里可以修改变量值来模拟传感器信号。比如托盘还没到取货台,但我想测试后续的取货逻辑,就可以临时把取货台传感器变量强制为1。不过用完一定要取消强制值,否则真实信号来了反而不生效,很容易把调试陷入“假信号”的陷阱里。
6. 从能跑到跑顺:参数管理、HMI联动与移植注意点
6.1 全局DB:参数集中管理比分散写死更省事
第一版程序我把传送带运行时间、推杆动作延时、货位数量这些参数零散地写在FB里。后来调参数时,要在好几个程序块里翻找,还容易漏改。重构之后,我把所有可调参数集中到一个全局DB里,每个参数写上注释和上下限。
比如这个DB里有:
- 传送带启动到停机的超时时间,默认4000ms;
- 推杆伸出保持时间,默认1000ms;
- 货位矩阵的行数和列数;
- 堆垛机定位允许误差;
- 模式切换后的复位延时。
这样调参只需要打开DB,修改保持值,再下载到PLCSIM。程序里的逻辑不会因为参数调整而变动,减少了很多不必要的实验。
如果你后续要给程序加配方功能,这个全局DB同样可以扩展成多套参数方案,通过HMI切换。
6.2 给仿真工程加一个HMI画面
TIA Portal V16的强项是可以把PLC程序、HMI画面、网络组态放在同一个项目里。我后期给这个立体仓库工程加了一块虚拟触摸屏TP700 Comfort,画面上放了:
- 自动运行启停按钮;
- 当前状态显示;
- 货位占用表,用几十个方块表示,黄色代表占用,绿色代表空闲;
- 故障信息显示和复位按钮;
- 手动模式下堆垛机单轴点动按钮。
HMI变量和PLC变量之间通过“连接”来共享。TIA Portal里建好HMI连接后,把PLC变量拖到HMI画面元件上即可。因为PLCSIM已经在跑,HMI的仿真也可以直接启动,相当于在电脑上同时跑PLC仿真和触摸屏仿真,效果非常接近真实柜体调试。
这个环节对项目交付特别有帮助。很多客户或同行评审没时间看你复杂的SCL代码,但一眼就能看懂货位占用表。HMI画面也是一个很好的“程序说明书”,它反映了你对整个工艺的理解。
6.3 从S7-1500移植到S7-1200的差异提醒
如果你用的是S7-1200而不是S7-1500,程序大体可以移植,但要注意几个差别。S7-1200的指令集比S7-1500精简一些,一些高级指令用不了;S7-1200的工作内存也小,货位矩阵如果做得很大,DB数组占用的空间可能会超限。
因此在定义货位矩阵时,建议用你最小需要的规模。如果现场只有60个库位,就不必开到一个1000维的数组。还有就是S7-1200的某些FB背景数据块数量有限制,逻辑块数量太多时会报资源不足。遇到这种情况,把一部分FC合并到OB1里或者精简变量定义,通常能解决。
我个人在写这类程序时的经验是:先把工艺流程图按状态机画清楚,再去做IO分配和变量表,最后才动笔写代码。很多初学者喜欢一上来就打开TIA Portal写梯形图,写到一半发现状态关系理不清,翻工无数次。这个项目真正吃功夫的,不是指令的熟练程度,而是你把“什么时候做什么事”这个逻辑骨架搭得多干净。
本文还有配套的精品资源,点击获取