4. VisionPro脚本与作业配置优化
在VisionPro中,C#脚本、ToolGroup与Job构成了从“单点算法”到“完整视觉作业”的三级承载结构。很多项目在算法层面已经调通,但上线后出现节拍波动、参数传递混乱、脚本难以维护等问题,根源往往不在视觉工具本身,而在于这三者的架构划分与参数传递方式不合理。本节围绕“怎么分层、怎么传参、怎么提速”三个问题展开。
一、三层架构的职责边界
VisionPro的作业组织可以理解为三个层次:Job是面向产线的作业容器,负责与PLC、相机触发、结果输出对接;ToolGroup是Job内部的功能分组单元,通常按工位、按检测项或按流程阶段划分;C#脚本则是嵌入在Job或ToolGroup中的可编程节点,用于完成工具无法直接表达的判断、计算、通信和流程控制。
合理的划分原则是:Job管“调度与接口”,ToolGroup管“功能聚合”,脚本管“逻辑与胶水”。例如一个双相机定位+测量作业,Job负责触发两台相机并汇总结果;ToolGroup分为“上相机定位组”“下相机测量组”“结果判定组”;脚本只处理坐标转换、OK/NG判定和与PLC的握手信号,而不去重复实现CogFindCircle、CogCaliper等已有工具的功能。
常见的错误架构是把所有逻辑塞进一个脚本,让脚本直接调用大量工具并串联全部流程。这样做的后果是:脚本与工具强耦合,单个工具参数调整就要改脚本;调试时无法单独运行某个ToolGroup;Job的输入输出接口被脚本内部变量绑架,换线换型时改动面巨大。
二、参数传递的三种方式与选择
VisionPro中参数传递主要有三条路径,理解它们的差异是避免“参数找不到、改不动”的关键。
第一条是Job的Inputs/Outputs。这是Job对外暴露的接口,适合放换型参数、阈值、补偿量等需要由上位机或PLC动态下发的值。例如把“定位偏移补偿X”“定位偏移补偿Y”“NG重试次数”定义为Job Inputs,换型时只需改这三个值,无需打开脚本。Job Outputs则用于输出最终判定、测量值、耗时等。
第二条是ToolGroup的输入输出端子。ToolGroup内部工具的结果可以通过端子暴露给同组或下游组使用。例如定位组的CogFindLine输出角度θ,通过端子连接到测量组,测量组在标定后的坐标系下做测量。这种方式是“数据驱动”的,工具结果变化会自动传递,不需要脚本干预。
第三条是脚本读写工具或Job的终端。脚本可以通过mToolBlock.Inputs、mToolBlock.Outputs访问所在ToolGroup的端子,也可以通过mJob访问Job级变量。脚本适合做“需要计算或判断才能确定”的传递,例如根据多个测量值计算综合评分,再写入Job Output。
选择原则可以概括为:能走端子就不走脚本,能走Job接口就不写死在脚本里。端子传递是声明式的,VisionPro可以自动做类型检查和依赖排序;脚本传递是命令式的,灵活但容易引入隐式依赖。
三、执行效率优化的关键手段
脚本和作业配置对节拍的影响,通常集中在以下几个方面。
第一,减少脚本中的重复计算。标定矩阵、坐标变换参数、查表数据等不随每帧变化的内容,应放在脚本的GroupRun之外初始化,或使用静态变量缓存。如果每帧都重新构造矩阵、重新读取配置文件,单帧可能多出几毫秒到几十毫秒。
第二,避免在脚本中做图像遍历。C#脚本适合做数值计算和逻辑判断,不适合逐像素访问图像。需要像素级操作时,优先使用Cognex自带的CogImageConvert、CogBlob、CogCaliper等工具,它们经过优化且支持多线程。
第三,合理设置ToolGroup的并行执行。VisionPro允许将互不依赖的ToolGroup设置为并行运行。例如上相机定位组和下相机测量组如果使用不同图像、无数据依赖,可以并行;但判定组依赖前两组结果,必须串行。并行设置不当会导致资源竞争,反而降低稳定性。
第四,控制脚本的异常处理粒度。脚本中每个可能失败的操作都应有明确的异常捕获和返回值,避免异常向上抛出导致整个Job中断。同时,异常处理本身也有开销,不应在每帧都执行大量try-catch嵌套。
第五,优化Job的触发与采集配置。如果相机触发到Job执行的链路中存在不必要的等待或轮询,应改为事件驱动。例如使用mJob.Run()的同步调用时,确认没有在脚本中插入Thread.Sleep或忙等待。
四、一个可参考的配置示例
以下是一个双相机定位测量Job的参数配置片段,展示了Job Inputs、ToolGroup端子和脚本读写的配合方式。参数值为示例,实际项目需根据标定结果和工艺公差设定。
// Job Inputs(由上位机下发)
OffsetX_um = 0 // X方向补偿,单位微米
OffsetY_um = 0 // Y方向补偿,单位微米
WidthTol_um = 50 // 宽度公差,单位微米
RetryCount = 2 // NG重试次数
// ToolGroup: LocateGroup 输出端子
LocateGroup.X_px → 定位X像素坐标
LocateGroup.Y_px → 定位Y像素坐标
LocateGroup.Angle_deg → 定位角度
// ToolGroup: MeasureGroup 输入端子
MeasureGroup.RefX_px ← LocateGroup.X_px
MeasureGroup.RefY_px ← LocateGroup.Y_px
MeasureGroup.RefAngle ← LocateGroup.Angle_deg
// C#脚本:坐标转换与判定
double x_um = (LocateGroup.X_px - CalibCenterX) * ScaleX_um_per_px + OffsetX_um;
double y_um = (LocateGroup.Y_px - CalibCenterY) * ScaleY_um_per_px + OffsetY_um;
double width_um = MeasureGroup.Width_px * ScaleX_um_per_px;
bool ok = Math.Abs(width_um - NominalWidth_um) <= WidthTol_um;
mJob.Outputs["ResultOK"].Value = ok;
mJob.Outputs["Width_um"].Value = width_um;
这个示例中,定位结果通过端子传给测量组,测量组在定位坐标系下完成测量;脚本只做单位换算、补偿和公差判定,不重复实现定位和测量算法。换型时只需修改Job Inputs中的补偿量和公差,脚本和ToolGroup结构保持不变。
五、架构设计中的常见陷阱
陷阱一:脚本直接引用具体工具名称。例如在脚本中写mToolBlock.Tools["CogFindLine1"].Outputs["Angle"],一旦工具重命名或替换,脚本立即报错。更稳妥的做法是通过ToolGroup端子访问,端子名称作为稳定接口。
陷阱二:Job Outputs在脚本中直接赋值而不经过类型检查。VisionPro的Outputs有类型约束,脚本赋值时如果类型不匹配会在运行时抛出异常。建议在脚本开头对关键Output做一次类型确认,或在Job配置中明确每个Output的数据类型。
陷阱三:ToolGroup粒度过细或过粗。过细会导致端子连接数量爆炸,过粗则无法单独调试和复用。一般建议一个ToolGroup对应一个可独立验证的功能单元,例如“定位”“测量”“判定”“通信”各成一组。
陷阱四:忽略脚本的线程安全。如果Job配置为多线程或并行执行,脚本中访问的静态变量、共享缓存必须加锁或改为每帧局部变量。否则会出现偶发的数据错乱,且难以复现。
综合来看,VisionPro脚本与作业配置优化的核心不是写更复杂的代码,而是把“调度、功能、逻辑”三层分清楚,让参数沿着明确的路径流动,让每帧只做必要的工作。架构清晰之后,节拍和稳定性问题往往会在排查阶段就暴露出来,而不是等到产线停线才被发现。