← 로봇 통신 강의 목록으로
🤖
MODBUS
MODBUS · 선수: 05강

07. MODBUS CLIENT (로봇 = 마스터)

06편에서 로봇은 제어받는 입장(Slave Server)이었습니다. 이번 편은 입장을 뒤집어 로봇이 Master Client가 되어 전동 그리퍼·다른 로봇·PLC를 능동 제어합니다. MBC_* 명령으로 한 로봇이 최대 4개 Server와 동시 연결해 4종 데이터를 읽고 씁니다. Modbus는 실수를 직접 못 보내므로 IEEE754 변환과 SWAP_WORD(byte order 보정)가 왜 필요한지 익힙니다.

MODBUS ClientMBC_*그리퍼IEEE754SWAP_WORDlatch 함정
소요 시간
약 2시간
난이도
📊 중급
선수 조건
🎯 05강
결과물
로봇=Master 구조에서 MBC_* 연결/데이터 명령으로 그리퍼를 제어하고, IEEE754_ENCODE/DECODE·SWAP_WORD로 실수·byte order를 처리하며 latch 함정을 피할 수 있습니다.

이 강의에서 배우는 것

  • 1로봇=Master Client 구조에서 그리퍼·PLC·다른 로봇을 능동 제어하는 법을 설명한다
  • 2한 로봇이 최대 4개 Server와 동시 연결(연결 번호 1~4)하는 구조를 안다
  • 3MBC 연결 명령과 데이터 명령(Bit/Word, 'W'/'D' 타입)을 구분해 쓴다
  • 4SWAP_WORD·IEEE754_ENCODE/DECODE가 왜 필요한지 알고 직접 변환한다

소개

로봇(Master/Client)이 먼저 요청을 보냅니다 — 그리퍼의 Holding Register에 "열어라"를 쓰고, PLC의 Input Register에서 센서 값을 읽습니다. 상대 장비(Slave/Server)는 응답할 뿐 먼저 말을 걸지 않습니다. 06편과 정반대(06: 로봇=Server 수동 / 07: 로봇=Client 능동)입니다.

핵심 개념

1) 한 로봇 = 최대 4개 Server 동시 연결

로봇 하나가 그리퍼(연결1)·PLC(연결2)·비전(연결3)·다른 로봇(연결4)을 동시에 제어할 수 있습니다. 각 연결은 연결 번호 1~4로 구분하며, 모든 MBC_* 데이터 명령의 첫 인자가 이 번호입니다.

2) MBC_* 명령 — Bit vs Word

분류명령비고
연결MBC_RTU_OPEN / MBC_TCP_OPEN먼저 호출해야 데이터 명령 동작
BitREAD_DINPUT/READ_COIL/WRITE_COIL0 또는 1, 길이 1~48
WordREAD_INPUT/READ_HOLDING/WRITE_HOLDING'W'=16bit 1개, 'D'=2개를 32bit로

'W'(Word)는 16bit 레지스터 1개, 'D'(Double Word)는 연속 2개를 32bit로 합칩니다(저장 순서 Low word 먼저). 시작 주소는 0-base(화면에서는 1부터).

3) 변환 명령은 왜 필요한가

Modbus 레지스터는 16bit 정수만 실어 나릅니다. 실수도, 16bit를 넘는 정수도 직접 못 보내고, 장비마다 byte order(High/Low word 순서)가 다릅니다. IEEE754_ENCODE(실수→32bit 정수, 10.5→1093140480) 후 전송하고 IEEE754_DECODE 로 복원하며, byte order가 반대면 SWAP_WORD(10→655360)로 보정합니다.

4) 그리퍼 레지스터 맵 (XEG-64)

영역주소의미
HR(R/W)1600방향 0=닫기/1=열기
HR1601이동 행정 0.01mm
HR1606실행(1 쓰면 동작→완료 후 0 자동복귀)
IR(R)769상태 0 Idle/1 Busy/2 Pos도달
IR770현재 위치 0.01mm
⚠️

완료 판정 함정: IR[769]==2(Pos)만 보면 직전 동작의 상태가 latch 되어 즉시 통과합니다. 반드시 IR[769]==2 그리고 HR[1606]==0(실행 플래그 자동 리셋)을 함께 확인하세요.

핵심 예제

로봇(Master Client) 역할로 그리퍼 모델을 확인하고 50.00mm 열었다 닫습니다.

python
def run_gripper(m, direction, stroke=5000, speed=5000):
    m.write_holding(1600, direction)   # ① 방향(0=닫기/1=열기)
    m.write_holding(1601, stroke)      # ② 행정(0.01mm)
    m.write_holding(1602, speed)       # ③ 속도
    m.write_holding(1606, 1)           # ④ 실행 트리거
    while not (m.read_input(769,1)[0]==2 and m.read_holding(1606,1)[0]==0):
        time.sleep(0.05)               # ⑤ latch 함정 회피: 둘 다 확인

with RobotMaster(host, port) as m:     # MBC_TCP_OPEN(1,"...",502)
    model = m.read_holding(1536, 1)[0] # 2624 = XEG-64
    run_gripper(m, 1, 5000)            # 열기 50.00mm
    run_gripper(m, 0, 5000)            # 닫기
ℹ️

검증값: ieee754_encode(10.5)=1093140480, swap_word(10)=655360. 실장비 대응: with RobotMaster↔MBC_TCP_OPEN, write_holding↔MBC_WRITE_HOLDING, read_input↔MBC_READ_INPUT. 그리퍼 서버는 별도 터미널에서 gripper_sim.py --port 1503 로 띄웁니다.

자주 하는 실수

Q. IR[769]==2 로 완료를 봤는데 동작 시작 전에 통과해요.

A. latch 함정입니다. 직전 동작이 끝나면 IR[769]는 2(Pos)로 남아 있어 다음 명령 직후에도 잠시 2입니다. 그리퍼가 동작 시 0으로 만드는 HR[1606]을 함께 보고, IR[769]==2 그리고 HR[1606]==0 일 때만 완료로 판단하세요.

Q. 실수 좌표(10.5)를 레지스터에 그대로 썼더니 깨져요.

A. Modbus는 실수를 직접 못 보냅니다. 전송 전 IEEE754_ENCODE(10.5)→1093140480 로 바꿔 보내고 받는 쪽은 IEEE754_DECODE 로 복원하세요. 16bit를 넘는 정수 좌표는 'D' 타입(또는 split_word)으로.

Q. 그리퍼가 안 움직이거나 엉뚱한 위치로 가요.

A. 쓰기 순서가 틀렸습니다. 방향(1600)·행정(1601)·속도(1602)를 먼저 쓰고, 실행 트리거(1606=1)는 마지막입니다. 트리거가 올라간 순간의 값이 사용됩니다.

정리

  • 로봇=Master Client. 4종 레지스터를 능동적으로 읽고 쓰며 연결 번호 1~4로 최대 4 Server 동시 연결
  • 연결을 먼저 열고(MBC_*_OPEN), Bit 명령과 Word 명령('W'/'D')으로 데이터를 주고받는다
  • 그리퍼 사이클: 방향·행정 쓰기 → HR1606=1 → IR769==2 그리고 HR1606==0 폴링(latch 회피)
  • 실수는 IEEE754_ENCODE/DECODE, byte order는 SWAP_WORD로 처리한다

과제

  1. 그리퍼 열기/닫기 사이클을 완주하고 IR[770] 으로 위치(50.00mm→0.00mm)를 확인
  2. 완료 조건에서 HR[1606]==0 을 빼면 즉시 통과(latch)하는 현상을 재현
  3. ieee754_encode(10.5) 와 decode 왕복, swap_word(10) 결과를 검산
예제 코드 / 강의 자료

전체 강의 자료와 예제 코드(시뮬레이터·과제·정답 포함)는 GitHub에서 자유롭게 받아볼 수 있습니다.

GitHub에서 보기 ↗