上个月帮朋友排查一条包装线扫码枪触发延时的问题,PLC程序看着没问题,可一上现场就偶尔丢料。折腾了半天才发现,是光电传感器响应时间和进料速度的配合出了偏差。这种问题放在以前,只能靠现场一遍遍试,既费时间又费差旅费。要是办公室里就能把PLC、传感器、摄像头、变频器全部模拟出来,提前把各种工况跑透,很多现场调试的坑根本不用踩。这篇文章就写写我自己攒的一套“零成本模拟工业设备”方案,用纯软件方式把PLC、传感器、摄像头串成一条完整测试链路,覆盖程序逻辑验证、通讯协议调试、视觉识别测试的全流程场景。适合做设备调试、PLC编程、自动化项目交付的朋友参考,也适合想理解工业控制全链路的学生拿来练手。
先说结论:这套方案不花一分钱买硬件,用的全是免费工具和仿真器,但跑出来的通讯链路、数据格式、时序逻辑,和真实设备高度一致。我靠这套环境给好几个项目做过前置验证,大部分程序问题在办公室就能暴露,现场调试周期能缩短一半以上。
1. 方案设计思路:为什么要在一台电脑里“造”一条产线
1.1 现场调试的真实痛点
搞自动化的人都有体会,现场调试的时间窗口被压缩得越来越短。电气图纸设计、柜内接线、程序开发这些环节还能按部就班,可到了联调阶段,经常发现传感器还没到货、变频器型号和图纸对不上、摄像头协议文档缺失。更麻烦的是,PLC程序在办公室跑仿真能通过,真接到设备上就乱跳,多半是通讯逻辑、时序配合这类问题没暴露出来。
传统做法是等硬件齐了再联调,但自动化项目的节奏往往不允许。这时候就需要一套能在开发阶段就模拟出“设备侧行为”的测试环境,让PLC程序、上位机、HMI在一个逼真的虚拟环境里先跑起来,把通讯协议、数据格式、扫描周期这些最容易出问题的地方提前验证掉。
1.2 三层模拟架构的设计逻辑
这套方案的核心思路,是把工业控制系统拆成三个层面来模拟:
- 设备层:用PLCSIM或GX Simulator运行真实的PLC程序,用Modbus Slave工具模拟变频器、远程IO、智能仪表,用虚拟摄像机和RTSP流模拟工业相机。
- 通讯层:通过VMware虚拟网卡、VSPD虚拟串口,让仿真PLC和模拟设备建立真实的工业通讯链路,走Modbus TCP、Modbus RTU或Profinet协议。
- 应用层:用真实的PLC编程软件、HMI运行时、上位机调试工具读写数据,程序代码不用改,通讯地址直接对上。
这种分层的好处是每一层都能独立替换。比如第2层通讯链路验证完了,后面真要接实体设备,只要把设备层的Modbus Slave换成真实变频器,其他代码基本不用动。
1.3 工具链选型明细
我整理了一份常用工具清单,全部免费或试用版可用:
| 功能模块 | 推荐工具 | 主要用途 |
|---|---|---|
| 西门子PLC仿真 | TIA Portal + PLCSIM / PLCSIM Advanced | 运行S7-1200/1500/300/400程序,模拟Profinet通讯 |
| 三菱PLC仿真 | GX Works2 / GX Works3内置模拟器 | 运行FX/Q系列程序,模拟软元件输入输出 |
| Modbus从站模拟 | Modbus Slave、ModRSsim2 | 模拟变频器、远程IO、智能仪表的寄存器数据 |
| Modbus主站调试 | Modbus Poll | 模拟触摸屏或上位机读取PLC数据,验证地址映射 |
| 虚拟串口 | VSPD、Virtual Serial Port Driver | 创造成对虚拟串口,模拟RS485总线 |
| 虚拟摄像头 | OBS Studio Virtual Camera、e2eSoft VCam | 把程序生成的测试画面变成摄像头信号 |
| 网络摄像头模拟 | FFmpeg + RTSP服务器 | 模拟海康/宇视等网络相机的RTSP取流地址 |
| 图像生成与识别 | Python + OpenCV | 生成测试图像、模拟光照变化、执行颜色/形状识别 |
| 通讯抓包 | Wireshark | 分析Modbus TCP报文、RTSP协议流 |
选这些工具的核心依据是生态成熟度。PLCSIM和GX Simulator能真实执行厂商指令集,Modbus Slave能模拟标准从站行为,这些不是普通的“假数据生成器”,而是真的在跑协议栈,所以验证结果可信度很高。
2. PLC仿真环境搭建:让你的程序先在虚拟PLC里“跑”起来
2.1 西门子PLCSIM与虚拟机的网络模式选择
不少同行问“TIA用VMware连PLC用什么网络连接模式”,其实要看你的PLCSIM运行在哪里。PLCSIM自带虚拟网卡,和电脑物理网卡是隔离的,默认情况下它能和TIA Portal通信,但要和宿主机上的Modbus Slave模拟工具通信,就必须打通网络。
实际测试下来,最佳配置是把VMware虚拟机的网络模式设置为桥接模式,让虚拟机里的TIA/PLCSIM直接暴露在局域网网段。然后在TIA里给虚拟PLC分配一个固定IP,比如192.168.1.10,宿主机的Modbus Slave工具设置为192.168.1.100,双方处于同一网段就能直接通信。
如果PLCSIM跑在宿主机上,而Modbus Slave也在宿主机,就不需要虚拟机网络桥接,直接用Windows回环地址127.0.0.1或者虚拟网卡的IP就行。
注意:无论采用哪种模式,都要把Windows防火墙里对应的TCP端口放行。Modbus TCP默认端口502,PLCSIM的S7通讯端口是102。我试过在桥接模式下忘了放行防火墙,折腾了半小时才找到原因。
2.2 三菱GX Works2模拟器与传感器接线模拟
三菱的模拟器和西门子PLCSIM思路类似,但细节不太一样。用GX Works2打开程序后,点“调试”→“模拟开始”,程序就进入仿真运行状态。这时候左侧导航栏会出现软元件监视窗口,可以直接强制X、M、D寄存器的值。
这里有个和现场强相关的技巧:三菱FX3U的输入端默认是漏型(NPN)接线,传感器公共端接24V,信号输出接X端。但很多传感器是PNP型,输出高电平,直接接到FX3U输入端会不动作,需要改用源型接法或加转换继电器。在模拟环境里怎么验证这种接线差异?
办法很简单:用模拟器强制X0为ON/OFF,模拟不同传感器类型的信号行为。如果程序逻辑里写的是“X0常开,接通时启动”,那NPN传感器的低电平有效逻辑和PNP传感器的高电平有效逻辑产生的行为会完全不同。提前在模拟器里把两种逻辑都跑一遍,就会发现程序里如果直接用了“LD X0”,对PNP传感器来说逻辑方向反了,必须在程序里改为“LDI X0”,或者加上中间继电器转换。
2.3 博途里查看PLC资源使用情况
项目交付时经常被用户问“程序占了多少内存?CPU负载高不高?”这些问题在PLCSIM里可以提前摸清。打开TIA Portal,在项目树里选中PLC设备,右键“编译”→“软件”,编译后能在输出窗口看到块的大小和占用率。更直观的方式是在线模式下,打开“在线与诊断”→“诊断”→“诊断状态”,里面能看到CPU循环时间、通信负载率、内存占用等数据。
这些数据对优化程序很有用。比如我发现某个项目在模拟器里循环时间已经达到20ms,而现场要求控制在10ms以内,说明程序里某个功能块执行时间太长,需要拆解或改用中断方式处理。这类问题不通过仿真环境根本发现不了。
3. 传感器模拟与信号注入:把“现场信号”喂给PLC
3.1 数字量传感器模拟:强制位与Modbus线圈
数字量传感器在模拟环境里最容易处理,但想逼真地模拟出“时序”,还得动点脑筋。最简单的方式是用PLC仿真器的软元件强制功能,手动置位/复位一个位,模拟光电开关、接近开关的接通和断开。这种方式适合单点测试,比如验证程序里某个分支逻辑。
更接近真实场景的方式,是用Modbus Slave工具模拟远程IO模块。比如现场用的是分布式IO站,采集了一排光电传感器信号后走Modbus TCP送给PLC。那在模拟环境里,安装Modbus Slave,配置一个保持寄存器或线圈区,把你的光电传感器信号映射到对应地址。PLC程序里正常的Modbus通讯指令去读这个从站,就能读到“传感器”的状态。
这里有个细节:模拟NPN和PNP传感器时,在线圈里的值含义不一样。如果程序里定义“1”代表传感器导通,那PNP传感器的输出逻辑是“物体到位=线圈置1”;而NPN传感器是“物体到位=线圈置0”,因为它是低电平有效。仿真时记得把这个逻辑对应清楚,不然程序测试出来是对的,现场接上NPN传感器反而全反了。
3.2 模拟量信号:用曲线注入替代手填寄存器
温度、压力、辐照度这类模拟量传感器,输出4-20mA或0-10V信号,转换成数字量后通常是16位整数。模拟环境里直接修改Modbus寄存器的值就能模拟,但手填数字太僵硬,而且没法模拟温升过程、惯性滞后这些真实特性。
我的做法是用Python脚本按一定时间步长,生成一条平滑变化的曲线数据,通过Modbus TCP写入从站寄存器。比如模拟一个车间温度从20℃升到35℃的过程,用斜坡函数设定升温速率0.1℃/秒,再叠加一个0.2℃幅度的随机噪声,模拟传感器测量波动。PLC程序里如果有上下限报警、超温联锁逻辑,在这种数据下测试才真正有意义。
给寄存器写值时注意数据类型映射。温度传感器输出的是带一位小数甚至两位小数的浮点值,而Modbus保持寄存器通常是整数。可以约定实际值乘以10或100存储在寄存器里,PLC侧再除以10或100还原。这个换算关系必须在模拟阶段就定下,并写进通讯接口文档里。
3.3 串口型传感器的虚拟串口模拟
很多传感器走RS485串口,比如局放TEV传感器、深视智能温度传感器,协议多半是Modbus RTU。仿真这类设备,用VSPD虚拟串口工具创建一对互联的COM口,比如COM3和COM4。Modbus Slave工具绑定COM4,模拟传感器的从站响应;PLC或上位机的程序打开COM3,发送Modbus RTU请求,虚拟串口会把请求转发到COM4,Modbus Slave收到后应答,通讯链路就通了。
具体配置时要注意:VSPD创建一对串口后,主站和从站程序都要打开对应的COM口,且波特率、数据位、停止位、校验位必须完全一致。比如传感器设定9600,8,N,1,Modbus Slave和主站串口参数也要一致。这个环节有个经典坑:用VSPD模拟串口时,如果从站程序设置的响应延时太短,虚拟串口来不及转发,主站会报超时。我一般把Modbus Slave的响应延时设置为10到20毫秒,和真实设备更接近。
3.4 循迹与颜色传感器:从“IO模拟”到“视觉模拟”
循迹传感器的应用在智能车、AGV上非常普遍,五路循迹传感器的优点在于能同时检测多个位置的黑线偏移量,方便纠偏算法做PID调节。但单纯模拟IO信号只能验证逻辑分支,完美的线居中、左偏、右偏这些状态变化,光靠手动强制位效率太低。
更聪明的做法是“视觉模拟”和“IO模拟”结合。用Python生成一张含黑线的白底图像,黑线位置随时间左右偏移,用OpenCV处理图像,把黑线相对于屏幕中心的位置换算成“左偏、居中、右偏”的逻辑,再通过Modbus寄存器或串口把状态发给PLC。这样PLC收到的信号变化规律和真实循迹过程完全一致,你就能在模拟环境里调试循迹PID参数,而不只是验证“有没有收到信号”。
颜色传感器的模拟思路更直接。颜色传感器通常输出的是RGB数值或颜色类别编码(比如红=1、绿=2、蓝=3),在模拟环境里用Modbus寄存器填一个数值当作颜色类别。但如果要测试分拣逻辑中“相机拍照和传感器信号哪个先到”的时序问题,就得结合后面的摄像头模拟方式一起做。
4. 摄像头与视觉信号模拟:让程序“看到”不存在的画面
4.1 用OpenCV生成画面,再推到虚拟摄像头
视觉检测是这几年自动化产线的标配功能,但相机价格不菲、视野调试麻烦,在开发阶段模拟摄像头能省下大量时间。最常用的链路是:Python脚本用OpenCV生成带缺陷的产品图,通过OBS Studio的虚拟摄像头功能输出成标准摄像头设备,让OpenCV的VideoCapture、海康的SDK、HMI的视频组件直接去读这个“摄像头”。
OBS Studio配置虚拟摄像头时,输出分辨率默认是1920x1080,但很多工业视觉程序只认640x480或1280x720,所以要先设置好画布和输出分辨率,再启动虚拟摄像头服务。如果程序打开摄像头后一直是黑屏或无法识别,多半是像素格式不兼容。工业SDK通常要求YUY2或MJPG格式,而OBS默认输出可能是NV12或I420。这时候在OBS输出设置里把颜色格式强制改成YUY2,问题基本能解决。
4.2 模拟海康/宇视网络摄像头取流地址
网络摄像头的模拟更加简单直接。用FFmpeg读取OpenCV生成的测试视频或图片序列,推流到本地的RTSP服务上。FFmpeg推流命令大致是:
ffmpeg -re -loop 1 -i test.jpg -c:v libx264 -preset ultrafast -tune zerolatency -f rtsp -rtsp_transport tcp rtsp://127.0.0.1:554/live/test推流起来后,用VLC打开地址验证是否能正常播放。然后在你的视觉程序里配置取流地址,模拟海康常见的路径结构:
- 海康:rtsp://用户名:密码@IP:554/Streaming/Channels/101
- 大华:rtsp://用户名:密码@IP:554/cam/realmonitor?channel=1&subtype=0
- 宇视:rtsp://用户名:密码@IP:554/live1
你完全可以在模拟环境里用这些标准路径结构,把IP改成127.0.0.1或虚拟网卡IP,这样上位机程序里的取流地址配置和现场发布时一模一样,提前验证地址格式和鉴权逻辑。
4.3 嵌入式摄像头场景:树莓派OV5647模拟与QEMU环境
智能车、低端视觉工位常用树莓派加OV5647摄像头模块,Linux环境的摄像头接口走V4L2。开发时如果手头没有树莓派,可以在QEMU模拟的ARM64虚拟机里安装带V4L2驱动的Linux系统,再用v4l2loopback内核模块创建一个虚拟摄像头设备。
做法是给QEMU虚拟机添加一个USB摄像头重定向,或者直接用modprobe v4l2loopback创建/dev/video0设备,然后用FFmpeg把OpenCV生成的测试画面推到这个虚拟设备上。树莓派的视觉程序打开/dev/video0读取图像,就和读取真实OV5647摄像头模块一样。这样在不买树莓派、不买OV5647的情况下,先把图像采集、校正、识别算法在模拟环境里跑通。
4.4 测试图像集的设计思路
模拟摄像头的核心不只是“能出画面”,而是“画面能模拟现场多样工况”。我给你几个实用的图像生成方向:
- 光照变化:用OpenCV调整图像亮度、对比度、色温,模拟车间不同时段的光线变化,验证视觉程序的亮度适应能力。
- 噪声叠加:给图像加高斯噪声、椒盐噪声,模拟传感器暗光下的噪点和坏点。
- 位置偏移:把产品的像素位置整体平移、旋转几个角度,验证模板匹配算法对位置偏差的容错能力。
- 遮挡模拟:在产品图像上画几条黑色条带,模拟飞溅异物遮挡镜头,测试视觉程序断料或报警逻辑。
这些图像不用拍实物,直接在Python里用几何绘制就能生成,脚本加入随机函数,每次运行还能产生不同组合,实现自动化回归测试。
5. 全流程联调实操:一条虚拟分拣线的诞生
5.1 场景设计与信号流定义
前面各个模块单独讲了一堆,现在把它们串起来。我搭建的演示案例是一条皮带分拣线,任务描述如下:
产线包含一条变频驱动的皮带线,皮带入口装一个光电传感器检测来料,中段装一套工业相机识别来料颜色(红/绿/蓝三色),出口有两个分拣气缸,依据颜色把物料推到不同料箱。PLC作为主站,通过Modbus TCP读取一个变频器从站的状态和速度给定。
信号流如下:光电传感器触发→PLC启动皮带变频器→物料到达相机拍照位→相机视觉程序识别颜色→识别结果写入Modbus寄存器→PLC读取结果→根据颜色控制Y0/Y1气缸→气缸动作→到位传感器反馈→流程结束。
5.2 PLC程序设计:Modbus多从站轮询的关键写法
这步我用西门子S7-1200做演示。PLC作为Modbus主站,需要先调用Modbus_Comm_Load配置通讯端口参数,再调用Modbus_Master功能块执行读写请求。多从站轮询的常见写法是状态机:
Step 0: 写速度给定到从站1寄存器 Step 1: 读从站1状态字 Step 2: 写速度给定到从站2寄存器 Step 3: 读从站2状态字 ...每个Step之间用完成位触发跳转,轮询周期就是所有Step执行一遍的时间。模拟32台变频器的通讯需求,本质上就是轮询链表里有32个节点,每个节点包含站地址、功能码、起始地址、数据长度。程序不应该为每台变频器写重复代码,用数组+指针的方式管理从站地址表,配合循环执行轮询,代码量能压缩到原来的五分之一。
5.3 模拟设备配置:变频器从站、相机视觉、传感器逻辑
Modbus Slave模拟变频器时,每个从站对应一台变频器,寄存器的规划需要提前设计。我用的映射表是:
| 寄存器地址 | 数据类型 | 含义 | 读写方向 |
|---|---|---|---|
| 40001 | 保持寄存器 | 速度给定,单位0.1%(600=60.0%) | PLC写→变频器 |
| 40002 | 保持寄存器 | 当前频率,单位0.01Hz | 变频器→PLC读 |
| 40003 | 保持寄存器 | 运行状态字(bit0运行,bit1故障) | 变频器→PLC读 |
| 40004 | 保持寄存器 | 故障码 | 变频器→PLC读 |
相机视觉模拟用Python的OpenCV实现:从RTSP流读取画面,用HSV颜色空间分离红绿蓝,计算最大连通域的颜色类别,把结果写到一个模拟Modbus从站的40005寄存器(1=红,2=绿,3=蓝,0=无料)。PLC通过Modbus从站地址3读取该值。
光电传感器用一个Modbus线圈映射到PLC的输入过程映像,在Python脚本里根据“模拟物料到达时间”自动置位或复位线圈。
5.4 联调步骤与每步验证点
这是整个联调过程中最重要的部分,我拆成8个步骤:
- 启动VMware里的TIA博途和PLCSIM,加载分拣线PLC程序,虚拟PLC分配IP 192.168.1.10。验证TIA在线连接正常,程序能下载到虚拟PLC。
- 在宿主机启动Modbus Slave,建立3个从站:1号从站模拟变频器,3号从站模拟相机结果,4号从站模拟光电传感器。分别配置对应寄存器表。
- 用Modbus Poll手动写入从站1的速度给定寄存器为600(即60%),观察PLC监控表里对应的速度给定值是否变成60.0%。这一步验证PLC和Modbus从站的地址映射是否一致。
- 启动相机模拟程序,确认RTSP流能出画面。在测试图像里画一个红色方块,视觉程序识别结果写入3号从站40005寄存器,手动刷新看值是否为1。
- 编写Python脚本,让光电传感器从站4的对应线圈按时间序列自动置位和复位,模拟来料间隔。观察PLC程序是否能正确触发皮带启动逻辑。
- 在PLC程序里预设识别结果和气缸动作的映射:颜色=1时Y0置位,延时1秒复位;颜色=2时Y1置位;颜色=3时Y0和Y1都置位。在模拟器里观察对应的输出变量变化是否和预期一致。
- 并闭光电传感器模拟,确认皮带经过延时后自动停止,验证断料保护逻辑。
- 用Wireshark抓包分析PLC到Modbus从站的Modbus TCP报文,确认请求响应时间小于100毫秒,轮询周期稳定。
这样8步走下来,从通讯、逻辑、视觉到时序全部验证一遍。
5.5 关于“一个西门子PLC带32台变频器”的可行性验证
“西门子PLC与32个变频器Modbus通讯控制是否可行”是个经典问题。很多人担心通讯周期太长导致控制不及时,这个担忧在模拟环境里能直接量化。
我的模拟做法是在Modbus Slave里同时建立32个从站,从站地址从1到32,每个从站只包含4-5个寄存器,保持程序里轮询链路的正常执行,然后在Wireshark里观察一周期的总耗时。实测下来,在波特率115200且用Modbus TCP时,32个从站读写一遍大约耗时300到500毫秒,取决于每个从站的响应延时。如果每个从站只执行“写速度+读频率+读状态”3个请求,通讯阶跃响应能控制在1秒以内,对一般输送线应用完全够用。关键在于控制轮询链路的数据量,不要一次读取大块无用寄存器,尽量把每个从站的读取请求精简到必需的最小长度。
6. 常见问题速查与避坑技巧
6.1 PLCSIM和Modbus Slave连不上
这是遇到频率最高的问题。检查顺序是这样的:先看PLCSIM虚拟PLC的IP和Modbus Slave所在主机IP是否在同一网段,再看两边的防火墙是否放行了502和102端口,最后用Wireshark抓包确认请求是否到达、是否有RST包。有个常见陷阱是虚拟机网络模式选择了NAT,导致虚拟机里的PLCSIM IP虽然是192.168.1.10,但宿主机根本不认识这个地址,改成桥接模式后立刻恢复。
6.2 虚拟串口对不上
VSPD创建了COM3和COM4,但Modbus Slave绑定COM4后,PLC或上位机打开COM3一直报超时。多数情况是主站程序和从站程序的串口参数不一致,或者两个程序都绑定到了COM4导致冲突。解决思路:主站绑定COM3,从站绑定COM4,两者波特率一致,VSPD虚拟串口默认不处理数据内容,只做透传,所以参数完全一致才能通。
6.3 虚拟摄像头黑屏
三道检查:OBS是否真的启动了虚拟摄像头服务;输出分辨率是否符合程序的预期;颜色格式是否被识别。我遇到最头疼的是OpenCV用V4L2方式打开虚拟摄像头时,要求输出格式是MJPG,而OBS默认输出NV12,需要强制改成MJPG或YUY2。另外帧率最好设置成30FPS,很多工业视觉程序对帧率有下限要求,低于15FPS会被判定为连接异常。
6.4 模拟量数据“跳变”厉害
模拟量在模拟环境里也容易跳变,原因是写入的数据不连续。我建议在Python脚本里对所有模拟量寄存器用斜坡函数控制变化速率,比如目标值是80,每100毫秒只写一个递增值,做一个2秒的斜坡。这比一步到位写入更能还原真实传感器特性。PLC侧如果扫描周期不长,可以加一个模拟量滤波块,把一阶惯性滤波的时间常数设置1到3秒,效果和现场调试时基本一致。
6.5 视觉识别结果偶发不稳定
模拟图像虽然可控,但随机噪声还是会影响识别结果。遇到这种情况,先用“固定帧”方式排查算法本身,再逐步叠加噪声,找出算法容错的边界。另外,视觉识别结果写入Modbus寄存器的时机要和PLC的扫描周期对齐,否则PLC读到的是半帧数据。我习惯在视觉脚本里加一个“数据有效”标志位,PLC读到标志位为1时才读取结果,读完立即复位,避免脏数据。
6.6 用AI生成的PLC代码,在模拟环境里先测一圈
现在用AI写PLC代码已经很常见了,但代码生成不等于代码可用。我的习惯是把AI生成的梯形图或结构化文本工程导入TIA或GX Works2,先在PLCSIM或三菱模拟器里完整跑一遍联调流程,确认地址映射、时序逻辑、通讯块配置都正确后再考虑下载到真实设备。模拟环境里跑AI代码还有个好处,能快速暴露AI模型对工艺理解不准确的问题,比现场翻车成本低得多。
最后分享一个我常用的小技巧:整套模拟环境配置完成后,给虚拟机打一个快照,记录PLCSIM IP、Modbus Slave寄存器表、OBS虚拟摄像头设置这类基线信息。以后接到新项目,直接回滚快照,只改寄存器映射表和IO表就能复用环境,根本不用从零开始搭。这套“零成本模拟工业设备”方案,本质上是把你的测试工作前置到开发阶段,让问题暴露得越早,改造成本就越低。