目录
- 1.3.1 通讯管理:通讯管理的心跳管理功能的使用方法
- 1.3.2 全局触发:使用全局触发功能执行流程的方法
- 1.3.3 全局变量:全局变量关联流程中具体模块结果的方法
- 1.3.4 全局脚本:方案加载完成信号发给通信设备的方法
- 1.3.5 全局脚本:通信设备ID获取方法
- 1.3.6 全局脚本:PLC通讯字符触发流程执行的方法
- 1.3.7 全局脚本:通过全局脚本加载本地图像的方法
- 1.3.8 全局脚本:通过全局脚本获取通讯输入的参数并赋值给全局变量
- 1.3.9 全局脚本:VM加载方案后自动执行的方法
- 1.3.10 全局脚本:多流程协作控制的方法
- 1.3.11 全局脚本:通过通讯触发快速匹配模块换型的方法
1.3.1 通讯管理:通讯管理的心跳管理功能的使用方法
描述
环境:VM4.0.0
问题:当外部设备与视觉保持连接过程中,由于各种不可控的原因(例如网线被意外拔出,网口松动,视觉程序意外退出),如何让外部设备的程序可以知道:与视觉的通讯已经中断。
可以通过通讯管理模块中的心跳功能实现能够给出上述问题的解决方案。
第一步:打开通讯管理,点工具栏通讯管理图标即可进入。如下图黄色箭头所示的图标。
第二步:找到心跳管理模块,设置心跳,如下图所示:
心跳类型选择多数据,时间间隔设置1000ms,这样与视觉连接的客户端就会每隔1s收到不同的字符串,比如当前收到“HeartBeat0”,经过1s后将收到“HeartBeat1”,再经过1s又收到”HeartBeat0”,如此循环。这样,当客户端不再收到来自视觉的发送的字符,或者视觉发送的字符不再变化,都说明通讯发生了异常。
问题根因
- 不了解通讯管理模块中的心跳功能怎么使用
- 心跳类型单数据和多数据的区别
1.3.2 全局触发:使用全局触发功能执行流程的方法
描述
环境:VM4.0.0
现象:我们这里以TCP通讯为例,视觉作为TCP服务端,与视觉交互的第三方设备作为TCP客户端。当TCP客户端连接上视觉服务端后,客户端发送字符串T1,视觉执行流程1;
客户端发送字符串T2,视觉执行流程2。
解答
这样的需求我们可以通过全局触发功能实现。这里介绍两种方法,方法一为更通用的方法,其接收的数据类型可以是int,float,string,byte等类型;方法二为简单方法,但接收的数据类型只能是string类型。
方法一:
第一步: 打开VM后,在快捷菜单中点击通信按钮
在打开通信界面后,点击设备列表后的加号,在协议类型中选择TCP服务端,设置需要的本机IP和本机端口,点击创建。
第二步:点击接收事件,进入接收事件窗口,点击事件列表后的加号,选择字节匹配处理方式,选择协议组装事件类型,点击创建。
将绑定设备选为需要进行通信的设备的名称,这里选择TCP服务端,点击规则列表下的加号,根据需要添加相应的规则。比如这里接收字符串T1,就将类型设为string,比较规则设置为等号。
需要注意的是,在规则列表中目前只支持与逻辑,也就是说必须全部满足该事件下的规则才能触发该事件。这里由于要求通讯接收到T1时执行流程1,接收到T2时执行流程2,属于或的逻辑,因此需要使用两个接收事件。第一个事件接收T1,第二个事件接收T2。
第三步:在快捷菜单中点击全局触发按钮。
点击事件触发序号下的加号,根据项目情况添加触发事件。
第四步:为了看到效果,分别建立两个一样的流程。
当执行该流程后给客户端发送流程已执行,打开网络调试助手,实际效果如下。
需要注意的是:这种使用接收事件进行触发的方法属于通用型方法,接收的数据类型可以是int,float,string,byte类型。
但是,如果接收的数据类型为string类型,还有一种更简单的方法。
方法二:
第一步:与方法一的第一步相同,创建TCP服务端
第二步:借助全局触发中的字符串触发。假如现在希望客户端给服务端发送T3,执行流程3,可以按下图所示进行配置。
第三步:添加流程3,客户端发送T3,执行效果如下
问题根因
不熟悉全局全局触发工具的使用。
1.3.3 全局变量:全局变量关联流程中具体模块结果的方法
描述
环境:VM4.0.0
问题:将视觉流程中模板匹配算法模块运行的结果数据:特征匹配点X关联全局变量MatchResultX。
解答
在流程运行的主界面中,按照下面1,2,3,4步骤操作,第一步选中算法模块,第二步选择模块结果Tab页,第三步点击订阅数据图标,第4步选择全局变量。
问题根因
不了解全局变量的绑定操作
1.3.4 全局脚本:方案加载完成信号发给通信设备的方法
描述
环境:VM4.0.0
现象:需要在方案加载完成后,发送加载完成信号到全局变量,发送给通信设备。
解答
全局脚本的使用可以通过打开示例,完成常用的基本功能开发。
打开全局通信代码后,在脚本中添加代码
问题根因
全局脚本和通信接口不熟悉。
1.3.5 全局脚本:通信设备ID获取方法
描述
环境:VM4.0.0
现象:4.0版本之前,全局脚本中通信数据接收函数中的DeviceID是按照设备管理列表中至上而下、从0开始依此增1,现在这种方法行不通。
解答
VM4.0版本每次增加设备列表都会分配唯一的ID号,后续全局脚本中判断设备ID通过这个唯一ID识别,不再从上到下默认排序。
问题根因
版本更新。
1.3.6 全局脚本:PLC通讯字符触发流程执行的方法
描述
环境:VM4.0.0
现象:PLC通讯字符改变时,触发流程执行一次的方法
解答
打开全局通信脚本,在UserGlobalMethods_OnReceiveCommunicateDataEvent里面修改,修改代码如下:
1. C#
2.
3. string strTemp="0000";
4. public override void UserGlobalMethods_OnReceiveCommunicateDataEvent(ReceiveDataInfo dataInfo)
5. {
6. if(dataInfo == null || dataInfo.DeviceData==null)
7. {return;}
8. //接收到的数据转成字符串
9. string str = System.Text.Encoding.Default.GetString(dataInfo.DeviceData);
10.
11. if(dataInfo.DeviceID==1)
12. {
13. //解析收到的数据
14. if(str=="0100"&&strTemp=="0000")
15. {
16. ImvsPlatformSDK_API.IMVS_PF_ExecuteOnce_V30_CS(m_operateHandle,10000,null);
17. }
18.
19. if(str=="0400"&&strTemp=="0000")
20. {
21. //执行流程2 一次
22. ImvsPlatformSDK_API.IMVS_PF_ExecuteOnce_V30_CS(m_operateHandle,10001,null); }
23. strTemp=str;
24. }
25. }
26. }
问题根因
不熟悉全局脚本、寄存器机制。
1.3.7 全局脚本:通过全局脚本加载本地图像的方法
描述
环境:VM4.0.0
现象:VM通过全局脚本加载本地图像
解答
通过VM的全局脚本加载本地图像的步骤如下所示:
1、打开全局脚本,选择需要的示例
2、在运行函数中插入如下代码
1. public int Process()
2. {
3. //m_operateHandle 二次开发SDK操作句柄
4. if (m_operateHandle == IntPtr.Zero)
5. { return ImvsSdkPFDefine.IMVS_EC_NULL_PTR; }
6.
7. ImvsSdkPFDefine.IMVS_PF_INPUT_IMAGE_INFO stImageInfo = new ImvsSdkPFDefine.IMVS_PF_INPUT_IMAGE_INFO();
8. stImageInfo.nDataType = 1;
9. stImageInfo.nModuleID = 16;//图像源模块序号
10. stImageInfo.strImagePath = "E:\\VSproject\\Demo\\12.jpg";
11.
12. ImvsPlatformSDK_API.IMVS_PF_SetImageData_CS(m_operateHandle, stImageInfo);
13.
14. //System.Threading.Thread.Sleep(200);
15.
16. //自定义执行逻辑
17. //流程1运行一次
18. int nRet = ImvsPlatformSDK_API.IMVS_PF_ExecuteOnce_V30_CS(m_operateHandle, 10002, null);
19. return nRet;
20. }
问题根因
不熟悉全局脚本相关接口。
1.3.8 全局脚本:通过全局脚本获取通讯输入的参数并赋值给全局变量
描述
环境:VM4.0.0及以上
现象:全局脚本根据外部通讯输入的数值赋值给全局变量,实现输入与全局变量之间的数值绑定。(一般应用于定位、标定等需要外界物理值的场景)
解答
第一步,在vm通讯管理中设置好通讯设备,连接。
第二步,根据通讯设备、接收的信息格式设置接收事件
第三步,在全局变量中设置中对应的变量
第四步,在全局脚本中根据输入的字符串进行分割设置对应的全局变量
成果展示:
实现模块直接绑定通讯输入的点位信息。
问题根因
不熟悉模块之间的业务关系。
1.3.9 全局脚本:VM加载方案后自动执行的方法
描述
环境:VM4.0.0
现象:如何让VM在方案加载后自动执行流程?
解答
可以通过全局脚本控制方案加载之后希望执行的操作,将如下代码添加到全局脚本中。
public override int InitAfterLoadSol()
{
//加载方案完成信号,在方案加载回调函数中获取信号
Sleep(500);
//控制流程1执行一次
ImvsPlatformSDK_API.IMVS_PF_ExecuteOnce_V30_CS(m_operateHandle, 10000, null);
return 0;
}
问题根因
不熟悉全局脚本的方案控制。
1.3.10 全局脚本:多流程协作控制的方法
描述
环境:VM4.0及以上
现象:如何实现多流程间的协作控制,如:如何控制实现流程A、B执行完毕执行流程C的逻辑?
解答
1.可以使用全局脚本来实现多流程的协作控制,主要通过在流程运行状态回调中判断流程的执行状态来控制流程的执行,示例代码如下。
C#
using System;
using VM.GlobalScript.Methods;
using System.Linq;
using System.Windows.Forms;
using iMVS_6000PlatformSDKCS;
using System.Runtime.InteropServices;
using System.Threading;
using System.Collections.Generic;
using System.Threading.Tasks;
/*****************************************
* 示例说明:该示例用于检测流程的运行状态来执行剩余的逻辑
* 例如:流程0和流程1执行完之后需要执行流程2
* ***************************************/
public class UserGlobalScript : UserGlobalMethods, IScriptMethods
{
/// <summary>
/// 初始化函数
/// </summary>
/// <returns>成功:返回0</returns>
public int Init()
{
//二次开发SDK初始化
InitSDK();
//需要等待多少个流程就添加多少个
objProcessStatusDict.Add(10000, new ProcessWorkStatus() { });
objProcessStatusDict.Add(10001, new ProcessWorkStatus() { });
return 0;
}
private Dictionary<uint, ProcessWorkStatus> objProcessStatusDict = new Dictionary<uint, ProcessWorkStatus>();
/// <summary>
/// 运行函数
/// 单次执行:该函数执行一次
/// 连续执行:以一定时间间隔重复执行该函数
/// </summary>
/// <returns>成功:返回0</returns>
public int Process()
{
//m_operateHandle 二次开发SDK操作句柄
if (m_operateHandle == IntPtr.Zero)
{ return ImvsSdkPFDefine.IMVS_EC_NULL_PTR; }
//自定义执行逻辑
//默认执行全部流程,如果自定义流程执行逻辑,请移除DefaultExecuteProcess方法
int nRet = DefaultExecuteProcess();
return 0;
}
/// <summary>
///流程运行状态空闲回调
/// </summary>
/// <param name="workStatus"></param>
public void ExecuteProcessWorkStatus(ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS workStatus)
{
try
{
//1为忙碌状态,0位空闲状态,为0时说明流程执行完毕
if (objProcessStatusDict.ContainsKey(workStatus.nProcessID))
{
objProcessStatusDict[workStatus.nProcessID].Status = workStatus.nWorkStatus;
}
//如果都为true 说明已经执行过一次
if (objProcessStatusDict.All(x => x.Value.IsExecute))
{
//全部置位
foreach (var item in objProcessStatusDict)
{
item.Value.IsExecute = false;
}
Task.Run(() =>
{
//执行后续逻辑动作
ImvsPlatformSDK_API.IMVS_PF_ExecuteOnce_V30_CS(m_operateHandle, 10002, null);
});
}
}
catch (Exception ex)
{
//MessageBox.Show(ex.ToString());
}
}
/// <summary>
/// SDK回调函数
/// </summary>
public override void ResultDataCallBack(IntPtr outputPlatformInfo, IntPtr puser)
{
base.ResultDataCallBack(outputPlatformInfo, puser);
ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO struInfo = (ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO)Marshal.PtrToStructure(outputPlatformInfo, typeof(ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO));
switch (struInfo.nInfoType)
{
//获取模块结果数据
case (uint)ImvsSdkPFDefine.IMVS_CTRLC_OUTPUT_PlATFORM_INFO_TYPE.IMVS_ENUM_CTRLC_OUTPUT_PLATFORM_INFO_MODULE_RESULT:
{
ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST_P resultInfo = (ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST_P)Marshal.PtrToStructure(struInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST_P));
break;
}
///获取流程运行状态
case (uint)ImvsSdkPFDefine.IMVS_CTRLC_OUTPUT_PlATFORM_INFO_TYPE.IMVS_ENUM_CTRLC_OUTPUT_PLATFORM_INFO_WORK_STATE:
{
ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS stWorkStatus = (ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS)Marshal.PtrToStructure(struInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS));
//处理流程运行状态
ExecuteProcessWorkStatus(stWorkStatus);
break;
}
default:
break;
}
}
}
public class ProcessWorkStatus
{
public ProcessWorkStatus()
{
IsExecute = false;
}
public bool IsExecute { get; set; }
private uint _status;
public uint Status
{
get { return _status; }
set
{
if (_status != value)
{
IsExecute = (value == 0 && _status == 1);
_status = value;
}
}
}
}
问题根因
不熟悉全局脚本控制多流程的使用。
1.3.11 全局脚本:通过通讯触发快速匹配模块换型的方法
描述
环境:VM4.0及以上
现象:如何实现根据通讯信号切换快速匹配的模型文件并触发流程执行?
解答
1.动态切换模板需在全局脚本中调用相关接口实现,可以在全局脚本的通讯数据接收回调中实现代码逻辑,代码如下。
C#
using System;
using VM.GlobalScript.Methods;
using System.Windows.Forms;
using iMVS_6000PlatformSDKCS;
using System.Runtime.InteropServices;
/******************************
* 示例说明: 接收全局通信模块数据示例
* 前提: 全局通信模块中开启有通信设备
* 控制逻辑: 1.接收来自全局通信模块接收到的数据
* 2.如果接收到数据字符T1/T2,则加载对应模型文件并执行流程1一次
* ***************************************/
public class UserGlobalScript : UserGlobalMethods, IScriptMethods
{
/// <summary>
/// 初始化函数
/// </summary>
/// <returns>成功:返回0</returns>
public int Init()
{
//二次开发SDK初始化
InitSDK();
//设置与全局通信模块的通信端口
StartGlobalCommunicate();
//注册通信数据接收事件
RegesiterReceiveCommunicateDataEvent();
return 0;
}
/// <summary>
/// 运行函数
/// 单次执行:该函数执行一次
/// 连续执行:以一定时间间隔重复执行该函数
/// </summary>
/// <returns>成功:返回0</returns>
public int Process()
{
//m_operateHandle 二次开发SDK操作句柄
if (m_operateHandle == IntPtr.Zero)
{ return ImvsSdkPFDefine.IMVS_EC_NULL_PTR; }
//默认执行全部流程,如果自定义流程执行逻辑,请移除DefaultExecuteProcess方法
int nRet = DefaultExecuteProcess();
return nRet;
}
/// <summary>
/// 通信数据接收函数
/// </summary>
public override void UserGlobalMethods_OnReceiveCommunicateDataEvent(ReceiveDataInfo dataInfo)
{
if (dataInfo == null || dataInfo.DeviceData == null)
{ return; }
//接收到的数据转成字符串
string str = System.Text.Encoding.Default.GetString(dataInfo.DeviceData);
//创建导入模型结构体
ImvsSdkPFDefine.IMVS_PF_IMPORT_MODULE_DATA_INPUT stImportData = new ImvsSdkPFDefine.IMVS_PF_IMPORT_MODULE_DATA_INPUT();
stImportData.stImportModuData = new ImvsSdkPFDefine.IMVS_PF_IMPORT_MODULE_DATA[ImvsSdkPFDefine.IMVS_PF_MAX_IMPORT_NUM];
//这里的deviceIndex和全局通信模块中的一致
if (dataInfo.DeviceID == 1)
{
//解析收到的数据
if (str == "T1")
{
//导入一个模板
string strImportFilePath = "E:\\Project\\VMProject\\模板切换\\3.fmxml";
stImportData.stImportModuData = new ImvsSdkPFDefine.IMVS_PF_IMPORT_MODULE_DATA[ImvsSdkPFDefine.IMVS_PF_MAX_IMPORT_NUM];
stImportData.nDataNum = 1;
stImportData.nDataType = 1;
//操作模块ID
stImportData.nModuleID = 1;
stImportData.stImportModuData[0].pData = Marshal.StringToHGlobalAnsi(strImportFilePath);
int iDataLen = System.Text.Encoding.Default.GetBytes(strImportFilePath).Length;
stImportData.stImportModuData[0].nDataLen = (uint)iDataLen;
}
if (str == "T2")
{
//创建模型文件字符串数组,同时导入两个模板
string[] strImportFilePath = new System.String[] { "E:\\Project\\VMProject\\模板切换\\1.fmxml", "E:\\Project\\VMProject\\模板切换\\2.fmxml" };
stImportData.nDataNum = 2;
stImportData.nDataType = 1;
stImportData.nModuleID = 1;
int count = 0;
foreach (var iter in strImportFilePath)
{
stImportData.stImportModuData[count].pData = Marshal.StringToHGlobalAnsi(iter);
int iDataLen = System.Text.Encoding.Default.GetBytes(iter).Length;
stImportData.stImportModuData[count].nDataLen = (uint)iDataLen;
count++;
}
}
//导入模型
ImvsPlatformSDK_API.IMVS_PF_ImportModuleData_CS(m_operateHandle, stImportData);
//执行流程1
ImvsPlatformSDK_API.IMVS_PF_ExecuteOnce_V30_CS(m_operateHandle, 10000, null);
}
}
/// <summary>
/// SDK回调函数
/// </summary>
public override void ResultDataCallBack(IntPtr outputPlatformInfo, IntPtr puser)
{
base.ResultDataCallBack(outputPlatformInfo, puser);
ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO struInfo = (ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO)Marshal.PtrToStructure(outputPlatformInfo, typeof(ImvsSdkPFDefine.IMVS_PF_OUTPUT_PLATFORM_INFO));
switch (struInfo.nInfoType)
{
//获取模块结果数据
case (uint)ImvsSdkPFDefine.IMVS_CTRLC_OUTPUT_PlATFORM_INFO_TYPE.IMVS_ENUM_CTRLC_OUTPUT_PLATFORM_INFO_MODULE_RESULT:
{
ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST_P resultInfo = (ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST_P)Marshal.PtrToStructure(struInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_MODULE_RESULT_INFO_LIST_P));
break;
}
///获取流程运行状态
case (uint)ImvsSdkPFDefine.IMVS_CTRLC_OUTPUT_PlATFORM_INFO_TYPE.IMVS_ENUM_CTRLC_OUTPUT_PLATFORM_INFO_WORK_STATE:
{
ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS stWorkStatus = (ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS)Marshal.PtrToStructure(struInfo.pData, typeof(ImvsSdkPFDefine.IMVS_PF_MODULE_WORK_STAUS));
break;
}
default:
break;
}
}
}
问题根因
不熟悉全局脚本通讯回调及模板导入相关接口的使用。