OPC UA Server Example

In this example you’ll learn how to enable the OPC UA addin and convert RoboDK into an OPC UA server. We’ll browse some settings by using UaExpert software and Beckhoff TwinCAT3 TF6100.

OPC UA -图像4

Configure your OPC UA Server

The OPC UA add-in allows you to configure some settings such as the server port. You can also choose to activate the server, deactivate it or automatically start with RoboDK.

With the OPC UA add-in enabled, selectOPC UA-OPC-UA Settingsto configure your OPC UA settings.

OPC UA Settings Screen is shown on the Left side as shown in the following image.

OPC UA -图像5

OPC UA -图像6

If you see a message such as “RoboDK’s OPC UA server running on port 4840” it means the OPC UA server in RoboDK started.

Create your Own Station

You can test the OPC UA connectivity with any RoboDK station that has one or more robots.

OPC UA -图像7

Implementation with UaExpert

You can use UaExpert software to test the connectivity with the RoboDK OPC UA Server.

You can download the free version of the UaExpert software from the Unified Automation website:https://www.unified-automation.com/downloads/opc-ua-clients.html.

OPC UA -图像8

Add Server

Launch the UaExpert and Click the “+” Button to Add the RoboDK OPC UA Server.

OPC UA -图像9

Expand the Custom Discovery and select theoption to add the RoboDK OPC UA Server.

OPC UA -图像10

Enter the URL of the OPC UA server, opc.tcp://127.0.0.1:48440 which you configured in the previous step.

OPC UA -图像11

Connect the OPC UA Server with “None” Security.

OPC UA -图像12

Server is configured.

OPC UA -图像13

Connect to the Server

Now you can connect to the RoboDK OPC UA Server from UaExpert.

OPC UA -图像14

You can see the Nodes and Methods when the connection is established.

OPC UA -图像15

Nodes

There are some nodes inside the RoboDK OPC UA server to let you exchange some basic information about your station.

RoboDK

RoboDK节点是一个节点,提供实际的版本sion of your RoboDK Software.

OPC UA -图像16

The version RoboDK 64 Bit v5.5.3.23031 was used in this example.

OPC UA -图像17

SimulationSpeed

Simulation Speed is a node that shows the actual Simulation Speed and allows the user to overwrite the current Simulation Speed.

OPC UA -图像18

The node value is referenced to the Slide bar of simulation speed.

The current Simulation can be read from this node and can overwrite the simulation speed.

OPC UA -图像19

Station

Station Node is a node that allows the user to get the current name of the Station in RoboDK.

OPC UA -图像20

As you see below, the Station node is referenced to your “Station Name” in RoboDK.

OPC UA -图像21

Station parameters/Station Value

Station Parameter and Station Value are a pair set Node that allows the user to get or set any parameters inside your Station. The RoboDK OPC UA Server will continuously monitor the actual value of “StationParameter” and return the Value of that “StationParameter”, from the Station Value Node.

OPC UA -图像22

You can view your Station parameters by Right Click your RoboDK Station>Station parameters.

OPC UA -图像23

In the Constant parameters field, you can see the default station parameters and their value.

OPC UA -图像24

Station parameter is referenced to the “Parameter” field and Station Value is referenced to the “Value” field.

OPC UA -图像25

And we can create our own Parameters by clicking the “Add” Button.

OPC UA -图像26

A new Station parameter is added.

OPC UA -图像27

Enter your Parameter name and the Parameter Value, then press Apply to save it.

OPC UA -图像28

You can get your own station parameter as well.

OPC UA -图像29

Time

The node time is a node that allows you to get the current time of the RoboDK Station.

OPC UA -图像30

A value with DataTime format is returned.

OPC UA -图像31

And this Node is updated continually.

OPC UA -图像32

Methods

RoboDK OPC UA Server is also provided with some methods to allow the user to access the RoboDK station ‘s Data dynamically.

We can just right click the Method>Call to execute the method.

OPC UA -图像33

getItem

getItem is a Method that allows the user to get the pointer of your Item.

OPC UA -图像34

For the InputArguments, Device Name is required, you can image the Device Name is your Station Name,Robot Name..etc.. And Item ID is the OutputArguments that return the Pointer of that Device.

OPC UA -图像35

In this Example, I received the Item ID (Pointer) of my ABB Robot that is named as “ABB_RB1”.

OPC UA -图像36

0 is returned if the Item Name is invalid or does not exist inside your station.

OPC UA -图像37

getJoints

getJonits is a method that allows the user to get the joint value of the robot from the station, based on the Item ID.

OPC UA -图像38

The Item ID is the pointer value of your Item, and you can get it from getItem() Method.

OPC UA -图像39

We will get the Item ID with this “ABB_RB1” Item name, and a UInt64 value is returned.

OPC UA -图像40

关节传递项ID时返回值in the method that we got in the previous.

OPC UA -图像41

getJointsStr

getJointsStr is a method that allows the user to get the Joints value based on a String Value.

OPC UA -图像42

We can pass the Robot name (String) in this method.

OPC UA -图像43

In My Station, ABB_RB1 is my robot’s name.

OPC UA -图像44

We can just pass “ABB_RB1” in the Robot name parameter and call the method - The joint value in String format is returned.

OPC UA -图像45

setJointsStr

setJointsStr is a method that allows the user to set the Joints value of the Robot, based on a String Value.

OPC UA -图像46

In the Robot name, ABB_RB1 is passed, and we can just pass a string with the joint value in the Joints parameter.

For example:-0.000000,0.000000,-0.000000,-0.000000,-0.0,-0.000000

OPC UA -图像47

Implementation with Beckhoff TwinCAT3

Add Server

Now we can insert the OPC UA Client by I/O>Devices>Add New Item.

OPC UA -图像48

Select Virtual OPC UA Device from OPC >OK.

OPC UA -图像49

OPC UA Virtual is inserted.

OPC UA -图像50

We need to add an OPC UA Client to access the RoboDK OPC UA Server.

Select Device 1 >Right Click >Add New Item.

OPC UA -图像51

Select “OPC UA Client(Module)” and Ok.

OPC UA -图像52

OPC UA Client is inserted.

OPC UA -图像53

Configure the Server

打开OPC UA客户>去设置选项卡>点击the “Select Endpoint” to configure the OPC UA Server endpoint that you would like to access.

OPC UA -图像54

Enter the RoboDK OPC UA server URL and Update it.

OPC UA - 55形象

Add RoboDK Server Method

Press “Add Nodes” to browse the node that is inside the OPC UA Server.

OPC UA - 56

If the connection between TwinCAT and OPC UA Server is established, you can Browse the details of OPC UA server.

OPC UA -图像57

Select all Methods and Ok.

OPC UA -图像58

Methods are inserted in your Configuration.

OPC UA -图像59

Auto Generate RoboDK Method

Configure your Name Prefix in this field.

OPC UA -图像60

Press “Create Plc Code” to create the PLC Code from TwinCAT.

OPC UA -图像61

An OpcUaClient folder is created in your project, and all RoboDK Method are created in IEC61131-3 Function Block format.

OPC UA -图像62

PLC Program Example

This section shows a sample program of a Beckhoff TwinCAT PLC that communicates with RoboDK OPC UA server.

PROGRAM MAIN

VAR

bConnected :BOOL;

StationPointer :DINT;

iStep :INT;

bStart :BOOL;;

i :INT;

TON :TON;

bReset :BOOL;

bWrite :BOOL;

TON2 :TON;

bShow :BOOL:=TRUE;

bVis :BOOL:=True;

END_VAR

VAR

Robot_name :STRING(80):='ABB_RB1';

Item_ID :ULINT;

arrJoints :ARRAY[0..11]OF LREAL;

strJoints :STRING(80):='';

arrJointsFromStr:ARRAY[1..11]OF LREAL;

sSeparator :STRING(1) := ',';

arrJointsCommand:ARRAY[1..11]OF LREAL;

strJointsCommand:STRING(80);

END_VAR

VAR CONSTANT

cStepWaitCmd :INT:=0;

cStepInit :INT:=5;

cStepGetItem :INT:=10;

cStepGetItemReset :INT:=20;

cStepGetItemError :INT:=990;

cStepGetJoints :INT:=30;

cStepGetJointsReset :INT:=40;

cStepGetJointsError :INT:=991;

cStepGetJointsStr :INT:=50;

cStepGetJointsStrReset:INT:=60;

cStepGetJointsStrError:INT:=992;

cStepSetJointStrDelay :INT:=69;

cStepSetJointsStr :INT:=70;

cStepSetJointsStrReset:INT:=80;

cStepSetJointsStrError:INT:=993;

cStepEnd :INT:=300;

cStepWaitReset :INT:=999;

END_VAR

VAR

aSplit :ARRAY[1..11] OF STRING(80);

bResultSplit :BOOL;

debug:BOOL;

URL :STRING:='http://192.168.3.42:8091';

END_VAR

bConnected:=OPCUA_VirtualClient_RoboDK_Station.bConnected;

CASE iStep OF

cStepWaitCmd:

IF bStart THEN

iStep:=cStepInit;

bStart:=FALSE;

END_IF

cStepInit:

StationPointer:=0;

FOR i :=1 TO 11 DO

arrJoints[i]:=0.0;

arrJointsFromStr[i]:=0.0;

aSplit[i]:='';

END_FOR

IF NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bBusy

AND NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bError

AND NOT OPCUA_VirtualClient_RoboDK_Station.getJoints.bBusy

AND NOT OPCUA_VirtualClient_RoboDK_Station.getJoints.bError

AND NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy

AND NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bError

AND NOT OPCUA_VirtualClient_RoboDK_Station.setJoints.bBusy

AND NOT OPCUA_VirtualClient_RoboDK_Station.setJoints.bError

AND NOT OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy

AND NOT OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError

THEN

iStep:=cStepGetItem;

END_IF

iStep:=cStepGetItem;

cStepGetItem:

IF OPCUA_VirtualClient_RoboDK_Station.getItem.bDone THEN

iStep:=cStepGetItemReset;

Item_ID:=OPCUA_VirtualClient_RoboDK_Station.getItem.Item_ID;

ELSIF OPCUA_VirtualClient_RoboDK_Station.getItem.bError THEN

iStep:=cStepGetItemError;

END_IF

cStepGetItemReset:

IF NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bError

AND NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bBusy

THEN

iStep:=cStepGetJoints;

END_IF

cStepGetJoints:

IF OPCUA_VirtualClient_RoboDK_Station.getJoints.bDone

AND NOT OPCUA_VirtualClient_RoboDK_Station.getJoints.bBusy

THEN

iStep:=cStepGetJointsReset;

ELSIF OPCUA_VirtualClient_RoboDK_Station.getJoints.bError THEN

iStep:=991;

END_IF

cStepGetJointsReset:

IF NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bError

AND NOT OPCUA_VirtualClient_RoboDK_Station.getItem.bBusy

THEN

iStep:=cStepGetJointsStr;

END_IF;

cStepGetJointsStr:

IF OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bDone

AND NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy

THEN

iStep:=cStepGetJointsStrReset;

ELSIF OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bError THEN

iStep:=cStepGetJointsStrError;

END_IF

cStepGetJointsStrReset:

IF NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bError

AND NOT OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy

THEN

iStep:=cStepSetJointStrDelay;

END_IF;

cStepSetJointStrDelay:

strJointsCommand:=''; strJointsCommand:=CONCAT(LREAL_TO_STRING(arrJointsCommand[1]),strJointsCommand);

strJointsCommand:=CONCAT(strJointsCommand,',');

strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[2]));

strJointsCommand:=CONCAT(strJointsCommand,',');

strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[3]));

strJointsCommand:=CONCAT(strJointsCommand,',');

strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[4]));

strJointsCommand:=CONCAT(strJointsCommand,',');

strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[5]));

strJointsCommand:=CONCAT(strJointsCommand,',');

strJointsCommand:=CONCAT(strJointsCommand,LREAL_TO_STRING(arrJointsCommand[6]));

TON2(IN:=TRUE,PT:=T#0.2S);

IF TON2.Q THEN

TON2(IN:=FALSE);

iStep:=cStepSetJointsStr;

END_IF

cStepSetJointsStr:

IF (

OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bDone

AND NOT

OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy

)

OR NOT bWrite

THEN

iStep:=cStepSetJointsStrReset;

ELSIF OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError

THEN

iStep:=cStepSetJointsStrError;

END_IF

cStepSetJointsStrReset:

bWrite:=FALSE;

OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bExecute:=FALSE;

IF NOT OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError

AND NOT OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy

THEN

iStep:=cStepEnd;

END_IF;

cStepEnd:

TON(IN:=TRUE,PT:=T#0.1S);

IF TON.Q THEN

TON(IN:=FALSE);

IF NOT debug THEN

iStep:=10;

ELSE

iStep:=cStepSetJointStrDelay;

END_IF;

END_IF

cStepGetItemError:

Item_ID:=0;

iStep:=cStepWaitReset;

cStepGetJointsError:

FOR i :=0 TO 11 DO

arrJoints[i]:=-99999.99;

END_FOR

iStep:=cStepWaitReset;

cStepGetJointsStrError:

strJoints:='';

iStep:=cStepWaitReset;

cStepWaitReset:

IF bReset THEN

iStep:=cStepInit;

bReset:=FALSE;

END_IF;

END_CASE

aSplit[1] := strJoints;

FOR i:=1 TO 7 DO

bResultSplit := FindAndSplit(

pSeparator := ADR(sSeparator)

,pSrcString := ADR(aSplit[i])

,pLeftString:= ADR(aSplit[i])

,nLeftSize := SIZEOF(aSplit[i])

,pRightString:= ADR(aSplit[i+1])

,nRightSize := SIZEOF(aSplit[i+1])

,bSearchFromRight := FALSE );

IF NOT bResultSplit THEN

EXIT;

END_IF

END_FOR

FOR i :=1 TO 6 DO

arrJointsFromStr[i]:=STRING_TO_LREAL(aSplit[i]);

END_FOR;

//

OPCUA_VirtualClient_RoboDK_Station.getItem(

bExecute:=iStep=cStepGetItem

,Item_Name:=Robot_name

);

OPCUA_VirtualClient_RoboDK_Station.getJoints(

bExecute:=iStep=cStepGetJoints

,Item_ID:=Item_ID,Joints=>arrJoints

);

OPCUA_VirtualClient_RoboDK_Station.getJointsStr(

bExecute:=iStep=cStepGetJointsStr

,Robot_name:=Robot_name,Joints=>strJoints

);

IF bWrite THEN

OPCUA_VirtualClient_RoboDK_Station.setJointsStr(

bExecute:=TRUE

,Robot_name:=Robot_name,Joints:=strJointsCommand);

END_IF;