MQTT_SCHEMA ROBOT_ARM - zero1ne-26/doc GitHub Wiki

λ‘œλ΄‡νŒ” MQTT μŠ€ν‚€λ§ˆ

μž‘μ„±: μ„ μš°μ°¬. 곡톡 κ·œμ•½μ€ MQTT_SCHEMA λ₯Ό λ”°λ₯Έλ‹€ (CloudEvents 1.0 envelope, robot/{robot_id}/* ν† ν”½ β€” ꡬ독 츑은 data.* 둜 ν•œ κ²Ή 벗겨 μ½λŠ”λ‹€). sequence 의 "SPOT 이동 β†’ λ‘œλ΄‡νŒ” μž‘μ—… β†’ SPOT 볡귀" νλ¦„μ—μ„œ 6Β·7Β·8번 단계λ₯Ό λ‹΄λ‹Ήν•œλ‹€. κ΅¬ν˜„: UF850/test/mqtt_listener.py


λͺ©μ°¨


κ°œμš”

ν•­λͺ© λ‚΄μš©
robot_id arm-01
λ‘œλ΄‡ UFACTORY UF850 + xArm Gripper G1 + RealSense D435i (μ»¨νŠΈλ‘€λ°•μŠ€ 직결 λ…ΈνŠΈλΆμ—μ„œ λ¦¬μŠ€λ„ˆ μƒμ‹œ ꡬ동)
λ™μž‘ μ§€μ • λ°”κ΅¬λ‹ˆ(1/2)λ₯Ό κ³ μ • μ’Œν‘œμ—μ„œ pick β†’ μΉ΄λ©”λΌλ‘œ κ²€μΆœν•œ 적재 케이지(SPOT 등짐) μœ„μ— drop β†’ ν™ˆ 볡귀
μ œκ³΅κ°’ session_id (μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜ μ„œλ²„ λ°œκΈ‰) β€” REQUEST 둜 λ°›μœΌλ©΄ RESPONSE 에 κ·ΈλŒ€λ‘œ echo
μž‘μ„± 주체 μ„ μš°μ°¬
μ΅œμ’… μˆ˜μ •μΌ 2026-09-04

ν† ν”½ λͺ©λ‘

ꡬ뢄 Topic λ°©ν–₯ μ„€λͺ…
REQUEST robot/arm-01/command μ„œλ²„ β†’ λ‘œλ΄‡νŒ” λ‘œλ΄‡νŒ” μ œμ–΄ λͺ…λ Ή 전솑 (sequence 6Β·7번)
RESPONSE robot/arm-01/ack λ‘œλ΄‡νŒ” β†’ μ„œλ²„ λ‘œλ΄‡νŒ” μ œμ–΄ κ²°κ³Ό μˆ˜μ‹  (sequence 8번) β€” ACCEPTED ν›„ μ’…κ²° 1회, 총 2회
STATE robot/arm-01/state λ‘œλ΄‡νŒ” β†’ μ„œλ²„ μƒμ‹œ μƒνƒœ 1Hz retained + LWT (availability)

μ™„λ£Œλ³΄κ³ λ₯Ό REQUEST 토픽이 μ•„λ‹Œ ack 둜 λΆ„λ¦¬ν•˜λŠ” μ΄μœ λŠ” SPOT κ³Ό 동일 β€” λ¦¬μŠ€λ„ˆκ°€ command λ₯Ό ꡬ독 쀑이라 같은 토픽에 λ°œν–‰ν•˜λ©΄ 자기 λ°œν–‰μ„ μžκΈ°κ°€ λ˜λ°›λŠ”λ‹€ (MQTT_SCHEMA-SPOT μ°Έκ³ ).


REQUEST

Topic: robot/arm-01/command

Payload (envelope data)

{
  "session_id": "abc123",
  "command_id": "cmd-0101",
  "action": "pick_basket",
  "params": { "basket": 1 }
}
ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
session_id string N μ˜€μΌ€μŠ€νŠΈλ ˆμ΄μ…˜ μ„œλ²„ λ°œκΈ‰ μ„Έμ…˜ μ‹λ³„μž β€” RESPONSE 에 echo
command_id string Y λͺ…λ Ή μ‹λ³„μž (μ„œλ²„ λΆ€μ—¬) β€” RESPONSE λ§€μΉ­ ν‚€. μ—†μœΌλ©΄ νŒ”μ΄ λ°œκΈ‰
action string Y pick_basket (ν˜„μž¬ 유일)
params.basket int Y 집을 λ°”κ΅¬λ‹ˆ 번호: 1 | 2

μ˜ˆμ‹œ (envelope 전체)

{
  "specversion": "1.0",
  "type": "robot.command",
  "source": "/services/orchestrator",
  "id": "01HW9XJ1A2B3C4D5E6F7G8H9JK",
  "time": "2026-09-04T10:00:00.000Z",
  "datacontenttype": "application/json",
  "data": {
    "session_id": "abc123",
    "command_id": "cmd-0101",
    "action": "pick_basket",
    "params": { "basket": 1 }
  }
}

λ©±λ“±μ„±: envelope id 둜 dedup ν•œλ‹€ (QoS 1 μž¬μ „μ†‘ 쀑볡 λ°©μ§€). μž¬μ‹œλ„λŠ” 같은 envelope κ·ΈλŒ€λ‘œ μž¬λ°œν–‰ν•  것.


RESPONSE

Topic: robot/arm-01/ack

command_id(와 session_id)λ₯Ό echo ν•˜λ©° 2λ‹¨κ³„λ‘œ μ˜¨λ‹€: μ ‘μˆ˜ μ‹œ ACCEPTED, μž‘μ—… μ’…λ£Œ μ‹œ SUCCESS λ˜λŠ” FAULT. μ ‘μˆ˜κ°€ μ•ˆ 되면 REJECTED/BUSY 1회둜 λλ‚œλ‹€ (이후 μ™„λ£Œλ³΄κ³  μ—†μŒ β€” μ„œλ²„λŠ” ACCEPTED λ₯Ό 받은 λͺ…λ Ήλ§Œ μ’…κ²° ack λ₯Ό 기닀릴 것).

Payload (envelope data)

{
  "robot_id": "arm-01",
  "session_id": "abc123",
  "command_id": "cmd-0101",
  "status": "SUCCESS",
  "result": "ok",
  "timestamp": "2026-09-04T10:00:41.000Z"
}
ν•„λ“œ νƒ€μž… ν•„μˆ˜ μ„€λͺ…
robot_id string Y arm-01
session_id string N REQUEST κ°’ echo
command_id string Y REQUEST κ°’ echo β€” λ§€μΉ­ ν‚€
status string Y ACCEPTED | SUCCESS | FAULT | REJECTED | BUSY
result string N μ’…κ²° ack 의 μ‹€ν–‰ κ²°κ³Ό μ½”λ“œ (μ•„λž˜ ν‘œ)
fault_detail object N {code, message} β€” status κ°€ enum 을 μœ μ§€ν•˜λ„λ‘ μ„ΈλΆ€λŠ” μ—¬κΈ°λ‘œ
timestamp string Y RFC3339 UTC

status / result / fault_detail.code

status result fault_detail.code 의미 Β· μ„œλ²„κ°€ ν•  일
ACCEPTED – – μ ‘μˆ˜, μ‹€ν–‰ μ‹œμž‘ (μ•½ 30~60초 μ†Œμš”)
SUCCESS ok – pick & place μ™„λ£Œ, ν™ˆ 볡귀 β†’ SPOT λ‹€μŒ 이동 κ°€λŠ₯ (sequence 8번 = {status:"complete"})
FAULT returned STOPPED_RETURNED 도쀑 μ •μ§€(좩돌 λ“±) β†’ 물체λ₯Ό pick 지점에 λ˜λŒλ €λ†“κ³  ν™ˆ 볡귀. μž¬μ‹œλ„ κ°€λŠ₯
FAULT homed STOPPED_HOMED 도쀑 μ •μ§€ β†’ (물체 없이) ν™ˆ 볡귀. μž¬μ‹œλ„ κ°€λŠ₯
FAULT unreachable UNREACHABLE pick/place 지점이 도달 λ²”μœ„ λ°– β€” μ§‘κΈ° 전에 쀑단. SPOT μž¬μ •λ ¬ ν›„ μž¬μ „μ†‘
FAULT need_human NEED_HUMAN 볡ꡬ μ‹€νŒ¨ β€” νŒ”μ΄ 잠긴 채 μ •μ§€. μ‚¬λžŒ 확인 μ „ μž¬μ‹œλ„ κΈˆμ§€
FAULT – CRASHED μ‹€ν–‰ 슀크립트 비정상 μ’…λ£Œ
REJECTED – UNKNOWN_ACTION / BAD_PARAM action/params 였λ₯˜ β€” μ™„λ£Œλ³΄κ³  μ—†μŒ
BUSY – BUSY 이전 λͺ…λ Ή μ‹€ν–‰ 쀑 (λ™μ‹œ 1개) β€” μ™„λ£Œ ack ν›„ μž¬μ „μ†‘

STATE (μƒμ‹œ μƒνƒœ)

Topic: robot/arm-01/state β€” 1Hz, retained, LWT

{
  "robot_id": "arm-01",
  "connection": "online",
  "timestamp": "2026-09-04T10:00:00.000Z",
  "fsm_state": "IDLE",
  "command_id": null
}
ν•„λ“œ μ„€λͺ…
connection online β€” λ¦¬μŠ€λ„ˆ death μ‹œ LWT κ°€ offline 을 retain λ°œν–‰ (별도 availability ν† ν”½ μ—†μŒ)
fsm_state IDLE | EXECUTING | UNKNOWN(offline)
command_id EXECUTING 쀑이면 μ‹€ν–‰ 쀑 λͺ…λ Ή id

timestamp κ°€ 10초 이상 였래되면 λ¦¬μŠ€λ„ˆ/브둜컀 μ—°κ²° μ΄μƒμœΌλ‘œ κ°„μ£Ό.


QoS / 기타 μ„€μ •

ν•­λͺ© λ‚΄μš©
QoS μ „ ν† ν”½ 1
Retain state 만 βœ… (command/ack ❌)
LWT state 에 connection:"offline" retain
envelope CloudEvents 1.0, id=dedup ν‚€ (uuid4 hex)
λ™μ‹œμ„± λͺ…λ Ή 1κ°œμ”© 직렬 처리 β€” μ‹€ν–‰ 쀑 μˆ˜μ‹ μ€ BUSY

λΉ„κ³ 

  • sequence μ •ν•©: 6번(μ„œλ²„ λ°œν–‰) = REQUEST, 7번(νŒ” μˆ˜μ‹ Β·μ‹€ν–‰) = λ¦¬μŠ€λ„ˆ, 8번(μž‘μ—… μ™„λ£Œ {status:"complete"}) = μ’…κ²° ack (SUCCESS/FAULT). μ •μ±… 2Β·3(도착 μ™„λ£Œ ν›„μ—λ§Œ μ§€μ‹œ, 이동 μ‹€νŒ¨ μ‹œ λ―Έμ§€μ‹œ)κ³Ό μ •μ±… 5(적재 쀑 SPOT μ •μ§€ μœ μ§€)λŠ” μ„œλ²„/SPOT μΈ‘ μ±…μž„μ΄λ©° νŒ”μ€ 이λ₯Ό μ „μ œν•œλ‹€ β€” 캑처·적재 μˆœκ°„ SPOT 이 적재 지점에 μ •μ§€ν•΄ μžˆμ–΄μ•Ό ν•œλ‹€.
  • μ •λ ¬ ν—ˆμš© 였차: 적재(place) μœ„μΉ˜λŠ” κ³ μ • μ’Œν‘œκ°€ μ•„λ‹ˆλΌ λ§€ λͺ…λ Ήλ§ˆλ‹€ RealSense 둜 케이지λ₯Ό κ²€μΆœν•˜λ―€λ‘œ, SPOT μ •μ°¨ μ˜€μ°¨λŠ” "카메라 μ‹œμ•Ό(≀1.2m) + νŒ” 도달 λ²”μœ„(λ² μ΄μŠ€μ—μ„œ μˆ˜ν‰ ≀750mm)" μ•ˆμ΄λ©΄ ν‘μˆ˜λœλ‹€. κ·Έ 밖이면 μ§‘κΈ° 전에 UNREACHABLE 둜 μ‘λ‹΅ν•˜λ‹ˆ SPOT μž¬μ •λ ¬ ν›„ μž¬μ „μ†‘ν•˜λ©΄ λœλ‹€ (sequence μ •μ±… 4의 AprilTag 정렬은 이 λ²”μœ„ μ•ˆμ— λ“€μ–΄μ˜€κ²Œ ν•˜λŠ” μš©λ„λ‘œ 유효).
  • pick μ’Œν‘œ(λ°”κ΅¬λ‹ˆ 1Β·2)λŠ” ν˜„μž₯μ—μ„œ ν•˜λ“œμ½”λ”©Β·μΊ˜λ¦¬λΈŒλ ˆμ΄μ…˜λœ 값이닀. μ…‹μ—… μ ˆμ°¨λŠ” UF850 README μ°Έκ³ .
  • λ°œν–‰ ν…ŒμŠ€νŠΈ:
    mosquitto_pub -h <broker> -t robot/arm-01/command -q 1 -m '{
      "specversion":"1.0","type":"robot.command","source":"/test","id":"t-001",
      "time":"2026-09-04T10:00:00Z","data":{"command_id":"cmd-t1","action":"pick_basket","params":{"basket":1}}}'
    mosquitto_sub -h <broker> -t 'robot/arm-01/#' -q 1 -v
⚠️ **GitHub.com Fallback** ⚠️