February 27, 2021

디바이스마트 미디어:

디바이스마트 국내 온라인 유통사 유일 벨로다인 라이다 공급! -

2021-02-16

★총 상금 500만원 /2021 ICT 융합 프로젝트 공모전★ -

2021-01-18

디바이스마트 온라인 매거진 전자책(PDF)이 무료! -

2020-09-29

[61호]음성으로 제어하는 간접등 만들기 -

2020-08-26

디바이스마트 자체제작 코딩키트 ‘코딩 도담도담’ 출시 -

2020-08-10

GGM AC모터 대량등록! -

2020-07-10

[60호]초소형 레이더 MDR, 어떻게 제어하고 활용하나 -

2020-06-30

[60호]NANO 33 IoT보드를 활용한 블루투스 수평계 만들기 -

2020-06-30

라즈베리파이3가 드디어 출시!!! (Now Raspberry Pi 3 is Coming!!) -

2016-02-29

MoonWalker Actuator 판매개시!! -

2015-08-27

디바이스마트 레이저가공, 밀링, 선반, 라우터 등 커스텀서비스 견적요청 방법 설명동영상 입니다. -

2015-06-09

디바이스마트와 인텔®이 함께하는 IoT 경진대회! -

2015-05-19

드디어 adafruit도 디바이스마트에서 쉽고 저렴하게 !! -

2015-03-25

[29호] Intel Edison Review -

2015-03-10

Pololu 공식 Distributor 디바이스마트, Pololu 상품 판매 개시!! -

2015-03-09

[칩센]블루투스 전 제품 10%가격할인!! -

2015-02-02

[Arduino]Uno(R3) 구입시 37종 센서키트 할인이벤트!! -

2015-02-02

[M.A.I]Ahram_ISP_V1.5 60개 한정수량 할인이벤트!! -

2015-02-02

[디웰전자] 전류센서 파격할인!! 50% 할인이벤트!! -

2015-02-02

[에스엔에스] 신상품 대량 입고기념 할인이벤트!! -

2015-02-02

MoonWalker Series Motor Controllers User’s Manual 13. 통신 프로토콜

MW001

MoonWalker Series

Motor Controllers

User’s Manual

MW-MDC24D100S / MW-MDC24D100D

MW-MDC24D200S / MW-MDC24D200D

MW-MDC24D500S / MW-MDC24D500D

 ※ 사용자 매뉴얼에 포함된 정보는 정확하고 신뢰성이 있는 내용입니다. 그러나 출판 당시 발견되지 않은 오류가 있을 수 있으니 사용자는 자신의 제품 검증을 수행하시기 바라며, 전적으로 사용자 매뉴얼에 포함된 정보에 의존하지 마시기 바랍니다.

 

13. 통신 프로토콜

이 장에서는 PC나 마이크로컨트롤러에서 제어기의 오브젝트 값을 읽고 쓰기 위한 통신 프로토콜에 대해 설명합니다. 제어기에 동작을 명령하거나 제어기의 구성 파라미터를 설정하는 것은 해당 오브젝트에 특정 값을 쓰는 것을 의미하며, 제어기의 상태를 읽거나 제어기의 구성 파라미터를 읽는 것은 해당 오브젝트에서 특정 값을 읽는 것을 의미합니다.
통신 프로토콜은 크게 CAN 포트에서 사용되는 프로토콜과 시리얼(USB, RS-232) 포트에서 사용되는 프로토콜로 구분됩니다. 시리얼 포트 프로토콜은 다시 패킷의 구조에 따라 바이너리(binary) 형태와 텍스트(text) 형태로 구분됩니다.

13.1 용어의 정의

제어기의 객체를 통신 프로토콜로 읽고 쓰는데 사용되는 용어를 표 13‑1에서 정의합니다.

표 13‑1 통신 프로토콜에 사용되는 용어

Term Description
Index 오브젝트의 참조 색인
Sub-index 오브젝트의 참조 부-색인
Short Name Index와 호환되는 오브젝트의 짧은 이름
Long Name Index와 호환되는 오브젝트의 긴 이름

상기 표에서 사용되는 용어 중 Index, Short Name, Long Name은 오브젝트를 표현하는 방식의 차이입니다. Index는 제어기 내부의 오브젝트를 참조하는 색인으로, CAN 및 시리얼 바이너리 패킷에서 사용됩니다.

Sub-index는 오브젝트를 참조하는 부-색인으로, 통상 모터의 채널 번호를 의미합니다. 채널 1에 연결된 모터에 대한 명령이나 설정이라면 Sub-index로 1을, 채널 2에 연결된 모터의 경우는 2를 사용하면 됩니다. 연결된 모터가 아니라 제어기 자체에 대한 것이라면 통상 Sub-index는 0이 됩니다. Sub-index는 상황에 따라 외부 I/O의 채널 번호가 되기도 합니다.

Short Name과 Long Name은 Index와 호환되는 오브젝트의 짧은 이름과 긴 이름으로, 시리얼 텍스트 패킷에서 사용됩니다. 이 이름은 제어기 내부에서 Index 값으로 변환되어 Index와 동일하게 사용됩니다.

만약 사용자가 제어기에 인가된 주 전원의 전압을 체크하는 ‘Battery Voltage’오브젝트의 내용을 읽고자 할 때, 시리얼 텍스트 기반으로 통신하는 경우, 해당 오브젝트의 Short Name인 bv나 Long Name인 battery_voltage를 사용하면 됩니다. CAN이나 시리얼 바이너리 패킷 통신을 사용하는 경우는 해당 오브젝트의 Index인 8을 사용하면 됩니다.

표 13‑1에서는 오브젝트의 4가지 속성을 보여줍니다. 각각의 오브젝트 타입에 따라 패킷의 길이가 달라질 수 있습니다.

표 13‑2 오브젝트의 타입

Object Type Size Description
INT8 1byte 부호를 가지는 8 bit 정수형
INT16 2bytes 부호를 가지는 16 bit 정수형
INT32 4bytes 부호를 가지는 32 bit 정수형
FLOAT 4bytes 부호를 가지는 32 bit 실수형

또한, 표 13‑2에서는 오브젝트의 엑세스 속성을 나타냅니다. RO로 표시된 오브젝트는 읽기 전용으로 상수(Constant)와 상태(Status) 오브젝트가 여기에 해당하며, 값을 쓰려고 할 때 에러를 리턴할 것입니다. WO로 표시된 오브젝트는 쓰기 전용으로 명령(Command) 오브젝트가 여기에 해당하며, 값을 읽으려고 할 때 에러를 리턴할 것입니다. RW로 표시된 오브젝트는 구성 파라미터(Configuration Parameter)와 변수(Variable) 오브젝트가 여기에 해당합니다.

표 13‑3 오브젝트의 엑세스 속성

Access Object Description
RO Constant, Status 읽기 전용 (Read Only)
WO Command 쓰기 전용 (Write Only)
RW Configuration Parameter, Variable 읽고 쓰기 가능 (Read Writeable)

 

13.2 CAN 메시지

제어기의 구성 파라미터(Configuration Parameter)를 설정하고 명령(Command)을 내리거나 상태(Status)를 읽기 위해서 제어기에 존재하는 여러 오브젝트들을 CAN 통신으로 엑세스 할 수 있습니다. 이 절은 제어기에 존재하는 오브젝트들을 엑세스하기 위한 CAN 통신의 메시지 구조에 대해 기술합니다.

※ 마스터 PC와 제어기가 CAN 버스에 연결되어 통신하기 위해서는, 네트워크에 연결된 모든 노드의 통신 속도가 일치해야 하고 각각의 장치 ID는 모두 달라야 합니다.

13.2.1 CAN 패킷의 기본 구조

마스터 PC와 제어기 간에 CAN 통신으로 주고받는 패킷의 주요 구성 요소는 Node ID와 메시지의 길이(Length) 그리고 전송되는 메시지(Message)가 됩니다(아래 그림 참조).

Node ID Length Message
11bit 0~8 0 ~ 8byte

Node ID로는 최대 11bit를 설정할 수 있는데, 제어기의 ‘Device ID’가 여기에 사용됩니다. 마스터에서 장치로 CAN 메시지를 보내거나 장치가 마스터로 회신 할 때, Node ID에는 장치 ID가 동일하게 지정되어야 합니다. Length는 메시지(Message)의 길이를 나타내는데, 메시지의 최대 크기가 8byte 이므로 0에서 8사이의 값이 됩니다. 메시지에는 전송되는 데이터를 담습니다.

다음 그림은 메시지(Message)의 기본 구조를 나타냅니다. 메시지는 최대 8byte 크기를 가질 수 있으며, 1byte의 Command와 2byte의 Index, 1byte의 Sub-index와 나머지는 상황에 맞는 오브젝트의 값(Value)으로 구성되어 있습니다. 상황에 따라 5th ~ 8th byte 지점의 값들은 존재할 수도 있고 아닐 수도 있습니다. 만약 5th byte 지점까지만 파라미터가 존재한다면 5th byte까지의 내용만 전송하면 됩니다.

1st byte 2nd byte 3rd byte 4th byte 5th byte 6th byte 7th byte 8th byte
Command Index Sub-index Value

여기서 Command는 표 13‑4과 같은 액세스 형식(Access Code)과 오브젝트 형식(Object Type)의 조합으로 1byte를 구성하게 됩니다.

표 13‑4 액세스 형식(Access Code)과 오브젝트 형식(Object Type)

구분 코드 내용
Access Code 0×10 오브젝트 쓰기 요청
0×20 오브젝트 쓰기 요청에 대한 응답
0×30 오브젝트 읽기 요청
0×40 오브젝트 읽기 요청에 대한 응답
0×80 오브젝트 읽기/쓰기 요청에 대한 에러 응답
Object Type 0×00 INT8 – 8 bit signed integer
0×04 INT16 – 16 bit signed integer
0×08 INT32 – 32 bit signed integer
0x0C FLOAT – 32 bit IEEE Standard 754 floating-point

Index나 Value와 같이 한 바이트 이상의 데이터가 메시지에 저장될 때는 데이터의 하위 바이트부터 왼쪽에 저장되는 리틀 인디안(Little-Endian)방식을 따릅니다.

 

13.2.2 오브젝트 읽기 요청

마스터 PC가 제어기의 오브젝트를 읽기 위해, 마스터 PC가 제어기에 보내는 쿼리 패킷을 구성합니다.
오브젝트의 값을 읽을 때는 표 13‑4의 Access Code 0x30과 읽고자 하는 Object Type을 조합해서 Command를 먼저 구성해야 합니다. 읽고자 하는 오브젝트의 형이 INT16 이라면 Command에는 0x34를 사용합니다.

1st byte 2nd byte 3rd byte 4th byte 5th byte 6th byte 7th byte 8th byte
Command Index Sub-index

 

13.2.3 오브젝트 쓰기 요청

마스터 PC가 제어기의 오브젝트에 값을 쓰기 위해, 마스터 PC가 제어기에 보내는 쿼리를 구성합니다.
오브젝트에 값을 쓸 때는, 4th byte 지점 까지는 오브젝트 읽기 요청과 동일하게 구성합니다. 단, Command는 표 13‑4의 Access Code에 의해 0x10과 Object Type에 맞는 조합으로 작성되어야 하며, 그 형식에 맞춰 오브젝트의 값(Value)을 작성합니다.

1st byte 2nd byte 3rd byte 4th byte 5th byte 6th byte 7th byte 8th byte
Command Index Sub-index Value(INT8)
Value(INT16)
Value(INT32)
Value(FLOAT)

 

13.2.4 오브젝트 읽기/쓰기 요청에 대한 성공 응답

제어기가 마스터 PC의 오브젝트 읽기/쓰기 요청에 응답하기 위해, 제어기가 마스터 PC에 보내는 응답 패킷을 구성합니다.
오브젝트의 값을 읽거나 쓰기가 성공한 경우에는 오브젝트의 값(Value)이 응답으로 돌아옵니다. 패킷의 구성은 오브젝트 쓰기 요청에서와 같습니다. 단, Command는 표 13‑4의 Access Code에 제시된 것처럼 0x20이나 0x40중 하나와 Object Type에 맞는 조합으로 작성됩니다.

1st byte 2nd byte 3rd byte 4th byte 5th byte 6th byte 7th byte 8th byte
Command Index Sub-index Value(INT8)
Value(INT16)
Value(INT32)
Value(FLOAT)

※ 제어기는 사용자가 쓴 값이 적용되지 않을 수 있기 때문에 사용자의 오브젝트를 읽는 요청뿐만 아니라 오브젝트에 쓰기 요청에 대해서도 해당 오브젝트의 값을 응답합니다.

13.2.5 오브젝트 읽기/쓰기 요청에 대한 실패 응답

제어기가 마스터 PC의 오브젝트 읽기/쓰기 요청에 실패를 알리기 위해, 제어기가 마스터 PC에 보내는 실패 응답 패킷을 구성합니다.
오브젝트의 내용을 읽거나 쓰기 위한 패킷을 제어기에 요청했을 때, 오류가 발생하는 경우는 다음 그림과 같은 형식의 오류 패킷이 돌아옵니다.

1st byte 2nd byte 3rd byte 4th byte 5th byte 6th byte 7th byte 8th byte
Command Error Code

오류 메시지는 표 13‑5에 나타나 있습니다. CAN 패킷에서 오류 메시지 내용은 전달되지 않으며 Error Code만 반환됩니다. 그리고 Command는 0x80이 반환됩니다.

표 13‑5 오브젝트의 읽기/쓰기 과정에서 발생하는 오류

Error Code Error Message 내용
1 undefined index Index나 Sub-index로 지정한 오브젝트가 존재하지 않음
2 packet format error 패킷의 구성이 잘못 되었음
3 variable access error 읽기 전용 오브젝트에 쓰거나, 쓰기 전용 오브젝트의 읽기를 시도함

※ 본 절의 오류 메시지는 패킷의 구성에 관련된 오류로 제어기의 오류 상황이나 오작동에 대한 부분이 아닙니다.

 

13.3 시리얼 바이너리 패킷

제어기의 오브젝트들은 시리얼(USB나 RS-232) 통신으로도 읽고 쓰기가 가능합니다. 시리얼 통신은 텍스트 기반의 패킷과 함께 바이너리 기반의 패킷 통신을 함께 지원합니다.

이 절은 제어기에 존재하는 오브젝트들을 엑세스하기 위한 시리얼 통신의 바이너리 패킷 구조에 관해 설명합니다.

13.3.1 바이너리 패킷의 기본 구조

바이너리 패킷의 메시지 구조는 CAN 패킷에서 사용되는 메시지 구조와 동일합니다. 단 CAN에서는 Object Type에 따라 패킷의 길이가 바뀌지만, 바이너리 패킷 구조에서는 Value의 최대 길이를 4byte로 고정하고 패킷 전체 길이를 13byte로 고정합니다.

1st byte 2nd byte 3rd byte 4th ~ 11th byte 12th byte 13th byte
STX (0×02) Length (=13) Device ID Message Checksum ETX (0×03)

상기 그림에서 처음과 끝의 STX, ETX는 시작과 끝을 의미하는 문자입니다. 그리고 Length는 13으로 고정되어 있습니다.

Checksum은 3rd ~ 11th byte 지점 까지를 바이트 단위로 더한 후 결과에서 1byte만 취한 값입니다. 다음은 C언어로 작성된 Checksum 계산 예제 코드입니다:

char Checksum (char *msg, int len)
{

char cs = 0;

for (int i=0; i<len; ++i)<br=”"> cs += msg[i];
return cs;

}

4th ~ 11th byte 영역의 Message는 CAN 통신에서의 메시지 구조와 동일합니다. 단 CAN은 8byte의 메시지를 모두 채우지 않아도 되지만, 시리얼 바이너리 패킷에서는 8byte의 메시지를 모두 채워야 합니다. 만약 메시지의 크기가 8byte가 되지 않는다면, 남는 공간에 0을 채우면 됩니다.

시리얼 바이너리 패킷에서도 CAN 패킷에서와 같이 리틀 인디안(Little-Endian)방식으로 패킷을 구성합니다.

13.3.2 오브젝트 읽기 요청

오브젝트의 값을 읽을 때는, 패킷의 4th ~ 11th byte 지점에 위치하는 Message를 아래와 같이 구성하면 됩니다. Command는 표 13‑4의 Access Code 0x30과 읽고자 하는 Object Type을 조합해서 Command를 먼저 구성해야 합니다.

4th byte 5th byte 6th byte 7th byte 8th byte 9th byte 10th byte 11th byte
Command Index Sub-index 0 0 0 0

 

13.3.3 오브젝트 쓰기 요청

오브젝트에 값을 쓸 때는, 7th byte 지점 까지는 오브젝트 읽기 요청과 동일하게 구성합니다. 단 Command는 표 13‑4의 Access Code에 의해 0x10과 오브젝트 형에 맞는 조합으로 작성되어야 하며, 그 형식에 맞춰 오브젝트의 값(Value)을 작성합니다.

4th byte 5th byte 6th byte 7th byte 8th byte 9th byte 10th byte 11th byte
Command Index Sub-index Value(INT8) 0 0 0
Value(INT16) 0 0
Value(INT32)
Value(FLOAT)

 

13.3.4 오브젝트 읽기/쓰기 요청에 대한 성공 응답

오브젝트의 값을 읽거나 쓰기가 성공한 경우에는 오브젝트의 값(Value)이 응답으로 돌아옵니다. 패킷의 구성은 오브젝트 쓰기 요청에서와 같습니다. 단, Command는 표 13‑4의 Access Code에 제시된 것처럼 0x20이나 0x40중 하나와 Object Type에 맞는 조합으로 작성됩니다.

4th byte 5th byte 6th byte 7th byte 8th byte 9th byte 10th byte 11th byte
Command Index Sub-index Value(INT8) 0 0 0
Value(INT16) 0 0
Value(INT32)
Value(FLOAT)

제어기는 사용자가 쓴 값이 적용되지 않을 수 있기 때문에 사용자의 오브젝트를 읽는 요청뿐만 아니라 오브젝트에 쓰기 요청에 대해서도 해당 오브젝트의 값을 응답합니다.

13.3.5 오브젝트 읽기/쓰기 요청에 대한 실패 응답

오브젝트의 내용을 읽거나 쓰기 위한 패킷을 제어기에 요청했을 때, 오류가 발생하는 경우는 다음 그림과 같은 형식의 오류 패킷이 돌아옵니다.

4th byte 5th byte 6th byte 7th byte 8th byte 9th byte 10th byte 11th byte
Command Error Code 0 0 0  0 0

오류 메시지는 표 13‑5에 나타나 있습니다. 시리얼 바이너리 패킷에서 오류 메시지 내용은 전달되지 않으며 Error Code만 반환됩니다. 그리고 Command는 0x80이 반환됩니다.

※ 오류 메시지는 패킷의 구성에 관련된 오류로 제어기의 오류 상황이나 오작동에 대한 부분이 아닙니다.

 

13.4 시리얼 텍스트 패킷

시리얼(USB나 RS-232) 통신에서는 텍스트(text) 기반으로 제어기의 오브젝트를 읽고 쓸 수 있도록 합니다. 이는 사용자가 통신을 위한 전용 프로그램을 사용하지 않더라도 Hyperterminal과 같은 유틸리티를 사용하여 제어기의 오브젝트들을 쉽게 엑세스 할 수 있도록 합니다.
시리얼 텍스트 기반 패킷에서는 Index를 직접적으로 사용하지 않고 표 13‑1의 Short Name이나 Long Name과 Sub-index를 사용합니다.

13.4.1 오브젝트 읽기 요청

오브젝트 값을 읽을 때는 텍스트 패킷을 다음과 같이 구성합니다.

Short/Long Name Sub-index CR/LF

Short/Long Name은 오브젝트의 Index에 해당하는 이름이며, Sub-index는 해당 Index에 따라 필요하면 모터 채널 혹은 외부 I/O의 채널을 의미합니다. Sub-index가 0인 경우 생략 가능합니다.
CR/LF는 Carriage Return/Line Feed의 약자로 ASCII 코드상 각각 0x0D, 0x0A입니다. 일반적으로는 키보드의 Enter 키에 해당하며 하이퍼터미널과 같은 유틸리티로 PC에서 연결했다면 명령 입력 후 Enter 키를 입력하는 것입니다. (이후 CR/LF를 ↵기호로 대체)
만약 채널 1에 연결된 모터에 내려진 전압 명령의 값을 알고자 할 때는 아래와 같이 입력합니다.

voltage_command1↵
vtc1ㅍ↵

모터의 전압 명령은 ‘Voltage Command’로, 이에 대한 Long Name은 voltage_command이고 Short Name은 vtc입니다. 그러므로 상기 두 명령은 동일한 결과를 가져옵니다.

13.4.2 오브젝트 쓰기 요청

오브젝트 값을 쓸 때는 텍스트 패킷을 다음과 같이 구성합니다.

Short/Long Name Sub-index = Value CR/LF

Short/Long Name은 오브젝트의 Index에 해당하는 이름이며, Sub-index는 해당 Index에 따라 필요하면 모터 채널 혹은 외부 I/O의 채널을 의미합니다. Sub-index가 0인 경우 생략 가능합니다.
만약 채널 1에 연결된 모터를 10V 전압으로 구동시키고자 할 때 아래와 같이 입력합니다.

vtc1=10↵
voltage_command1=10↵

모터의 전압 명령은 ‘Voltage Command’로, 이에 대한 Long Name은 voltage_command이고 Short Name은 vtc입니다. 그러므로 상기 두 명령은 동일한 결과를 가져옵니다.

그리고 본 제어기의 가장 큰 장점 중의 하나는 듀얼 채널 제어기에 특화된 명령을 가지고 있습니다. 듀얼 채널 제어기에서는 다음과 같은 명령을 사용할 수 있습니다:

·  m_position_command
·  m_velocity_command
·  m_current_command
·  m_velocity_command
·  m_lav_command

상기 명령을 인가하는 방법은 다음과 같은 형식을 가집니다. 여기서 Value1은 1번 채널을, Value2는 2번 채널을 의미합니다.

Short/Long Name = Value1 , Value2 CR/LF

여기서 Sub-Index는 의미가 없기 때문에 사용하지 않습니다. 대신 각각의 채널에 대한 값을 ‘,’로 구분하여 패킷을 구성합니다.

만약 두 모터에 위치 명령을 동시에 인가하는 m_position_command/mpc 오브젝트를 통해 명령을 내리고자 할 때 다음과 같이 입력하면 됩니다.

mpc=100,100↵
m_position_command=1000,2000↵

 

13.4.3 오브젝트 읽기/쓰기 요청에 대한 성공 응답

오브젝트의 값을 읽거나 쓰기가 성공한 경우에는 오브젝트의 값(Value)이 응답으로 돌아옵니다. 제어기가 응답하는 형식은 다음과 같습니다.

Short/Long Name Sub-index = Value CR/LF

 

사용자가 Short/Long Name 형식 중 하나로 질의를 하면, 같은 형식으로 응답합니다. 응답하는 문장의 끝에는 CR 문자와 LF 문자가 함께 붙습니다.

두 채널을 동시에 다루는 명령에 대해 다음과 같이 응답합니다.

Short/Long Name = Value1 , Value2 CR/LF

제어기는 사용자가 쓴 값이 적용되지 않을 수 있기 때문에 사용자의 오브젝트를 읽는 요청뿐만 아니라 오브젝트에 쓰기 요청에 대해서도 해당 오브젝트의 값을 응답합니다.

13.4.4 오브젝트 읽기/쓰기 요청에 대한 실패 응답

오브젝트의 내용을 읽거나 쓰기 위한 패킷을 제어기에 요청했을 때, 오류가 발생하는 경우는 다음 그림과 같은 형식의 오류 패킷이 돌아옵니다.

! Error Code , Error Message CR/LF

오류 메시지는 표 13‑5에 나타나 있습니다.

※ 오류 메시지는 패킷의 구성에 관련된 오류로 제어기의 오류 상황이나 오작동에 대한 부분이 아닙니다.

13.4.5 Device ID의 부여

만일 둘 이상의 제어기가 RS-422이나 RS-485 버스에 연결된 경우, 시리얼 텍스트 패킷에는 각각의 제어기를 구분하는 장치의 ID를 부여해야 합니다.
이 때는 다음 그림과 같이 패킷을 수신할 장치의 ID를 패킷 앞에 붙이면 됩니다.

Device ID ; Serial Text Packet

만약 ‘Device ID’ 1번을 가지는 제어기의 채널 1에 연결된 모터를 10V 전압으로 구동시키고자 할 때 아래와 같이 입력합니다.

1;vtc1=10↵
1;voltage_command1=10↵

제어기가 장치 ID를 가지는 패킷을 수신하였을 때는, 응답 패킷에도 장치 ID를 붙여 응답합니다. 응답 패킷도 다음과 같은 형태가 됩니다.

Device ID ; Serial Text Packet

※주의※
RS-422이나 RS-485 버스에 둘 이상의 제어기를 연결할 때는, 각각의 제어기 간에 Device ID가 서로 충돌하지 않도록 주의하십시오.

Leave A Comment

*