☰
博图S7-1200立体仓库PLC程序:货位管理、堆垛机与视觉协同
2026/10/21 12:40:08 网站建设 项目流程

简介:从国赛立体仓库赛项需求出发,这是一份可直接研读的西门子博图PLC工程包,面向自动化竞赛选手、工业现场调试人员及物流仓储系统学习者。资源以1200PLC为核心,涵盖立体仓库机器人MODBUSTCP通信、信捷视觉系统数据交互,以及西门子V90三轴伺服驱动器的点位控制逻辑,能帮助理解从设备层到控制层的完整信号链路。压缩包共45个文件,以xml配置文件、hsf项目段、plf设备数据、gd备份文件等为主,还有AP13工程文件与索引/日志类文件,项目结构完整,容量约19.88MB。已有1183人学习下载,是备战国赛或日常学习PLC与视觉/伺服集成的不错素材。通过解包后逐一分析示例程序,可掌握PLC与机器人、视觉系统的MODBUSTCP通信参数设置、伺服驱动器使能与回零控制等关键代码思路,节省自行搭建实验环境的时间。

1. 立体仓库PLC程序:从比赛项目到可落地的控制系统

在国赛的立体仓库赛项里,堆垛机高速取放货、机器人协同码垛、视觉系统实时识别托盘,整个流程如果只靠单片机或继电器,光调试就能让人崩溃。这套基于博图组态环境编写的1200PLC程序,把货位管理、堆垛机定位、视觉IO握手和机器人联锁全部装进一个可下载的工程包里,解决了赛场最核心的"货怎么进、怎么存、怎么出"三个问题。适合准备参加物流仓储类赛项的学生团队,以及正在做小型立体仓库项目的工程师参考——你拿到的不是一段段零散程序,而是一个能直接下载到PLC里跑起来、再按自己仓位改参数的完整方案。

2. 系统架构与技术栈:博图环境下的1200PLC如何与视觉、机器人协同

2.1 硬件拓扑与控制对象解析

立体仓库的物理结构通常包含立体货架、堆垛机(水平行走+垂直升降+货叉伸缩)、输送线、机器人抓取工位和视觉检测工位。这套程序把1200PLC当作唯一的大脑,通过以太网连接机器人控制器,通过IO硬接线连接视觉系统、光电传感器、气缸阀岛和伺服驱动器。整体拓扑呈现星型:PLC作为主站,机器人作为智能从站,视觉系统以"判断结果"的方式被动参与,不属于完整以太网通信配置。

具体到硬件选型,比赛现场常见的配置是:1200PLC(具体型号以带以太网口的1214C或1215C为主),两个伺服轴分别控制堆垛机的X轴和Z轴,一个步进或伺服控制货叉伸缩,机器人独立运行但接受PLC的启动信号和放行信号。信捷视觉系统通过IO输出一个"OK/NG"电平,PLC将这个电平锁存到内部位,再决定是否允许机器人继续堆码。

程序在设计时把硬件信号全部映射到符号表,而不是直接使用绝对地址。这样做的最大好处是:换一台PLC或者调整IO接线时,只需要改符号表中的设备号,不让程序逻辑跟着变。IO表大致分为几类:输入信号里包括各轴原点、限位、货物检测、机器人就绪、视觉OK;输出信号里包括各轴使能/方向/脉冲、气缸动作、机器人启动/复位、报警灯。整个IO数量控制在48点以内,正好符合国赛标准设备清单。

2.2 软件架构:程序块划分与数据流

博图工程里的程序块不是随便堆在一起的,而是按照"组织块→功能块→数据块"三层结构放置。OB1为循环组织块,负责调用主流程;每个功能块(FB)负责一个独立任务,比如FB_Stock_Manager管理货位状态,FB_Mover控制堆垛机,FB_Vision处理视觉握手;数据块则分两类,全局DB存放共享参数,背景DB存放FB的实例数据。

主程序的数据流大致是这样的:启动信号触发初始化,将仓库货位状态表清零;然后扫描输送线是否有货,有货就调用视觉识别功能,视觉结果OK后,堆垛机按货位表寻找空位并移动到位;到位后货叉伸出、托盘放下、货叉缩回,接着更新货位状态为占用;当出库指令到达,堆垛机从指定货位取货,移动到出库台,机器人按预设路径抓取并码放。整个过程是一个有限状态机,状态编号放在一个整型变量里,每个扫描周期根据当前状态决定下一步动作。

这种状态机写法比梯形图里到处置位复位M点要稳定得多。比赛现场最怕的"程序跑飞""状态错乱",大多是因为用起保停电路搭顺序控制,一旦条件临界就乱跳。而用一个状态整型+条件判定的写法,每个状态只有一个入口和一个出口,出问题时可从监控表直接锁定当前状态,十分钟就能定位故障位置。对二次开发来说,这种结构也更容易扩展:你只需要在状态机里加两个新状态,不用推倒重排。

3. 核心模块拆解:从货位分配到机器人动作的完整链路

3.1 货位状态管理:DB数据块设计

立体仓库的灵魂就是货位表。我先定义一个全局DB,名字叫DB_Storage,里面是一个二维数组或者结构体数组,用来描述每个货位的坐标、状态和存放的货物ID。因为博图支持使用UDT(用户自定义类型),我会先定义一个UDT_StorageCell,然后生成一个由多个该类型组成的一维数组。

TYPE UDT_StorageCell VERSION : 0.1 STRUCT CellNumber : INT; // 货位编号,从1开始 Occupied : BOOL; // 是否已占用 ProductCode : WORD; // 货物编码,对应视觉识别的结果 X_Position : REAL; // 货位X坐标,单位mm Z_Position : REAL; // 货位Z坐标,单位mm InUseTime : TIME; // 入库时间戳,用于先进先出策略 END_STRUCT END_TYPE

然后在全局DB里这样声明货位表:

DATA_BLOCK "DB_Storage" STRUCT Cells : ARRAY[1..12] OF "UDT_StorageCell"; // 12个货位 Count_Empty : INT; // 空货位数 Next_Out_Cell : INT; // 出库计数器 END_STRUCT END_DATA_BLOCK

这个数据块的含义很清晰:数组下标就是仓库的物理位置排布,每个元素里保存的坐标用于堆垛机定位。Occupied位用于判断该货位是否可用,ProductCode用于和视觉结果匹配,避免把不同编码的货物放到同一个位置。我一般把Count_Empty也放在DB里,这样界面组态时可以直接读取这个数值显示在触摸屏上,可以减少循环扫描时的统计计算。

货位分配逻辑使用一个简单的"最先找到空位"策略。寻找空货位的函数如下:

// 在FB_Stock_Manager中调用的方法 FUNCTION "FC_FindEmptyCell" : INT VAR_INPUT StorageDB : DB_ANY; // 指向DB_Storage的引用 END_VAR VAR_TEMP i : INT; END_VAR BEGIN FOR i := 1 TO 12 DO IF StorageDB.Cells[i].Occupied = FALSE THEN FC_FindEmptyCell := i; RETURN; END_IF; END_FOR; FC_FindEmptyCell := 0; // 0表示仓库已满 END_FUNCTION

从逻辑上可以看到,这个函数遍历12个货位,一旦遇到第一个非占用状态就返回该货位的编号。对于国赛这种小型仓库,12个货位线性扫描的耗时几乎可以忽略,不需要什么hash或贪心算法。如果你做的项目有几百个货位,就需要把这个循环改成分段扫描,或者维护一个空位索引表,否则每次入库都要扫描全部货位,响应时间会变长。参数说明里唯一要注意的是DB_ANY类型的使用,它让你可以传入不同的数据块实例,方便程序复用。

3.2 堆垛机运动控制:直线运动与区间判断

堆垛机的X轴和Z轴通常采用伺服或步进驱动,PLC发脉冲控制。比赛程序里最常用的做法是用高速计数器和比较指令做定位,而不是使用运动控制工艺对象。因为博图的Motion Control指令在比赛培训中普及度没那么高,而且调试运动曲线的时间成本太高,用简单的位置闭环反而更稳。

这里给出X轴走绝对定位的核心代码段,它运行在每个扫描周期内,但只在"移动到目标货位"状态下有效。

// 在OB1中调用FB_Mover IF State = 10 THEN // 状态10:定位到目标货位 // 读取当前X轴实际位置(编码器反馈) Act_X := HSC_ActualValue; // 高速计数器的当前值 // 目标位置从DB中取出 Target_X := StorageDB.Cells[TargetCell].X_Position; // 位置偏差 Dev_X := Target_X - Act_X; // 如果偏差大于2mm继续发脉冲,否则停止 IF ABS(Dev_X) > 2.0 THEN IF Dev_X > 0 THEN X_Pos_Enable := TRUE; X_Direction := TRUE; // 正向运行 ELSE X_Pos_Enable := TRUE; X_Direction := FALSE; // 反向运行 END_IF; X_Speed := 5000; // 脉冲频率 Hz ELSE X_Pos_Enable := FALSE; X_Direction := FALSE; // 到位后切换状态 State := 20; // 状态20:执行货叉动作 END_IF; END_IF;

这段程序逻辑非常直白,但有两个参数会直接影响运行稳定性。第一个是死区阈值2.0mm,如果货位间距很小或者机械间隙过大,需要把这个值放大到5mm甚至8mm,否则堆垛机永远无法"精确到位"。第二个是X_Speed脉冲频率,比赛用的步进电机一般不超过10kHz,伺服可以到50kHz,但高频时加减速不好控制,容易丢步。我一般会在调试时先用2000Hz跑通全行程,确认机械没有卡阻后再逐步升频,每次提升20%,同时观察高速计数器数值是否与机械位移一致。

实际工程中,这种"比较偏差发脉冲"的方法会有个隐患:停在目标位置附近时会反复正反转,形成震荡。常见解决办法是增加一个最小动作阈值,偏差低于该阈值就忽略方向输出。比如偏差小于0.5mm时,即使不满足2.0mm的死区,也强制停止脉冲,等待下个周期的微小修正。升级后的代码会在正反转切换前加一个延时,防止继电器触点频繁通断。

3.3 视觉识别交互:信捷视觉与PLC的IO握手

信捷视觉系统在国赛里一般用于识别托盘上的物料颜色或二维码。PLC与视觉之间的交互方式采用最简单可靠的握手:视觉检测完成后,输出一个高电平信号给PLC输入点;PLC收到后,先确认信号稳定建立(延时20ms消抖),再读取一个数据字表示识别结果编码。

视觉握手功能块的核心代码是:

// 在FB_Vision中处理 // 输入点: %I0.4 (视觉OK信号) / %I0.5 (视觉NG信号) // 输出点: %Q0.6 (视觉复位请求) IF "Vision_OK_Input" AND NOT "Vision_OK_Latched" THEN // 上升沿检测,锁存视觉OK状态 "Vision_OK_Latched" := TRUE; "Vision_Result_Code" := "Vision_Data_Word"; // 从视觉通过IO写入的编码 // 同时触发一个完成标志,交给状态机 "Vision_Processed" := TRUE; "State" := 30; // 进入入库决策状态 END_IF; // 视觉复位:处理完成后拉低复位请求,持续2秒 IF "Vision_Processed" THEN "Vision_Reset_Req" := TRUE; // 延时计时器,2秒后撤销复位 END_IF;

这里有个很关键的细节:视觉系统输出的脉冲可能很窄,比如只有10ms,如果PLC扫描周期是5ms,理论上能捕到,但如果程序逻辑里还有其他跳转,可能就错过了。所以我采用锁存法——看到上升沿后立刻用一个内部位把状态锁住,即使外部信号消失也不影响流程。这个做法在比赛现场救了不少队伍,好多团队直接在条件里写"IF Vision_OK THEN"导致偶发漏检。

视觉数据字(Vision_Data_Word)通常用格雷码或BCD码编码,比如1代表红色,2代表蓝色。程序里要做的就是把这个值映射到货位表的ProductCode上。有些赛题还要求视觉结果与当前仓储管理策略联动,比如指定编码只能入指定区域,这时需要在FB_Stock_Manager里加一个比较逻辑。

4. 项目运行与调试:从博图下载到整机联调的完整步骤

4.1 程序下载与初始化

拿到程序后,第一步不是急着下载,而是检查博图软件版本是否与PLC固件版本匹配。比赛常用的是博图V15和V17,如果程序是用V17写的,你的环境是V15,会直接打开失败;如果代码版本低于固件版本,下载时可能报错。我通常先在项目树里查看模块版本,如果PLC固件是4.0,那么博图V17可以正常下载,V15就需要更新到对应版本。

下载前必须做的一件事是设置IP地址。1200PLC默认以太网地址是192.168.0.1,电脑必须设置成同一网段的静态地址。在博图软件中:"在线访问>设置PG/PC接口",选择你的网卡,然后搜索设备。搜索到PLC后,检查设备名称和项目树里的设备是否一致,不一致时右键"下载"会提示替换设备。我习惯把PLC的IP改成192.168.0.10,电脑是192.168.0.20,这样多台设备联调时不容易冲突。

下载有两种方式:初次下载选择"全部覆盖",将组态、程序块、数据块连同硬件配置一起下载;如果只修改了某一个功能块,选择"仅下载更改"会更高效。但在比赛现场,我强烈建议每次都做一次完整下载,因为你会频繁修改DB初始值,完整下载能确保所有变量恢复初始状态,避免上一次调试留下的脏数据影响接下来验证。

4.2 单步调试与联动调试

程序下载完成后,先不要按总启动。把PLC拨到RUN状态,观察输出模块是否有异常动作。这一步能发现接线问题,比如某个输出点接了反逻辑,气缸可能在程序不动作时也会吸合。我一般会先在博图"在线监视"里把所有输出变量强制为FALSE,再逐个置位,确认每个执行器都能正常响应。

确认基础IO没问题后,开始单步执行。因为程序是状态机,所以我把状态变量加到监控表里,手动修改状态值,观察程序是否按预期跳转。比如强制State=10(定位到目标货位),此时如果堆垛机开始移动,说明定位程序响应正常;下一步强制State=20(货叉动作),如果气缸伸出,继续强制到状态30。这种单步调试的好处是能把每个环节拆开验证,快速区分是机械问题、硬件接线问题还是逻辑问题。

联动调试时按真实生产顺序操作:入库传感器给信号,视觉触发,堆垛机运动,货位表更新。此时把博图监控视图和数据块视图同时打开,一边观察程序运行,一边盯着货位表里的Occupied位变化。有一个实用技巧:在监控表里同时添加"State"和"TargetCell",当堆垛机运行时能看到当前状态和预定的目标货位,如果货位分配错了,立刻能发现是分配函数还是坐标数据有问题。

4.3 监控表与变量追踪

调试立体仓库程序时,监控表的组织方式很有讲究。我不会把所有变量都塞进一张表,而是分成三张:第一张是IO输入输出,观察所有传感器和输出动作;第二张是状态机核心变量,包括当前状态、目标货位、空货位计数、视觉结果;第三张是运动控制参数,包含两轴的实际位置、目标位置、偏差、速度。分表的好处是可以同时打开多个监控视图,用一台笔记本既看IO又看状态,效率翻倍。

还有一种情况是程序运行十几分钟后才偶尔出错,这种间歇性问题用监控表很难抓到。我会在博图里引入"IP地址触发"的方式,用PLC的CPU时钟脉冲去记录一个环形缓冲,把每次状态切换时的关键变量写入DB,当故障发生后离线读取这个缓冲,就能还原出故障前一秒发生了什么。虽然比赛不一定要求这么高级,但对于现场反复出现的偶发故障,这个"黑匣子"思路非常有效。

5. 踩坑记录与常见问题排查:立体仓库PLC调试的五个实际问题

5.1 程序下载后PLC报"数据块被优化访问冲突"

现象:下载完成后,程序运行在第一个扫描周期就报错,监控DB发现某些数组元素无法查看,触摸屏读取数据也显示乱码。原因是因为生成DB时勾选了"优化的块访问"选项,1200PLC默认会将DB的数据放在系统管理的存储区,普通的读取指令和HMI访问会遇到权限限制。解决:在DB属性里把"优化的块访问"取消勾选,重新编译并下载。从那以后我新建DB一律先检查这个属性,比赛程序里也是全部取消优化访问,方便后续用绝对地址监视。

5.2 堆垛机启动时"咔咔"抖动并伴随过载报警

现象:按下启动按钮后,X轴伺服没有立刻行走,而是停留在原地颤抖,几秒后驱动报警。原因是程序在首次扫描时就把使能信号输出给驱动器,但在没有完成回原点定位前,X轴实际位置被当作0,程序直接计算偏差并下达了位置指令,导致驱动器同时收到"使能和微小位移"的冲突指令。解决:在OB1中加一个初始化标志位,只有完成回原点后,运动控制功能块才允许输出使能。另外检查驱动器本身的加减速时间设置,斜坡太短同样引起机械抖动。

5.3 视觉系统偶尔漏检,导致入库流程卡死

现象:输送线上有货,但状态机一直停在等待视觉结果的那一步,而复位按钮一按又能继续。原因是视觉结果信号持续只有几个毫秒,PLC扫描周期超过了这个时间,无法稳定捕获。解决:将视觉OK信号并联一个中间继电器,利用其线圈保持信号,同时在PLC程序里用锁存指令。我专门给视觉功能块增加了信号保持逻辑,并在状态进入等待之前复位这个锁存位,确保每次只接受一个新的视觉结果。

5.4 货位表数值被莫名清零

现象:程序一直稳定运行,但每隔几十分钟会有一两个货位的Occupied位变成FALSE,而实际货位上仍有托盘。原因是最初把货位表放在M区,但M区会被我们定义的FC或者FB内部使用,地址重叠导致误写入。解决:将所有货位状态统一迁移到全局DB中,并删掉了自定义的M区数组,最终发现是某个FB里的临时变量使用了M301.0,和货位表第4个位置的地址冲突。从那以后,我只在符号表里定义变量,从不直接用M绝对地址。

5.5 机器人放行总是比预期慢一拍

现象:出库流程中,机器人已经抓完货物,PLC要等2秒才发放下一个动作信号,看起来像死等了。原因是控制逻辑里用了TON延时指令,但TON的设定时间放在了定时器的背景DB里,且程序运行时不小心把背景DB的默认值改掉了。解决:检查所有延时器的PT值,确保它们是显式的常量而不是未初始化的变量。同时调整了放行信号的时序,让机器人的完成反馈直接触发下一步,而不是依赖固定延时。

6. 二次开发思路:把比赛程序改造成可扩展的仓储控制系统

拿到这套程序后,如果只是跑通比赛流程,那其实只发挥了一半价值。我通常会先把货位表从12个扩展到30个,按照实际货架的物理排布修改X/Z坐标。数组长度改起来很容易,但要注意地址重叠和扫描周期变长的问题。1200PLC扫描30个货位的循环不会明显增加CPU负担,但如果扩展超过100个货位,建议把FC_FindEmptyCell改成二分查找或空位索引表,否则每次入库的响应时间会指数增加。

第二个值得改造的点是出库策略。比赛程序默认是先进先出,但实际场景会要求先进后出,甚至按订单号随机出库。你可以在状态机里新增一个"策略选择"变量,用整数0、1、2分别表示FIFO、FILO、按订单出库。在出库函数里根据这个变量选择不同的遍历方向,最小改动量只是写两个循环。如果想让系统更智能,可以加入一个"最近使用时间"字段,每隔半小时自动整理库存,把低频货物放到里侧货位,这个逻辑同样可以放在OB30循环中断里,不影响主流程。

视觉部分也建议做扩展。比赛里信捷视觉只输出OK/NG和一个编码,实际项目中我更倾向于让视觉直接通过Profinet或者TCP/IP发送结构化数据,比如识别到的条码、尺寸、重量。1200PLC的开放式以太网通信支持TCP主动连接,你可以把那套IO握手机制替换成简单的字符串解析,把视觉数据写到DB的字符串区域,再由状态机读取。这种方式虽然增加了通信调试工作量,但对后续对接WMS系统或者MES系统非常有利。

还有一个常用改造:增加触摸屏HMI。比赛程序大多只关注PLC逻辑,缺少人机交互界面。二次开发时,在博图里添加一个精简面板,关联货位表的数组变量,把每个货位的占用状态用色块显示出来,操作员就能直观看到仓库利用率和空位分布。我给这套程序加过一个简单页面,用表格控件绑定DB的Cells数组,每个单元格显示"空/满/禁用",并且允许点击空闲货位手动指定入库目标。这个过程让我深刻体会到,好的交互设计能减少一半现场调试压力。从那以后,我每次拿到程序都会先看一眼DB变量命名是否清晰,再决定要不要直接给它补一个HMI页面。这个习惯帮我省下了大量重复沟通的时间,也希望你能在项目里用上这些细节,少走我当时走过的弯路。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询