OPC-UA

OPC-UA 활성화 -in

이문서에서는 RoboDK에 OPC-UA 연결을추가하는방법을설명합니다. OPC UA 연결을사용하면이프로토콜을지원하는 PLC 및기타장치와상호작용할수있습니다. 프로젝트에 OPC UA 서버및클라이언트기능을추가하려면 RoboDK에서 OPC-UA add-in을활성화해야합니다.

RoboDK에는 RoboDK 프로젝트에 OPC UA 호환성을추가할수있는 OPC-UA add-in이포함되어있습니다.

기본적으로 RoboDK는 OPC-UA add-in이비활성화되어있습니다. 활성화하면 RoboDK를시작할때마다추가기능이표시됩니다.

다음단계에따라 OPC UA Add-in을활성화할수있습니다:

1.도구-Add-in을선택합니다.

2.OPC-UA를더블클릭합니다.

OPC-UA 기능이포함된추가도구모음이표시됩니다.

OPC UA - 영상 1    OPC UA - 영상 2

도구모음에 OPC-UA 버튼이표시되고메뉴에도 OPC-UA 항목이표시됩니다.

OPC UA - 영상 3

OPC UA 서버 예제

이예제에서는 OPC UA add-in을활성화하고 RoboDK를 OPC UA 서버로변환하는방법을배웁니다. UaExpert 소프트웨어와벡호프트윈캣3 TF6100을사용하여몇가지설정을살펴봅니다.

OPC UA - 영상 4

OPC UA 서버 구성

OPC UA add-in을사용하면서버포트와같은일부설정을구성할수있습니다. 서버를활성화하거나비활성화하거나 RoboDK로자동시작하도록선택할수도있습니다.

OPC UA Add-in이활성화된상태에서 OPC UA-OPC-UA 설정을 선택하여 OPC UA 설정을구성합니다.

다음이미지와같이왼쪽에 OPC UA 설정화면이표시됩니다.

OPC UA - 영상 5

OPC UA - 영상 6

"포트 4840에서실행중인 RoboDK의 OPC UA 서버"와같은메시지가표시되면 RoboDK의 OPC UA 서버가시작되었다는의미입니다.

나만의 스테이션 만들기

하나이상의로봇이있는모든 RoboDK 스테이션에서 OPC UA 연결을테스트할수있습니다.

OPC UA - 영상 7

UaExpert

UaExpert 소프트웨어를사용하여 RoboDK OPC UA 서버와의연결을테스트할수있습니다.

Unified Automation 웹사이트(https://www.unified-automation.com/downloads/opc-ua-clients.html)에서무료버전의 UaExpert 소프트웨어를다운로드할수있습니다.

OPC UA - 영상 8

UaExpert 서버 추가

UaExpert를실행하고 "+" 버튼을클릭하여 RoboDK OPC UA 서버를추가합니다.

OPC UA - 영상 9

사용자지정검색을확장하고 <두 번 클릭하여 서버 추가> 옵션을선택하여 RoboDK OPC UA 서버를추가합니다.

OPC UA - 영상 10

이전 단계에서 구성한 OPC UA 서버의 URL인 opc.tcp://127.0.0.1:48440을 입력합니다.

OPC UA - 영상 11

보안이 "없음"인 OPC UA 서버를연결합니다.

OPC UA - 영상 12

서버가구성되었습니다.

OPC UA - 영상 13

서버에 연결

이제 UaExpert에서 RoboDK OPC UA 서버에연결할수있습니다.

OPC UA - 영상 14

연결이설정되면노드및메소드를볼수있습니다.

OPC UA - 영상 15

서버 노드

RoboDK OPC UA 서버내부에는스테이션에대한몇가지기본정보를교환할수있는몇가지노드가있습니다.

RoboDK

RoboDK 노드는 RoboDK 소프트웨어의실제버전을제공하는노드입니다.

OPC UA - 영상 16

이예제에서는 RoboDK 64비트 v5.5.3.23031 버전이사용되었습니다.

OPC UA - 영상 17

SimulationSpeed

시뮬레이션 속도는 실제 시뮬레이션 속도를 표시하고 사용자가 현재 시뮬레이션 속도를 덮어쓸 수 있는 노드입니다.

OPC UA - 영상 18

노드 값은 시뮬레이션 속도의 슬라이드 바를 참조합니다.

이 노드에서 현재 시뮬레이션을 읽을 수 있으며 시뮬레이션 속도를 덮어쓸 수 있습니다.

OPC UA - 영상 19

스테이션

스테이션노드는사용자가 RoboDK에서스테이션의현재이름을가져올수있는노드입니다.

OPC UA - 영상 20

아래에서볼수있듯이스테이션노드는 RoboDK에서 "스테이션이름"으로참조됩니다.

OPC UA - 영상 21

스테이션 파라미터/스테이션 값

스테이션파라미터와스테이션값은사용자가스테이션내부의모든파라미터를가져오거나설정할수있는쌍으로구성된노드입니다. RoboDK OPC UA 서버는 "StationParameter"의실제값을지속적으로모니터링하고스테이션값노드에서해당 "StationParameter"의값을반환합니다.

OPC UA - 영상 22

Station 파라미터를보려면 RoboDK Station > Station 파라미터를우클릭하세요.

OPC UA - 영상 23

상수매개변수필드에서기본스테이션매개변수와해당값을확인할수있습니다.

OPC UA - 영상 24

스테이션매개변수는 '매개변수' 필드를참조하고스테이션값은 '값' 필드를참조합니다.

OPC UA - 영상 25

그리고 '추가' 버튼을클릭하여자신만의파라미터를만들수있습니다.

OPC UA - 영상 26

새로운스테이션매개변수가추가됩니다.

OPC UA - 영상 27

파라미터이름과파라미터값을입력한다음적용을눌러저장합니다.

OPC UA - 영상 28

자신만의스테이션파라미터를설정할수도있습니다.

OPC UA - 영상 29

시간

노드시간은 RoboDK 스테이션의현재시간을얻을수있는노드입니다.

OPC UA - 영상 30

DataTime 형식의값이반환됩니다.

OPC UA - 영상 31

그리고이노드는지속적으로업데이트됩니다.

OPC UA - 영상 32

방법

RoboDK OPC UA 서버에는사용자가 RoboDK 스테이션의데이터에동적으로액세스할수있는몇가지방법도제공됩니다.

메서드> 호출을마우스오른쪽버튼으로클릭하여메서드를실행할수있습니다.

OPC UA - 영상 33

getItem

getItem은사용자가아이템의포인터를가져올수있는메서드입니다.

OPC UA - 영상 34

InputArguments의경우장치이름은필수이며, 장치이름은스테이션이름, 로봇이름등을이미지화할수있습니다. 그리고 Item ID는해당장치의포인터를반환하는 OutputArguments입니다.

OPC UA - 영상 35

이예제에서는 ABB 로봇의아이템 ID(포인터)가 "ABB_RB1"로지정되었습니다.

OPC UA - 영상 36

아이템이름이유효하지않거나스테이션에존재하지않는경우 0이반환됩니다.

OPC UA - 영상 37

getJoints

getJonits는사용자가아이템 ID를기반으로스테이션에서로봇의조인트값을가져올수있는메서드입니다.

OPC UA - 영상 38

아이템 ID는아이템의포인터값으로, getItem() 메서드에서가져올수있습니다.

OPC UA - 영상 39

이 "ABB_RB1" 아이템이름으로아이템 ID를가져오고 UInt64 값을반환합니다.

OPC UA - 영상 40

조인트값은이전메서드에서가져온항목 ID를전달하면서반환됩니다.

OPC UA - 영상 41

getJointsStr

getJointsStr은사용자가문자열값을기반으로조인트값을가져올수있는메서드입니다.

OPC UA - 영상 42

이메서드에서로봇이름(문자열)을전달할수있습니다.

OPC UA - 영상 43

내스테이션에서 ABB_RB1은내로봇의이름입니다.

OPC UA - 영상 44

로봇이름매개변수에 "ABB_RB1"을전달하고메서드를호출하면문자열형식의조인트값이반환됩니다.

OPC UA - 영상 45

setJointsStr

setJointsStr은사용자가문자열값을기반으로로봇의조인트값을설정할수있는메서드입니다.

OPC UA - 영상 46

로봇이름에는 ABB_RB1이전달되며, 조인트매개변수에는조인트값이포함된문자열을전달하면됩니다.

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

OPC UA - 영상 47

벡호프 트윈캣 3

Beckhoff TwinCAT 3 소프트웨어를사용하여 RoboDK OPC UA 서버와의연결을테스트할수있습니다.

트윈캣3 서버 추가

I/O>장치>새 항목 추가를 선택하여 OPC UA 클라이언트를 생성하여 시작할 수 있습니다.

OPC UA - 영상 48

OPC > 확인에서 가상 OPC UA 장치를 선택합니다.

OPC UA - 영상 49

OPC UA Virtual이삽입됩니다.

OPC UA - 영상 50

RoboDK OPC UA 서버에액세스하려면 OPC UA 클라이언트를추가해야합니다.

장치 1 > 마우스오른쪽버튼클릭 > 새항목추가를선택합니다.

OPC UA - 영상 51

"OPC UA 클라이언트(모듈)"를선택하고확인을선택합니다.

OPC UA - 영상 52

OPC UA 클라이언트가삽입됩니다.

OPC UA - 영상 53

서버 구성

OPC UA 클라이언트를열고 > 설정탭으로이동한후 > "엔드포인트선택"을클릭하여액세스하려는 OPC UA 서버엔드포인트를구성합니다.

OPC UA - 영상 54

RoboDK OPC UA 서버 URL을입력하고업데이트합니다.

OPC UA - 영상 55

RoboDK 서버 메서드 추가

"노드추가"를눌러 OPC UA 서버내부에있는노드를찾습니다.

OPC UA - 영상 56

트윈캣과 OPC UA 서버 간의 연결이 설정되면, OPC UA 서버의 세부 정보를 찾아볼 수 있습니다.

OPC UA - 영상 57

모든방법을선택하고확인을선택합니다.

OPC UA - 영상 58

메소드가구성에삽입됩니다.

OPC UA - 영상 59

자동 생성 RoboDK 메서드

이필드에서이름접두사를구성합니다.

OPC UA - 영상 60

트윈캣에서 PLC 코드를생성하려면 "Create Plc Code"를누르세요.

OPC UA - 영상 61

프로젝트에 OpcUaClient 폴더가생성되고모든 RoboDK 메서드는 IEC61131-3 기능블록형식으로생성됩니다.

OPC UA - 영상 62

PLC 프로그램 예제

이섹션에서는 RoboDK OPC UA 서버와통신하는 Beckhoff TwinCAT PLC의샘플프로그램을보여줍니다.

프로그램 주요 내용

VAR

   bConnected      :BOOL;

   스테이션 포인터    :DINT;

   iStep           :INT;

   bStart          :BOOL;;

   i               INT;

   TON             TON;

   bReset          :BOOL;

   bWrite          :BOOL;

   TON2            :TON;

   bShow           :BOOL:=TRUE;

   bVis            :BOOL:=True;

END_VAR

 

VAR

   로봇_이름         :문자열(80):='abb_rb1';

   Item_ID         :ULINT;

   arrJoints       :array[0..11]의 lreal;

   strJoints       :문자열(80):='';

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

   sSeparator      :문자열(1) := ',';

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

   strJointsCommand:STRING(80);

END_VAR

 

VAR 상수

   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;

 

사례 i단계

  

 

   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

      OPCUA_VirtualClient_RoboDK_Station.getItem.bBusy가 아닌 경우

              그리고 OPCUA_VirtualClient_RoboDK_Station.getItem.bError가 아닙니다.

              그리고 OPCUA_VirtualClient_RoboDK_Station.getJoints.bBusy가 아닙니다.

              그리고 OPCUA_VirtualClient_RoboDK_Station.getJoints.bError가 아닙니다.

              그리고 OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy가 아닙니다.

              그리고 OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bError가 아닙니다.

              그리고 OPCUA_VirtualClient_RoboDK_Station.setJoints.bBusy가 아닙니다.

              그리고 OPCUA_VirtualClient_RoboDK_Station.setJoints.bError가 아닙니다.

              그리고 OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy가 아닙니다.

              그리고 OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError가 아닙니다.

              그때

              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:

 

      OPCUA_VirtualClient_RoboDK_Station.getItem.bError가 아닌 경우

              그리고 OPCUA_VirtualClient_RoboDK_Station.getItem.bBusy가 아닙니다.

              그때

              iStep:=cStepGetJoints;

        END_IF

   cStepGetJoints:

 

        IF OPCUA_VirtualClient_RoboDK_Station.getJoints.bDone

              그리고 OPCUA_VirtualClient_RoboDK_Station.getJoints.bBusy가 아닙니다.

              그때

              iStep:=cStepGetJointsReset;

        ELSIF OPCUA_VirtualClient_RoboDK_Station.getJoints.bError THEN

              iStep:=991;

        END_IF

       

   cStepGetJointsReset:

 

      OPCUA_VirtualClient_RoboDK_Station.getItem.bError가 아닌 경우

              그리고 OPCUA_VirtualClient_RoboDK_Station.getItem.bBusy가 아닙니다.

       

              그때

              iStep:=cStepGetJointsStr;

        END_IF;

       

   cStepGetJointsStr:

 

        IF OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bDone

              그리고 OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy가 아닙니다.

              그때

              iStep:=cStepGetJointsStrReset;

        ELSIF OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bError THEN

              iStep:=cStepGetJointsStrError;

        END_IF         

 

   cStepGetJointsStrReset:

 

   OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bError가 아닌 경우

              그리고 OPCUA_VirtualClient_RoboDK_Station.getJointsStr.bBusy가 아닙니다.

              그때

                   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

              그리고   

        OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy

         )

              또는 bWrite

              그때

              iStep:=cStepSetJointsStrReset;

        ELSIF OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError           

          그때

              iStep:=cStepSetJointsStrError;

        END_IF    

             

   cStepSetJointsStrReset:

        bWrite:=FALSE;

         OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bExecute:=FALSE;

        IF NOT OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bError

              그리고 OPCUA_VirtualClient_RoboDK_Station.setJointsStr.bBusy가 아닙니다.

              그때

              아이스텝:=c스텝엔드;

        END_IF;

       

   cStepEnd:

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

        IF TON.Q THEN

              ton(in:=false);

              디버그하지 않으면

                   iStep:=10;

              기타

                   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:=로봇_이름

);

 

 

OPCUA_VirtualClient_RoboDK_Station.getJoints(

bExecute:=iStep=cStepGetJoints

,Item_ID:=Item_ID,Joints=>arrJoints

);

 

 

OPCUA_VirtualClient_RoboDK_Station.getJointsStr(

bExecute:=iStep=cStepGetJointsStr

,로봇_이름:=로봇_이름,조인트=>strJoints

);

 

IF bWrite THEN

OPCUA_VirtualClient_RoboDK_Station.setJointsStr(

   bExecute:=TRUE

   ,로봇_이름:=로봇_이름,조인트:=strJointsCommand);

END_IF;

OPC UA 클라이언트 예제

이예제는 RoboDK에 OPC-UA 클라이언트연결을추가하는방법을보여줍니다. RoboDK에는 RoboDK 프로젝트에 OPC UA 호환성을추가할수있는 OPC-UA add-in이포함되어있습니다.

이예제에서는 OPC UA 클라이언트를통해 RoboDK Station에서데이터를가져오는방법을배웁니다.

OPC UA - 영상 63

스테이션매개변수화면이표시되면 '모두지우기'를눌러모든스테이션매개변수를삭제합니다.

OPC UA - 영상 64

인터페이스를 통한 구현

OPC UA 서버가구성되고시작된상태에서 RoboDK 프로젝트를하나더생성할수있습니다.

OPC UA - 영상 65

클라이언트 추가

이섹션에서는 OPC UA 클라이언트를추가하는방법을설명합니다.

엔드포인트 URL을입력합니다(예: opc.TCP://127.0.0.1:48441).

IP 주소및포트구성을 Target OPC UA 서버와일치시켜야합니다.

OPC UA - 영상 66

'연결'을눌러연결을설정합니다.

"서버변수가검색되었습니다."라는메시지가표시되면연결이설정된것입니다. 스테이션항목을마우스오른쪽버튼으로클릭하고 '스테이션매개변수'를선택하여변수를확인하세요."라는메시지가표시되면연결이설정됩니다.

OPC UA - 영상 67

스테이션을마우스오른쪽버튼으로클릭하고"스테이션매개변수"를선택합니다.

OPC UA - 영상 68

클라이언트 노드

노드 섹션에서각노드의세부정보를확인할수있습니다.

OPC UA - 영상 69

RoboDK API

RoboDK의 OPC UA 클라이언트를통해 OPC UA 서버에서노드데이터를가져온후, RoboDK-Python-API를사용하여이러한데이터를가져올수도있습니다.

설치

이링크를참조하여 RoboDK Python-API를설치할수있습니다.

https://robodk.com/doc/en/PythonAPI/intro.html#how-to-install

또는Python용 RobodK 패키지를수동으로설치하세요:

pip 설치 RobodK

스크립트

이예제스크립트는RoboDK의 Python API를통해스테이션파라미터를가져오는방법을보여줍니다.

robodk에서 로보링크 가져오기 # RoboDK API

 

RDK = robolink.Robolink()

 

robodk에서 가져 오기 * # RoboDK API

로보링크에서 가져오기 * # 로봇 도구 상자

itemlist = RDK.ItemList()

if 항목 목록:

    # 모든 스테이션 매개변수 가져오기

    print('Vaild 매개변수가 스테이션에 구성되었습니다...')

    StationParameters=RDK.getParams()

    를 스테이션 파라미터의 스테이션 파라미터로 설정합니다:

        print("스테이션 매개변수 %s : %s"%(StationParameter[0],str((StationParameter[1]))))

else:

    print('매개변수 목록 없음...')

다음은예제스크립트의결과입니다:

베일드매개변수는스테이션에서구성됩니다...

스테이션매개변수 RoboDK : RoboDK 64 비트 v5.5.3.23031.

스테이션매개변수시간 : 02/14/2023 03:58:29.191.000.000

스테이션파라미터시뮬레이션속도 : 13.8551

스테이션매개변수스테이션 : MyTestStation