4 OPCUA可执行模型-工业4.0 的管理壳(AAS) 的实现

管理壳是I4.0 的重要概念,在I.40 的观点下,今后所有的生产设备都有一个管理壳,两台设备只要通过网线连接起来就能够相互协同操作 。以后部署一条生产线就像在电化教室中将电脑连上网线就能够打网络游戏那么简单 。这就是所谓的“即插即制造 Plug And ” 。目前这样的爽事还没有实现 。
网络上关于管理壳AAS 的描述非常多,但是看完这些关于管理壳的介绍之后,大多数人仍然一头雾水,不知道从何做起 。在这里讨论如何构建”即插即制造“的演示系统 。在讨论之前,我们也大致介绍一下管理壳的基本概念 。在文章的后半部分,我们将讨论如何去实现它们 。
什么是资产管理壳(AAS)?
它是一个资产的信息和功能的虚拟表现 。它提供了信息交换的标准化通信 。它是工业4.0 信息和增值功能的访问点 。
为什么需要资产管理壳(AssetShell)?
资产管理的壳的目的是沿着生产系统的生命周期交换资产相关的数据 。它借用了计算机中“Plug-and-Play 的概念,希望实现插入即生产,(”Plug-and-“)的愿景 。
显然,这里的Plug 并非物理的插入,而是信息模型之间的数据的对接 。设备A Plug In 设备B 那么设备A就能够访问设备B 的信息模型 。
这里的Plug 是一个网络的连接· 。
另外一种方式是上层软件访问底层的管理壳 。例如MES 软件访问设备的管理壳(信息模型) 。
直白一点,管理壳是设备的数字化模型 。Plug 就是访问设备的AAS 模型,并且可通过OPC UA 的方法来“启动”,停止设备 。设置设备的属性等等 。
如何实现资产管理壳
首先要使用构建PnP 系统的信息模型 。第二步使用OPC UA 实现AAS 之间交换数据的的通信接口 。
PnP 系统架构 云层
Web UI 能够控制PnP 系统的操作,实时地演示系统的AAS数据
平台层

4  OPCUA可执行模型-工业4.0 的管理壳(AAS) 的实现

文章插图
使用 表现AAS 数据的公共信息模型
OPCUA 实现机器人,转台的互操作 。并且作为AAS 的通信接口 。
TSN 保证AAS 通信的数据传输的实时性和确定性
现场层
厂商独立资产的协同操作,实现PnP 的操作 。
TSN 系统架构
云端层提供了一个Web 为基础的HMI接口,演示和操作整个TSN 机器人控制系统 。
通信层 使用OPCUA /TSN 提供交换机械臂控制命令和状态反馈 。同时它使用 和OPC UA 将云端与现场层连接 。
现场层 包含了各种工业设施(TSN交换机,TSN 终端,,工业机械臂,转台等等 。实现TSN为基础的机械臂控制和转台操作 。
从开发者的角度看AAS
说到这里,你也许仍然是一头雾水 。在开发者的角度看,AAS 是什么?如何在实践工程中应用?以笔者看来,AAS的本质是标准化的设备OPC UA 信息模型,比如,对于一个机械臂而言,它的型号,操作参数等等属性都包含在AAS 模型中 。应用程序可以通过AAS 子模型中的属性来操控机械臂 。
另一方面,AAS 还不仅仅是设备中的OPC UA 信息模型 。AAS 在设备的整个生命周期内都能够使用 。比如在数字仿真,数字孪生系统中,AAS 中包含了3D 模型,也包括了设备的机械特性,电功率等等 。某些模型也许在控制系统中并不需要,但是在仿真和设计,维护时需要使用 。从这个意义上讲,AAS 是设备的总的信息模型,或者说是设备的”百科全书“!在产品的生命周期中都可以查阅使用 。
构建AAS 的另外一个好处是不同厂商设备的AAS 标准化,使工程设计过程中的设备模型与厂商无关 。并且实现不同厂商设备的互换性 。因此,人们计划建立一个存储AAS 模型的网站,在设计过程中能够查阅AAS 模型 。最终形成一个工业4.0 平台和生态系统 。
再一次强调的是管理壳成败的关键是标准化和生态系统的形成 。
4  OPCUA可执行模型-工业4.0 的管理壳(AAS) 的实现

文章插图
另一个重要的标准是Ecl@ss。它们也正在与AAS 标准化相互融合,比如能够使用Ecl@ss 对AAS的子模型做出标识和语义规范 。
从上图可见,系统设计师在系统设计过程中可用查阅 网站,获取相应的,然后构建自己设备的AAS 。可用设想,如果全世界的大多数物品的AAS 都构建完成,并且查阅到的话,系统设计会变得如此的简单 。这也应了一句化 。软件工程师的一切努力都是为了让自己早日失业!
回到我们的正题,对于当前的系统工程师而言,自己构建一个AAS 就可以实现Plug-and- 的 了 。
演示系统的实现
在许多场合,100页PPT 不如一个Demo 程序来的痛快 。软件工程师需要细节 。网络上有一个项目,是韩国汉阳大学开发的 。针对的正是上面介绍的系统,两个机械臂和一个转台 。
- /AAS-based-PnP-Demo
我们从中可以看出一点管理壳实现的影子 。我大致看了一些它们的代码,在这个项目中:
管理壳是使用AML 语言描述的 。每个设备构建了AAS模型,但是它使用的并不是AAS 的格式,而是CAEX 文件格式 。
下面是它们的描述
【4OPCUA可执行模型-工业4.0 的管理壳(AAS) 的实现】CAEXEditorCAEXEditor20130613Fraunhofer IOSBwww.mes.fraunhofer.de2.2.152017-02-20T15:02:20.0500020+01:000.3.5start/stop3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=StartCommand3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=PositionDataX3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=PositionDataY3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=PositionDataZ3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=PositionDataA3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=PositionDataB3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=PositionDataC3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=kuka_gripper3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=kuka_sensors3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=kuka_light3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=kuka_state3a6d6b22-9a1b-4959-a413-e581aa834e00ns=1;s=table_to_kukastart/stopda51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Command:EPSON_C4_Start_Setda51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_X_Datada51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_Y_Datada51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_Z_Datada51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_U_Datada51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_V_Datada51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_W_Datada51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_Gripper_Statusda51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_SensorLR_Running_Statusda51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_Indicator_Light_Statusda51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Command:Epson_C4_Running_Statusda51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_C4_Robot_Monitoring:EPSON_C4_Turntable_Running_Statusstart/stop4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Command:EPSON_SCARA_Start_Set4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Monitoring:EPSON_SCARA_X_Data4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Monitoring:EPSON_SCARA_Y_Data4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Monitoring:EPSON_SCARA_Z_Datada51cded-5ec5-4112-bdee-526cb5f0113cns=1;s=::EPSON_SCARA_Robot_Monitoring:EPSON_SCARA_U_Data4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Monitoring:EPSON_SCARA_V_Data4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Monitoring:EPSON_SCARA_Gripper_Status4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Monitoring:EPSON_SCARA_SensorLR_Running_Status4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Monitoring:EPSON_SCARA_Indicator_Light_Status4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Command:Epson_SCARA_Running_Status4936367c-364a-4ad9-b12e-fd1bd93600adns=1;s=::EPSON_SCARA_Robot_Monitoring:EPSON_SCARA_Turntable_Running_Statusstart/stopd5a1d4da-8afb-44d4-a28f-438bfd2f2fc9ns=6;s=::Program2:PLC_Start_Setd5a1d4da-8afb-44d4-a28f-438bfd2f2fc9ns=6;s=::Program2:Kuka_Statusd5a1d4da-8afb-44d4-a28f-438bfd2f2fc9ns=6;s=::Program2:Epson1_Statusd5a1d4da-8afb-44d4-a28f-438bfd2f2fc9ns=6;s=::Program2:Epson2_Statusd5a1d4da-8afb-44d4-a28f-438bfd2f2fc9ns=6;s=::Program2:PLC_Kuka_Statusd5a1d4da-8afb-44d4-a28f-438bfd2f2fc9ns=6;s=::Program2:PLC_Epson1_Statusd5a1d4da-8afb-44d4-a28f-438bfd2f2fc9ns=6;s=::Program2:PLC_Epson2_Statusd5a1d4da-8afb-44d4-a28f-438bfd2f2fc9ns=6;s=::Program2:PLC_Table_Stateopc.tcp://192.168.0.177:4841opc.tcp://192.168.0.42:4842opc.tcp://192.168.0.43:4843opc.tcp://192.168.0.44:4844Standard Automation Markup Language Interface Class Library2.2.0Automation Markup Language base role class library2.2.00.2.40.10.1If this attribute is given all others except of the namespace table are obsolet.http://opcfoundation.org/UA/0.1FALSEFALSE(S7-1200)0.1InputOutputOptionaloptionalOptional0.10.10.10.10.10.10.1
那么,哪一个来访问和控制这个管理壳呢?结果发现它是在云端程序中实现了一个端应用程序 。这个程序通过访问机械臂和转台的AAS 来实现操作的 。
/*note read/write copy from 0115client.c (git version open62541 0.3)*//*this is the opc client in cloud*/#include #include "open62541.h"#include /**************udp client*/////#include #include #include #include #include #include //#include #include #include #define MYPORT 5555char* SERVERIP = "192.168.0.100";struct sockaddr_in servaddr;#define ERR_EXIT(m) \do \{ \perror(m); \exit(EXIT_FAILURE); \} while(0)UA_Variant value[40]; /* Variants can hold scalar values and arrays of any type */UA_String S_data[40]; /* Variants can hold scalar values and arrays of any type */UA_String Test;UA_Variant UI;/*************udp client************/void main(int argc, char *argv[]){int i;char button[100] = {0};int n = 0; // this n ensures the sequence running of s1 t1 s2 t2...int sock,con;char recvbuf[1024] = {0};for(i=0;i<40;i++) S_data[i].data=http://www.kingceram.com/post/malloc(sizeof(UA_String));/* Create a client and connect */UA_Client *client = UA_Client_new(UA_ClientConfig_standard);UA_StatusCode status = UA_Client_connect(client,"opc.tcp://192.168.0.178:16664");//aml-opcua aggregation server port 16664if(status != UA_STATUSCODE_GOOD) {UA_Client_delete(client);return status;}while (1){ status =UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.table_to_epson1"), &UI);//change idTest= *(UA_String*)UI.data;printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);//change id // ns[2] = 1//read(sock,recvbuf,sizeof(recvbuf));//printf("recvbuf:%s\n",recvbuf);strcpy(button,Test.data);//printf("button:%s\n",button);//sleep(1);/*in case 1, Table, Epson1 and KUKA are operating*/if ((strcmp(button, "S1") == 0)||(strcmp(button, "S2") == 0)||(strcmp(button, "S3") == 0)||(strcmp(button, "T1") == 0)||(strcmp(button, "T2") == 0)||(strcmp(button, "T3") == 0))//use if or while?after: n == 1// in case 1, if needed, divide if n == 0 and if n == 4 to make sequence of 2345{/* 1. opc ua client write Start Command to E1, Table, KUKA in amlopcua aggregation server*///UA_String write 1 Turn_table_startS_data[0].length = strlen(button);//printf("button:%s\n",button);strcpy(S_data[0].data,button);//printf("S_data[0].data%s\n",S_data[0].data);UA_Variant_setScalarCopy(&value[0], &S_data[0], &UA_TYPES[UA_TYPES_STRING]);UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.PLC_Start"), &value[0]); //change id // ns[2] = 1printf("writing \"StartCommand\" = 1 to Rotation Table: %s\n", S_data[0].data);//UA_String write 2 KUKA_start S_data[1].length = strlen(button);strcpy(S_data[1].data,button);UA_Variant_setScalarCopy(&value[1], &S_data[1], &UA_TYPES[UA_TYPES_STRING]);UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "5edaf471-ae3c-4854-bcc3-a9340f6da7c2.StartCommand"), &value[1]); //change idprintf("writing \"StartCommand\" = 1 to KUKA: %s\n", S_data[1].data);//UA_String write 3 Epson1_start S_data[2].length = strlen(button);strcpy(S_data[2].data,button);UA_Variant_setScalarCopy(&value[2], &S_data[2], &UA_TYPES[UA_TYPES_STRING]);UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "65b425fa-0bdb-496e-a1ae-28171cea1fcd.StartCommand"), &value[2]); //change idprintf("writing \"StartCommand\" = 1 to Epons1: %s\n", S_data[2].data);//UA_String write 4 Epson2_start S_data[3].length = strlen(button);strcpy(S_data[3].data,button);UA_Variant_setScalarCopy(&value[3], &S_data[3], &UA_TYPES[UA_TYPES_STRING]);UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "d6a952c0-2c6c-4941-9c13-94177a3566f7.StartCommand"), &value[3]); //change idprintf("writing \"StartCommand\" = 1 to Epons2: %s\n", S_data[3].data);n = 1;}//maping code//* 2. read (PLC)Table state, and write it to Epson1*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.table_to_epson1"), &value[4]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[4], &UA_TYPES[UA_TYPES_STRING])) {//Test= *(UA_String*)value[4].data;//printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write "0" to Epson1UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "5edaf471-ae3c-4854-bcc3-a9340f6da7c2.table_to_epson1"), &value[4]);//change id//printf("writing \"Table off state\" = 0 to Epson1: %s\n",Test.data);/*****************************Do we need to clear the "state 0" at each step????? memset(positionstr, 0, sizeof(positionstr));how to ensure the sequence execution of each informtion flow?????******************************************************************************************************************************//* 3. read E1 state, and write it to Table*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "5edaf471-ae3c-4854-bcc3-a9340f6da7c2.epson1_state"), &value[5]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[5], &UA_TYPES[UA_TYPES_STRING])) {//Test= *(UA_String*)value[5].data;//printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write to TableUA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.epson1_to_table"), &value[5]);//change id// printf("writing \"Epson1 off state\" = 0 to Table: %s\n",Test.data);/* 4. read Table state, and write it to KUKA*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.table_to_kuka"), &value[6]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[6], &UA_TYPES[UA_TYPES_STRING])) {//Test= *(UA_String*)value[6].data;//printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write to Epson1UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "65b425fa-0bdb-496e-a1ae-28171cea1fcd.table_to_kuka"), &value[6]);//change id//printf("writing \"Epson1 off state\" = 0 to Table: %s\n",Test.data);/* 5. read KUKA state, and write it to Table*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "65b425fa-0bdb-496e-a1ae-28171cea1fcd.kuka_state"), &value[7]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[7], &UA_TYPES[UA_TYPES_STRING])) {//Test= *(UA_String*)value[7].data;//printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write to TableUA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.kuka_to_table"), &value[7]);//change id// printf("writing \"Epson1 off state\" = 0 to Table: %s\n",Test.data);/* 2. read (PLC)Table state, and write it to Epson2*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.table_to_epson2"), &value[16]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[16], &UA_TYPES[UA_TYPES_STRING])) {//Test= *(UA_String*)value[16].data;//printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write "0" to Epson2UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "d6a952c0-2c6c-4941-9c13-94177a3566f7.table_to_epson2"), &value[16]);//change id//printf("writing \"Table off state\" = 0 to Epson1: %s\n",Test.data);/* 3. read E2 state, and write it to Table*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "d6a952c0-2c6c-4941-9c13-94177a3566f7.epson2_state"), &value[17]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[17], &UA_TYPES[UA_TYPES_STRING])) {//Test= *(UA_String*)value[17].data;//printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write to TableUA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.epson2_to_table"), &value[17]);//change id// printf("writing \"Epson1 off state\" = 0 to Table: %s\n",Test.data);#if 0/* 4. read Table state, and write it to KUKA*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.table_to_kuka"), &value[18]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[18], &UA_TYPES[UA_TYPES_STRING])) {Test= *(UA_String*)value[18].data;printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write to TableUA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "65b425fa-0bdb-496e-a1ae-28171cea1fcd.table_to_kuka"), &value[18]);//change idprintf("writing \"Epson1 off state\" = 0 to Table: %s\n",Test.data);/* 5. read KUKA state, and write it to Table*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "65b425fa-0bdb-496e-a1ae-28171cea1fcd.kuka_state"), &value[19]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[19], &UA_TYPES[UA_TYPES_STRING])) {Test= *(UA_String*)value[19].data;printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write to TableUA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.kuka_to_table"), &value[19]);//change idprintf("writing \"Epson1 off state\" = 0 to Table: %s\n",Test.data); /* 2. read (PLC)Table state, and write it to Epson1*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.table_to_epson1"), &value[28]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[28], &UA_TYPES[UA_TYPES_STRING])) {Test= *(UA_String*)value[28].data;printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write "0" to Epson2UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "5edaf471-ae3c-4854-bcc3-a9340f6da7c2.table_to_epson1"), &value[28]);//change idprintf("writing \"Table off state\" = 0 to Epson1: %s\n",Test.data);/* 3. read E1 state, and write it to Table*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "5edaf471-ae3c-4854-bcc3-a9340f6da7c2.epson1_state"), &value[29]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[29], &UA_TYPES[UA_TYPES_STRING])) {Test= *(UA_String*)value[29].data;printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write to TableUA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.epson1_to_table"), &value[29]);//change idprintf("writing \"Epson1 off state\" = 0 to Table: %s\n",Test.data);/* 4. read Table state, and write it to Epson2*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.table_to_epson2"), &value[30]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[30], &UA_TYPES[UA_TYPES_STRING])) {Test= *(UA_String*)value[30].data;printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write to TableUA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "d6a952c0-2c6c-4941-9c13-94177a3566f7.table_to_epson2"), &value[30]);//change idprintf("writing \"Epson1 off state\" = 0 to Table: %s\n",Test.data);/* 5. read KUKA state, and write it to Table*///UA_String readstatus = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "d6a952c0-2c6c-4941-9c13-94177a3566f7.epson2_state"), &value[31]);//change idif (status == UA_STATUSCODE_GOOD &&UA_Variant_hasScalarType(&value[31], &UA_TYPES[UA_TYPES_STRING])) {Test= *(UA_String*)value[31].data;printf("reading the \"Table_Epson1\" = 0 is: %s\n", Test.data);}//UA_String write to TableUA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "0a04cce4-a64a-4566-b916-06a8639d7dcd.epson2_to_table"), &value[31]);//change idprintf("writing \"Epson1 off state\" = 0 to Table: %s\n",Test.data); #endif}UA_Client_delete(client); /* Disconnects the client internally */return status;}
进一步的思考
前面的几篇文章我们已经介绍了利用功能块的概念来设计分布式OPCUA 控制系统的相关问题 。我们完全可用使用功能块网络实现上面的控制程序 。只是某些细节需要进一步思考 。
至于AAS 注册网站,等概念我们在后续的文章中再进一步介绍
要提醒读者的是,我也正在学习中,文章中的内容也许存在理解错误,往读者提出宝贵意见 。