MQTT_SCHEMA SPOT - zero1ne-26/doc GitHub Wiki

SPOT ์ œ์–ด MQTT ์Šคํ‚ค๋งˆ

ํ•ญ๋ชฉ ๋‚ด์šฉ
์ œ๊ณต๊ฐ’ session_id (์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์„œ๋ฒ„์—์„œ ๋ฐœ๊ธ‰)
์ž‘์„ฑ ์ฃผ์ฒด SPOT ๊ฐœ๋ฐœ ๋‹ด๋‹น
์ตœ์ข… ์ˆ˜์ •์ผ 2026-08-30
์ƒํƒœ ์ดˆ์•ˆ โ€” ํ˜‘์˜ ํ•„์š”. ์‹œ๋‚˜๋ฆฌ์˜ค๋ณ„ ํ๋ฆ„ยท์ •์ฑ…์€ sequence ํŽ˜์ด์ง€, ํ•ฉ์˜ยท๋ฏธํ•ฉ์˜ ์‚ฌํ•ญ์€ 8์ ˆ

0. ์ด ๋ฌธ์„œ์˜ ๋ฒ”์œ„

์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์„œ๋ฒ„ โ†” SPOT ์‚ฌ์ด์—์„œ ์˜ค๊ฐ€๋Š” ๊ฒƒ๋งŒ ์ ์Šต๋‹ˆ๋‹ค.

์„œ๋ฒ„๊ฐ€ ์ •ํ•˜๋Š” ๊ฒƒ     ๋ฌด์—‡์„ ํ•  ๊ฒƒ์ธ๊ฐ€      "p2 ๋กœ ๊ฐ€๋ผ"  "์•ˆ๋‚ด ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์‹คํ–‰ํ•˜๋ผ"
SPOT ์ด ์ •ํ•˜๋Š” ๊ฒƒ    ์–ด๋–ป๊ฒŒ ํ•  ๊ฒƒ์ธ๊ฐ€      ์–ด๋А ๊ฒฝ๋กœ๋กœ, ๋ช‡ ๋„๋กœ ๋Œ์•„์„œ, ์–ด๋–ค ์ž์„ธ๋กœ

์ž์„ธ(pose)ยท๊ฒฝ๋กœยท์ •๋ฐ€์ •๋ ฌ ๊ฐ™์€ ๋™์ž‘ ํŒŒ๋ผ๋ฏธํ„ฐ๋Š” ์ด ๋ฌธ์„œ์— ์—†์Šต๋‹ˆ๋‹ค. SPOT ๋‚ด๋ถ€์—์„œ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ๊ทธ ๊ฐ’์„ ์•Œ ํ•„์š”๋„, ๋ณด๋‚ผ ํ•„์š”๋„ ์—†์Šต๋‹ˆ๋‹ค.

์ด ์›์น™์€ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์„œ๋ฒ„ ๋‹ด๋‹น์ž ์š”์ฒญ("ํฌ์ฆˆ๋‚˜ ์ด๋™ ๋กœ์ง์€ ๋กœ๋ด‡์—์„œ ์ž์ฒด ์ฒ˜๋ฆฌ")์„ ๊ทธ๋Œ€๋กœ ๋ฐ˜์˜ํ•œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.


1. ํ† ํ”ฝ ๋ชฉ๋ก

๊ตฌ๋ถ„ Topic ๋ฐฉํ–ฅ QoS Retained ์„ค๋ช…
REQUEST robot/spot-01/command OC ์„œ๋ฒ„ โ†’ SPOT 1 โœ• ์ œ์–ด ๋ช…๋ น
RESPONSE robot/spot-01/ack SPOT โ†’ ๊ตฌ๋…์ž 1 โœ• ์ ‘์ˆ˜ยท์™„๋ฃŒ ๋ณด๊ณ 
์ƒํƒœ robot/spot-01/state SPOT โ†’ ๊ตฌ๋…์ž 1 โ—‹ 1Hz ์ƒํƒœ
๋ชฉ์ ์ง€ robot/spot-01/waypoints SPOT โ†’ ๊ตฌ๋…์ž 1 โ—‹ ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ณณ ๋ชฉ๋ก
์‹œ๋‚˜๋ฆฌ์˜ค robot/spot-01/scenarios ๊ด€๋ฆฌ์žUI โ†’ ๊ตฌ๋…์ž 1 โ—‹ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค ๋ชฉ๋ก (๋กœ๋ด‡ํŒ€ UI ๊ฐ€ ๋ฐœํ–‰)
์•ˆ์ „ robot/spot-01/estop SPOT โ†’ ๊ตฌ๋…์ž 2 โ—‹ ๋น„์ƒ์ •์ง€ ๋ฐœ์ƒยทํ•ด์ œ
์ง„ํ–‰ robot/spot-01/plan SPOT โ†’ ๊ตฌ๋…์ž 1 โœ• ์‹œ๋‚˜๋ฆฌ์˜ค ์Šคํ… ์ง„ํ–‰์ƒํ™ฉ
์žฅ์•  robot/spot-01/fault SPOT โ†’ ๊ตฌ๋…์ž 1 โ—‹ ์žฅ์•  ์•Œ๋ฆผ (BATTERY_LOW ๋“ฑ)
์„ธ์…˜ server/session/start OC ์„œ๋ฒ„ โ†’ SPOT(๊ตฌ๋…) 1 โœ• ์„ธ์…˜ ์‹œ์ž‘ โ†’ SPOT ์ด home ์œผ๋กœ ์ด๋™ (ยง3-1)
์„ธ์…˜ server/session/end OC ์„œ๋ฒ„ โ†’ SPOT(๊ตฌ๋…) 1 โœ• ์„ธ์…˜ ์ข…๋ฃŒ โ†’ SPOT ์ด ์ถฉ์ „ ์œ„์น˜๋กœ ๋ณต๊ท€ (ยง3-1)

๋กœ๋ด‡ ํ† ํ”ฝ์— ๋ช…๋ น์„ ๋ฐœํ–‰ํ•˜๋Š” ๊ฒƒ์€ OC ์„œ๋ฒ„๋ฟ์ž…๋‹ˆ๋‹ค. ํƒœ๋ธ”๋ฆฟยท๊ด€๋ฆฌ์ž ํ™”๋ฉดยท๋„์ฐฉ ์ž๋™ํ™”๊ฐ€ ๊ฐ๊ฐ ์„œ๋ฒ„์— ์š”์ฒญํ•˜๊ณ , ์„œ๋ฒ„๊ฐ€ ๋กœ๋ด‡๋ณ„ ํ๋กœ ์ˆœ์„œ๋ฅผ ์ •ํ•ด ์ด ํ† ํ”ฝ์œผ๋กœ ๋ƒ…๋‹ˆ๋‹ค (2026-08-10 ํ•ฉ์˜, ยง8).

๋ฌด์—‡์ด ์–ธ์ œ ๋ช…๋ น์„ ๋งŒ๋“œ๋Š”์ง€๋Š” ์ด ๋ฌธ์„œ์˜ ๋ฒ”์œ„๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ๊ด€๋ฆฌํ•˜๋ฉฐ LOCATION_AUTOMATION_DESIGN ์— ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ํ๋ฆ„์€ ์„œ๋ฒ„ ์‚ฌ์ •์œผ๋กœ ๊ณ„์† ๋ฐ”๋€Œ๋ฏ€๋กœ(2026-08-22 ์— ๋„์ฐฉ ์ž๋™ํ™”์™€ ๋””๋ฐ”์ด์Šค ํ๊ฐ€ ๋“ค์–ด์™”๋‹ค) ์—ฌ๊ธฐ ์˜ฎ๊ฒจ ์ ์œผ๋ฉด ๊ณง ์–ด๊ธ‹๋‚ฉ๋‹ˆ๋‹ค. ์ด ๋ฌธ์„œ๋Š” ๋กœ๋ด‡์ด ๋ฌด์—‡์„ ๋ฐ›๊ณ  ๋ฌด์—‡์„ ๋Œ๋ ค์ฃผ๋Š”์ง€๋งŒ ๋‹ค๋ฃน๋‹ˆ๋‹ค โ€” ๊ทธ๊ฑด ์„œ๋ฒ„๊ฐ€ ๋ฐ”๋€Œ์–ด๋„ ๊ทธ๋Œ€๋กœ์ž…๋‹ˆ๋‹ค.

๋ช…๋ น๋งŒ retained ๋ฅผ ์“ฐ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋กœ๋ด‡์ด ์žฌ์ ‘์†ํ•  ๋•Œ ๋ธŒ๋กœ์ปค๊ฐ€ ์˜› ๋ช…๋ น์„ ๋‹ค์‹œ ๋ฐฐ๋‹ฌํ•˜๋ฉด ์•„๋ฌด๋„ ์‹œํ‚ค์ง€ ์•Š์•˜๋Š”๋ฐ ๋กœ๋ด‡์ด ์›€์ง์ž…๋‹ˆ๋‹ค.


2. ๊ณตํ†ต ํŽ˜์ด๋กœ๋“œ

๋ชจ๋“  ๋ฉ”์‹œ์ง€๋Š” CloudEvents 1.0 ๋ด‰ํˆฌ๋ฅผ ์”๋‹ˆ๋‹ค.

{
  "specversion": "1.0",
  "type": "robot.command",          // ๋ฉ”์‹œ์ง€ ์ข…๋ฅ˜
  "source": "/services/orchestration-server",
  "id": "0d3fโ€ฆ",                    // ๋ฉ”์‹œ์ง€ ๊ณ ์œ  id (์ค‘๋ณต ์ˆ˜์‹  ํŒ๋ณ„์šฉ)
  "time": "2026-08-08T04:12:03Z",
  "datacontenttype": "application/json",
  "subject": "robot/spot-01",
  "data": { /* ์•„๋ž˜ ์ ˆ๋“ค */ }
}

data ๊ณตํ†ต ํ•„๋“œ (REQUEST)

ํ•„๋“œ ํƒ€์ž… ํ•„์ˆ˜ ์„ค๋ช…
session_id string Y ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์„œ๋ฒ„ ๋ฐœ๊ธ‰. SPOT ์€ ํ•ด์„ํ•˜์ง€ ์•Š๊ณ  ์‘๋‹ต์— ๊ทธ๋Œ€๋กœ ์‹ค์–ด ๋˜๋Œ๋ ค์ค๋‹ˆ๋‹ค (ํ˜•์‹ ์ œ์•ฝ ์—†์Œ)
command_id string Y ๋ช…๋ น ํ•œ ๊ฑด์˜ ๊ณ ์œ  id. ์‘๋‹ต ๋งค์นญ ํ‚ค
action string Y ๋ฌด์—‡์„ ํ•  ๊ฒƒ์ธ๊ฐ€ (3์ ˆ)
params object N action ๋ณ„ ํŒŒ๋ผ๋ฏธํ„ฐ

command_id ๊ฐ€ ์™œ ํ•„์š”ํ•œ๊ฐ€ โ€” ๋ช…๋ น์„ ๋ณด๋‚ด๊ณ  ๊ฒฐ๊ณผ๊ฐ€ ํ•œ์ฐธ ๋’ค์— ๋”ฐ๋กœ ์˜ต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๋ช…๋ น์ด ๋™์‹œ์— ๋Œ ์ˆ˜ ์žˆ์–ด์„œ, ์ด ๊ฐ’์ด ์—†์œผ๋ฉด ์–ด๋А ์‘๋‹ต์ด ์–ด๋А ๋ช…๋ น์˜ ๊ฒƒ์ธ์ง€ ์•Œ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

์ค‘๋ณต ์–ต์ œ๋Š” ๋ด‰ํˆฌ์˜ id ๋กœ๋งŒ ํ•ฉ๋‹ˆ๋‹ค (command_id ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค). ์ตœ๊ทผ 512๊ฑด์„ ๊ธฐ์–ตํ•˜๋ฉฐ, ๋กœ๋ด‡์ด ์žฌ์‹œ์ž‘ํ•˜๋ฉด ๊ทธ ๊ธฐ์–ต์€ ์‚ฌ๋ผ์ง‘๋‹ˆ๋‹ค.

โš ๏ธ ๊ทธ๋ž˜์„œ ๊ฐ™์€ command_id ๋ฅผ ์ƒˆ ๋ด‰ํˆฌ id ๋กœ ๋‹ค์‹œ ๋ณด๋‚ด๋ฉด ๋กœ๋ด‡์€ ๋˜ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. QoS 1 ์žฌ์ „์†ก(๋ธŒ๋กœ์ปค๊ฐ€ ๊ฐ™์€ ๋ด‰ํˆฌ๋ฅผ ๋‹ค์‹œ ๋ฐฐ๋‹ฌ)์€ ๊ฑธ๋Ÿฌ์ง€์ง€๋งŒ, ์„œ๋ฒ„๊ฐ€ ์ง์ ‘ ๋งŒ๋“œ๋Š” ์žฌ์‹œ๋„๋Š” ๊ฑธ๋Ÿฌ์ง€์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์žฌ์‹œ๋„ํ•  ๋•Œ๋Š” ๋กœ๋ด‡์ด ์ •๋ง ๋ชป ๋ฐ›์•˜๋Š”์ง€ (ack ๊ฐ€ ํ•˜๋‚˜๋„ ์•ˆ ์™”๋Š”์ง€) ๋จผ์ € ํ™•์ธํ•ด์ฃผ์„ธ์š”.


3. REQUEST (ํƒœ๋ธ”๋ฆฟยทOC โ†’ SPOT)

Topic: robot/spot-01/command

action params ์„ค๋ช…
navigate_to { "destination": "p2" } ์ด๋ฆ„ ๋ถ™์ธ ์ง€์ ์œผ๋กœ ์ด๋™
run_scenario { "scenario_id": "guide", "variables": {โ€ฆ} } ์‹œ๋‚˜๋ฆฌ์˜ค ์‹คํ–‰ (์•„๋ž˜)
follow { "mode": "start" | "stop" } ์‚ฌ๋žŒ ์ถ”์ข… ์‹œ์ž‘ยท์ •์ง€
return_home {} ์ถฉ์ „ ์œ„์น˜๋กœ ๋ณต๊ท€ ํ›„ ์ฐฉ์„, ๋ชจํ„ฐ ์ „์› ๋‚ด๋ฆผ โ€” ๋‹ค์Œ ์ด๋™ ๋ช…๋ น์—์„œ ์ž๋™์œผ๋กœ ๋‹ค์‹œ ์ผœ์ง (2026-10-04)
stop {} ์ฆ‰์‹œ ์ •์ง€. ์–ด๋–ค ์ƒํƒœ์—์„œ๋„ ์ˆ˜์šฉ
stand {} ์ผ์–ด์„œ๊ธฐ โ€” ๋ชจํ„ฐ๋„ ํ•จ๊ป˜ ์ผœ์ง (2026-09-06 ๊ณ„์•ฝ ์Šน๊ฒฉ)
sit {} ์•‰๊ธฐ (2026-09-06 ๊ณ„์•ฝ ์Šน๊ฒฉ)
power_off {} ์•‰ํžˆ๊ณ  ๋ชจํ„ฐ ์ „์› ๋‚ด๋ฆผ โ€” ๋‹ค์‹œ ์›€์ง์ด๋ ค๋ฉด stand (2026-09-06 ์‹ ๊ทœ)
warm_up { "rotate": false, "take_lease": true } ์ค€๋น„ ์ ๊ฒ€ยท๋ณต๊ตฌ. ์—ฐ๊ฒฐยท์‹œ๊ฐ„๋™๊ธฐยทE-Stopยท์ œ์–ด๊ถŒยท๋งตยท์œ„์น˜์ถ”์ •์„ ํ•œ ๋ฒˆ์— ํ™•์ธํ•˜๊ณ  ๊ฒฐ๊ณผ๋ฅผ ๋Œ๋ ค์คŒ. ๊ธฐ๋ณธ์€ ๋กœ๋ด‡์ด ์›€์ง์ด์ง€ ์•Š์Œ (์•„๋ž˜) (2026-09-29 ์‹ ๊ทœ)

๐Ÿšจ stop ์€ ์„œ๋ฒ„ ํ๋ฅผ ์šฐํšŒํ•ด ์ฆ‰์‹œ ๋ฐœํ–‰ํ•ด์ฃผ์„ธ์š”. ๋กœ๋ด‡์€ ์‹คํ–‰ ์ค‘์—๋„ stop ๋งŒ์€ BUSY ๋กœ ๊ฑฐ์ ˆํ•˜์ง€ ์•Š์ง€๋งŒ, ๊ทธ๊ฑด ๋ช…๋ น์ด ๋„์ฐฉํ–ˆ์„ ๋•Œ์˜ ์ด์•ผ๊ธฐ์ž…๋‹ˆ๋‹ค. ์•ž ๋ช…๋ น์˜ ์ข…๊ฒฐ ack ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋Š” ํ์— stop ์ด ๋“ค์–ด๊ฐ€๋ฉด ์ฃผํ–‰์ด ๋๋‚  ๋•Œ๊นŒ์ง€ ์ •์ง€๊ฐ€ ๋‚˜๊ฐ€์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ์•ˆ์ „ ๊ฒฝ๋กœ๊ฐ€ ์กฐ์šฉํžˆ ๋ฌด๋ ฅํ™”๋ฉ๋‹ˆ๋‹ค.

์œ„ 9๊ฐœ๊ฐ€ ๊ณ„์•ฝ์˜ ์ „๋ถ€์ž…๋‹ˆ๋‹ค. (2026-09-06: standยทsit์ด ๊ด€๋ฆฌ์ž ์ „์šฉ์—์„œ ๊ณ„์•ฝ์œผ๋กœ ์Šน๊ฒฉ๋˜๊ณ  power_off๊ฐ€ ์‹ ์„ค๋์Šต๋‹ˆ๋‹ค. 2026-09-29: warm_up ์ด ์‹ ์„ค๋์Šต๋‹ˆ๋‹ค.) ๋กœ๋ด‡์€ ์ด ๋ฐ–์—๋„ relocalize ยท pose ยท execute_plan ยท align_tag ยท take_control/release_control ์„ ๋ฐ›์ง€๋งŒ ๊ด€๋ฆฌ์ž UI ์ „์šฉ์ด๋ผ ๊ณ„์•ฝ์ด ์•„๋‹™๋‹ˆ๋‹ค. ์˜ˆ๊ณ  ์—†์ด ๋ฐ”๋€Œ๋ฏ€๋กœ ์„œ๋ฒ„๋Š” ์“ฐ์ง€ ๋งˆ์„ธ์š”.

์˜ˆ์‹œ

{
  "session_id": "01HW9X8M2K",
  "command_id": "cmd-0042",
  "action": "navigate_to",
  "params": { "destination": "p2" }
}

destination ๊ฐ’

robot/spot-01/waypoints (5์ ˆ)์— ์‹ค๋ ค ์˜ค๋Š” label ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. ์ž๋™ ์ƒ์„ฑ๋œ ๊ฒฝ์œ ์ง€๋Š” ๋ชฉ์ ์ง€๊ฐ€ ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค โ€” ๊ทธ๊ฑด ๊ธธ์ด์ง€ ์žฅ์†Œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค. ๋ชฉ๋ก์— ์—†๋Š” ๊ฐ’์„ ๋ณด๋‚ด๋ฉด REJECTED ๋กœ ๊ฑฐ๋ถ€ํ•˜๊ณ , fault_detail.code ์— ์ด์œ ๋ฅผ, fault_detail.message ์— ๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ณณ ์ด๋ฆ„๋“ค์„ ์ ์–ด ๋Œ๋ ค์ค๋‹ˆ๋‹ค.

โš ๏ธ ๊ทธ ๋ชฉ๋ก์€ ์‚ฌ๋žŒ์ด ์ฝ๋Š” ๋ฌธ์žฅ ์•ˆ์— ๋“ค์–ด ์žˆ์Šต๋‹ˆ๋‹ค ("'x' is not in the map. known: origin, p2, p3"). ๋ฐฐ์—ด ํ•„๋“œ๊ฐ€ ์•„๋‹ˆ๋ฏ€๋กœ ํŒŒ์‹ฑํ•˜์ง€ ๋งˆ์„ธ์š” โ€” ๋ชฉ๋ก์ด ํ•„์š”ํ•˜๋ฉด waypoints ํ† ํ”ฝ์„ ์ฝ์–ด์ฃผ์„ธ์š”.

โš ๏ธ ๊ฐ™์€ label ์ด ๋‘ ๊ฐœ ์ด์ƒ์ด๋ฉด ๊ทธ ์ด๋ฆ„์€ ๋ชฉ์ ์ง€๋กœ ์“ธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋А ์ชฝ์ธ์ง€ ์ •ํ•  ์ˆ˜ ์—†์–ด AMBIGUOUS_WAYPOINT ๋กœ ๊ฑฐ๋ถ€ํ•ฉ๋‹ˆ๋‹ค. ๋ง์—†์ด ํ•˜๋‚˜๋ฅผ ๊ณ ๋ฅด๋ฉด ์—‰๋šฑํ•œ ๊ณณ์œผ๋กœ ๊ฐ‘๋‹ˆ๋‹ค โ€” ํ˜„์žฅ ๋งต์˜ p3 ๋‘ ๊ฐœ๊ฐ€ 2.7m ๋–จ์–ด์ ธ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๋ชฉ๋ก์— ๊ฐ™์€ ์ด๋ฆ„์ด ๋‘˜ ๋ณด์ด๋ฉด ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์ง€ ๋งˆ์„ธ์š”.

์ค‘๊ฐ„ ๊ฒฝ์œ ์ง€๋Š” SPOT ์ด ์•Œ์•„์„œ ์ง€๋‚˜๊ฐ‘๋‹ˆ๋‹ค. ์„œ๋ฒ„๋Š” ์ตœ์ข… ๋ชฉ์ ์ง€๋งŒ ์ง€์ •ํ•ฉ๋‹ˆ๋‹ค.

variables ๊ฐ’

scenarios ํ† ํ”ฝ(5์ ˆ)์˜ variables ๋Š” ํ‚ค๊ฐ€ ๋ณ€์ˆ˜๋ช…, ๊ฐ’์ด ๊ธฐ๋ณธ๊ฐ’์ž…๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ๋ณด๋‚ด๋Š” variables ๋Š” ๊ทธ ๊ธฐ๋ณธ๊ฐ’์„ ๋ฎ์–ด์”๋‹ˆ๋‹ค.

  • ์ƒ๋žตํ•ด๋„ ๋ฉ๋‹ˆ๋‹ค. ๊ธฐ๋ณธ๊ฐ’์œผ๋กœ ์‹คํ–‰๋˜๋ฉฐ BAD_PARAM ์ด ๋‚˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค
  • ์ผ๋ถ€๋งŒ ๋ณด๋‚ด๋„ ๋ฉ๋‹ˆ๋‹ค. ๋ณด๋‚ธ ํ‚ค๋งŒ ๋ฎ์–ด์”๋‹ˆ๋‹ค
  • ๋ชฉ์ ์ง€๋ฅผ ๋œปํ•˜๋Š” ๋ณ€์ˆ˜์˜ ๊ฐ’์€ waypoints ์˜ label ์ด์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค โ€” ๊ทธ ์™ธ์—๋Š” ์Šคํ…์ด ์‹คํ–‰๋  ๋•Œ REJECTED(UNKNOWN_WAYPOINT)๋กœ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค

scenarios ์˜ unsupported_steps ๊ฐ€ ๋น„์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด ๊ทธ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์•„์ง ๋ชป ํ•˜๋Š” ๋™์ž‘์„ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ํ•˜๋ฉด ๊ทธ ์Šคํ…์—์„œ ๋ฉˆ์ถฅ๋‹ˆ๋‹ค.

warm_up โ€” ์ค€๋น„ ์ ๊ฒ€

๋กœ๋ด‡ ๋‹ด๋‹น์ž๊ฐ€ ์—†์–ด๋„ "์ง€๊ธˆ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋Œ๋ ค๋„ ๋˜๋Š”๊ฐ€" ๋ฅผ ํ™•์ธํ•˜๊ณ , ์•ˆ ๋˜๋ฉด ๋ฌด์—‡์„ ํ•ด์•ผ ํ•˜๋Š”์ง€ ๋ฐ›๋Š” ๋ช…๋ น์ž…๋‹ˆ๋‹ค. ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€์˜ ๋ฒ„ํŠผ ํ•˜๋‚˜๋กœ ์“ฐ๋Š” ๊ฒƒ์„ ์ „์ œ๋กœ ํ•ฉ๋‹ˆ๋‹ค.

์–ธ์ œ ๋ˆ„๋ฅด๋‚˜ โ€” ์ „์‹œ ์‹œ์ž‘ ์ „, SPOT ์ „์›์„ ์ผ  ๋’ค, ๋ช…๋ น์ด ์•ˆ ๋จน์„ ๋•Œ.

param ํƒ€์ž… ๊ธฐ๋ณธ ์„ค๋ช…
rotate bool false true ๋ฉด ํƒœ๊ทธ๊ฐ€ ์•ˆ ๋ณด์ผ ๋•Œ ์ผ์–ด์„œ์„œ ์ œ์ž๋ฆฌ ํšŒ์ „ํ•˜๋ฉฐ ์œ„์น˜๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค. ๋กœ๋ด‡์ด ์›€์ง์ด๋ฏ€๋กœ ์˜†์— ์‚ฌ๋žŒ์ด ์žˆ์„ ๋•Œ๋งŒ. false ๋ฉด ๋กœ๋ด‡์€ ์›€์ง์ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค
take_lease bool true ์ œ์–ด๊ถŒ์ด ์—†์œผ๋ฉด ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค. false ๋ฉด ๊ฐ€์ ธ์˜ค์ง€ ์•Š๊ณ  ๋ˆ„๊ฐ€ ์ฅ๊ณ  ์žˆ๋Š”์ง€๋งŒ ์•Œ๋ ค์ค๋‹ˆ๋‹ค

๋‘˜ ๋‹ค ์ƒ๋žตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค ("params": {}).

ํ•˜๋Š” ์ผ (์ˆœ์„œ๋Œ€๋กœ, ๊ธฐ๋ณธ์€ ์ „๋ถ€ ๋ฌด๋ชจ์…˜)

์ˆœ์„œ ํ•ญ๋ชฉ ๋‚ด์šฉ
1 ์—ฐ๊ฒฐยท์‹œ๊ฐ„๋™๊ธฐ ๋กœ๋ด‡์ด ์•ˆ ๋‹ฟ์œผ๋ฉด ๋‹ค์‹œ ์ ‘์†ํ•˜๊ณ , ์‹œ๊ฐ„ ๋™๊ธฐ๋Š” ์ƒˆ ์‘๋‹ต์„ ๋ฐ›์„ ๋•Œ๊นŒ์ง€ ํ™•์ธ
2 E-Stop ๋“ฑ๋ก ์‹œ๋„ (๋ชจํ„ฐ๊ฐ€ ๊บผ์ ธ ์žˆ์„ ๋•Œ๋งŒ ๋ฉ๋‹ˆ๋‹ค)
3 ์ œ์–ด๊ถŒ ์—†์œผ๋ฉด ๊ฐ€์ ธ์˜ด (take_lease)
4 ๋งต ๋กœ๋ด‡ ์•ˆ์˜ ๋งต์ด ๋น„์–ด ์žˆ์œผ๋ฉด ๋‹ค์‹œ ์˜ฌ๋ฆผ (SPOT ์žฌ๋ถ€ํŒ… ์‹œ ๋น„์›Œ์ง‘๋‹ˆ๋‹ค)
5 ์œ„์น˜์ถ”์ • ํƒœ๊ทธ๊ฐ€ ๋ณด์ด๋ฉด ์›€์ง์ด์ง€ ์•Š๊ณ  ์žก์Œ. ์•ˆ ๋ณด์ด๋ฉด rotate: true ์ผ ๋•Œ๋งŒ ํšŒ์ „ ํƒ์ƒ‰
6 ๊ฒฐ๊ณผ ๋ณด๊ณ  ์ค€๋น„ ์—ฌ๋ถ€์™€ ๋ง‰ํžŒ ์ด์œ , ๋‹ค์Œ์— ํ•  ์ผ

์‘๋‹ต โ€” ๋‹ค๋ฅธ ๋ช…๋ น์ฒ˜๋Ÿผ 2๋ฒˆ ์˜ต๋‹ˆ๋‹ค. ๋ณดํ†ต 2~5์ดˆ ์•ˆ์— ์™„๋ฃŒ ์‘๋‹ต์ด ์˜ต๋‹ˆ๋‹ค.

์™„๋ฃŒ status ๋œป ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€๊ฐ€ ํ•  ์ผ
SUCCESS ์ค€๋น„ ์™„๋ฃŒ. ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋Œ๋ ค๋„ ๋ฉ๋‹ˆ๋‹ค "์ค€๋น„ ์™„๋ฃŒ" ํ‘œ์‹œ
FAULT_HW + fault_detail.code = "NOT_READY" ๋ฏธ์ค€๋น„. ๋กœ๋ด‡ ๊ณ ์žฅ์ด ์•„๋‹ˆ๋ผ ์กฐ์น˜๊ฐ€ ํ•„์š”ํ•œ ์ƒํƒœ fault_detail.message ๋ฅผ ๊ทธ๋Œ€๋กœ ํ™”๋ฉด์— ๋ณด์—ฌ์ฃผ์„ธ์š”

warm_up ์€ ์‹คํ–‰ ์ค‘์ธ ๋‹ค๋ฅธ warm_up ์ด ์žˆ์œผ๋ฉด BUSY ๋ฅผ ๋Œ๋ ค์ค๋‹ˆ๋‹ค. ์ถฉ์ „ ์ค‘์—๋„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค โ€” ์ ๊ฒ€๋งŒ ํ•˜๊ณ  ๋กœ๋ด‡์„ ์ผ์œผํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋ฏธ์ค€๋น„์ผ ๋•Œ์˜ ์‹ค์ œ ์‘๋‹ต (์ถฉ์ „ ์ผ€์ด๋ธ”์ด ๊ฝ‚ํžŒ ์ƒํƒœ, 2026-09-29 ํ˜„์žฅ):

{
  "command_id": "cmd-c902af65",
  "status": "FAULT_HW",
  "fault_detail": {
    "code": "NOT_READY",
    "message": "์ถฉ์ „ ์ผ€์ด๋ธ”์„ ๋ฝ‘์œผ์„ธ์š”",
    "report": {
      "connection": "online",
      "timesync": "ready(fresh)",
      "estop": "registered",
      "lease": "owned",
      "map": "present (40 waypoints)",
      "localization": "ok",
      "commands_accepted": false,
      "block_reasons": ["CHARGING"],
      "localized": true,
      "is_lost": false,
      "battery_pct": 89,
      "charging_state": "CHARGING",
      "ready": false,
      "next": "์ถฉ์ „ ์ผ€์ด๋ธ”์„ ๋ฝ‘์œผ์„ธ์š”"
    }
  }
}

fault_detail.message ๋Š” ์‚ฌ๋žŒ์ด ์ฝ๋Š” ์กฐ์น˜ ์•ˆ๋‚ด์ž…๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ ๊ฐœ๋ฉด / ๋กœ ์ด์–ด์ง‘๋‹ˆ๋‹ค.

๋ง‰ํžŒ ์ด์œ  (report.block_reasons) message ์˜ˆ
CHARGING ์ถฉ์ „ ์ผ€์ด๋ธ”์„ ๋ฝ‘์œผ์„ธ์š”
ESTOP_HARDWARE ๋กœ๋ด‡ ๋’ท๋ฉด์˜ ๋นจ๊ฐ„ MOTOR LOCKOUT ๋ฒ„ํŠผ์„ ํ™•์ธํ•˜์„ธ์š”
ESTOP_NOT_REGISTERED ๋กœ๋ด‡์„ ์•‰ํ˜€ ๋ชจํ„ฐ๋ฅผ ๋ˆ ๋’ค 20์ดˆ ๊ธฐ๋‹ค๋ ธ๋‹ค ๋‹ค์‹œ
FAULT_LEASE ์ œ์–ด๊ถŒ์ด ์—†์Šต๋‹ˆ๋‹ค โ€” ๋‹ค์‹œ ๋ˆ„๋ฅด๊ฑฐ๋‚˜ ํƒœ๋ธ”๋ฆฟ ์กฐ์ข…์„ ๋๋‚ด์„ธ์š”
BATTERY_LOW ๋ฐฐํ„ฐ๋ฆฌ ๋ถ€์กฑ โ€” ์ถฉ์ „ํ•˜์„ธ์š”
TIME_SYNC_NOT_READY ์‹œ๊ฐ„ ๋™๊ธฐ ๋Œ€๊ธฐ ์ค‘ โ€” 10์ดˆ ๋’ค ๋‹ค์‹œ
(์œ„์น˜์ถ”์ • ์•ˆ ๋จ) ํƒœ๊ทธ๊ฐ€ ๋ณด์ด๊ฒŒ ํ•˜๊ฑฐ๋‚˜ rotate: true ๋กœ ๋‹ค์‹œ
(๋กœ๋ด‡์ด ์•ˆ ๋‹ฟ์Œ) ๋กœ๋ด‡ ์ „์›ยท์œ ์„  ์ผ€์ด๋ธ”์„ ํ™•์ธํ•˜์„ธ์š”

โš ๏ธ message ๋ฌธ๊ตฌ๋Š” ๋ฐ”๋€” ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŒŒ์‹ฑํ•˜์ง€ ๋ง๊ณ  ๊ทธ๋Œ€๋กœ ๋ณด์—ฌ์ฃผ์„ธ์š”. ํ”„๋กœ๊ทธ๋žจ์œผ๋กœ ํŒ๋‹จํ•˜๋ ค๋ฉด report.ready ์™€ report.block_reasons ๋ฅผ ์“ฐ์„ธ์š”.

โ„น๏ธ warm_up ์„ ๋ˆ„๋ฅด์ง€ ์•Š์•„๋„ SPOT ์€ ์ „์›์ด ์ผœ์ง€๋ฉด ์—ฐ๊ฒฐยท๋งตยท์œ„์น˜์ถ”์ •์„ ์Šค์Šค๋กœ ๋ณต๊ตฌํ•ฉ๋‹ˆ๋‹ค(์›€์ง์ด์ง€ ์•Š๋Š” ๊ฒƒ๋งŒ). warm_up ์€ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธํ•˜๊ณ  ๋น ์ง„ ๊ฒƒ์„ ์ฑ„์šฐ๋Š” ์šฉ๋„์ž…๋‹ˆ๋‹ค.


3-1. ์„ธ์…˜ ํ† ํ”ฝ (SPOT ์ด ๊ตฌ๋…)

OC ์„œ๋ฒ„๊ฐ€ Vision ์— ์„ธ์…˜ ์‹œ์ž‘ยท์ข…๋ฃŒ๋ฅผ ์•Œ๋ฆฌ๋Š” ํ† ํ”ฝ(ORCHESTRATION_SERVER)์„ SPOT ๋„ ๊ฐ™์ด ๊ตฌ๋…ํ•ด์„œ ์Šค์Šค๋กœ ์›€์ง์ž…๋‹ˆ๋‹ค. robot/spot-01/command ๋กœ ๋”ฐ๋กœ ๋ช…๋ น์„ ๋ณด๋‚ด์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

Topic Payload SPOT ๋™์ž‘
server/session/start { "session_id": "โ€ฆ" } ํ•˜๋˜ ๋™์ž‘์„ ๋ฉˆ์ถ”๊ณ  home ์œผ๋กœ ์ด๋™. ๋„์ฐฉ ํ›„ ๊ฐ์ • ํ‘œํ˜„ ํ—ˆ์šฉ
server/session/end { "session_id": "โ€ฆ" } ๊ฐ์ • ํ‘œํ˜„ ์ค‘๋‹จ โ†’ ์ถฉ์ „ ์œ„์น˜๋กœ ๋ณต๊ท€ โ†’ ์ฐฉ์„ โ†’ ๋ชจํ„ฐ ์ „์› ๋‚ด๋ฆผ

โš ๏ธ server/session/end ๊ฐ€ ์˜ค์ง€ ์•Š์œผ๋ฉด SPOT ์€ ๋ณต๊ท€ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋งˆ์ง€๋ง‰ ์ž๋ฆฌ์— ์„œ์„œ ๊ณ„์† ๊ธฐ๋‹ค๋ฆฌ๊ณ , ์‹œ๊ฐ„์ด ์ง€๋‚˜๋„ ์Šค์Šค๋กœ ๋Œ์•„๊ฐ€์ง€ ์•Š์Šต๋‹ˆ๋‹ค (2026-10-04 ์ „์‹œ์žฅ: ์ข…๋ฃŒ ๋ฉ”์‹œ์ง€๊ฐ€ ์˜ค์ง€ ์•Š์•„ 9๋ถ„๊ฐ„ ๋Œ€๊ธฐ, ๊ด€๋ฆฌ์ž ์ฝ˜์†”์˜ return_home ์œผ๋กœ ์ˆ˜๋™ ๋ณต๊ท€). ์„ธ์…˜์ด ๋๋‚˜๋Š” ๋ชจ๋“  ๊ฒฝ๋กœ(์‚ฌ์šฉ์ž ์ข…๋ฃŒยทํƒ€์ž„์•„์›ƒยท๊ด€๋ฆฌ์ž ๊ฐ•์ œ ์ข…๋ฃŒยท์ƒˆ ์„ธ์…˜์œผ๋กœ ๊ต์ฒด)์—์„œ ๋ฐœํ–‰ํ•ด ์ฃผ์„ธ์š”. ๋ฐœํ–‰์ด ์–ด๋ ค์šด ๊ฒฝ๋กœ๊ฐ€ ์žˆ์œผ๋ฉด ๋Œ€์‹  return_home ๋ช…๋ น์„ ๋ณด๋‚ด๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์„œ๋ฒ„ ๋‹ต(2026-10-04, orchestration-server 148): ๋„ค ๊ฒฝ๋กœ ๋ชจ๋‘์—์„œ ๋‚ธ๋‹ค โ€” ํƒœ๋ธ”๋ฆฟ ์ข…๋ฃŒ ยท ๊ด€๋ฆฌ์ž ๊ฐ•์ œ ์ข…๋ฃŒ ยท ๊ฐ™์€ ํƒœ๋ธ”๋ฆฟ์˜ ์ƒˆ ์„ธ์…˜(์ด์ „ ์„ธ์…˜ end โ†’ ์ƒˆ start ์ˆœ) ยท ์œ ํœด ํƒ€์ž„์•„์›ƒ(์•ฑ ์„ค์ • session_idle_timeout_minutes, ๊ธฐ๋ณธ 15๋ถ„). 10-04 ์˜ 9๋ถ„ ๋Œ€๊ธฐ๋Š” ํƒœ๋ธ”๋ฆฟ์ด ์ข…๋ฃŒ ์—†์ด ์„ธ์…˜์„ ๋ฒ„๋ฆฐ ๊ฒฝ์šฐ๋กœ, ๊ทธ๋•Œ๋Š” 24์‹œ๊ฐ„ ๋’ค์—์•ผ DB ๋งŒ ๋‹ซํ˜”๋‹ค. ์ด์ œ ํ™œ๋™์ด 15๋ถ„ ๋ฉˆ์ถ”๋ฉด ์„œ๋ฒ„๊ฐ€ end ๋ฅผ ๋‚ธ๋‹ค.

์„ธ๋ถ€ ๊ทœ์น™

์ƒํ™ฉ SPOT ๋™์ž‘
retained ๋กœ ์˜จ ๋ฉ”์‹œ์ง€ ๋ฌด์‹œ. ์žฌ์ ‘์† ๋•Œ ์˜› ์„ธ์…˜์ด ๋˜์‚ด์•„๋‚˜์ง€ ์•Š๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค โ€” retained ๋กœ ๋ฐœํ–‰ํ•˜์ง€ ๋งˆ์„ธ์š”
์„ธ์…˜ ์ค‘์— ๋‹ค๋ฅธ session_id ์˜ start ์ƒˆ ์„ธ์…˜์œผ๋กœ ๊ฐˆ์•„ํƒ‘๋‹ˆ๋‹ค. ์ง„ํ–‰ ์ค‘์ด๋˜ ๋ช…๋ น์€ ABORTED
์ง€๊ธˆ ์„ธ์…˜์ด ์•„๋‹Œ session_id ์˜ end ๋ฌด์‹œ (๋Šฆ๊ฒŒ ์˜จ ์ด์ „ ์„ธ์…˜์˜ ์ข…๋ฃŒ๊ฐ€ ์ง€๊ธˆ ์‘๋Œ€๋ฅผ ๋Š์ง€ ์•Š๊ฒŒ)
๋ณต๊ท€ ์ค‘์— ๊ฐ™์€ end ๊ฐ€ ๋˜ ์˜ด ๋ฌด์‹œ (์ง„ํ–‰ ์ค‘์ธ ๋ณต๊ท€ ์œ ์ง€)
start ์‹œ์ ์— ์ถฉ์ „ ์ผ€์ด๋ธ”์ด ๊ฝ‚ํ˜€ ์žˆ์Œ ๋ฝ‘ํžˆ๊ธฐ๋ฅผ ์ตœ๋Œ€ 30์ดˆ ๋Œ€๊ธฐ โ†’ ๋ฝ‘ํžˆ๋ฉด 3์ดˆ ๋’ค ์ถœ๋ฐœ, ์•ˆ ๋ฝ‘ํžˆ๋ฉด ๊ทธ ์„ธ์…˜์€ ์ด๋™ ์—†์ด ์ทจ์†Œ
end ์‹œ์ ์— ์ถฉ์ „ ์ค‘ ์ด๋™ํ•˜์ง€ ์•Š์Œ (์ด๋ฏธ ์ถฉ์ „ ์œ„์น˜๋กœ ๊ฐ„์ฃผ)
๋ณต๊ท€๊ฐ€ FAULT_NAV ๋กœ ์‹คํŒจ (์‚ฌ๋žŒ์— ๋ง‰ํž˜ ๋“ฑ) SPOT ์ด 10์ดˆ ๋’ค ์Šค์Šค๋กœ ์žฌ์‹œ๋„, ์ตœ๋Œ€ 3ํšŒ. ๊ทธ ์‚ฌ์ด ๋‹ค๋ฅธ ๋ช…๋ นยท์„ธ์…˜ยทSTOP ์ด ์˜ค๋ฉด ์žฌ์‹œ๋„ ์ทจ์†Œ

๊ฒฐ๊ณผ ๋ณด๊ณ 

์„ธ์…˜ ํ† ํ”ฝ์œผ๋กœ ์‹œ์ž‘๋œ ์ด๋™(ํ™ˆ ์ด๋™ยท์ถฉ์ „ ๋ณต๊ท€)์˜ ์™„๋ฃŒ๋Š” robot/spot-01/ack ๋กœ ๋‚˜๊ฐ‘๋‹ˆ๋‹ค. OC ๊ฐ€ ๋ณด๋‚ธ ๋ช…๋ น์ด ์•„๋‹ˆ๋ฏ€๋กœ command_id ๋Š” SPOT ์ด ๋งŒ๋“  cmd-xxxxxxxx, session_id ๋Š” null ์ž…๋‹ˆ๋‹ค โ€” OC ์˜ ๋Œ€๊ธฐ ๋ชฉ๋ก๊ณผ ๋งค์นญ๋˜์ง€ ์•Š์œผ๋‹ˆ ๋ฌด์‹œํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ ‘์ˆ˜(ACCEPTED) ack ๋Š” ์—†๊ณ  ์™„๋ฃŒ(SUCCESSยทFAULT_NAVยทABORTED)๋งŒ ๋‚˜๊ฐ‘๋‹ˆ๋‹ค.

๊ฐ์ • ํ‘œํ˜„(cctv/person/emotion ์ง์ ‘ ๊ตฌ๋…)์˜ ์™„๋ฃŒ๋„ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ ๋‚˜๊ฐ‘๋‹ˆ๋‹ค.

๊ฐ™์€ ๋™์ž‘์„ ๋ช…๋ น์œผ๋กœ ๋ณด๋‚ด๋ ค๋ฉด

robot/spot-01/command ์— action: "session_start"(params.destination ์ƒ๋žต ์‹œ home) ยท "session_end" ๋ฅผ ๋ณด๋‚ด๋„ ๊ฐ™์€ ์ฒ˜๋ฆฌ์ž…๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ์ผ๋ฐ˜ ๋ช…๋ น์ฒ˜๋Ÿผ ์ ‘์ˆ˜ยท์™„๋ฃŒ ack ๊ฐ€ ์š”์ฒญ์˜ command_id ๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค.


4. RESPONSE (SPOT โ†’ ๊ตฌ๋…์ž)

Topic: robot/spot-01/ack

ํ•œ ๋ช…๋ น์— ์‘๋‹ต์ด 2๋ฒˆ ์˜ต๋‹ˆ๋‹ค.

โ‘  ์ ‘์ˆ˜ ์‘๋‹ต   ์ฆ‰์‹œ      "๋ฐ›์•˜๋‹ค" ๋˜๋Š” "๋ชป ๋ฐ›๋Š”๋‹ค"
โ‘ก ์™„๋ฃŒ ์‘๋‹ต   ๋‚˜์ค‘์—    "๋‹ค ํ–ˆ๋‹ค" ๋˜๋Š” "์ด๋ž˜์„œ ์‹คํŒจํ–ˆ๋‹ค"
ํ•„๋“œ ํƒ€์ž… ํ•„์ˆ˜ ์„ค๋ช…
command_id string Y ์š”์ฒญ์˜ ๊ฐ’
session_id string | null Y ์š”์ฒญ์˜ ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ๋˜๋Œ๋ ค์ค๋‹ˆ๋‹ค. ๋กœ๋ด‡์ด ๊ทธ ๋ช…๋ น์„ ๋ชจ๋ฅด๋ฉด null
robot_id string Y spot-01
status string Y ์•„๋ž˜ ํ‘œ
timestamp string Y ๋ฐœํ–‰ ์‹œ๊ฐ (UTC, ISO 8601)
fsm_state string Y ๋ณด๊ณ  ์‹œ์ ์˜ ๋กœ๋ด‡ ์ƒํƒœ
posture string Y stand | sit | unknown
location string | null Y ์™„๋ฃŒ ์‹œ์ ์˜ ์›จ์ดํฌ์ธํŠธ ์ด๋ฆ„. ๋ชจ๋ฅด๋ฉด null
map_id string | null Y ๋กœ๋“œ๋œ ๋งต. ์—†์œผ๋ฉด null
fault_detail object | null Y ์‹คํŒจ ์‹œ ์•„๋ž˜ ํ‘œ. ์„ฑ๊ณต์ด์–ด๋„ ํ‚ค๋Š” ์˜ต๋‹ˆ๋‹ค (๊ฐ’์ด null)

โš ๏ธ โ‘ ์ ‘์ˆ˜์™€ โ‘ก์™„๋ฃŒ๋Š” ์‹ค๋ฆฌ๋Š” ํ•„๋“œ๊ฐ€ ๋‹ค๋ฆ…๋‹ˆ๋‹ค.

์‹ค๋ฆฌ๋Š” ํ•„๋“œ
โ‘  ์ ‘์ˆ˜ command_id ยท session_id ยท robot_id ยท status ยท timestamp ยท fsm_state 6๊ฐœ. ๊ฑฐ๋ถ€์ผ ๋•Œ๋งŒ fault_detail ์ด ๋” ๋ถ™์Šต๋‹ˆ๋‹ค
โ‘ก ์™„๋ฃŒ ์œ„ ํ‘œ 10๊ฐœ ์ „๋ถ€. ๊ฐ’์ด ์—†์œผ๋ฉด null ์ด๋ฉฐ ํ‚ค๋ฅผ ์ƒ๋žตํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค

์ ‘์ˆ˜ ack ์—์„œ locationยทmap_idยทposture ๋ฅผ ์ฝ์œผ๋ฉด undefined ์ž…๋‹ˆ๋‹ค โ€” ์•„์ง ์‹œ์ž‘๋„ ์•ˆ ํ•œ ๋ช…๋ น์ด๋ผ ๊ฐ’์ด ์—†๋Š” ๊ฒŒ ๋งž์Šต๋‹ˆ๋‹ค.

status

๊ฐ’ ๋‹จ๊ณ„ ๋œป ์„œ๋ฒ„๊ฐ€ ํ•  ์ผ
ACCEPTED โ‘  ์ ‘์ˆ˜๋จ. ์‹คํ–‰ ์‹œ์ž‘ ์™„๋ฃŒ ์‘๋‹ต์„ ๊ธฐ๋‹ค๋ฆฝ๋‹ˆ๋‹ค
BUSY โ‘  ๋‹ค๋ฅธ ๋ช…๋ น ์‹คํ–‰ ์ค‘ ์žฌ์‹œ๋„ ๋˜๋Š” ๋Œ€๊ธฐ. ์™„๋ฃŒ ์‘๋‹ต์€ ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค
REJECTED โ‘  ์ง€๊ธˆ ์ƒํƒœ์—์„œ ๋ถˆ๊ฐ€ ์žฌ๊ณ„ํš. ์™„๋ฃŒ ์‘๋‹ต์€ ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค
SUCCESS โ‘ก ์ •์ƒ ์™„๋ฃŒ ๋‹ค์Œ ๋‹จ๊ณ„
ABORTED โ‘ก STOP ์œผ๋กœ ์ค‘๋‹จ๋จ ์‚ฌ๋žŒ์ด ๊ฐœ์ž…ํ•œ ๊ฒƒ
FAULT_NAV โ‘ก ๊ฒฝ๋กœ ์‹คํŒจยท์œ„์น˜ ์ƒ์‹ค NOT_LOCALIZED ๋ฉด ์žฌ์‹œ๋„ ๊ธˆ์ง€ (์•„๋ž˜ ์ฐธ๊ณ )
FAULT_LEASE โ‘ก ์ œ์–ด๊ถŒ์„ ๋บ๊น€ state.commands_accepted ๊ฐ€ true ๋กœ ๋Œ์•„์˜ฌ ๋•Œ๊นŒ์ง€ ๋Œ€๊ธฐ
FAULT_HW โ‘ก ํ•˜๋“œ์›จ์–ด ๋ฌธ์ œ ์šด์˜์ž ํ˜ธ์ถœ
TIMEOUT โ‘ก ์ œํ•œ ์‹œ๊ฐ„ ์ดˆ๊ณผ ์žฌ์‹œ๋„

โš ๏ธ navigate_to ๋Š” TIMEOUT ์„ ๋‚ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋กœ๋ด‡์€ ๋„์ฐฉํ•˜๊ฑฐ๋‚˜ ์‹คํŒจํ•  ๋•Œ๊นŒ์ง€ ๊ณ„์† ๊ฐ‘๋‹ˆ๋‹ค. ์„œ๋ฒ„๊ฐ€ ์ž์ฒด ์ƒํ•œ์„ ๊ฑธ์–ด์ฃผ์„ธ์š” โ€” ์ฃผํ–‰ ์†๋„๊ฐ€ 0.15 m/s ์ด๋ฏ€๋กœ ๊ฒฝ๋กœ ๊ธธ์ด(m) รท 0.15 ์— ์—ฌ์œ ๋ฅผ ๋”ํ•œ ๊ฐ’์ด ๊ธฐ์ค€์ด ๋ฉ๋‹ˆ๋‹ค. ์ƒํ•œ์„ ๋„˜๊ฒผ๋‹ค๊ณ  ํŒ๋‹จํ•˜๋ฉด ๊ฐ™์€ ๋ช…๋ น์„ ์žฌ์‹œ๋„ํ•˜์ง€ ๋ง๊ณ  stop ์„ ๋จผ์ € ๋ณด๋‚ด์ฃผ์„ธ์š”. ๋กœ๋ด‡์€ ์•„์ง ๊ทธ ๋ช…๋ น์„ ์‹คํ–‰ ์ค‘์ด๋ผ ์ƒˆ ๋ช…๋ น์€ BUSY ๋กœ ๊ฑฐ์ ˆ๋ฉ๋‹ˆ๋‹ค.

orchestration-server ๊ฐ€ ๊ฑฐ๋Š” ์ƒํ•œ์€ ์•ฑ ์„ค์ • spot_command_timeout_seconds (๊ธฐ๋ณธ 30์ดˆ) ์ž…๋‹ˆ๋‹ค. ๋ฐฑ์˜คํ”ผ์Šค ์„ค์ • ํ™”๋ฉด์—์„œ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ๊ณ , ํ์— ์ด๋ฏธ ๋“ค์–ด๊ฐ„ ๋ช…๋ น๋„ ๋ฐœํ–‰ ์ง์ „์— ๋‹ค์‹œ ์ฝ์œผ๋ฏ€๋กœ ๊ณ ์น˜๋ฉด ๋ฐ”๋กœ ๋‹ค์Œ ๋ช…๋ น๋ถ€ํ„ฐ ๋จน์Šต๋‹ˆ๋‹ค. ์ž๋™ํ™” ์•ก์…˜์— timeout_ms ๋ฅผ ์ง์ ‘ ์ ์–ด ๋‘” ๊ฒฝ์šฐ์—๋Š” ๊ทธ ๊ฐ’์ด ์šฐ์„ ํ•ฉ๋‹ˆ๋‹ค. ์ƒํ•œ์— ๊ฑธ๋ ค ๋ฉˆ์ถ˜ ๋ช…๋ น์€ ์Šคํƒœํ”„ ํ™”๋ฉด /staff/spot ์— ๋œจ๊ณ , ๊ฑฐ๊ธฐ์„œ ์ฆ‰์‹œ ์ •์ง€ โ†’ ์žฌ์‹œ๋„ ์ˆœ์œผ๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

โš ๏ธ BUSYยทREJECTED ๋Š” ์™„๋ฃŒ ์‘๋‹ต์ด ์˜ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋ฌด์กฐ๊ฑด ๊ธฐ๋‹ค๋ฆฌ๋ฉด ์˜์›ํžˆ ๋ธ”๋กœํ‚น๋ฉ๋‹ˆ๋‹ค. ACCEPTED ๋ฅผ ๋ฐ›์€ ๋ช…๋ น๋งŒ ๊ธฐ๋‹ค๋ ค์ฃผ์„ธ์š”.

โš ๏ธ ์˜ˆ์™ธ ํ•˜๋‚˜ โ€” run_scenario ์•ˆ์—์„œ๋Š” REJECTED ๊ฐ€ ์™„๋ฃŒ ์‘๋‹ต์œผ๋กœ ์˜ต๋‹ˆ๋‹ค. ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ์Šคํ…์„ ์‹œ์ž‘ํ•œ ๋’ค์—์•ผ ๋ชฉ์ ์ง€ ์ด๋ฆ„์„ ํ’€๊ธฐ ๋•Œ๋ฌธ์—, ๊ทธ ์ด๋ฆ„์ด ํ‹€๋ ธ์œผ๋ฉด ์ ‘์ˆ˜๋Š” ACCEPTED ๋กœ ๋๋‚˜๊ณ  ์‹คํŒจ๊ฐ€ โ‘ก๋‹จ๊ณ„๋กœ ์˜ต๋‹ˆ๋‹ค (fault_detail.failed_step ์œผ๋กœ ์–ด๋А ์Šคํ…์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค). ACCEPTED ๋ฅผ ๋ฐ›์€ ๋ช…๋ น์€ REJECTED ๋กœ ๋๋‚  ์ˆ˜๋„ ์žˆ๋‹ค๊ณ  ๋ณด๊ณ  ์ข…๊ฒฐ ์ฒ˜๋ฆฌํ•ด์ฃผ์„ธ์š”.

fault_detail ๊ตฌ์กฐ

ํ•„๋“œ ํƒ€์ž… ์–ธ์ œ
code string ํ•ญ์ƒ (์•„๋ž˜ ํ‘œ)
message string ํ•ญ์ƒ. ์‚ฌ๋žŒ์ด ์ฝ๋Š” ๋ฌธ์žฅ
failed_step number run_scenarioยทํ”Œ๋žœ ์‹คํŒจ ์‹œ์—๋งŒ. ์‹คํŒจํ•œ ์Šคํ…์˜ 0-๋ฒ ์ด์Šค ์ฒจ์ž
plan_id string ใ€ƒ

fault_detail.code

์ฝ”๋“œ ์–ธ์ œ ์„œ๋ฒ„๊ฐ€ ํ•  ์ผ
UNKNOWN_ACTION ๋ชจ๋ฅด๋Š” action ์˜คํƒ€์ด๊ฑฐ๋‚˜ ๋ฏธ์ง€์›. ์žฌ์‹œ๋„ ๋ฌด์˜๋ฏธ
BAD_PARAM ํ•„์ˆ˜ ํŒŒ๋ผ๋ฏธํ„ฐ ์—†์Œ ๋น ์ง„ ์ด๋ฆ„์ด message ์— ์ ํž™๋‹ˆ๋‹ค
UNKNOWN_WAYPOINT destination ์ด ๋ชฉ๋ก์— ์—†์Œ waypoints ๋ฅผ ๋‹ค์‹œ ์ฝ์œผ์„ธ์š”
AMBIGUOUS_WAYPOINT ๊ฐ™์€ ์ด๋ฆ„์˜ ์ง€์ ์ด ๋‘˜ ์ด์ƒ ๊ทธ ์ด๋ฆ„์€ ์“ธ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค (3์ ˆ)
NOT_A_DESTINATION ์ž๋™ ์ƒ์„ฑ ๊ฒฝ์œ ์ง€๋ฅผ ๋ชฉ์ ์ง€๋กœ ์ง€์ • ๊ธธ์ด์ง€ ์žฅ์†Œ๊ฐ€ ์•„๋‹™๋‹ˆ๋‹ค
NOT_LOCALIZED ๋กœ๋ด‡์ด ์ž๊ธฐ ์œ„์น˜๋ฅผ ๋ชจ๋ฆ„ ์žฌ์‹œ๋„ ๊ธˆ์ง€. ์œ„์น˜์ถ”์ •๋ถ€ํ„ฐ
BATTERY_LOW ๋ฐฐํ„ฐ๋ฆฌ ์ž ๊ธˆ โ€” ๋ณต๊ท€ ํ›„ ์ฐฉ์„ ์ƒํƒœ (9.2์ ˆ) ์ถฉ์ „ ์ „๊นŒ์ง€ ์•ˆ ํ’€๋ฆฝ๋‹ˆ๋‹ค. ์šด์˜์ž ํ˜ธ์ถœ
MOTION_DISABLED ์šด์˜์ž๊ฐ€ ๋ชจ์…˜์„ ์ „๋ฉด ์ฐจ๋‹จํ•จ ์‚ฌ๋žŒ์ด ํ’€์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. stop ์€ ๊ณ„์† ๋จน์Šต๋‹ˆ๋‹ค
DISPATCH_ERROR ๋กœ๋ด‡ ๋‚ด๋ถ€ ์˜ˆ์™ธ ๋กœ๊ทธ ํ™•์ธ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค

ack ์™€ plan ์—๋Š” ์š”์ฒญ์˜ session_id ๋ฅผ ๊ทธ๋Œ€๋กœ ์‹ค์–ด ๋˜๋Œ๋ ค์ค๋‹ˆ๋‹ค. OC ์„œ๋ฒ„๊ฐ€ ์ด ๊ฐ’์„ ์žฌ๋ฐœํ–‰ ํ† ํ”ฝ ์ด๋ฆ„ ์•ˆ์˜ ๋ผ์šฐํŒ… ํ‚ค๋กœ ์“ฐ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค (orchestration/{session_id}/spot/ack). ์ด ๊ฐ’์ด ์—†์œผ๋ฉด ์žฌ๋ฐœํ–‰ ์ž์ฒด๊ฐ€ ์ผ์–ด๋‚˜์ง€ ์•Š์•„ ํ™”๋ฉด์— ์•„๋ฌด๊ฒƒ๋„ ๋œจ์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ๋ฉ”์‹œ์ง€ ์œ ์‹ค์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ๋ผ์šฐํŒ… ์‹คํŒจ์ž…๋‹ˆ๋‹ค.

์˜ˆ์‹œ

// โ‘  ์ ‘์ˆ˜
{ "command_id": "cmd-0042", "session_id": "01HW9X8M2K", "robot_id": "spot-01",
  "status": "ACCEPTED", "timestamp": "2026-08-08T04:12:03Z",
  "fsm_state": "NAVIGATING" }

// โ‘ก ์™„๋ฃŒ (์„ฑ๊ณต)
{ "command_id": "cmd-0042", "session_id": "01HW9X8M2K", "robot_id": "spot-01",
  "status": "SUCCESS", "timestamp": "2026-08-08T04:14:11Z",
  "fsm_state": "IDLE", "posture": "stand",
  "location": "p2", "map_id": "map_0807_2112", "fault_detail": null }

// โ‘ก ์™„๋ฃŒ (์‹คํŒจ)
{ "command_id": "cmd-0042", "session_id": "01HW9X8M2K", "robot_id": "spot-01",
  "status": "FAULT_NAV", "timestamp": "2026-08-08T04:13:40Z",
  "fsm_state": "IDLE", "posture": "stand",
  "location": null, "map_id": "map_0807_2112",
  "fault_detail": { "code": "NOT_LOCALIZED",
                    "message": "robot does not know where it is" } }

5. ์ƒํƒœ ยท ๋ชฉ๋ก ํ† ํ”ฝ

robot/spot-01/state โ€” 1Hz, retained

{
  "connection": "online",              // offline ์ด๋ฉด SPOT ์ด ์ฃฝ์€ ๊ฒƒ (์•„๋ž˜ ์ฐธ๊ณ )
  "timestamp": "2026-08-08T04:12:03Z",
  "fsm_state": "IDLE",                 // IDLE|NAVIGATING|FOLLOWING|EXECUTING_PLAN
                                       // |POSING|INSPECTING|RELOCALIZING
  "battery_pct": 54,
  "battery_runtime_min": 93,
  "power_state": "ON",                 // ON|OFF  (๋ชจํ„ฐ ์ „์›)
  "posture": "stand",                  // stand|sit|unknown โ€” ์ „์›๊ณผ ๋ณ„๊ฐœ์ž…๋‹ˆ๋‹ค
  "shore_power": "OFF",                // ์ถฉ์ „ ์ผ€์ด๋ธ” ON|OFF
  "battery_status": "DISCHARGING",     // CHARGING|DISCHARGING
  "estop_state": "NONE",               // NONE|SOFTWARE|HARDWARE
  "lease_owned": true,                 // SPOT ์„œ๋ฒ„๊ฐ€ ์ œ์–ด๊ถŒ์„ ์ฅ๊ณ  ์žˆ๋‚˜
  "lease_owner": "orchestration",      // orchestration | operator | none
  "commands_accepted": true,           // โ˜… false ๋ฉด ์ง€๊ธˆ ๋ช…๋ น์„ ๋ณด๋‚ด๋„ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค
  "localized": true,                   // ์ž๊ธฐ ์œ„์น˜๋ฅผ ์•„๋‚˜
  "is_lost": false,                    // true ๋ฉด ์ด๋™ ๋ช…๋ น์ด ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค
  "current_waypoint_label": "p2",      // ์‚ฌ๋žŒ์ด ์ฝ๋Š” ์ด๋ฆ„
  "current_waypoint_id": "papery-toucan-iQ1qโ€ฆ",   // ๊ทธ๋ž˜ํ”„ ์ƒ์˜ ๊ณ ์œ  id
  "target_waypoint_label": null,       // ์ด๋™ ์ค‘์ด๋ฉด ๋ชฉ์ ์ง€
  "target_waypoint_id": null,
  "map_id": "map_0807_2112",
  "current_command_id": null,          // ์‹คํ–‰ ์ค‘์ธ ๋ช…๋ น. ์—†์œผ๋ฉด null
  "seed_tform_body": { "x": 1.46, "y": 0.24, "z": -0.42, "yaw_deg": 55.0 },
  "world_position_cm": null,           // ๋ณด์ •๋˜๋ฉด { "x": 812.4, "y": -230.1 } (cm, zยทyaw ์—†์Œ)
  "anchor_offset": null,               // ์œ„ ๋ณ€ํ™˜์˜ ๊ทผ๊ฑฐ {rotation_deg, tx_cm, ty_cm}
  "faults": []                         // ์žˆ์œผ๋ฉด [{ "name": "โ€ฆ", "severity": 2 }]
}

commands_accepted ๋ฅผ ๋ณด๊ณ  ๋ฐœํ–‰ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•ด์ฃผ์„ธ์š”. false ๊ฐ€ ๋˜๋Š” ๊ฒฝ์šฐ๋Š” ๊ด€๋ฆฌ์ž๊ฐ€ ํ˜„์žฅ์—์„œ ์ œ์–ด๊ถŒ์„ ๊ฐ€์ ธ๊ฐ”์„ ๋•Œ, ๋น„์ƒ์ •์ง€ ์ค‘์ผ ๋•Œ, ๋ฐฐํ„ฐ๋ฆฌ๊ฐ€ ๋ฐ”๋‹ฅ์ด๊ฑฐ๋‚˜ ์ž ๊ฒผ์„ ๋•Œ(9.2์ ˆ), ๊ทธ๋ฆฌ๊ณ  ๋กœ๋ด‡์ด ๊ด€์ „ ๋ชจ๋“œ๋กœ ๋ถ™์–ด ์žˆ์„ ๋•Œ์ž…๋‹ˆ๋‹ค. ์•ž์˜ ๊ฒƒ๋“ค์€ lease_owner ยท estop_state ยท battery_pct ๋กœ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ด€์ „ ๋ชจ๋“œ๋Š” SPOT ์„œ๋ฒ„๊ฐ€ E-Stop ๋“ฑ๋ก์„ ๋ชป ํ•œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค โ€” ์ƒํƒœยท์นด๋ฉ”๋ผยท์œ„์น˜๋Š” ์ „๋ถ€ ์ •์ƒ์ด๊ณ  ๋ชจ์…˜๋งŒ ๋ถˆ๊ฐ€ํ•˜๋ฉฐ, ์กฐ๊ฑด์ด ํ’€๋ฆฌ๋ฉด ์Šค์Šค๋กœ ๋ณต๊ตฌ๋ฉ๋‹ˆ๋‹ค. state ๋งŒ์œผ๋กœ๋Š” ์ด ๊ฒฝ์šฐ๋ฅผ ๋”ฐ๋กœ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†์œผ๋‹ˆ, ๋‹ค๋ฅธ ์…‹์ด ์ •์ƒ์ธ๋ฐ commands_accepted ๊ฐ€ false ๋ฉด ์ด๊ฒƒ์ด๋ผ๊ณ  ๋ณด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ง„๋‹จ์šฉ ํ•„๋“œ๊ฐ€ ๋ช‡ ๊ฐœ ๋” ์‹ค๋ฆฝ๋‹ˆ๋‹ค (temp_c ยท joints ยท joint_max_load ยท joints_detail). ๊ณ„์•ฝ์ด ์•„๋‹ˆ๋ผ ์˜ˆ๊ณ  ์—†์ด ๋ฐ”๋€Œ๋ฏ€๋กœ ํ™”๋ฉด์—์„œ ์“ฐ์ง€ ๋งˆ์„ธ์š”.

์ด ํ† ํ”ฝ์˜ ๋ฐœํ–‰์ž๋Š” SPOT ์„œ๋ฒ„ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค โ€” ๋ด‰ํˆฌ์˜ source ๋Š” ํ•ญ์ƒ /services/spot-mcp-server ์ž…๋‹ˆ๋‹ค.

current_command_id ๋Š” ack ๋ฅผ ๋†“์ณค์„ ๋•Œ์˜ ๋ณต๊ตฌ ๋‹จ์„œ์ž…๋‹ˆ๋‹ค. ์™„๋ฃŒ ack ๋Š” retained ๊ฐ€ ์•„๋‹ˆ๋ผ, ์„œ๋ฒ„๊ฐ€ ์žฌ์‹œ์ž‘ํ•˜๊ฑฐ๋‚˜ ๋ธŒ๋กœ์ปค ์—ฐ๊ฒฐ์ด ๋Š๊ธด ์‚ฌ์ด์— ์˜ค๋ฉด ์œ ์‹ค๋ฉ๋‹ˆ๋‹ค. ๊ทธ๋•Œ ์ด ๊ฐ’์„ ๋ณด๋ฉด ๋กœ๋ด‡์ด ์•„์ง ๊ทธ ๋ช…๋ น์„ ์‹คํ–‰ ์ค‘์ธ์ง€ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค โ€” null ์ธ๋ฐ ์„œ๋ฒ„ ํ์— pending ์ด ๋‚จ์•„ ์žˆ๋‹ค๋ฉด ๊ทธ ๋ช…๋ น์€ ์ด๋ฏธ ๋๋‚œ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

์ ‘์ˆ˜ ACCEPTED ์‹œ์ ์— ์‹ค๋ฆฌ๊ณ  ์™„๋ฃŒ ack ์‹œ์ ์— ๋‚ด๋ ค๊ฐ‘๋‹ˆ๋‹ค. MQTT ๋กœ ๋ฐ›์€ ๋ช…๋ น๋งŒ ์‹ค๋ฆฝ๋‹ˆ๋‹ค โ€” ๊ด€๋ฆฌ์ž UI ๊ฐ€ MCP ๋กœ ์ง์ ‘ ์‹œํ‚จ ๋™์ž‘ ์ค‘์—๋Š” null ์ด๊ณ , ๊ทธ๋•Œ๋Š” fsm_state ๊ฐ€ IDLE ์ด ์•„๋‹Œ ๊ฒƒ์œผ๋กœ ํŒ๋‹จํ•ด์ฃผ์„ธ์š”.

state ํŽ˜์ด๋กœ๋“œ์—๋Š” robot_id ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค. ์–ด๋А ๋กœ๋ด‡์ธ์ง€๋Š” ํ† ํ”ฝ ๊ฒฝ๋กœ์˜ {id} ์„ธ๊ทธ๋จผํŠธ๋กœ ํŒ๋‹จํ•ด์ฃผ์„ธ์š” (ack ์—๋Š” robot_id ๊ฐ€ ์‹ค๋ฆฝ๋‹ˆ๋‹ค).

world_position_cm ์€ ์•ต์ปค ํƒœ๊ทธ๋กœ ๋ณด์ •ํ•œ ๋’ค์—๋งŒ ๊ฐ’์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ „์—๋Š” null ์ž…๋‹ˆ๋‹ค. ์ฝ˜์†”์ด ์ด ์ขŒํ‘œ๋ฅผ ์ง€๋„์— ๋˜์ฐ์œผ๋ ค๋ฉด ์—ญ๋ณ€ํ™˜์ด ํ•„์š”ํ•œ๋ฐ, ๊ทผ๊ฑฐ๋Š” anchor_offset ๋ฟ์ž…๋‹ˆ๋‹ค. ๋งต์„ ๋‹ค์‹œ ๋…นํ™”ํ•˜๋ฉด ๋‘˜ ๋‹ค null ๋กœ ๋Œ์•„๊ฐ‘๋‹ˆ๋‹ค.

connection: offline ์€ SPOT ์ด ๋ฐœํ–‰ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. SPOT ์ด ์ฃฝ์œผ๋ฉด ๋ธŒ๋กœ์ปค๊ฐ€ ๋Œ€์‹  ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค(MQTT LWT). retained ๋ผ ๋Šฆ๊ฒŒ ๋ถ™์€ ๊ตฌ๋…์ž๋„ ์ฆ‰์‹œ ์••๋‹ˆ๋‹ค. ๋‹ค๋งŒ ๋ธŒ๋กœ์ปค๊ฐ€ ์•Œ์•„์ฑ„๋Š” ๋ฐ ์ตœ๋Œ€ 60์ดˆ ๊ฑธ๋ฆฌ๋ฏ€๋กœ, timestamp ๋ฅผ ๊ฐ™์ด ๋ณด๊ณ  ์˜ค๋ž˜๋œ ๊ฐ’์ธ์ง€ ํŒ๋‹จํ•ด์ฃผ์„ธ์š”.

๊ทธ๋•Œ ์˜ค๋Š” ๊ฒƒ์€ ์œ„ ์ „๋ฌธ์ด ์•„๋‹ˆ๋ผ ์•„๋ž˜ 3ํ•„๋“œ์งœ๋ฆฌ์ž…๋‹ˆ๋‹ค (๋ธŒ๋กœ์ปค๊ฐ€ ๋ฏธ๋ฆฌ ๋“ฑ๋ก๋œ ํŽ˜์ด๋กœ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ๋ฑ‰๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค):

{ "specversion": "1.0", "type": "robot.state",
  "source": "/services/spot-mcp-server", "subject": "robot/spot-01",
  "data": { "robot_id": "spot-01", "connection": "offline",
            "timestamp": "2026-08-08T04:20:00Z" } }

โš ๏ธ ๊ฐ™์€ ํ† ํ”ฝ์— ์Šคํ‚ค๋งˆ๊ฐ€ ๋‘˜์ด๋ผ๋Š” ๋œป์ž…๋‹ˆ๋‹ค. battery_pctยทfsm_state ๋ฅผ ํ•„์ˆ˜๋กœ ํŒŒ์‹ฑํ•˜๋ฉด ๋กœ๋ด‡์ด ์ฃฝ๋Š” ์ˆœ๊ฐ„ ํŒŒ์„œ๊ฐ€ ๊นจ์ง‘๋‹ˆ๋‹ค. connection ์„ ๋จผ์ € ๋ณด๊ณ  ๋ถ„๊ธฐํ•ด์ฃผ์„ธ์š”.

โš ๏ธ ์ด ๋ฉ”์‹œ์ง€๋„ retained ๋ผ ์ง์ „์˜ ์ •์ƒ state ๋ฅผ ๋ฎ์–ด์”๋‹ˆ๋‹ค. "์ฃฝ๊ธฐ ์ง์ „ ๋ฐฐํ„ฐ๋ฆฌ๊ฐ€ ๋ช‡ %์˜€๋‚˜" ๋Š” ๋ธŒ๋กœ์ปค์— ๋‚จ์ง€ ์•Š์Šต๋‹ˆ๋‹ค โ€” ํ•„์š”ํ•˜๋ฉด ์„œ๋ฒ„๊ฐ€ ๋งˆ์ง€๋ง‰ ๊ฐ’์„ ๋ณด๊ด€ํ•ด์ฃผ์„ธ์š”.

robot/spot-01/waypoints โ€” retained

๊ฐˆ ์ˆ˜ ์žˆ๋Š” ๊ณณ ๋ชฉ๋ก. ๋งต์„ ์ƒˆ๋กœ ๋งŒ๋“ค ๋•Œ๋งˆ๋‹ค ๊ฐฑ์‹ ๋ฉ๋‹ˆ๋‹ค.

{
  "map_id": "map_0807_2112",
  "updated_at": "2026-08-07T12:54:48Z",
  "waypoints": [
    { "label": "origin", "fiducials": [1] },
    { "label": "p2",     "fiducials": [0, 2] },
    { "label": "p3",     "fiducials": [0] }
  ]
}

retained ๋ผ์„œ ์„œ๋ฒ„๊ฐ€ ์–ธ์ œ ์ผœ์ง€๋“  ์ ‘์† ์ฆ‰์‹œ ๋ชฉ๋ก์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. ํƒœ๋ธ”๋ฆฟ ๋ชฉ์ ์ง€ ๋ฉ”๋‰ด๋ฅผ ์ด๊ฑธ๋กœ ์ฑ„์šฐ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

โš ๏ธ label ์€ ์œ ์ผํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋งต์„ ๋…นํ™”ํ•  ๋•Œ ๊ฐ™์€ ์ด๋ฆ„์„ ๋‘ ๋ฒˆ ๋ถ™์ด๋ฉด ๊ทธ๋Œ€๋กœ ๋‘˜ ๋‹ค ์‹ค๋ ค ์˜ต๋‹ˆ๋‹ค. ๊ทธ ์ด๋ฆ„์€ ๋ชฉ์ ์ง€๋กœ ๋ชป ์”๋‹ˆ๋‹ค(3์ ˆ) โ€” ๋ฉ”๋‰ด๋ฅผ ๋งŒ๋“ค๊ธฐ ์ „์— ์ค‘๋ณต์„ ๊ฑธ๋Ÿฌ์ฃผ์„ธ์š”.

robot/spot-01/scenarios โ€” retained

์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์‹œ๋‚˜๋ฆฌ์˜ค ๋ชฉ๋ก. ๊ด€๋ฆฌ์ž UI ์˜ ํŽธ์ง‘๊ธฐ๊ฐ€ ์ €์žฅํ•  ๋•Œ ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค.

{
  "updated_at": "2026-08-08Tโ€ฆZ",
  "scenarios": [
    { "id": "guide", "label": "์ „์‹œ ์•ˆ๋‚ด",
      "variables": { "spot": "p2" },        // ์‹คํ–‰ ์‹œ ์ฑ„์šธ ๊ฐ’
      "unsupported_steps": [] }             // ์•„์ง ๋ชป ํ•˜๋Š” ๋™์ž‘์ด ์žˆ์œผ๋ฉด ์—ฌ๊ธฐ ํ‘œ์‹œ
  ]
}

์Šคํ… ๋‚ด์šฉ์€ ์‹ค๋ ค ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์„œ๋ฒ„๋Š” id ์™€ label ๋งŒ ์•Œ๋ฉด ๋˜๊ณ , ๊ทธ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์–ด๋–ค ๋™์ž‘๋“ค๋กœ ์ด๋ฃจ์–ด์กŒ๋Š”์ง€๋Š” SPOT ์ด ์••๋‹ˆ๋‹ค.

robot/spot-01/plan โ€” ์‹œ๋‚˜๋ฆฌ์˜ค ์ง„ํ–‰ ์ƒํ™ฉ

{ "session_id": "01HW9X8M2K", "command_id": "cmd-0050",
  "plan_id": "p-1", "scenario_id": "guide", "action": "navigate_to",
  "step_index": 0, "total_steps": 3,
  "status": "SUCCESS", "timestamp": "2026-08-08T04:12:03Z" }

์—ฌ๋Ÿฌ ๋‹จ๊ณ„์งœ๋ฆฌ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์–ด๋””๊นŒ์ง€ ๊ฐ”๋Š”์ง€ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค. ํƒœ๋ธ”๋ฆฟ ์ง„ํ–‰ ํ‘œ์‹œ์— ์“ธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • step_index ๋Š” 0๋ถ€ํ„ฐ ์…‰๋‹ˆ๋‹ค (0 โ‰ค step_index < total_steps). ์™„๋ฃŒ ack ์˜ fault_detail.failed_step ๋„ ๊ฐ™์€ ๊ธฐ์ค€์ž…๋‹ˆ๋‹ค. ์–ด๊ธ‹๋‚˜๋ฉด ๊ฐ™์€ ์Šคํ…์ด ํ† ํ”ฝ๋งˆ๋‹ค ๋‹ค๋ฅธ ๋ฒˆํ˜ธ๋กœ ๋‚˜๊ฐ‘๋‹ˆ๋‹ค.
  • ์Šคํ…๋‹น 1๊ฑด, ๊ทธ ์Šคํ…์ด ๋๋‚œ ์‹œ์ ์—๋งŒ ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹œ์ž‘ ์ด๋ฒคํŠธ๋Š” ์—†์Šต๋‹ˆ๋‹ค. ์ง„ํ–‰ ์ค‘์ธ ์Šคํ…์€ "๋งˆ์ง€๋ง‰ ๋ฐœํ–‰ + 1" ๋กœ ๋ณด๋ฉด ๋ฉ๋‹ˆ๋‹ค.
  • ์‹คํŒจํ•œ ์Šคํ…๋„ 1๊ฑด ๋ฐœํ–‰๋ฉ๋‹ˆ๋‹ค โ€” status ๊ฐ€ SUCCESS ๊ฐ€ ์•„๋‹ˆ๊ณ  aborted: true ๊ฐ€ ๋ถ™์Šต๋‹ˆ๋‹ค. ๊ทธ ๋’ค ์Šคํ…์€ ๋ฐœํ–‰๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • total_steps ๋Š” ํ•ญ์ƒ ์‹ค๋ฆฝ๋‹ˆ๋‹ค. ์Šคํ…์ด ์‹คํŒจํ•˜๋ฉด ๊ฑฐ๊ธฐ์„œ ๋ฉˆ์ถ”๊ณ  ๋‚˜๋จธ์ง€๋Š” ๋ฐœํ–‰๋˜์ง€ ์•Š์œผ๋ฏ€๋กœ, ์ด ๊ฐ’์ด ์—†์œผ๋ฉด "3๊ฐœ ์ค‘ 1๊ฐœ๋งŒ ์™”๋‹ค" ์™€ "1๊ฐœ์งœ๋ฆฌ๊ฐ€ ๋‹ค ์™”๋‹ค" ๋ฅผ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.
  • ์ค‘๋‹จ๋˜๋ฉด aborted: true ๊ฐ€ ๋ถ™์Šต๋‹ˆ๋‹ค. ํ‰์†Œ์—๋Š” ํ‚ค ์ž์ฒด๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.
ํ•„๋“œ ํƒ€์ž… ํ•„์ˆ˜ ์„ค๋ช…
plan_id string Y ์‹คํ–‰ ํ•œ ๊ฑด์˜ id. SPOT ์ด ๋ฐœ๊ธ‰ํ•˜๋ฉฐ command_id ์™€ 1:1 ์ž…๋‹ˆ๋‹ค. ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋‹ค์‹œ ๋Œ๋ฆฌ๋ฉด ์ƒˆ๋กœ ๋ฐœ๊ธ‰๋ฉ๋‹ˆ๋‹ค
command_id string Y ์š”์ฒญ์˜ ๊ฐ’
session_id string | null Y ์š”์ฒญ์˜ ๊ฐ’ (์žฌ๋ฐœํ–‰ ๋ผ์šฐํŒ… ํ‚ค)
robot_id string Y spot-01
scenario_id string | null Y run_scenario ๊ฐ€ ์•„๋‹ˆ๋ฉด null
action string Y ๊ทธ ์Šคํ…์ด ๋ฌด์—‡์ด์—ˆ๋‚˜ (navigate_to ๋“ฑ)
step_index number Y 0-๋ฒ ์ด์Šค
total_steps number Y ์ „์ฒด ์Šคํ… ์ˆ˜
status string Y SUCCESS | ABORTED | FAULT_NAV | FAULT_LEASE | FAULT_HW | TIMEOUT
timestamp string Y ๋ฐœํ–‰ ์‹œ๊ฐ
aborted bool N ์ค‘๋‹จยท์‹คํŒจ๋กœ ๋๋‚ฌ์„ ๋•Œ๋งŒ true

6. ์•ˆ์ „ ํ† ํ”ฝ

robot/spot-01/estop โ€” retained, QoS 2

๋น„์ƒ์ •์ง€๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ์™€ ํ•ด์ œ๋์„ ๋•Œ ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค.

{ "active": true,
  "source": "operator_console",
  "reason": "soft_stop: motion halted, freeze in place",
  "timestamp": "2026-08-08T04:12:03Z" }
reason ๋ฌด์—‡์ด ์ผ์–ด๋‚ฌ๋‚˜
soft_stop: โ€ฆ ์›€์ง์ž„๋งŒ ๋ฉˆ์ถค. ์„  ์ฑ„๋กœ ์œ ์ง€
stop_sit: โ€ฆ ๋ฉˆ์ถ”๊ณ  ์•‰์Œ
hard_estop: โ€ฆ ๋ชจํ„ฐ ์ „์› ์ฐจ๋‹จ
estop_release: โ€ฆ ํ•ด์ œ๋จ (active: false)

reason โ†” state.estop_state

reason state.estop_state
soft_stop ยท stop_sit NONE ๊ทธ๋Œ€๋กœ โ€” ๋กœ๋ด‡์˜ E-Stop ๋“ฑ๋ก์„ ๊ฑด๋“œ๋ฆฌ์ง€ ์•Š๊ณ , ์ œ์–ด๊ถŒ๊ณผ ์ •์ง€๋ช…๋ น๋งŒ์œผ๋กœ ์„ธ์›๋‹ˆ๋‹ค
hard_estop NONE ์ด ์•„๋‹ˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค (๋ชจํ„ฐ ์ „์› ์ฐจ๋‹จ)

โš ๏ธ estop.active: true ์ธ๋ฐ state.estop_state: NONE ์ธ ์ƒํƒœ๊ฐ€ ์ •์ƒ์ž…๋‹ˆ๋‹ค. ๋‘ ํ† ํ”ฝ์ด ์–ด๊ธ‹๋‚œ ๊ฒŒ ์•„๋‹ˆ๋ผ, ์†Œํ”„ํŠธ ์ •์ง€๋Š” E-Stop ๋ ˆ์ด์–ด๋ฅผ ์“ฐ์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํ™”๋ฉด์—๋Š” estop.active ๋ฅผ ๋„์šฐ๊ณ , estop_state ๋Š” "๋ชจํ„ฐ ์ „์›์ด ๋Š๊ฒผ๋‚˜" ๋กœ๋งŒ ์ฝ์–ด์ฃผ์„ธ์š”.

๋ˆ„๊ฐ€ ํ‘ธ๋‚˜

ํ•ด์ œ๋Š” ๊ณ„์•ฝ action ์— ์—†์Šต๋‹ˆ๋‹ค. ์šด์˜์ž๊ฐ€ ๊ด€๋ฆฌ์ž UI ๋˜๋Š” ํƒœ๋ธ”๋ฆฟ์—์„œ ํ’‰๋‹ˆ๋‹ค. ์„œ๋ฒ„๋Š” estop ํ† ํ”ฝ์œผ๋กœ ํ•ด์ œ ์‚ฌ์‹ค(active: false)์„ ๋ฐ›์„ ๋ฟ, ํ•ด์ œ๋ฅผ ์š”์ฒญํ•  ์ˆ˜๋‹จ์ด ์—†์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•˜๋‹ค๋ฉด ํ˜‘์˜ ๋Œ€์ƒ์ž…๋‹ˆ๋‹ค(8์ ˆ).

robot/spot-01/fault โ€” retained, QoS 1

๋กœ๋ด‡์ด ์Šค์Šค๋กœ ํŒ๋‹จํ•œ ์žฅ์• ๋ฅผ ์•Œ๋ฆฝ๋‹ˆ๋‹ค. ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ค‘๋‹จ์‹œํ‚ค๋Š” ์‚ฌ๊ฑด์ด ์—ฌ๊ธฐ๋กœ ๋‚˜์˜ต๋‹ˆ๋‹ค.

{ "robot_id": "spot-01", "code": "BATTERY_LOW", "active": true,
  "message": "battery 32% - returning to charge",
  "battery_pct": 32.0,
  "timestamp": "2026-08-30T06:14:03Z" }
code ์–ธ์ œ
BATTERY_LOW ๋ฐฐํ„ฐ๋ฆฌ๊ฐ€ ํ•˜๋“œ ๋ฆฌ๋ฐ‹์— ๋‹ฟ์Œ (9.2์ ˆ)
  • message ๋Š” ์‚ฌ๋žŒ์ด ์ฝ๋Š” ๋ฌธ์žฅ์ด๋ฉฐ ์ƒํ™ฉ๋งˆ๋‹ค ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๋ถ„๊ธฐ์— ์“ฐ์ง€ ๋งˆ์„ธ์š”

  • ์ฝ”๋“œ๋ณ„ ์ถ”๊ฐ€ ํ•„๋“œ๊ฐ€ ๋ถ™์Šต๋‹ˆ๋‹ค (BATTERY_LOW ๋Š” battery_pct)

  • active ๋กœ ๋ฐœ์ƒ๊ณผ ํ•ด์ œ๋ฅผ ๊ฐ€๋ฆ…๋‹ˆ๋‹ค โ€” ํ•ด์ œ๋˜๋ฉด ๊ฐ™์€ code ์— active: false ๊ฐ€ ํ•œ ๋ฒˆ ๋” ๋‚˜๊ฐ‘๋‹ˆ๋‹ค (estop ํ† ํ”ฝ๊ณผ ๊ฐ™์€ ๊ทœ์•ฝ)

  • SPOT ์„œ๋ฒ„๊ฐ€ ์žฌ์‹œ์ž‘ํ•˜๋ฉด, ์ง€๊ธˆ ์•„๋ฌด ์žฅ์• ๊ฐ€ ์—†์„ ๋•Œ ํ•ด์ œ๋ฅผ ํ•œ ๋ฒˆ ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค. retained ๋Š” ํ”„๋กœ์„ธ์Šค๊ฐ€ ์ฃฝ์–ด๋„ ๋ธŒ๋กœ์ปค์— ๋‚จ์•„ ์žˆ์–ด์„œ, ์ƒˆ๋กœ ๋œฌ ์„œ๋ฒ„๋Š” ๋ฌด์—‡์ด ๊ฑธ๋ ค ์žˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋ฐœ์ƒ์„ ๋ณธ ์  ์—†๋Š”๋ฐ ํ•ด์ œ๊ฐ€ ์˜ค๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค๊ณ  ๋ณด์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค โ€” ์ด๋ฏธ ํ•ด์ œ๋œ ์ƒํƒœ๋ผ๋ฉด ๋ฌด์‹œํ•˜์…”๋„ ๋ฉ๋‹ˆ๋‹ค

retained ๋ผ์„œ ๋Šฆ๊ฒŒ ๋ถ™์€ ๊ตฌ๋…์ž๋„ ์ฆ‰์‹œ ํ˜„์žฌ ์ƒํƒœ๋ฅผ ๋ฐ›์Šต๋‹ˆ๋‹ค. active ๋ฅผ ๋ณด๊ณ  ํŒ๋‹จํ•ด์ฃผ์„ธ์š” โ€” timestamp ๋งŒ ๋ณด๋ฉด "์˜ค๋ž˜๋œ ์žฅ์• " ์ธ์ง€ "์˜ค๋ž˜ ์ง€์† ์ค‘์ธ ์žฅ์• " ์ธ์ง€ ๊ตฌ๋ถ„ํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

state.faults ๋Š” ์ด๊ฒƒ๊ณผ ๋‹ค๋ฆ…๋‹ˆ๋‹ค. ๊ทธ์ชฝ์€ ๋กœ๋ด‡ ํ•˜๋“œ์›จ์–ด๊ฐ€ ๋ณด๊ณ ํ•˜๋Š” ์‹œ์Šคํ…œ ํดํŠธ ๋ชฉ๋ก({name, severity})์ด๊ณ , ์ด ํ† ํ”ฝ์€ SPOT ์„œ๋ฒ„์˜ ํŒ๋‹จ์ž…๋‹ˆ๋‹ค.


7. ์‹œ๋‚˜๋ฆฌ์˜ค๋ณ„ ํ๋ฆ„

์‹œํ€€์Šค ๋‹ค์ด์–ด๊ทธ๋žจ๊ณผ ์‹œ๋‚˜๋ฆฌ์˜ค๋ณ„ ์ •์ฑ… ์ œ์•ˆ์€ sequence ํŽ˜์ด์ง€์— ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ™์€ ๋‚ด์šฉ์„ ๋‘ ๊ณณ์— ๋‘๋ฉด ํ•œ์ชฝ๋งŒ ๊ณ ์ณ์ ธ ์–ด๊ธ‹๋‚˜๋ฏ€๋กœ ๋งํฌ๋กœ ๋‘ก๋‹ˆ๋‹ค.

์‹œ๋‚˜๋ฆฌ์˜ค ์“ฐ๋Š” action ํŠนํžˆ ๋ณผ ๊ฒƒ
์ง€์  ์ด๋™ navigate_to NOT_LOCALIZED ๋Š” ์žฌ์‹œ๋„ํ•ด๋„ ์•ˆ ํ’€๋ฆฝ๋‹ˆ๋‹ค
์‹œ๋‚˜๋ฆฌ์˜ค ์‹คํ–‰ run_scenario ์ด๋ฆ„๋งŒ ๋ณด๋‚ด๋ฉด ๋ฉ๋‹ˆ๋‹ค. ์ง„ํ–‰๋ฅ ์€ plan ํ† ํ”ฝ
์‚ฌ๋žŒ ์ถ”์ข… follow โš ๏ธ ๊ตฌํ˜„ ์ง„ํ–‰ ์ค‘. ๋ฐฉ์น˜๋˜๋ฉด ์Šค์Šค๋กœ ๋๋‚ฉ๋‹ˆ๋‹ค(์‹œ๊ฐ„์€ ์กฐ์ • ์ค‘)
๋กœ๋ด‡ํŒ” ์—ฐ๋™ navigate_to ์™„๋ฃŒ(SUCCESS)๋ฅผ ๋ฐ›๊ณ  ํŒ”์— ์ง€์‹œํ•ด์ฃผ์„ธ์š”
๋น„์ƒ์ •์ง€ยท๋ณต๊ตฌ stop estop ํ† ํ”ฝ์ด retained ๋กœ ์˜ต๋‹ˆ๋‹ค
์ œ์–ด๊ถŒ ์ธ์ˆ˜ยท์ธ๊ณ„ โ€” state.commands_accepted ๋กœ ํŒ๋‹จ

8. ํ•ฉ์˜๋œ ๊ฒƒ ยท ๋‚จ์€ ๊ฒƒ

ํ•ฉ์˜๋จ

# ํ•ญ๋ชฉ ๊ฒฐ๋ก 
1 ๋™์‹œ ๋ฐœํ–‰ ์ •๋ฆฌ OC ์„œ๋ฒ„๊ฐ€ ๋กœ๋ด‡๋ณ„ ํ๋กœ ์ˆœ์„œ๋ฅผ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค (2026-08-10). ํƒœ๋ธ”๋ฆฟยท๊ด€๋ฆฌ์ž ํ™”๋ฉดยท๋„์ฐฉ ์ž๋™ํ™”๋Š” ์„œ๋ฒ„์— ์š”์ฒญํ•˜๊ณ , ๋กœ๋ด‡ ํ† ํ”ฝ์— ๋‚ด๋Š” ๊ฒƒ์€ ์„œ๋ฒ„๋ฟ์ž…๋‹ˆ๋‹ค. SPOT ์€ ํ•œ ๋ฒˆ์— ํ•˜๋‚˜๋งŒ ์‹คํ–‰ํ•˜๊ณ  ์‹คํ–‰ ์ค‘ ์ƒˆ ๋ช…๋ น์€ BUSY ๋กœ ๊ฑฐ์ ˆํ•˜๋ฏ€๋กœ(ยง9.1), ์—ฌ๋Ÿฌ ๊ณณ์ด ๊ฐ์ž ๋ณด๋‚ด๋ฉด ๋’ค์—ฃ๊ฒƒ์ด ์ฃฝ์Šต๋‹ˆ๋‹ค โ€” ๊ทธ๋ž˜์„œ ํ•œ ๊ณณ์œผ๋กœ ๋ชจ์•˜์Šต๋‹ˆ๋‹ค

๋กœ๋ด‡ ์ชฝ์€ ์ด ๊ฒฐ์ •์œผ๋กœ ๋ฐ”๋€ ๊ฒƒ์ด ์—†์Šต๋‹ˆ๋‹ค. ๋ฐ›๋Š” ํ† ํ”ฝยทํŽ˜์ด๋กœ๋“œยทack ๊ทœ์•ฝ์ด ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ฌด์—‡์ด ์–ธ์ œ ๋ช…๋ น์„ ๋งŒ๋“œ๋Š”์ง€๋Š” LOCATION_AUTOMATION_DESIGN ์„ ๋ณด์„ธ์š”.

๋‚จ์€ ๊ฒƒ

# ํ•ญ๋ชฉ ์ง€๊ธˆ ๋ฌผ์–ด๋ณด๊ณ  ์‹ถ์€ ๊ฒƒ
2 ์‹œ๋‚˜๋ฆฌ์˜ค ๋ชฉ๋ก ๋ฐœํ–‰ ์ฃผ์ฒด ๋กœ๋ด‡ํŒ€ ๊ด€๋ฆฌ์ž UI ๊ฐ€ scenarios ํ† ํ”ฝ(retained)์œผ๋กœ ๋ฐœํ–‰ ์„œ๋ฒ„๊ฐ€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๋งŒ๋“ค๊ฑฐ๋‚˜ ๊ด€๋ฆฌํ•  ๊ณ„ํš์ด ์žˆ๋‹ค๋ฉด ๋ฐœํ–‰ ์ฃผ์ฒด๋ฅผ ์˜ฎ๊ฒจ์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ง€๊ธˆ ๊ณ„ํš์„ ์•Œ๋ ค์ฃผ์„ธ์š”
3 ๋ชฉ์ ์ง€ ๋ผ๋ฒจ waypoints ํ† ํ”ฝ์˜ label ์ด ์ •๋ณธ ์ „์‹œ์žฅ ๋งต์„ ์•„์ง ์•ˆ ์ฐ์–ด ๋ผ๋ฒจ์ด ํ™•์ •๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค. ํ™•์ •๋˜๋ฉด device_locations.spot_waypoint_label ์— ๋„ฃ์„ ๊ฐ’์„ ์ „๋‹ฌํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค
4 ๋น„์ƒ์ •์ง€ ์•Œ๋ฆผ ํ† ํ”ฝ robot/spot-01/estop ์„ ์ •๋ณธ์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค (2026-08-30). ์ „์—ญ MQTT_SCHEMA ์˜ safety/estop ์€ ์˜ค์ผ€์ŠคํŠธ๋ ˆ์ด์…˜ ์„œ๋ฒ„๊ฐ€ ๋ฆด๋ ˆ์ดํ•˜์ง€ ์•Š์•„ ์•„๋ฌด๋„ ๋ฐ›์ง€ ๋ชปํ•ฉ๋‹ˆ๋‹ค. ๊ทธ์ชฝ์„ ๊ตฌ๋… ์ค‘์ธ ์„œ๋น„์Šค๊ฐ€ ์žˆ์œผ๋ฉด ์•Œ๋ ค์ฃผ์„ธ์š” โ€” ์–‘์ชฝ ๋ฐœํ–‰์œผ๋กœ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค

9. ๊ณตํ†ต ์ •์ฑ…

์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๊ฐ€๋ฆฌ์ง€ ์•Š๊ณ  ์ ์šฉ๋˜๋Š” ๊ฒƒ๋“ค์ž…๋‹ˆ๋‹ค.

9.1 ํ•œ ๋ฒˆ์— ํ•˜๋‚˜

SPOT ์€ ๋ช…๋ น์„ ํ•˜๋‚˜์”ฉ๋งŒ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค. ์‹คํ–‰ ์ค‘ ์ƒˆ ๋ช…๋ น์€ BUSY ๋กœ ๊ฑฐ์ ˆํ•ฉ๋‹ˆ๋‹ค (STOP ์ œ์™ธ).

์ œ์•ˆ โ€” ์„œ๋ฒ„๊ฐ€ ํ๋ฅผ ๊ด€๋ฆฌํ•ด์ฃผ์„ธ์š”. ์•ž ๋ช…๋ น์˜ ์™„๋ฃŒ ์‘๋‹ต(SUCCESS/FAULT_*)์„ ๋ฐ›์€ ๋’ค ๋‹ค์Œ์„ ๋ณด๋‚ด๋Š” ๋ฐฉ์‹์ด ๊ฐ€์žฅ ๋‹จ์ˆœํ•ฉ๋‹ˆ๋‹ค.

9.2 ๋ฐฐํ„ฐ๋ฆฌ

์ˆ˜์ค€ ๋ฌด์Šจ ์ผ์ด ์ผ์–ด๋‚˜๋‚˜ ๋ˆ„๊ฐ€ ์„œ๋ฒ„ ๋Œ€์‘ ์ œ์•ˆ
35% ์ดํ•˜ ์ƒํƒœ์— ํ‘œ์‹œ๋งŒ โ€” ๊ธด ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ƒˆ๋กœ ์‹œ์ž‘ํ•˜์ง€ ์•Š๊ธฐ
32% ์ดํ•˜ ์Šค์Šค๋กœ ์ถฉ์ „์†Œ๋กœ ๋ณต๊ท€ํ•ฉ๋‹ˆ๋‹ค. ๋ง‰ํžˆ๋ฉด 30% ๊นŒ์ง€ ์žฌ์‹œ๋„ํ•˜๊ณ , ๊ทธ๋™์•ˆ fault ํ† ํ”ฝ์— BATTERY_LOW ๋ฅผ ๋ƒ…๋‹ˆ๋‹ค SPOT ์ง„ํ–‰ ์ค‘์ธ ์‹œ๋‚˜๋ฆฌ์˜ค๊ฐ€ ์ค‘๋‹จ๋ฉ๋‹ˆ๋‹ค
30% ์ดํ•˜ ๋ณต๊ท€๋ฅผ ํฌ๊ธฐํ•˜๊ณ  ๊ทธ ์ž๋ฆฌ์— ์•‰์€ ๋’ค ๋ชจ์…˜์„ ์ž ๊ธ‰๋‹ˆ๋‹ค. ์ด๋•Œ commands_accepted ๊ฐ€ false ๋กœ ๋‚ด๋ ค๊ฐ€๊ณ , ์ด๋™ ๋ช…๋ น์€ REJECTED(BATTERY_LOW)๋กœ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค SPOT ์šด์˜์ž ํ˜ธ์ถœ. ์ถฉ์ „ ์ „๊นŒ์ง€ ์•ˆ ํ’€๋ฆฝ๋‹ˆ๋‹ค
30% ๋ฏธ๋งŒ ์ „์› ์ธ๊ฐ€(power_on)๊ฐ€ ๊ฑฐ๋ถ€๋ฉ๋‹ˆ๋‹ค ๋กœ๋ด‡ ํŽŒ์›จ์–ด ์šฐ๋ฆฌ๊ฐ€ ๋ชป ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค. ์œ„ ๋‘ ์ค„์ด ์—ฌ๊ธฐ ๋‹ฟ์ง€ ์•Š์œผ๋ ค๋Š” ์žฅ์น˜์ž…๋‹ˆ๋‹ค
25% ๋ฏธ๋งŒ ์ž ๊ธฐ์ง€ ์•Š์•˜๋”๋ผ๋„ commands_accepted ๋ฅผ false ๋กœ ๋‚ด๋ฆฝ๋‹ˆ๋‹ค (๋งˆ์ง€๋ง‰ ๋ฐฉ์–ด์„ ) SPOT ๋ช…๋ น์„ ๋ณด๋‚ด์ง€ ๋งˆ์„ธ์š”

9.3 ์œ ํœด ์‹œ ์ž๋™ ์ฐฉ์„

3๋ถ„ ๋™์•ˆ ๋ช…๋ น์ด ์—†์œผ๋ฉด SPOT ์ด ์Šค์Šค๋กœ ์•‰์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ๋ช…๋ น์— ์ž๋™์œผ๋กœ ๋‹ค์‹œ ์ผ์–ด์„ญ๋‹ˆ๋‹ค.

์„œ ์žˆ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ๋ฐฐํ„ฐ๋ฆฌ๊ฐ€ ๋น ๋ฅด๊ฒŒ ๋‹ณ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค(์‹ค์ธก: ์„ธ์…˜ ์†Œ๋น„์˜ ๋Œ€๋ถ€๋ถ„์ด ๊ธฐ๋ฆฝ ์œ ์ง€). ์„œ๋ฒ„๊ฐ€ ๋”ฐ๋กœ ํ•  ์ผ์€ ์—†์Šต๋‹ˆ๋‹ค.

9.4 ๋กœ๋ด‡์ด ์ฃฝ์—ˆ์„ ๋•Œ

state ํ† ํ”ฝ์— connection:"offline" ์ด ๋œน๋‹ˆ๋‹ค. SPOT ์ด ๋ฐœํ–‰ํ•˜๋Š” ๊ฒŒ ์•„๋‹ˆ๋ผ
๋ธŒ๋กœ์ปค๊ฐ€ ๋Œ€์‹  ๋ฐœํ–‰ํ•ฉ๋‹ˆ๋‹ค(MQTT LWT).

๋ธŒ๋กœ์ปค๊ฐ€ ์•Œ์•„์ฑ„๋Š” ๋ฐ ์ตœ๋Œ€ 60์ดˆ ๊ฑธ๋ฆฌ๋ฏ€๋กœ, timestamp ๋ฅผ ๊ฐ™์ด ๋ณด๊ณ  ์˜ค๋ž˜๋œ ๊ฐ’์ธ์ง€ ํŒ๋‹จํ•ด์ฃผ์„ธ์š”.


10. QoS / ๊ธฐํƒ€ ์„ค์ •

ํ•ญ๋ชฉ ๊ฐ’ ์ด์œ 
๋ช…๋ น QoS 1 ์ตœ์†Œ 1ํšŒ ์ „๋‹ฌ ๋ณด์žฅ. ์ค‘๋ณต์€ ๋ด‰ํˆฌ์˜ id ๋กœ ๊ฑธ๋Ÿฌ๋ƒ„
๋ช…๋ น retained โœ• ์žฌ์ ‘์† ์‹œ ์˜› ๋ช…๋ น์ด ์žฌ์‹คํ–‰๋˜๋ฉด ์•ˆ ๋จ
์ƒํƒœ retained โ—‹ ์‹ ๊ทœ ๊ตฌ๋…์ž๊ฐ€ ์ฆ‰์‹œ ํ˜„์žฌ ์ƒํƒœ ํš๋“
E-Stop QoS 2 ์ •ํ™•ํžˆ 1ํšŒ. ์•ˆ์ „ ๋ฉ”์‹œ์ง€๋Š” ์ค‘๋ณตยท์œ ์‹ค ๋‘˜ ๋‹ค ๊ณค๋ž€
clean session true ์˜คํ”„๋ผ์ธ ๋™์•ˆ ์Œ“์ธ ์˜› ๋ช…๋ น์„ ๋ฐ›์ง€ ์•Š์Œ

๋ถ€๋ก. ์‹ค์ œ๋กœ ๊ฒ€์ฆ๋œ ๊ฒƒ

๋ฌธ์„œ ๋‚ด์šฉ ์ค‘ ์‹ค๋ฌผ ๋กœ๋ด‡์œผ๋กœ ํ™•์ธํ•œ ๊ฒƒ๊ณผ ์•„์ง ์•„๋‹Œ ๊ฒƒ์„ ๊ตฌ๋ถ„ํ•ฉ๋‹ˆ๋‹ค. ์•ˆ ํ•ด๋ณธ ๊ฒƒ์„ ํ–ˆ๋‹ค๊ณ  ์ ์œผ๋ฉด ๊ทธ๊ฑธ ์ „์ œ๋กœ ๊ฐœ๋ฐœํ•˜์‹œ๊ฒŒ ๋˜๋ฏ€๋กœ ๋‚˜๋ˆ  ์ ์—ˆ์Šต๋‹ˆ๋‹ค.

ํ•ญ๋ชฉ ์ƒํƒœ
navigate_to โ†’ ์™„์ฃผ โœ… 2026-08-07 ์›จ์ดํฌ์ธํŠธ 7๊ฐœ ํ†ต๊ณผ. 2026-08-30 ๊ด€๋ฆฌ์ž ํ™”๋ฉด โ†’ OC โ†’ MQTT ๊ฒฝ๋กœ๋กœ ์žฌํ™•์ธ
run_scenario โœ… 3์Šคํ… ์ „๋ถ€ SUCCESS, session_id ๊ทธ๋Œ€๋กœ ๋˜๋Œ์•„์˜ด
follow ์‹œ์ž‘ยท์ •์ง€ โš ๏ธ ๊ตฌํ˜„ ์ง„ํ–‰ ์ค‘ โ€” ๋Œ€์ƒ ์ถ”์ ์ด ๋ถˆ์•ˆ์ •ํ•ฉ๋‹ˆ๋‹ค. ์‹œ์—ฐ์— ๋„ฃ์ง€ ๋งˆ์„ธ์š”
์ถ”์ข… ์ค‘ STOP โœ… 1์ดˆ ์•ˆ์— ์ •์ง€
state 1Hz โœ…
stop ์ง€๋ น ์ˆ˜์šฉ โœ… 2026-08-30, 4ํšŒ ์ „๋ถ€ ์ฆ‰์‹œ ACCEPTED (์ฃผํ–‰ ์ค‘ ์‹ค์ œ ์ •์ง€๊ฑฐ๋ฆฌ๋Š” 2026-08-09 ๊ธฐ๋ก)
waypoints retained โœ…
state.commands_accepted โœ… 2026-08-30, ์‹ค์ œ ๊ฒŒ์ดํŠธ๋กœ ๋™์ž‘ ํ™•์ธ
return_home โœ… 2026-10-04 ์ „์‹œ์žฅ, ๊ด€๋ฆฌ์ž ์ฝ˜์†” โ†’ ๊ธธ๋ชฉ ๊ฒฝ์œ  ๋ณต๊ท€ยท์ฐฉ์„ยท๋ชจํ„ฐ OFF ํ™•์ธ
๋กœ๋ด‡ํŒ” ์—ฐ๋™ ์ „์ฒด ํ๋ฆ„ โฌœ ๋ฏธ์‹œํ—˜
world_position_cm / anchor_offset โฌœ ๊ตฌํ˜„๋จ, ์‹ค๋ฌผ ๋ณด์ • ๋ฏธ๊ฒ€์ฆ