C# 视觉检测实战:PLC 按钮触发 VisionPro 检测,OK 亮灯 / NG 灭灯(西门子 PLC,含界面显示与图片存档)
在机器视觉项目里,最常见的一种工作模式是:工人按下按钮(或产品到位),相机拍照、视觉软件判定 OK/NG,再把结果送给 PLC,由 PLC 决定放行还是剔除。本文用一个 WinForms 小项目,演示如何用 Cognex VisionPro 做视觉判定、用 HslCommunication 与西门子 S7-1200 交互,实现「PLC 按钮触发 → 视觉检测 → 结果回写 PLC + 界面显示 + 图片本地存档」的完整闭环。适合有一定 C# 基础、第一次做视觉与 PLC 联调的初学者。
一、项目整体方案
整个程序围绕一个循环展开:
- 程序启动,初始化西门子 PLC 对象,并加载 VisionPro 工程文件(
.vpp,工具块 ToolBlock); - 点击「连接西门子」,连接成功后启动定时器,周期性轮询 PLC 的输入点 I0.0(按钮信号);
- 当检测到 I0.0 为 true(按钮按下/产品到位),运行 VisionPro 工具块进行检测;
- 取出输出图像显示到界面,取出检测结果字符串
Output(OK / NG); - 根据结果控制 PLC 上的指示灯:
- OK :向 PLC 的
DB50.DBD0写 1(亮灯 ),界面标签显示绿色 OK,图片存到imgs/OK; - NG / 识别错误 :写 0(灭灯),标签显示红色,图片存到对应文件夹。
- OK :向 PLC 的
- 处理完继续轮询,等待下一次触发。
下面是程序的界面布局,包含「连接西门子」按钮、VisionPro 图像显示区和结果标签:
【插图 1:程序界面布局图】
整个检测流程如下图所示(含轮询触发、视觉判定、结果回写与存档的闭环):
【插图 2:视觉检测整体流程图】
二、技术准备
2.1 涉及的组件
| 组件 | 作用 |
|---|---|
| Cognex VisionPro | 康耐视视觉库,负责加载视觉工程、运行检测、输出图像与结果、保存图片 |
| HslCommunication | 工业通信库,用 SiemensS7Net 读写西门子 S7-1200 |
.vpp 工程文件 |
在 VisionPro 里编辑好的工具块(本项目为 vpps/yaohe.vpp) |
VisionPro 相关引用(DLL):Cognex.VisionPro、Cognex.VisionPro.Core、
Cognex.VisionPro.ImageFile、Cognex.VisionPro.ToolBlock、显示控件
CogRecordDisplay 等;HslCommunication 通过 NuGet 安装。
2.2 核心对象说明
CogToolBlock:工具块,相当于把一组视觉工具(取像、定位、检测等)封装成一个整体,
调用Run()执行,通过Outputs["名称"].Value取输出;CogRecordDisplay:VisionPro 的图像显示控件,用来显示检测图像;CogImageFileTool:图像保存工具,二开存图推荐用它;SiemensS7Net:HslCommunication 的西门子通信类。
三、初始化:PLC 对象与加载视觉工程
窗体加载时完成两件事:创建 PLC 对象、从文件加载 ToolBlock。
csharp
SiemensS7Net s7 = null;
CogToolBlock cogToolBlock;
CogImageFileTool _fileTool = new CogImageFileTool(); // 用于保存图像
private void Form1_Load(object sender, EventArgs e)
{
// 1. 初始化西门子 PLC:型号 S1200、IP,设置连接超时
s7 = new SiemensS7Net(SiemensPLCS.S1200, "192.168.8.10")
{
ConnectTimeOut = 5000
};
// 2. 加载 VisionPro 工程文件(ToolBlock)
string vpppath = Environment.CurrentDirectory + "\\vpps\\yaohe.vpp";
cogToolBlock = CogSerializer.LoadObjectFromFile(vpppath) as CogToolBlock;
}
CogSerializer.LoadObjectFromFile用于把.vpp文件反序列化成对应的视觉对象,这里加载的是 ToolBlock,所以用
as CogToolBlock。注意.vpp文件要放到输出目录(本项目为
bin\Debug\vpps\),并在工程里设置较新则复制。
四、连接 PLC 并启动轮询
点击「连接西门子」,异步连接成功后启动定时器,定时去读按钮信号:
csharp
private async void button1_Click(object sender, EventArgs e)
{
// 异步连接 PLC,返回 OperateResult
OperateResult result = await s7.ConnectServerAsync();
if (result.IsSuccess)
{
MessageBox.Show("连接成功!!!");
timer1.Interval = 500; // 每 500ms 轮询一次
timer1.Start();
}
else
{
MessageBox.Show("连接失败!!!");
}
}
用定时器轮询输入点,是上位机获取 PLC 触发信号的简单方式。轮询周期要结合实际节拍
设置,太短会增加通信次数,太长可能响应不及时。
五、核心:轮询触发、视觉检测与结果处理
定时器 Tick 中:先读 I0.0,按下才检测;运行 ToolBlock,取图像与结果,按 OK/NG 分别处理。
csharp
private void timer1_Tick(object sender, EventArgs e)
{
// 1. 读取按钮信号 I0.0(ReadBool 的结果在 .Content)
bool buttonresult = s7.ReadBool("I0.0").Content;
if (buttonresult)
{
// 2. 运行视觉工具块
cogToolBlock.Run();
// 3. 取输出图像,显示到控件并自适应大小
ICogImage OutputImage = (ICogImage)cogToolBlock.Outputs["OutputImage"].Value;
cogRecordDisplay1.Image = OutputImage;
cogRecordDisplay1.Fit();
// 4. 取检测结果字符串
string result = cogToolBlock.Outputs["Output"].Value.ToString();
// 5. 按结果分别回写 PLC、更新界面、保存图片
if (result == "OK")
{
s7.Write("DB50.DBD0", 1); // OK:写 1 亮灯
label1.Text = "OK";
label1.ForeColor = Color.DarkGreen;
SaveImage(OutputImage, "OK");
}
else if (result == "NG")
{
s7.Write("DB50.DBD0", 0); // NG:写 0 灭灯
label1.Text = "NG";
label1.ForeColor = Color.DarkRed;
SaveImage(OutputImage, "NG");
}
else
{
s7.Write("DB50.DBD0", 0); // 识别异常:写 0 灭灯
label1.Text = "识别错误";
label1.ForeColor = Color.DarkRed;
SaveImage(OutputImage, "错误识别");
}
}
}
关键点:
- ToolBlock 的输出通过
Outputs["名称"].Value获取,名称要和.vpp工程里配置的输出
端子名一致(本项目为OutputImage和Output); cogRecordDisplay1.Fit()让图像自适应控件大小;- 结果通过
DB50.DBD0(32 位双字)控制指示灯:OK 写 1 亮灯,NG/异常写 0 灭灯。
六、图片本地存档
检测图片按结果分类保存,文件名带时间,方便追溯。VisionPro 二开存图推荐使用
CogImageFileTool:
csharp
private void SaveImage(ICogImage _img, string str)
{
// 按结果拼目录:imgs/OK、imgs/NG、imgs/错误识别
string fileName = Directory.GetCurrentDirectory() + $"\\imgs\\{str}";
Directory.CreateDirectory(fileName);
// 拼接文件名:结果 + 当前时间
string imgName = $"{str}--{DateTime.Now.ToString("HH时mm分ss秒")}.bmp";
// 用 CogImageFileTool 保存
_fileTool.InputImage = _img;
_fileTool.Operator.Open($"{fileName}\\{imgName}", CogImageFileModeConstants.Write);
_fileTool.Run();
}
正式项目中图片命名通常会带上产品序列号、批次等信息,便于质量追溯;保存格式也可选用
jpg/png 等。
七、常见坑
- 连不上 PLC? 检查网线、同网段、能否 ping 通、PLC 型号与 IP;S7-1200 还需在博途
里允许 PUT/GET、DB 块取消「优化的块访问」。 - 加载 .vpp 报错? 文件路径要正确(建议用
Environment.CurrentDirectory拼相对
路径),并把.vpp复制到输出目录;加载后用as转换要确认类型匹配。 - 取输出为 null / 报错?
Outputs["名称"]的名称必须和 ToolBlock 里配置的输出端子
完全一致,注意大小写。 - 图像不显示? 要给
cogRecordDisplay.Image赋值并调用Fit();确认 ToolBlock
确实输出了ICogImage。 - 按钮按下没反应? 确认轮询定时器已启动、I0.0 地址正确、ReadBool 用
.Content
取值;按钮信号最好在 PLC 或上位机做去抖。 - 重复触发 / 一次按下检测多次? 轮询期间按钮一直为 true 会反复触发,可在检测后
等待信号复位(下降沿)再允许下一次,或由 PLC 做单次触发。 - 图片保存失败? 先
Directory.CreateDirectory确保目录存在;注意文件占用与命名
冲突。 - 本项目以跑通功能为主,正式部署可补充异常处理、断线重连、日志,并把 IP、地址等
放到配置文件。
八、小结
- 这是一个典型的「PLC 触发 + 视觉检测 + 结果回写 + 图片存档」视觉检测闭环;
- 用
CogSerializer.LoadObjectFromFile加载 ToolBlock,Run()执行,
Outputs["..."].Value取图像与结果; - 用 HslCommunication 的
SiemensS7Net:ConnectServerAsync连接、
ReadBool("I0.0")读触发、Write("DB50.DBD0",值)控制亮灯(1)/灭灯(0); - 图像用
CogRecordDisplay显示、CogImageFileTool按 OK/NG 分类存档; - 注意轮询去抖、单次触发、输出端子名一致等联调细节。
掌握这套流程后,再配合实际相机和 PLC,就能快速搭建一个视觉检测工位。建议对照本文代码
亲手连接相机与 PLC 跑一遍,加深理解。

