
CVX通信控制器的代码架构和功能
代码结构总结 (Code Structure Summary)
核心类 CVX 负责与视觉控制器的TCP通信,包含:
1. 枚举定义 (Enumeration)
-
CVXResponseCode
: 定义通信返回码
-
-
OK = 0
: 成功
-
CommandError = 2
: 命令错误
-
ParameterError = 22
: 参数错误
-
Timeout = 99
: 超时
-
2. 私有成员 (Private Members)
-
Socket client
: TCP套接字连接
-
byte[] bytes
: 数据缓冲区(1024字节)
-
char[] separator
: 分隔符
{',', '\r'}
3. 通信协议 (Communication Protocol)
-
编码
: UTF-8发送请求
-
解码
: ASCII接收响应
-
格式
:
"命令\r"
或"命令,参数1,参数2\r"
-
响应
: 成功
"CMD,data\r"
或错误"ER,CMD,nn\r"
4. 功能模块 (Function Modules)
连接管理:
-
Connect(ip, port, timeout)
- 建立TCP连接
-
Dispose()
- 释放资源
模式控制:
-
ReadRunSetupMode()
- 读取运行/设置模式
-
SetRunMode()
- 设置为运行模式
程序管理:
-
ReadProgram()
- 读取当前程序信息
-
ChangeProgram()
- 切换程序
-
Reset()
- 重置程序
执行控制:
-
ReadExecNo()
/
WriteExecNo()
- 执行条件编号管理
视觉处理:
-
Trigger()
- 触发相机获取结果数据
-
ImageRegistration()
- 保存参考图像
cs
using System; // 导入 System 命名空间,它包含了基本的数据类型、事件、异常处理等核心功能。using System.Collections.Generic; // 导入 System.Collections.Generic 命名空间,它提供了泛型集合的支持,如 List<T> 和 Dictionary<T,K>。using System.Globalization; // 导入 System.Globalization 命名空间,用于处理与区域性相关的信息,如此处的数字格式转换。using System.Linq; // 导入 System.Linq 命名空间,它提供了 LINQ (Language-Integrated Query) 功能,可以对数据进行查询。using System.Net; // 导入 System.Net 命名空间,它为网络协议提供了简单的编程接口,如此处的 IPAddress 和 IPEndPoint。using System.Net.Sockets; // 导入 System.Net.Sockets 命名空间,它提供了用于网络通信的套接字(Socket)的实现。using System.Text; // 导入 System.Text 命名空间,它包含了字符编码和解码的功能,如 ASCII 和 UTF-8。using System.Threading.Tasks; // 导入 System.Threading.Tasks 命名空间,用于支持异步编程。using System.Timers; // 导入 System.Timers 命名空间,提供基于服务器的定时器功能(在此文件中未使用)。namespace CVXCommunication // 定义一个名为 CVXCommunication 的命名空间,用于组织与 CVX 控制器通信相关的类。{ /// <summary> /// Defines the communication return codes from CVX. /// 定义了从 CVX 控制器返回的通信代码。 /// </summary> public enum CVXResponseCode // 定义一个公共枚举类型 CVXResponseCode,用于表示 CVX 的响应状态。 { OK = 0, // 0: 表示命令成功执行。 CommandError = 2, // 2: 表示命令错误。 CommandDisabled = 3, // 3: 表示命令当前被禁用。 ParameterError = 22, // 22: 表示参数错误。 Timeout = 99 // 99: 表示通信超时。 } /// <summary> /// This class is responsible for controlling the CVX /// 这个类负责控制 CVX 控制器。 /// </summary> public class CVX: IDisposable // 定义一个名为 CVX 的公共类,它实现了 IDisposable 接口,以便正确释放资源。 { /// <summary> /// Socket that handles the TCP communication. /// 用于处理 TCP 通信的套接字。 /// </summary> private Socket client; // 声明一个私有的 Socket 对象,用于客户端网络通信。 /// <summary> /// Data buffer for incoming data. /// 用于接收传入数据的数据缓冲区。 /// </summary> byte[] bytes = new byte[1024]; // 声明并初始化一个1024字节的数组,用作接收网络数据的缓冲区。 /// <summary> /// Separator characters for the incoming messages. /// Configured in the CVX controller (Network Settings >> Non-Procedural). /// 用于传入消息的分隔符。 /// 在 CVX 控制器中配置 (网络设置 >> 无协议)。 /// </summary> char[] separator = { ',', '\r' }; // 声明并初始化一个字符数组,包含逗号和回车符,用于解析从控制器返回的响应字符串。 /// <summary> /// Encodes the messages and decodes the responses. /// 编码消息并解码响应。 /// </summary> /// <param name="req">The sending message</param> /// <param name="req">要发送的消息</param> /// <returns>The incoming message</returns> /// <returns>接收到的消息</returns> private string sendMessage(string req) // 定义一个私有方法 sendMessage,用于向控制器发送请求并接收响应。 { byte[] byteData = Encoding.UTF8.GetBytes(req); // 将输入的字符串请求 `req` 编码为 UTF-8 格式的字节数组。 int bytesRead = client.Send(byteData); // 通过客户端套接字发送编码后的字节数据。 int bytesRec = client.Receive(bytes); // 从套接字接收响应数据,并存入 `bytes` 缓冲区,返回接收到的字节数。 return Encoding.ASCII.GetString(bytes, 0, bytesRec); // 将接收到的字节数据(从0到bytesRec)解码为 ASCII 字符串并返回。 } #region Interface // 开始一个名为 "Interface" 的代码区域,方便在编辑器中折叠。 #region Connection // 开始一个名为 "Connection" 的子代码区域。 /// <summary> /// Starts the connection with the CVX. /// The controller IP and Port are configured in Network Settings (Non-Procedural). /// 开始与 CVX 的连接。 /// 控制器的 IP 和端口在网络设置(无协议)中配置。 /// </summary> /// <param name="ip">Controller IP address</param> /// <param name="ip">控制器 IP 地址</param> /// <param name="port">Controller port</param> /// <param name="port">控制器端口</param> /// /// <param name="timeout">Communication timeout in milliseconds</param> /// /// <param name="timeout">通信超时时间(毫秒)</param> /// <returns></returns> /// <returns>连接成功返回 true,否则返回 false</returns> public bool Connect(string ip, int port, int timeout) // 定义一个公共方法 Connect,用于建立与 CVX 控制器的 TCP 连接。 { try // 开始一个 try-catch 块,用于捕获连接过程中可能发生的异常。 { IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ip), port); // 根据传入的 IP 地址字符串和端口号,创建一个 IPEndPoint 对象,表示远程服务器的终结点。 client = new Socket(SocketType.Stream, ProtocolType.Tcp); // 创建一个新的 Socket 实例,指定套接字类型为流式(Stream),协议为 TCP。 client.ReceiveTimeout = timeout; // 设置接收数据的超时时间,单位为毫秒。 client.Connect(remoteEP); // 尝试连接到指定的远程终结点。 return true; // 如果连接成功,返回 true。 } catch // 如果在 try 块中发生任何异常。 { return false; // 连接失败,返回 false。 } } /// <summary> /// Release the socket when the object is destroyed. /// 当对象被销毁时,释放套接字。 /// </summary> public void Dispose() // 实现 IDisposable 接口的 Dispose 方法,用于释放托管和非托管资源。 { client?.Shutdown(SocketShutdown.Both); // 如果 client 不为 null,则关闭套接字的发送和接收功能。 client?.Close(); // 如果 client 不为 null,则关闭套接字连接并释放所有相关资源。 } #endregion // 结束 "Connection" 代码区域。 /// <summary> /// Checks if the controller is in the setup or run mode. /// Request message = "RM\r" /// Response message = "RM,n\r" [0 = setup; 1 = run] when message OK /// Response message = "ER,RM,nn\r" [nn = error code] when message error /// This method works both in Setup or Run Mode /// 检查控制器是处于设置模式还是运行模式。 /// 请求消息 = "RM\r" /// 响应消息(成功时)= "RM,n\r" [0 = 设置模式; 1 = 运行模式] /// 响应消息(错误时)= "ER,RM,nn\r" [nn = 错误码] /// 此方法在设置模式和运行模式下均可工作。 /// </summary> /// <param name="isRunMode">Output response</param> /// <param name="isRunMode">输出响应结果,true 表示运行模式</param> /// <returns>Error code</returns> /// <returns>错误码</returns> public CVXResponseCode ReadRunSetupMode(out bool isRunMode) // 定义公共方法 ReadRunSetupMode,用于读取控制器的运行模式。 { isRunMode = false; // 初始化输出参数 isRunMode 为 false。 string res = sendMessage("RM\r"); // 发送 "RM\r" 命令并获取响应字符串。 string[] resSplit = res.Split(separator); // 使用预定义的分隔符(逗号和回车)分割响应字符串。 if (String.Compare(resSplit[0], "RM") == 0) // 比较响应的第一个部分是否为 "RM",判断是否为成功响应。 { isRunMode = ( String.Compare(resSplit[1], "1") == 0 ? true : false); // 如果第二个部分是 "1",则设置 isRunMode 为 true,否则为 false。 return CVXResponseCode.OK; // 返回 OK 状态码,表示命令成功。 }
return (CVXResponseCode)Convert.ToInt32(resSplit[2]); // 如果是错误响应,则将第三个部分(错误码)转换为整数,并强制转换为 CVXResponseCode 枚举类型后返回。 } /// <summary> /// Set the controller in run mode. /// Request message = "R0\r" /// Response message = "R0\r" when message ok /// Response message = "ER,R0,nn\r" [nn = error code] when message error /// This method works both in Setup or Run Mode /// 将控制器设置为运行模式。 /// 请求消息 = "R0\r" /// 响应消息(成功时) = "R0\r" /// 响应消息(错误时) = "ER,R0,nn\r" [nn = 错误码] /// 此方法在设置模式和运行模式下均可工作。 /// </summary> /// <returns>Error code</returns> /// <returns>错误码</returns> public CVXResponseCode SetRunMode() // 定义公共方法 SetRunMode,用于将控制器设置为运行模式。 { string res = sendMessage("R0\r"); // 发送 "R0\r" 命令并获取响应字符串。 string[] resSplit = res.Split(separator); // 使用分隔符分割响应字符串。 if (String.Compare(resSplit[0], "R0") == 0) // 检查响应的第一个部分是否为 "R0"。 return CVXResponseCode.OK; // 如果是,则表示命令成功,返回 OK 状态码。 return (CVXResponseCode)Convert.ToInt32(resSplit[2]); // 如果是错误响应,则转换并返回错误码。 } /// <summary> /// Read the current program. /// Request message = "PR\r" /// Response message = "PR,d,nnn\r" [d = sd card number (1 or 2); nnn = program number (0 to 999)] when message ok /// Response message = "ER,PR,nn\r" [nn = error code] when message error /// This method only works in Run Mode /// 读取当前程序。 /// 请求消息 = "PR\r" /// 响应消息(成功时) = "PR,d,nnn\r" [d = SD卡号 (1 或 2); nnn = 程序号 (0 到 999)] /// 响应消息(错误时) = "ER,PR,nn\r" [nn = 错误码] /// 此方法仅在运行模式下工作。 /// </summary> /// <param name="sdcardNumber">output current sdcard</param> /// <param name="sdcardNumber">输出当前的 SD 卡号</param> /// <param name="programNumber">output current program</param> /// <param name="programNumber">输出当前的程序号</param> /// <returns>Error code</returns> /// <returns>错误码</returns> public CVXResponseCode ReadProgram(out int sdcardNumber, out int programNumber) // 定义公共方法 ReadProgram,用于读取当前加载的程序信息。 { sdcardNumber = -1; // 初始化输出参数 sdcardNumber 为 -1。 programNumber = -1; // 初始化输出参数 programNumber 为 -1。 string res = sendMessage("PR\r"); // 发送 "PR\r" 命令并获取响应。 string[] resSplit = res.Split(separator); // 分割响应字符串。 if (String.Compare(resSplit[0], "PR") == 0) // 检查响应的第一个部分是否为 "PR"。 { sdcardNumber = Convert.ToInt32(resSplit[1]); // 如果成功,将第二个部分转换为整数,并赋值给 sdcardNumber。 programNumber = Convert.ToInt32(resSplit[2]); // 将第三个部分转换为整数,并赋值给 programNumber。 return CVXResponseCode.OK; // 返回 OK 状态码。 } return (CVXResponseCode)Convert.ToInt32(resSplit[2]); // 如果是错误响应,则转换并返回错误码。 } /// <summary> /// Sets the program in the controller /// Request message = "PW,d,nnn\r" [d = sd card number (1 or 2); nnn = program number (0 to 999)] /// Response message = "PW\r" when message ok /// Response message = "ER,PW,nn\r" [nn = error code] when message error /// This method only works in Run Mode /// 在控制器中设置程序。 /// 请求消息 = "PW,d,nnn\r" [d = SD卡号 (1 或 2); nnn = 程序号 (0 到 999)] /// 响应消息(成功时) = "PW\r" /// 响应消息(错误时) = "ER,PW,nn\r" [nn = 错误码] /// 此方法仅在运行模式下工作。 /// </summary> /// <param name="sdcardNumber"></param> /// <param name="sdcardNumber">SD 卡号</param> /// <param name="programNumber"></param> /// <param name="programNumber">程序号</param> /// <returns>Error code</returns> /// <returns>错误码</returns> public CVXResponseCode ChangeProgram(int sdcardNumber, int programNumber) // 定义公共方法 ChangeProgram,用于切换控制器中的程序。 {
string msg = "PW," + sdcardNumber + "," + programNumber.ToString("000") + "\r"; // 构建请求消息字符串,程序号格式化为三位数字。 string res = sendMessage(msg); // 发送构建好的消息并获取响应。 string[] resSplit = res.Split(separator); // 分割响应字符串。 if (String.Compare(resSplit[0], "PW") == 0) // 检查响应的第一个部分是否为 "PW"。 return CVXResponseCode.OK; // 如果是,则返回 OK 状态码。 return (CVXResponseCode)Convert.ToInt32(resSplit[2]); // 如果是错误响应,则转换并返回错误码。 } /// <summary> /// Reads the current condition execution number. /// Request message = "EXR\r" /// Response message = "EXR,nn\r" [nn = execute condition number (0 to 99)] when message ok /// Response message = "ER,EXR,nn\r" [nn = error code] when message error /// This method only works in Run Mode /// 读取当前执行的条件编号。 /// 请求消息 = "EXR\r" /// 响应消息(成功时) = "EXR,nn\r" [nn = 执行条件编号 (0 到 99)] /// 响应消息(错误时) = "ER,EXR,nn\r" [nn = 错误码] /// 此方法仅在运行模式下工作。 /// </summary> /// <param name="execNo">output the current execution number</param> /// <param name="execNo">输出当前执行的编号</param> /// <returns>Error code</returns> /// <returns>错误码</returns> public CVXResponseCode ReadExecNo(out int execNo) // 定义公共方法 ReadExecNo,用于读取当前的执行条件编号。 {
execNo = -1; // 初始化输出参数 execNo 为 -1。 string res = sendMessage("EXR\r"); // 发送 "EXR\r" 命令并获取响应。 string[] resSplit = res.Split(separator); // 分割响应字符串。 if (String.Compare(resSplit[0], "EXR") == 0) // 检查响应的第一个部分是否为 "EXR"。 { execNo = Convert.ToInt32(resSplit[1]); // 如果成功,将第二个部分转换为整数,并赋值给 execNo。 return CVXResponseCode.OK; // 返回 OK 状态码。 } return (CVXResponseCode)Convert.ToInt32(resSplit[2]); // 如果是错误响应,则转换并返回错误码。 } /// <summary> /// Sets the condition execution number. /// Request message = "EXW,n\r" [n = execute condition number (0 to 99)] /// Response message = "EXW\r" when message ok /// Response message = "ER,EXW,nn\r" [nn = error code] when message error /// This method only works in Run Mode /// 设置执行条件编号。 /// 请求消息 = "EXW,n\r" [n = 执行条件编号 (0 到 99)] /// 响应消息(成功时) = "EXW\r" /// 响应消息(错误时) = "ER,EXW,nn\r" [nn = 错误码] /// 此方法仅在运行模式下工作。 /// </summary> /// <param name="execNo"></param> /// <param name="execNo">要设置的执行编号</param> /// <returns>Error code</returns> /// <returns>错误码</returns> public CVXResponseCode WriteExecNo(int execNo) // 定义公共方法 WriteExecNo,用于设置执行条件编号。 { string res = sendMessage("EXW," + execNo + "\r"); // 构建并发送 "EXW,n\r" 命令。 string[] resSplit = res.Split(separator); // 分割响应字符串。 if (String.Compare(resSplit[0], "EXW") == 0) // 检查响应的第一个部分是否为 "EXW"。 return CVXResponseCode.OK; // 如果是,则返回 OK 状态码。 return (CVXResponseCode)Convert.ToInt32(resSplit[2]); // 如果是错误响应,则转换并返回错误码。 } /// <summary> /// Reset the current program. /// Request message = "RS\r" /// Response message = "RS\r" when message ok /// Response message = "ER,RS,nn\r" [nn = error code] when message error /// This method only works in Run Mode /// 复位当前程序。 /// 请求消息 = "RS\r" /// 响应消息(成功时) = "RS\r" /// 响应消息(错误时) = "ER,RS,nn\r" [nn = 错误码] /// 此方法仅在运行模式下工作。 /// </summary> /// <returns>Error code</returns> /// <returns>错误码</returns> public CVXResponseCode Reset() // 定义公共方法 Reset,用于复位控制器程序。 {
string res = sendMessage("RS\r"); // 发送 "RS\r" 命令并获取响应。 string[] resSplit = res.Split(separator); // 分割响应字符串。 if (String.Compare(resSplit[0], "RS") == 0) // 检查响应的第一个部分是否为 "RS"。 return CVXResponseCode.OK; // 如果是,则返回 OK 状态码。 else // 否则,说明是错误响应。 return (CVXResponseCode)Convert.ToInt32(resSplit[2]); // 转换并返回错误码。 } /// <summary> /// Triggers the cameras and get the result data from the controller. /// The data must be configured in the controller (Output >> Ethernet (Non-procedural)) /// Request message = "TA\r" /// Response message = "TA\r" when message ok /// Response message = "ER,TA,nn\r" [nn = error code] when message error /// This method only works in Run Mode /// 触发相机并从控制器获取结果数据。 /// 数据必须在控制器中配置 (输出 >> 以太网 (无协议))。 /// 请求消息 = "TA\r" /// 响应消息(成功时) = "TA\r" /// 响应消息(错误时) = "ER,TA,nn\r" [nn = 错误码] /// 此方法仅在运行模式下工作。 /// </summary> /// <param name="resultData">output the data received from the controller</param> /// <param name="resultData">输出从控制器接收到的数据</param> /// <returns>Error code</returns> /// <returns>错误码</returns> public CVXResponseCode Trigger(out double[] resultData) // 定义公共方法 Trigger,用于触发相机并获取测量数据。 {
string res = sendMessage("TA\r"); // 发送 "TA\r" 触发命令并获取响应。 string[] resSplit = res.Split(separator); // 分割响应字符串。 if (String.Compare(resSplit[0], "TA") == 0) // 检查响应的第一个部分是否为 "TA",确认触发命令被接受。 { try // 开始一个新的 try-catch 块,用于捕获接收测量数据时可能发生的异常。 { int bytesRec = client.Receive(bytes); // 等待并接收第二条消息,即测量结果数据。 string result = Encoding.ASCII.GetString(bytes, 0, bytesRec); // 将接收到的字节解码为 ASCII 字符串。 string[] resultSplit = result.Split(separator); // 使用分隔符分割结果数据字符串。 resultData = new double[resultSplit.Length - 1]; // 初始化一个 double 数组来存储结果数据,长度-1 是因为分割后通常会有一个空字符串。 for (int i = 0; i < resultData.Length; i++) // 遍历分割后的字符串数组。 resultData[i] = Convert.ToDouble(resultSplit[i], CultureInfo.InvariantCulture); // 将每个字符串转换为 double 类型,并存入 resultData 数组。使用 InvariantCulture 确保小数点'.'被正确解析。 return CVXResponseCode.OK; // 数据接收和解析成功,返回 OK 状态码。 } catch(SocketException scktEx) // 捕获套接字相关的异常。 { if(scktEx.SocketErrorCode == SocketError.TimedOut) // 检查异常是否是由于超时引起的。 { resultData = null; // 将输出参数 resultData 设置为 null。 return CVXResponseCode.Timeout; // 返回 Timeout 状态码。 } } } resultData = null; // 如果触发命令失败或发生其他异常,将输出参数设置为 null。 return (CVXResponseCode)Convert.ToInt32(resSplit[2]); // 返回从错误响应中解析出的错误码。 } /// <summary> /// Saves the current image as a reference image. /// Request message = "BS,c,nnn\r" [c = camera number (1 to 4), nnn = reference image number (0 to 999)] /// Response message = "BS\r" when message ok /// Response message = "ER,BS,nn\r" [nn = error code] when message error /// This method only works in Run Mode /// 将当前图像保存为参考图像。 /// 请求消息 = "BS,c,nnn\r" [c = 相机号 (1 到 4), nnn = 参考图像号 (0 到 999)] /// 响应消息(成功时) = "BS\r" /// 响应消息(错误时) = "ER,BS,nn\r" [nn = 错误码] /// 此方法仅在运行模式下工作。 /// </summary> /// <param name="cameraNo">The camera number (1 to 4)</param> /// <param name="cameraNo">相机号 (1 到 4)</param> /// <param name="referenceNo">The image reference number (0 to 999)</param> /// <param name="referenceNo">参考图像号 (0 到 999)</param> /// <returns>Error code</returns> /// <returns>错误码</returns> public CVXResponseCode ImageRegistration(int cameraNo, int referenceNo) // 定义公共方法 ImageRegistration,用于图像注册。 { string res = sendMessage("BS," + cameraNo + "," + referenceNo + "\r"); // 构建并发送图像注册命令。 string[] resSplit = res.Split(separator); // 分割响应字符串。 if (String.Compare(resSplit[0], "BS") == 0) // 检查响应的第一个部分是否为 "BS"。 return CVXResponseCode.OK; // 如果是,则返回 OK 状态码。 else // 否则,说明是错误响应。 return (CVXResponseCode)Convert.ToInt32(resSplit[2]); // 转换并返回错误码。 } #endregion // 结束 "Interface" 代码区域。 }}
这段 C# 代码定义了一个名为 CVX
的类,封装了通过 TCP/IP 网络与基恩士(Keyence)CV-X 系列视觉控制器进行通信的逻辑。该类遵循无协议(Non-Procedural)通信方式,即通过发送特定的命令字符串并解析返回的响应字符串来与控制器交互。
主要功能和特点:
- 连接管理:
-
Connect(ip, port, timeout)
方法用于建立与指定 IP 地址和端口的 CVX 控制器的 TCP 连接,并可设置通信超时。
-
Dispose()
方法实现了
IDisposable
接口,用于在对象销毁时安全地关闭和释放网络套接字资源。
-
命令封装:将 CVX 控制器的各种文本命令封装成了易于调用的 C# 方法。例如:
-
-
模式控制
:
ReadRunSetupMode()
读取运行/设置模式,SetRunMode()
切换到运行模式。 -
程序管理
:
ReadProgram()
读取当前程序号,ChangeProgram()
切换程序。 -
执行条件
:
ReadExecNo()
和WriteExecNo()
用于读写执行条件编号。 -
基本操作
:
Reset()
复位程序,Trigger()
触发相机拍照并获取测量数据。 -
图像注册
:
ImageRegistration()
将当前图像保存为参考图像。
-
-
通信协议处理:
-
-
内部私有方法
sendMessage(string req)
负责处理底层的发送和接收逻辑,将字符串命令编码为字节流发送,并将接收到的字节流解码为字符串。 -
所有公共方法都遵循"发送命令 -> 接收响应 -> 解析响应"的模式。
-
响应字符串通过逗号
,
和回车符\r
分割,并根据协议规范进行解析。
-
-
错误处理:
-
-
定义了
CVXResponseCode
枚举,包含了控制器可能返回的各种状态码(如OK
,CommandError
,Timeout
等)。 -
每个方法都会解析控制器的响应,如果成功则返回
CVXResponseCode.OK
,如果控制器返回错误信息(通常以 "ER" 开头),则解析出错误码并返回对应的枚举值。 -
Trigger
方法特别处理了接收测量数据时的网络超时异常。
总之,
CVX
类是一个功能完备的客户端库,为.NET 应用程序提供了一个高级、面向对象的接口,使其能够方便地控制 CVX 视觉系统并与之交换数据,大大简化了与该设备集成的开发工作。主程序
这张 PlantUML 序列图详细描绘了
Program.cs
中Main
方法的执行逻辑:- 初始化与连接:
-
Program
首先向
Console
输出开始信息。 -
接着,它创建
CVX
类的一个实例。 -
然后调用
Connect
方法尝试与CVX 控制器
建立 TCP 连接。 -
这里使用
alt
/else
块表示两种可能:连接成功
:流程继续。
连接失败:向控制台输出错误信息,并终止程序。
-
-
控制器状态配置 (group):
-
-
这是一个连续的检查和设置过程,以确保控制器处于预期的工作状态。
-
模式检查
:
Program
调用ReadRunSetupMode
获取当前模式。如果不是运行模式(opt
块),则调用SetRunMode
进行设置。 -
程序检查
:
Program
调用ReadProgram
获取当前程序。如果与目标不符(opt
块),则调用ChangeProgram
切换程序。 -
执行编号检查
:
Program
调用ReadExecNo
获取执行编号。如果与目标不符(opt
块),则调用WriteExecNo
进行设置。
-
-
执行与数据获取 (group):
-
-
复位
:在所有配置完成后,
Program
调用Reset
方法复位控制器。 -
触发
:
Program
调用Trigger
方法。这是一个两步通信:CVX
先向Controller
发送触发命令TA\r
,Controller
先返回一个确认,然后再发送实际的测量数据。
-
-
显示结果 (group):
-
-
Program
在控制台打印提示信息。
-
使用
alt
/else
块处理Trigger
的返回结果:如果成功接收到数据,则使用
loop
循环遍历数组,将每个数据点打印到控制台。如果数据为
null
或返回码为超时,则打印"未收到数据"。
-
-
结束:
-
- 程序向控制台输出测试结束信息,并调用
ReadKey()
等待用户交互,防止窗口立即关闭。
该图清晰地展示了程序、通信库、硬件控制器和用户界面之间的交互顺序、条件分支和循环,完整地概括了主程序的业务逻辑。
这段代码是一个控制台应用程序,它作为
CVX
通信类的客户端示例和测试程序。其主要目的是演示如何使用CVX
类来与基恩士(Keyence)CV-X 视觉控制器进行一系列的自动化交互。程序执行的流程如下:
-
初始化与连接
:程序首先创建一个
CVX
类的实例,并尝试连接到硬编码的 IP 地址(192.168.0.10
)和端口(8500
)。如果连接失败,程序将显示错误信息并退出。 -
状态配置
:连接成功后,程序会执行一系列的检查和设置操作,以确保控制器处于预期的状态:
-
检查控制器是否在"运行模式",如果不在,则将其设置为运行模式。
-
检查当前加载的程序是否为目标程序(SD 卡 1 上的程序 0),如果不是,则切换到该程序。
-
检查当前的执行条件编号是否为目标编号(0),如果不是,则设置为该编号。
- 程序向控制台输出测试结束信息,并调用
-
执行与数据采集
:在控制器状态配置完成后,程序会复位当前程序,然后发送触发命令来让相机进行拍照和测量。
-
结果显示
:程序会接收触发后返回的测量数据。如果成功接收到数据,它会将每个数据点逐行打印到控制台;如果发生超时或未收到数据,则会显示相应的提示信息。
-
结束
:最后,程序会提示测试结束,并等待用户按键后才关闭窗口。
-
总而言之,该程序完整地展示了一个典型的工作流:连接设备 -> 配置运行环境 -> 执行任务 -> 获取并处理结果,为开发者提供了使用
CVX
类的清晰范例。csusing System; // 导入 System 命名空间,它提供了基本的功能,如此处用到的 Console 类用于控制台输入输出。namespace CVXCommunication // 定义一个名为 CVXCommunication 的命名空间,与 CVX 类所在的命名空间保持一致。{ public class Program // 定义一个名为 Program 的公共类。 { /// <summary> /// Example program to test the CVX communication. /// 用于测试 CVX 通信的示例程序。 /// </summary> /// <param name="args"></param> /// <param name="args">命令行参数</param> static void Main(string[] args) // 程序的入口点 Main 方法。 { CVX cvx; // 声明一个 CVX 类的实例变量,用于后续与控制器进行通信。 CVXResponseCode res; // 声明一个 CVXResponseCode 枚举变量,用于存储每个通信命令的返回结果。 bool isRunmode; // 声明一个布尔型变量,用于存储控制器是否处于运行模式的状态。 int readSdcard; // 声明一个整型变量,用于存储从控制器读取到的 SD 卡号。 int readProgram; // 声明一个整型变量,用于存储从控制器读取到的程序号。 int readExecNo; // 声明一个整型变量,用于存储从控制器读取到的执行条件编号。 double[] resultData; // 声明一个 double 数组,用于存储从控制器触发后返回的测量数据。 int targetSdcard = 1; // 定义一个整型变量,表示目标 SD 卡号为 1。 int targetProgram = 0; // 定义一个整型变量,表示目标程序号为 0。 int targetExecNo = 0; // 定义一个整型变量,表示目标执行条件编号为 0。 Console.WriteLine("Starting CVX Ethernet communication test..."); // 在控制台输出一行文字,提示测试开始。 cvx = new CVX(); // 创建 CVX 类的一个新实例,并将其赋值给 cvx 变量。 if(!cvx.Connect("192.168.0.10", 8500, 2000)) // 调用 Connect 方法尝试连接到指定的 IP 地址和端口,超时时间为2000毫秒。如果连接失败(! 表示取反)。 { Console.WriteLine("Error: Couldn't connect to CVX!"); // 在控制台输出错误信息,提示连接失败。 Console.ReadKey(); // 等待用户按下一个键,防止程序立即退出。 return; // 结束 Main 方法的执行,从而退出程序。 } Console.WriteLine("Connected to CVX!"); // 如果连接成功,在控制台输出成功连接的提示信息。 // Check if the controller mode and set the run mode if it's not in it. // 检查控制器模式,如果不是运行模式,则将其设置为运行模式。 res = cvx.ReadRunSetupMode(out isRunmode); // 调用 ReadRunSetupMode 方法,获取当前模式,并将结果存入 isRunmode 变量。 if (!isRunmode) // 判断当前是否 *不是* 运行模式。 res = cvx.SetRunMode(); // 如果不是运行模式,则调用 SetRunMode 方法将其设置为运行模式。 // Check the current program and changed it if needed // 检查当前程序,如果需要则进行更改。 res = cvx.ReadProgram(out readSdcard, out readProgram); // 调用 ReadProgram 方法,获取当前的 SD 卡号和程序号。 if (readSdcard != targetSdcard || readProgram != targetProgram) // 判断读取到的 SD 卡号或程序号是否与目标值不符。 res = cvx.ChangeProgram(targetSdcard, targetProgram); // 如果不符,则调用 ChangeProgram 方法切换到目标程序。 // Check the current Execution Number and change it if needed // 检查当前的执行编号,如果需要则进行更改。 res = cvx.ReadExecNo(out readExecNo); // 调用 ReadExecNo 方法,获取当前的执行条件编号。 if (readExecNo != targetExecNo) // 判断读取到的执行编号是否与目标值不符。 res = cvx.WriteExecNo(targetExecNo); // 如果不符,则调用 WriteExecNo 方法写入目标执行编号。 // Reset the program // 复位程序。 res = cvx.Reset(); // 调用 Reset 方法,复位控制器中的当前程序。 // Trigger the cameras and get the result // 触发相机并获取结果。 res = cvx.Trigger(out resultData); // 调用 Trigger 方法,触发相机拍照并获取测量数据。 Console.WriteLine("Cameras have been triggered. Results:"); // 在控制台输出提示信息,表示相机已触发,即将显示结果。 if (res == CVXResponseCode.Timeout || resultData == null) // 判断返回结果是否为超时,或者结果数据是否为 null。 Console.WriteLine("No data received"); // 如果是,则输出 "未收到数据"。 else // 否则,表示成功收到了数据。 foreach (double data in resultData) // 遍历 resultData 数组中的每一个 double 类型的元素。 Console.WriteLine(data); // 将每一个数据元素输出到控制台的新一行。 Console.WriteLine("CVX communication test ended."); // 在控制台输出测试结束的提示信息。 Console.ReadKey(); // 等待用户按下一个键,然后程序才会关闭。 } }}