[쉽고 간단한 안내서] TwinCAT 3으로 객체 지향 프로그래밍(OOP)하기

 

많은 사람들이 PLC 프로그램에 절차적 (Procedure Programming) 프로그래밍을 이용하여 프로그램을 작성하곤 했습니다. 절차적 프로그래밍은 말 그대로 절차적으로 코드를 구성합니다. 단순하게 순서에 맞춰서 프로그래밍을 한다고 볼 수 있습니다. IEC 61131-3 표준 중, ST언어의 기반이 되는 파스칼 또한 절차적 언어입니다.

점점 기술이 발전함에 따라 코드가 복잡해지면서 코딩한 사람이 코드를 읽고 이해하지 못하는 상황이 발생하게 됩니다. 이를 위해 객체 지향 프로그래밍 (Object-Oriented Programming, OOP) 등장하게 됩니다. 많은 사용자가 사용하는 JavaC#, C++같은 언어는 객체 지향 언어라는 특징을 갖고 있습니다. 객체지향 프로그래밍은 기능 별로 하나의 객체를 만들어서 프로그래밍을 하게 됩니다.

 


 <절차적 프로그래밍>



<객체 지향 프로그래밍>

 

PLC 프로그램에서 주로 사용하는 IEC 61131-3 표준 언어들은 객체 지향 프로그래밍을 할 수 있습니다. 객체 지향 프로그래밍을 하게 되면 코드를 쉽게 재사용할 수 있으며, 유지보수가 용이하고 코드의 품질을 향상시킬 수 있습니다. TwinCAT 3도 마찬가지로 객체 지향 프로그래밍을 지원하고 있습니다. 이번에는 TwinCAT 3에서 객체 지향 프로그래밍 하는 방법에 대해 다루도록 하겠습니다.

 

객체 지향 프로그래밍에 대해

앞서 언급하였듯 객체 지향 프로그래밍은 기능 별로 객체를 나눠서 프로그래밍을 합니다. 하드웨어 모듈 혹은 기능 단위로 객체를 나눌 수 있습니다. 객체를 조합하여 하나의 어플리케이션을 만들 수 있습니다. 이러한 객체들은 사용자가 정한 인터페이스를 통해 서로 간에 데이터를 주고받게 됩니다.

 

객체 지향 프로그래밍은 '유연성'이 중요합니다. 유연성을 가지기 위해서 객체 지향의 특징 4가지인 캡슐화, 상속, 추상화, 다형성을 이용하게 됩니다.

특징

설명

캡슐화(Encapsulation)

관련 있는 변수와 함수를 클래스로 묶되, 클래스에 들어가는 내용 중 중요한 내용이나 기능을 외부에서 접근하지 못하도록 '정보 은닉'을 할 수 있다.

상속(Inheritance)

자식(하위, 파생) 클래스가 부모(상위) 클래스의 멤버를 물려받아서 확장할 수 있다.

추상화(Abstraction)

공통적인 기능 및 속성을 묶어서 이름을 지정한다.

다형성(Polymorphism)

부모(상위) 클래스와 자식(하위, 파생) 클래스가 동일하게 받은 요청을 다르게 처리할 수 있다.

 

객체 지향 프로그래밍을 하게 되면 명확하고 구조화된 어플리케이션을 개발할 수 있게 됩니다. 정리하면 재사용성, 시간 및 비용 절감, 가독성, 확장성, 유연성 등의 이유로 객체 지향 프로그래밍을 사용합니다.

 

일반적으로 객체를 만들기 전에 클래스 (Class)를 만들게 됩니다. 클래스를 만들 때는 먼저, 추상화된 클래스가 어떠한 데이터와 기능을 포함할지 계획해야 합니다. 예를 들어 사각형이라는 클래스를 만든다고 가정하면, 사각형의 길이와 높이라는 데이터를 갖고 있고 이를 통해 넓이를 계산해주는 기능을 갖고 있습니다. 이렇게 클래스를 통해 객체를 잘 정의했다면 크기가 다른 사각형이 있더라도 같은 기능 (넓이 계산)을 구현할 수 있습니다.

 

TwinCAT 3에서는 Function Block, 메소드 (Method), 속성 (Properties), 상속 (Inheritance), 인터페이스 (Interface)를 통해서 객체 지향 프로그래밍을 지원합니다. TwinCAT 3에서 지원하는 각 요소를 살펴보도록 하겠습니다.


Function Block

TwinCAT에서는 Function Block을 실제 프로그램에서 많이 사용하고 있습니다. Function Block은 입력 및 출력 변수를 통해 데이터를 교환하고, 실행하면서 하나 혹은 여러 개의 값을 반환하는 POU (Program Organization Unit)입니다.  일반적으로 객체 지향 프로그래밍에서 말하는 '클래스 (Class)'TwinCAT 3에서는 Function Block이 그 역할을 합니다. Function Block의 내부는 POU와 마찬가지로 변수 선언 부분과 구현 부분으로 나뉘어져 있습니다.



참고로 PLC 프로젝트 안에서 POU를 추가할 때 Function Block를 생성할 수 있습니다. 하단부분에서 언어를 선택할 수 있으며, 아래 이미지에서는 ST언어로 선택된 것을 확인할 수 있습니다.



Function Block에서 사용할 수 있는 기능들을 통해 TwinCAT 3에서 클래스를 만들 수 있습니다. 로컬 변수와 속성 (Properties)을 이용하여 외부로부터 데이터를 안전하게 보호하는 캡슐화를 할 수 있으며, 내부기능 사용을 위한 메소드 (Method)를 활용할 수도 있습니다. 또한 FB_Init, FB_Exit 등과 같은 생성자와 파괴자를 통해 내부 데이터를 초기화 할 수도 있습니다. 또한 Function BlockFunction Block 형태를 복사한 인스턴스 형태로 호출하게 됩니다.

이러한 기능들을 세부적으로 하나씩 살펴보도록 하겠습니다.

 

메소드(Method)


이러한 아이콘을 사용하는 메소드는 사용자가 객체를 '무엇을' 하도록 만들 때 호출합니다. 예를 들어, 자동차는 '가속', '브레이크', '시동 켜기' 등이 메소드가 될 수 있습니다. 메소드는 단순하게 프로그램 구현 부분을 나눌 때 사용하는 Action과 비슷하지만 다른 점도 있습니다. 메소드는 입력 및 출력 변수를 선언할 수 있습니다. 또한 실행하면서 반환 값 (Result value)를 받을 수 있으며 PUBLIC, PROTECTED, INTERNAL과 같은 접근 권한을 설정할 수 있습니다. 메소드의 모든 데이터는 임시적이기 때문에 메소드가 실행되는 동안에만 유효합니다. , TwinCAT은 메소드에서 선언한 모든 변수와 Function Block을 메소드가 호출될 때마다 다시 초기화 합니다.

 

Function Block를 마우스 오른쪽 클릭한 후 Add를 통해 메소드를 추가할 수 있습니다. 반환 값으로 받을 데이터 타입을 선택할 수 있으며, Function Block과 마찬가지로 언어도 선택할 수 있습니다.

 



 

메소드를 생성한 후 PLC 프로젝트 트리에서 확인하면 Function Block에 메소드가 속한 것을 확인할 수 있습니다.

 

메소드 또한 변수 선언 부분과 구현 부분으로 나뉩니다. 위에서 예제로 생성한 FB_Rectangle 하단에 CalcuateArea라는 메소드가 속해 있기 때문에 nLengthnWidth라는 변수는 FB_Rectangle와 함께 사용합니다.


속성(Property)


 속성은 객체의 '특성'입니다. 예를 들어, 자동차의 '색상'과 같은 것들이 속성이 될 수 있습니다. 자동차의 색상은 아무런 일을 하지 않으며, 각 자동차마다 고유의 특징을 갖는 자동차 번호판과 다르게 자동차 별로 중복될 수 있습니다. 속성은 데이터에 대한 외부의 접근을 허용함과 동시에 필터역할을 합니다. 이러한 기능을 통해서 데이터를 캡슐화하고 잘못된 접근을 차단하여 데이터를 보호할 수 있습니다.

Function Block를 마우스 오른쪽 클릭한 후 Add를 통해 속성 추가할 수 있습니다. 반환 값으로 받을 데이터 타입을 선택할 수 있으며, 언어도 선택할 수 있습니다.

 

 




속성을 생성한 후 PLC 프로젝트 트리에서 확인하면 Function Block에 메소드가 속한 것을 확인할 수 있습니다. 속성의 하위에는 GetSet이 자동으로 생성됩니다.

 

속성 자체는 아무런 내용 없이 생성만해도 사용할 수 있습니다. Function Block에서 속성을 사용할 때 내부의 값을 Get을 통해서 읽을 수 있으며, Set을 통해 내부로 값을 쓸 수 있습니다. 만약 Get을 삭제할 경우 쓰기 전용으로 설정되고 Set을 삭제하면 읽기 전용이 됩니다. 속성 또한 메소드와 마찬가지로 PUBLIC, PROTECTED, INTERNAL과 같은 접근 권한을 설정할 수 있습니다.

 

생성자와 파괴자

생성자와 파괴자인 'FB_init', 'FB_reinit', 'FB_exit'는 객체의 초기화, 복사, 종료를 위해 사용합니다. FB_Init은 해당 객체가 생성될 때 암묵적으로 해당 메소드 안에 있는 코드가 실행됩니다. 이는 PLC 시작 전에 우선적으로 호출됩니다. 물론 명시적으로 실행 시점을 코드로 입력할 수도 있습니다.  FB_reinit은 프로그램이 처음 시작할 때 호출되지 않으며, Function Block의 선언이 변경되거나 인스턴스가 'Online Change'로 복사되었을 때 호출됩니다. 마지막으로 FB_exit은 다시 초기화 할 수 있도록 만듭니다. 변경되거나 삭제된 인스턴스에 대한 다운로드 및 재설정 시에 호출하여 이용합니다.

 


메소드를 FB_init, FB_reinit, FB_exit로 생성하며 당연히 Function Blcok에 속한 것을 확인할 수 있습니다.

 

THISSUPER

Function Block에서 사용할 수 있는 키워드에는 THISSUPER가 있습니다. THIS는 파생된 객체와 원본 객체의 방법 혹은 속성을 구별할 때 사용합니다. 예를 들어, 오토바이가 객체인 경우 오토바이의 '가속 방법'을 참조하기 위해 자동차의 THIS 포인터가 사용됩니다. SUPERTHIS와 반대로 원본 객체의 방법이나 속성을 가리킵니다. 예를 들어, 원본 객체인 자동차의 '가속 방법'을 사용할 때 오토바이의 '가속 방법'과 구별하는 데 사용합니다.



 

상속(Inheritance)과 확장(Extension)

TwinCAT 3에서 Function Block, 즉 클래스의 상속은 확장이라고 표현합니다. 상속 및 확장이라는 개념은 객체 지향 프로그래밍에서 매우 중요한 요소입니다. 상속은 말 그대로 기존 클래스가 갖고 있던 메소드, 속성들을 물려받는 것을 의미하며 부모와 자식으로 표현하곤 합니다. 이 때 기존 클래스를 부모 클래스 (Parent class), 기반 클래스 (Base class), 상위 클래스 (Super class)라고 표현하며 상속받는 클래스는 자식 클래스 (Child class), 파생 클래스 (Derived class), 하위 클래스 (Subclass)라고 표현합니다. 상속을 하면 기존 클래스를 물려받기 때문에 소프트웨어의 재사용이라는 개념을 적용할 수 있습니다.

예를 들어 기존에 만든 자동차라는 클래스가 있다고 가정하고 트럭이라는 클래스를 새로 만들려고 합니다. 트럭은 자동차의 확장된 형태로 볼 수 있습니다. 자동차와 동일하게 '시동 켜기', '가속하기' 등의 기능을 갖고 있으므로 트럭을 사용할 때 자동차의 기능을 그대로 가져와서 이용할 수 있습니다. 여기서 자동차라는 클래스는 부모 클래스이며 트럭은 자식 클래스가 됩니다. 아래 이미지처럼 자동차라는 부모 클래스 안에 전기차, 가솔린차, 디젤차라는 자식 클래스를 둘 수 있습니다.





TwinCAT 3에서 상속을 할 때에는 'EXTENDS'라는 확장자를 이용하여 구현할 수 있습니다. 부모 클래스는 자식 클래스에게 변수, 메소드, 속성을 상속받으며 PUBLIC, PROTECTED, INTERNAL과 같은 접근권한을 설정하여 상속을 할 수 있습니다. 아래 이미지처럼 POU에서 Function Block을 생성할 때 확장을 이용할 수 있습니다. FB_SampleEx FB_Sample을 확장하게 됩니다.



생성한 후 선언 부분을 보게 되면 'FUNCTION_BLOCK FB_Sample EXTENDS FB_SampleEx'으로 된 것을 확인할 수 있습니다.



이러한 확장 기능을 사용할 때, Function Block의 확장 수는 무제한입니다. 하나의 Function Block은 여러 개의 다른 Function Block으로 확장할 수 있습니다. 상속 또한 무제한이지만, 다중 상속은 사용할 수 없습니다.

 

메소드의 상속

메소드를 상속 받을 때의 특징을 알아보도록 하겠습니다. 우선, 자식 클래스가 상속 받는 메소드는 '추가나 변경 없이도 그대로 사용할 수 있습니다'. 아래처럼 FB_BaseClass를 상속 받은 FB_SubClassFB_BaseClass의 메소드인 'ExcuteProcess'가 보이지 않는 것을 확인할 수 있습니다. FB_SubClass를 사용할 때 ExcuteProcess라는 메소드를 그대로 사용할 수 있습니다.



 

상속받은 메소드는 '오버라이트 (Overwrite)' 할 수 있습니다. 오버라이트는 클래스의 메소드나 속성을 구현할 때 같은 작업을 하지만, 다른 방식으로 동작하는 것을 의미합니다. 예를 들어, '가속'이라는 작업을 할 때 자동차는 엑셀을 밟는 동작으로 가속하지만 오토바이는 핸들 바를 움직이는 동작으로 가속하게 됩니다. '가속'이라는 작업은 같지만 방법이 다를 때 오버라이트를 하게 됩니다.

 

아래와 같이 FB_BaseClass에 이미 구현되어 있는 ExcuteProcess라는 메소드를 FB_SubClass에도 구현한 것을 확인할 수 있습니다. 이 때, ExcuteProcess라는 메소드의 이름은 같지만 내부 코드는 다릅니다. 이렇게 메소드를 다시 정의할 수도 있습니다.





마지막으로 메소드도 '확장'할 수 있습니다. FB_SubClassExcuteProcess라는 메소드를 오버라이트하여 다시 정의했지만, 'Super'이라는 키워드를 이용하여 FB_BaseClass에 있는 메소드를 접근할 수 있습니다. 아래 코드에서 보듯, SUPER 키워드를 이용해 FB_BaseClass에 있는 메소드를 사용하여 결과 값을 반환하고 있습니다.




인터페이스 (Interface)

인터페이스는 어떤 기능을 할지 정하지 않고, 비슷한 기능을 모아서 어떻게 만들 것인지 추상적으로 선언하는 것을 의미합니다. 하나의 부모 클래스에 속하기에는 너무 다른 속성들을 가진 클래스를 사용할 때 이런 인터페이스를 활용하고는 합니다. 인터페이스를 사용하면 Function Block이 어떤 요소를 갖고 있는지 보증할 수 있습니다. 또한 프로그램이 유연해지고 하드웨어를 추상화할 수 있으며, 캡슐화 또한 가능하게 해줍니다.

 

TwinCAT 3의 인터페이스는 메소드와 속성의 프로토타입 (prototype)으로 표현합니다. 프로토타입은 단순하게 선언 부분으로만 이루어져 있으며, 메소드와 속성의 구현 부분은 없다는 것을 의미합니다. 또한 인터페이스는 Function Block이 어떤 것을 구현할 수 있는지 정의합니다. 인터페이스를 통해 공통된 속성을 가진 다른 Function Block을 동일한 방식으로 사용할 수 있습니다.

 

인터페이스 또한 POU처럼 생성합니다. 인터페이스도 상속 및 확장을 사용할 수 있는 것을 확인할 수 있습니다.



 

인터페이스를 생성한 후, 메소드나 속성을 선언할 수 있습니다. 하지만 인터페이스에 선언된 메소드나 속성은 실제로 무언가 동작하는 구현 부분이 없기 때문에 Function Block을 선언해주어야 합니다. 이 때 Keyword ImplementsFunction Block을 선언하고 그 안에 기능을 구현합니다.

 


인터페이스와 Function Block을 인스턴스화 하기 위해 프로그램에 선언합니다. 이 후 인터페이스가 가리키는 Function Block을 대입연산자인 ':='을 통해 할당합니다. 이렇게 할당까지 하면 다음부터는 Function Block을 직접 선언하고 호출하는 것이 아니라, 인터페이스를 불러와서 그 안에 있는 메소드나 속성을 사용합니다. 아래 예시를 보면, fbRectangleA iRectanble에 할당한 후, iRectangle라는 인터페이스를 사용하면 메소드를 바로 불러오는 것을 확인할 수 있습니다.





 

마치며

TwinCAT 3으로도 객체 지향 프로그래밍을 할 수 있고, 그에 대한 요소들을 살펴보았습니다. 객체 지향 프로그래밍은 PLC 언어의 표준이 정의되어 있는 IEC61131-3에도 기준이 포함되어 있습니다. 기존에 C++, Java와 같은 상위 프로그램을 사용했던 분들은 더욱 쉽게 PLC 언어에 적응할 수 있을 것 같습니다.

 

객체 지향 프로그래밍은 위에서 언급하였듯 코드를 재사용하기 용이하며, 품질을 향상시킬 수 있는 요소입니다. TwinCAT에서는 Function Block을 통해서 다양한 시퀀스를 구현하기 때문에, 객체 지향 프로그래밍을 이용하여 보다 구조화된 어플리케이션을 개발하는데 도움이 되었으면 합니다. 객체 지향 프로그래밍에 대한 추가적인 샘플은 [링크]를 통해서도 확인할 수 있습니다.

 

 

내용에 대해 심화 내용이 필요하신 경우, 해당 내용을 댓글로 적어 주시면 다음 연재 시 반영하도록 하겠습니다.

 

문의사항은 아래 연락처로 연락 부탁드립니다.

전화 : 02-2107-3242 (대표전화, 내선번호 1: 영업 및 마케팅, 내선번호 2: 기술)

홈페이지 : https://www.beckhoff.com/kr/

제품문의 : Info-KR@beckhoff.com

기술문의 : support-kr@beckhoff.com

 

참고자료

Object-oriented programming [링크]

 

 

 

본 문서의 무단전재 및 재배포를 금지합니다

본 문서는 공식 매뉴얼이 아닌, 교육용 참고자료임을 명시합니다


2021.07.09

작성자: Beckhoff Korea / Lisa Kim

댓글

이 블로그의 인기 게시물

[IPC 메뉴얼] BECKHOFF PC 기본 설정 방법

트라이텍, EtherCAT과 DeviceNet [월간CONTROL 2013/11]

[쉽고 간단한 안내서] TwinCAT PLC HMI와 TwinCAT HMI