电脑要安装Kepware软件,此实验用的版本为KEPServerEX 6.3(安装后需要购买授权,不过有一段时间的试用期,不影响实验)
Kepsever作为OPC UA服务器与PLC建立通讯,在VS2015中编写OPC UA客户端与Kepsever服务器进行通讯,从而读写PLC的tag值。
使用open62541需要首先获得相关的源文件和头文件,获取过程比较复杂,这里参考了网上别人发的教程。
参考文章链接:
按照以上文章介绍,将生成的open62541.h、open62541.c 拷贝到项目文件夹内
此外还需要所需lib包:WS2_32.Lib(opcua通讯用到的库,opcua使用socket通讯,需使用此库),添加#pragma comment(lib,"ws2_32.lib") 语句,有的文章说需要添加ws2_32.lib文件或ws2_32.dll到项目资源中,貌似影响不大
代码衔接上一篇,多了很多注释段,别介意)
// test01.cpp : 定义控制台应用程序的入口点。
#include "open62541.h" //open62541头文件,opcua开源库文件
#pragma comment(lib,"ws2_32.lib") //opcua通讯用到的库,opcua使用socket通讯,需使用此库
#include "stdafx.h"
#include <iostream>
#include<windows.h> //使用Sleep(1000)延时函数头文件
#include <stdio.h>
#include <process.h>
#include <conio.h>
#include "string.h"
//#include <opencv2/opencv.hpp> //opencv头文件
//#include<opencv2/core.hpp>
//#include<opencv2/imgproc.hpp>
//#include<opencv2/highgui.hpp>
//#include<opencv2/videoio.hpp>
using namespace std; //使用命名空间
//using namespace cv;
/*声明全局变量*/
//VideoCapture capture;
UA_Client *client = UA_Client_new(); //opcua客户端结构体,用于与PLC通讯
UA_StatusCode status; //用于存放opcua客户端执行操作后的状态反馈
/*主函数*/
int main()
{
/*Mat img;
Mat hsv;
Mat hsvsplit[3];
cv::namedWindow("test", WINDOW_FREERATIO);
cv::namedWindow("test1", WINDOW_FREERATIO);
cv::namedWindow("test2", WINDOW_FREERATIO);
cv::namedWindow("test3", WINDOW_FREERATIO);
cv::namedWindow("test4", WINDOW_FREERATIO);*/
client = UA_Client_new(); //创建opcua客户端
UA_ClientConfig_setDefault(UA_Client_getConfig(client)); //设置客户端为默认配置
status = UA_Client_connect(client, "opc.tcp://127.0.0.1:49320"); //连接服务器,此处连接KEPServer,URL可以通过任务栏KEPServer软件右键,“OPC UA配置”查看
//判断opcua客户端连接状态
if (status != UA_STATUSCODE_GOOD)
{
cout << "Connect OPC UA Sever Failed" << endl;
return 0;
}
else
{
cout << "Connect OPC UA Sever Successful" << endl;
}
//
//capture = VideoCapture(0); //打开摄像头
//capture.set(CAP_PROP_FRAME_WIDTH, 2448); // 设置图像宽度
//capture.set(CAP_PROP_FRAME_HEIGHT, 2048); // 设置图像高度
//capture.set(CAP_PROP_FPS, 5); // 设置帧率
//if (!capture.isOpened())
//{
// cout << "open camera failed." << endl;
// capture.release();
// return 0;
//}
//
//capture >> img; //读取视频流中的一帧,写入img
//cv::cvtColor(img, hsv, COLOR_BGR2HSV);
//cv::split(hsv, hsvsplit);
//cv::imshow("test", img); //在窗口显示一张图片
//cv::imshow("test1", hsv);
//cv::imshow("test2", hsvsplit[0]);
//cv::imshow("test3", hsvsplit[1]);
//cv::imshow("test4", hsvsplit[2]);
//cv::waitKey(0); //等待键盘按下,再执行后面的程序
//destroyAllWindows();
//capture.release();
UA_Client_delete(client); //释放opcua client
return 0;
}
将OPC UA头文件及连接服务器语句添加到main程序中,调试有120个错误,原因是头文件位置不对,存在重复定义
将头文件语句放到最上边,调试编译还有26个错误,原因是调试选择的x64平台,使用x86平台即可。这个问题没有解决,因为使用的opencv4.5.4要求必须是64位,不过我们后面使用Qt框架,Qt框架是跨平台的,应该可以消除此类错误。
调试平台切换为x86
将头文件放到最上面,将opencv相关语句注释掉,只保留连接Kepsever服务器语句,调试后发现服务器连接失败
需要更改Kepsever相关的OPC UA配置
电脑右下角任务栏右键点Kepsever图标,点击OPC UA配置-安全策略点击“无”
Kepsever软件中项目属性-OPC UA-允许匿名登录点“是”
配置完后,重新初始化kepsever运行时,再在VS中调试运行,显示连接成功
在Kepsever中增加PLC tag点,尝试用VS编程读写kepsever默认建立的用于测试的“通道 1.设备 1.标记 2”标签
发现读取失败,原因是VS中标签名称不能用中文
自己建立通道标签进行测试,“test.test.OPC_test”,由于没有实际连接PLC,通道建立选择Simulator模拟
更改VS程序读写的tag点为“test.test.OPC_test”,运行成功,能够读写操作
测试代码:
// test01.cpp : 定义控制台应用程序的入口点。
#include "open62541.h" //open62541头文件,opcua开源库文件
#pragma comment(lib,"ws2_32.lib") //opcua通讯用到的库,opcua使用socket通讯,需使用此库
#include "stdafx.h"
#include <iostream>
#include<windows.h> //使用Sleep(1000)延时函数头文件
#include <stdio.h>
#include <process.h>
#include <conio.h>
#include "string.h"
//#include <opencv2/opencv.hpp> //opencv头文件
//#include<opencv2/core.hpp>
//#include<opencv2/imgproc.hpp>
//#include<opencv2/highgui.hpp>
//#include<opencv2/videoio.hpp>
using namespace std; //使用命名空间
//using namespace cv;
/*声明全局变量*/
//VideoCapture capture;
UA_Client *client = UA_Client_new(); //opcua客户端结构体,用于与PLC通讯
UA_StatusCode status; //用于存放opcua客户端执行操作后的状态反馈
/*主函数*/
int main()
{
/*Mat img;
Mat hsv;
Mat hsvsplit[3];
cv::namedWindow("test", WINDOW_FREERATIO);
cv::namedWindow("test1", WINDOW_FREERATIO);
cv::namedWindow("test2", WINDOW_FREERATIO);
cv::namedWindow("test3", WINDOW_FREERATIO);
cv::namedWindow("test4", WINDOW_FREERATIO);*/
client = UA_Client_new(); //创建opcua客户端
UA_ClientConfig_setDefault(UA_Client_getConfig(client)); //设置客户端为默认配置
status = UA_Client_connect(client, "opc.tcp://127.0.0.1:49320"); //连接服务器,此处连接KEPServer,URL可以通过任务栏KEPServer软件右键,“OPC UA配置”查看
//判断opcua客户端连接状态
if (status != UA_STATUSCODE_GOOD)
{
cout << "Connect OPC UA Sever Failed" << endl;
return 0;
}
else
{
cout << "Connect OPC UA Sever Successful" << endl;
}
UA_Variant value; //opcua变量类型
UA_Variant_init(&value); //初始化,注意初始化后不能直接读取value.data的值,会导致内存指向错误,必须通过opcua读值或赋值后才能读取value.data
long OPC_test=5;
status = UA_Client_readValueAttribute(client, UA_NODEID_STRING(2, "test.test.OPC_test"), &value);
if (status != UA_STATUSCODE_GOOD)
{
cout << "OPC UA read Failed" << endl;
return 0;
}
else
{
cout << "OPC UA read Successful" << endl;
}
OPC_test = *(UA_UInt32*)value.data;
cout << "OPC_test原值:" << OPC_test<< endl;
OPC_test = OPC_test + 1;
UA_Variant_setScalar(&value, &OPC_test, &UA_TYPES[UA_TYPES_UINT32]); //将检测结果变量写入OPCUA变量
status = UA_Client_writeValueAttribute(client, UA_NODEID_STRING(2, "test.test.OPC_test"), &value); //将检测结果值写入PLC
if (status != UA_STATUSCODE_GOOD)
{
cout << "OPC UA write Failed" << endl;
return 0;
}
else
{
cout << "OPC UA write Successful" << endl;
}
status = UA_Client_readValueAttribute(client, UA_NODEID_STRING(2, "test.test.OPC_test"), &value);
if (status != UA_STATUSCODE_GOOD)
{
cout << "OPC UA read Failed" << endl;
return 0;
}
else
{
cout << "OPC UA read Successful" << endl;
}
OPC_test = *(UA_UInt32*)value.data;
cout << "OPC_test更改后:" << OPC_test << endl;
//
//capture = VideoCapture(0); //打开摄像头
//capture.set(CAP_PROP_FRAME_WIDTH, 2448); // 设置图像宽度
//capture.set(CAP_PROP_FRAME_HEIGHT, 2048); // 设置图像高度
//capture.set(CAP_PROP_FPS, 5); // 设置帧率
//if (!capture.isOpened())
//{
// cout << "open camera failed." << endl;
// capture.release();
// return 0;
//}
//
//capture >> img; //读取视频流中的一帧,写入img
//cv::cvtColor(img, hsv, COLOR_BGR2HSV);
//cv::split(hsv, hsvsplit);
//cv::imshow("test", img); //在窗口显示一张图片
//cv::imshow("test1", hsv);
//cv::imshow("test2", hsvsplit[0]);
//cv::imshow("test3", hsvsplit[1]);
//cv::imshow("test4", hsvsplit[2]);
//cv::waitKey(0); //等待键盘按下,再执行后面的程序
//destroyAllWindows();
//capture.release();
UA_Client_delete(client); //释放opcua client
return 0;
}
1.读取test点进行显示
2.变量加1,写入test点
3.再读取test点进行显示
总结:
1.open62541是OPC UA开源代码,虽然生成源文件和头文件需要下载源码和cmake,使用上比较麻烦,但只需要使用一次,生成后可以直接用,一劳永逸
2.在VS中选择x64平台会报错,选择x86平台可以用,应该是ws2_32.lib相关的库不支持64位,目前没有解决,继续后面的实验,看看用Qt后是否可以解决
3.在做OPC UA通讯实验前也实验了OPC DA读写OPC服务器成功了,但是DA的代码比较繁琐,环境配置也比较繁琐,这里就放弃DA,选用UA了。
4.kepsever的安全策略和允许匿名登录需要配置,如果不配置的话应该需要增加一下安全验证方面的代码,这里没有用到,所有直接将安全策略降为最低
5.VS中读取kepsever中点名称不能有中文
6.VS中建立的变量,与读取的OPC点数据类型注意对应