Repository navigation
sequence
sequenceDiagram
participant 태블릿
participant MQTT as MQTT
participant SPOT
participant OC as OC-SERVER
participant 로봇팔
태블릿-->>MQTT: 1. pub (이동 명령 토픽) {destination: "A"}
MQTT-->>SPOT: 2. sub (이동 명령 토픽)
MQTT-->>OC: 3. sub (이동 명령 토픽) → 진행 중 상태 변경
SPOT-->>MQTT: 4. pub (이동 완료 토픽) {status: "arrived", location: "A"}
MQTT-->>OC: 5. sub (이동 완료 토픽)
OC-->>MQTT: 6. pub (로봇 팔 명령 토픽)
MQTT-->>로봇팔: 7. sub (로봇 팔 명령 토픽)
로봇팔-->>MQTT: 8. pub (로봇 팔 작업 완료) {status: "complete"}
MQTT-->>OC: 9. sub (로봇 팔 작업 완료)
OC-->>MQTT: 10. pub (이동 명령 토픽) {destination: "B"}
MQTT-->>SPOT: 11. sub (이동 명령 토픽)
SPOT-->>MQTT: 12. pub (이동 완료 토픽) {status: "arrived", location: "B"}
위 다이어그램에 대해 SPOT 쪽에서 제안하는 규칙입니다. 이견 있으면 알려주세요.
| # | 제안 | 왜 |
|---|---|---|
| 1 | 정밀 정렬은 SPOT 이 한다. 서버가 보낼 명령이 없다 | 로봇팔이 작업하려면 SPOT 이 cm 단위로 서 있어야 합니다. 적재 지점의 AprilTag 를 보고 SPOT 이 스스로 맞춥니다 |
| 2 | 이동 완료(4번)를 받은 뒤에 로봇팔에 지시(6번)한다 | 접수 응답은 "출발했다"일 뿐입니다. 도착 전에 팔이 움직이면 충돌합니다 |
| 3 | 이동이 실패하면 로봇팔 명령을 보내지 않는다 | SPOT 이 없는 자리에서 팔이 작업하면 위험합니다 |
| 4 | 적재 지점에 AprilTag(36h11 / 146mm)를 붙인다 | SPOT 이 자기 위치를 맞추는 기준입니다(팔을 위한 표식이 아닙니다). 웨이포인트 이동만으로는 오차가 수십 cm 라, 팔이 고정 좌표로 작업하려면 SPOT 이 매번 같은 자리에 서 줘야 합니다 |
| 5 | 적재 중에는 SPOT 에 다른 명령을 보내지 않는다 | 팔이 작업하는 동안 SPOT 이 움직이면 안 됩니다 |
| 6 | 목적지(destination)는 이름 붙인 지점만 쓴다 |
SPOT 이 waypoints 토픽(retained)으로 갈 수 있는 곳 목록을 발행합니다. 그 목록에 없는 값은 거부됩니다 |
| 7 | 이동 완료 응답에 결과 코드를 함께 싣는다 | 위 다이어그램의 {status:"arrived"} 는 성공만 표현합니다. 실패했을 때도 같은 토픽으로 이유가 와야 서버가 다음 판단을 할 수 있습니다 (자세한 값은 MQTT_SCHEMA-SPOT) |
미검증 — 이 흐름은 아직 로봇팔과 함께 시험해보지 않았습니다. 정렬 정확도와 소요 시간은 합동 시험 후에 채우겠습니다.
로봇팔이 관여하지 않는 SPOT 시나리오들입니다. 위 로봇팔 흐름과 같은 방식으로 그렸습니다 — 사람이 시작하는 명령은 태블릿이 발행하고, SPOT 과 OC 서버가 함께 구독합니다.
전시 컨셉은 고객의 요청을 받으면 시스템이 알아서 시나리오를 돌리는 것입니다. 그 "알아서" 가 일어나는 자리는 태블릿·OC 서버 쪽이고, SPOT 은 그 결과로 정해진 시나리오를 실행합니다.
고객 요청 → 어떤 시나리오를 돌릴지 판단 → 지령 발행 → SPOT 이 실행 (태블릿 / OC 서버) (판단 안 함)SPOT 은 "무엇을 할지" 를 스스로 고르지 않습니다. 받은 시나리오를 어떻게 수행할지(경로, 자세, 정렬)만 정합니다.
SPOT 이 지령 없이 스스로 하는 일은 두 가지뿐입니다 — 이미 받은 명령을 마무리하는 것(추종 종료 후 위치 재확인 등)과 안전 동작(통신 두절 시 정지, 유휴 시 착석).
토픽·페이로드 상세는 MQTT_SCHEMA-SPOT 참조.
sequenceDiagram
participant 태블릿
participant MQTT
participant SPOT
participant OC as OC-SERVER
태블릿-->>MQTT: 1. pub (command) {action:"navigate_to", destination:"p2"}
MQTT-->>SPOT: 2. sub (command)
MQTT-->>OC: 3. sub (command) → 진행 중 상태 변경
SPOT-->>MQTT: 4. pub (ack) {status:"ACCEPTED"}
MQTT-->>OC: 5. sub (ack)
Note over SPOT: 위치추정 확인 → 경로 계산 → 주행<br/>중간 경유지는 SPOT 이 알아서 지나간다
loop 1Hz
SPOT-->>MQTT: pub (state) {fsm:"NAVIGATING", current_waypoint_label:…}
MQTT-->>OC: sub (state)
end
alt 도착
SPOT-->>MQTT: 6. pub (ack) {status:"SUCCESS", location:"p2"}
MQTT-->>OC: 7. sub (ack)
else 자기 위치를 모름
SPOT-->>MQTT: 6. pub (ack) {status:"FAULT_NAV", code:"NOT_LOCALIZED"}
MQTT-->>OC: 7. sub (ack) → 운영자 호출
end
| # | 제안 | 왜 |
|---|---|---|
| 1 | 목적지는 이름 붙인 지점만 보낸다 | 자동 생성 경유지(waypoint_7)는 길이지 장소가 아닙니다. 목록은 waypoints 토픽(retained)에 있습니다 |
| 2 | 경로는 발행자가 정하지 않는다 | 어느 경유지를 거칠지는 SPOT 이 계산합니다. 최종 목적지만 주면 됩니다 |
| 3 | NOT_LOCALIZED 는 재시도하지 않는다 |
로봇이 자기 위치를 모르는 상태라 몇 번을 보내도 같은 실패입니다. 사람이 태그가 보이는 곳으로 옮겨야 풀립니다 |
| 4 | 그 외 FAULT_NAV 는 1회 재시도 후 다른 목적지로 재계획 |
사람이 길을 막고 있는 경우가 대부분이라 잠시 후면 풀립니다 |
| 5 | 이동 중 새 이동 명령은 BUSY 로 거절된다 |
앞 명령의 완료를 받고 다음을 보내주세요 |
속도 — 전시장 기본 0.15 m/s 로 고정입니다. 관객 사이를 다니므로 발행자가 올릴 수 없게 했습니다.
뒤로 걷지 않습니다 — 방향이 안 맞으면 회전해서 앞으로 갑니다. 관객 눈에 고장으로 보이고, 진행 방향을 카메라가 못 보기 때문입니다.
sequenceDiagram
participant 태블릿
participant MQTT
participant SPOT
participant OC as OC-SERVER
Note over MQTT,OC: 접속 시 scenarios (retained) 구독<br/>→ 실행 가능한 시나리오 목록 확보 (태블릿 메뉴를 이걸로 채운다)
Note over 태블릿: 고객 요청을 받아 어떤 시나리오를 돌릴지 판단
태블릿-->>MQTT: 1. pub (command) {action:"run_scenario", scenario_id:"guide"}
MQTT-->>SPOT: 2. sub (command)
MQTT-->>OC: 3. sub (command) → 진행 중 상태 변경
SPOT-->>MQTT: 4. pub (ack) {status:"ACCEPTED"}
MQTT-->>OC: 5. sub (ack)
Note over SPOT: 어떤 동작들로 이루어졌는지는 SPOT 이 안다<br/>발행자는 이름만 보냈다
SPOT-->>MQTT: 6. pub (plan) {step_index:0, total:3, status:"SUCCESS"}
MQTT-->>OC: 7. sub (plan) → 진행률 갱신
SPOT-->>MQTT: pub (plan) {step_index:1, …}
MQTT-->>OC: sub (plan)
SPOT-->>MQTT: pub (plan) {step_index:2, …}
MQTT-->>OC: sub (plan)
SPOT-->>MQTT: 8. pub (ack) {status:"SUCCESS"}
MQTT-->>OC: 9. sub (ack)
| # | 제안 | 왜 |
|---|---|---|
| 1 | 시나리오 이름만 보낸다 | "세부 로직은 로봇에서 처리" 원칙을 지키는 방법입니다. 인사 동작·대기 시간 같은 건 발행자가 몰라도 됩니다 |
| 2 | 시나리오 목록은 scenarios 토픽(retained)에서 받는다 |
관리자 UI 에서 시나리오를 고치면 자동으로 반영됩니다. 태블릿·서버 코드를 고칠 필요가 없습니다 |
| 3 | 진행률은 plan 토픽으로 나간다 |
3단계 중 2단계라는 걸 태블릿에 보여줄 수 있습니다. 완료만 기다리면 그 사이가 깜깜합니다 |
| 4 | 시나리오 안의 낱개 동작은 ack 를 쏘지 않는다 |
보내지 않은 명령의 응답이 오면 혼란스럽습니다. 시나리오 전체에 대해 한 번만 옵니다 |
| 5 | 로봇이 못 하는 동작이 섞여 있으면 unsupported_steps 로 알린다 |
조용히 빼고 실행하면 완전히 수행된 줄 압니다 |
변수 치환 — 시나리오에 $spot 같은 자리가 있으면 variables 로 채웁니다.
무엇으로 채울지(태블릿에서 고른 목적지 등)는 발행하는 쪽이 정합니다.
sequenceDiagram
participant 태블릿
participant MQTT
participant SPOT
participant OC as OC-SERVER
태블릿-->>MQTT: 1. pub (command) {action:"follow", mode:"start"}
MQTT-->>SPOT: 2. sub (command)
MQTT-->>OC: 3. sub (command) → 진행 중 상태 변경
SPOT-->>MQTT: 4. pub (ack) {status:"ACCEPTED"}
MQTT-->>OC: 5. sub (ack)
Note over SPOT: 제일 가까운 사람을 잡고 따라간다<br/>좌우로 둘러보는 중 = 아직 못 찾음
alt 손님이 그냥 자리를 뜸
Note over SPOT: 25초 동안 안 보이면 스스로 종료
SPOT-->>MQTT: 6. pub (ack) {status:"SUCCESS", reason:"target_lost"}
else 태블릿에서 종료
태블릿-->>MQTT: pub (command) {action:"follow", mode:"stop"}
MQTT-->>SPOT: sub (command)
SPOT-->>MQTT: 6. pub (ack) {status:"SUCCESS"}
end
MQTT-->>OC: 7. sub (ack)
Note over SPOT: 종료 후 자기 위치를 다시 잡는다<br/>추종은 맵 경로를 안 타서 위치가 흐려진다
| # | 제안 | 왜 |
|---|---|---|
| 1 | 대상은 시작 시점에 제일 가까운 사람 | 얼굴을 보지 않으므로 "누구"를 지정할 수 없습니다. 따라올 사람이 로봇 앞에 서면 됩니다 |
| 2 | 한 번 잡으면 다른 사람으로 바뀌지 않는다 | 관객이 앞을 스쳐도 유지합니다. 완전히 놓쳐야 다시 고릅니다 |
| 3 | 25초 동안 사람이 안 보이면 스스로 끝낸다 | 손님이 그냥 가버리는 게 전시에서 가장 흔합니다. 매번 종료 명령을 보내주기를 기대할 수 없습니다 |
| 4 | 한 번에 최대 5분 | 잊고 방치되는 것을 막습니다 |
| 5 | 종료 후 SPOT 이 스스로 위치를 다시 잡는다 | 추종은 맵 경로를 안 타서 끝나면 자기 위치가 흐려집니다. 이걸 안 하면 다음 이동 명령이 조용히 실패합니다 |
| 6 | 유지 거리 2m, 최대 0.2 m/s | 발행자가 바꿀 수 없게 했습니다. 관객에게 빠르게 접근하는 일이 없어야 합니다 |
관객이 보는 신호 — 좌우로 크게 둘러보면 "아직 못 찾음", 멈추고 따라오면 "잡았음"입니다. 동작은 이 하나뿐입니다. 여러 개를 두면 관객이 구분하지 못합니다.
sequenceDiagram
participant 운영자
participant SPOT
participant MQTT
participant OC as OC-SERVER
participant 태블릿
Note over SPOT: 이동 중 (command_id: cmd-0042)
운영자-->>SPOT: STOP (관리자 UI 또는 물리 버튼)
Note over SPOT: MQTT 를 거치지 않는 최단 경로로 즉시 정지
SPOT-->>MQTT: 1. pub (estop, retained) {active:true, reason:"soft_stop"}
MQTT-->>OC: 2. sub (estop)
MQTT-->>태블릿: 3. sub (estop) → 화면에 정지 표시
SPOT-->>MQTT: 4. pub (ack) {command_id:"cmd-0042", status:"ABORTED"}
MQTT-->>OC: 5. sub (ack)
Note over OC,태블릿: 명령 발행 중단
운영자-->>SPOT: RESUME
SPOT-->>MQTT: 6. pub (estop, retained) {active:false}
MQTT-->>OC: 7. sub (estop)
MQTT-->>태블릿: 8. sub (estop) → 정지 표시 해제
| # | 제안 | 왜 |
|---|---|---|
| 1 | 정지는 MQTT 를 거치지 않는다 | 브로커가 죽어도 멈춰야 합니다. MQTT 로는 "멈췄다"는 사실만 알립니다 |
| 2 | 정지는 무엇보다 우선한다 |
BUSY 여도 받습니다. 다른 명령이 돌고 있어도 즉시 멈춥니다 |
| 3 | 기본 정지는 전원을 끄는 게 아니다 | 선 채로 멈춥니다. 바로 재개할 수 있습니다. 전원 차단은 별도 버튼입니다 |
| 4 | 진행 중이던 명령은 ABORTED 로 종료 보고한다 |
그 명령의 결과를 영원히 기다리지 않게 |
| 5 | estop.active=true 동안 명령 발행을 멈춘다 |
보내봐야 거부되거나, 더 나쁘게는 사람이 개입 중인데 다시 움직입니다 |
| 6 | 복구는 사람이 한다 | 자동 복구를 넣지 않았습니다. 왜 멈췄는지 사람이 확인해야 합니다 |
| 7 |
estop 은 retained 로 발행한다 |
태블릿·서버가 나중에 켜져도 지금 정지 상태임을 즉시 압니다 |
정지 트리거
| 트리거 | 누가 | 결과 | 복구 |
|---|---|---|---|
| STOP | 운영자 | 즉시 멈춤, 선 채로 | RESUME |
| STOP + SIT | 운영자 | 멈추고 앉음 | RESUME |
| 하드 E-Stop | 운영자 | 모터 전원 차단 | RESUME |
| 명령 만료 | 자동 | 조종자가 죽으면 3초 뒤 정지 | 연결 복구 후 재명령 |
| 데드맨 | 자동 | 통신 두절 30초 뒤 앉고 전원 차단 | RESUME |
전시 중 관리자가 로봇을 직접 몰아야 하는 상황이 생깁니다 — 장애물 제거, 위치 조정 등. 로봇은 한 번에 한 명만 몰 수 있어서, 관리자가 가져가는 동안 발행된 명령은 실패합니다.
sequenceDiagram
participant 관리자 as 관리자 노트북
participant SPOT
participant MQTT
participant OC as OC-SERVER
participant 태블릿
Note over MQTT,태블릿: 평상시 — state: commands_accepted=true
관리자-->>SPOT: 제어권 회수 (현장에서 직접 조작하려고)
SPOT-->>MQTT: 1. pub (state, retained) {commands_accepted:false, lease_owner:"operator"}
MQTT-->>OC: 2. sub (state)
MQTT-->>태블릿: 3. sub (state) → "점검 중" 표시
SPOT-->>MQTT: 4. pub (ack) {status:"FAULT_LEASE"}
MQTT-->>OC: 5. sub (ack)
Note over OC,태블릿: 명령 발행 중단하고 대기
관리자-->>SPOT: 제어권 반납 (버튼을 눌러야 함 — 자동 반납 없음)
SPOT-->>MQTT: 6. pub (state, retained) {commands_accepted:true, lease_owner:"orchestration"}
MQTT-->>OC: 7. sub (state)
MQTT-->>태블릿: 8. sub (state) → 정상 표시
| # | 제안 | 왜 |
|---|---|---|
| 1 | 현장 관리자가 발행자보다 우선한다 | 눈으로 보고 있는 사람이 판단할 수 있어야 합니다 |
| 2 |
state 에 commands_accepted 를 넣는다. 새 토픽은 만들지 않는다 |
이미 구독하는 state(1Hz, retained)에 불리언 하나면 충분합니다. 서버가 lease_owned 를 해석할 필요 없이 "지금 명령이 먹나" 를 바로 알 수 있습니다 |
| 3 |
commands_accepted:false 동안 발행을 멈춘다 |
보내면 전부 FAULT_LEASE 로 실패합니다 |
| 4 | 진행 중이던 명령은 FAULT_LEASE 로 종료 보고한다 |
그 명령의 결과를 영원히 기다리지 않게 |
| 5 | 자동 반납은 없다. 관리자가 직접 반납해야 한다 | 타이머로 자동 반납하면, 관리자가 로봇 옆에서 조치하는 중에 제어권이 넘어가 사람 옆에서 로봇이 움직입니다 |
commands_accepted가false가 되는 경우 — 관리자 제어권 회수, 비상정지 중, 배터리 부족. 이유는state의 다른 필드(lease_owner,estop_state,battery_pct)로 구분할 수 있습니다.
관리자가 반납을 잊으면 전시가 멈춥니다(로봇은 서 있는데 명령이 전부 거부). 관리자 UI 상단에 제어권 보유가 항상 표시되고, 오래 쥐고 있으면 경고가 뜹니다.
시나리오를 가리지 않고 적용됩니다.
SPOT 은 명령을 하나씩만 실행합니다. 실행 중 새 명령은 BUSY 로 거절합니다 (STOP 제외).
제안 — 발행하는 쪽이 순서를 관리해주세요. 앞 명령의 완료 응답을 받은 뒤 다음을 보내는 방식이 가장 단순합니다.
태블릿과 OC 서버가 둘 다 발행할 수 있다면, 서로 모르는 채로 동시에 보내면 뒤엣것이
BUSY로 거절됩니다. 누가 순서를 관리할지 정해야 합니다 (아래 협의 사항 1번).
| 수준 | SPOT 동작 | 대응 제안 |
|---|---|---|
| 35% 이하 | 상태에 표시 | 긴 시나리오를 새로 시작하지 않기 |
| 30% 미만 | 전원 인가가 거부될 수 있음 | 충전 안내 |
| 25% 이하 | 새 이동 명령 거부 | 운영자 호출 |
3분 동안 명령이 없으면 SPOT 이 스스로 앉습니다. 다음 명령에 자동으로 다시 일어섭니다. 서 있는 것만으로 배터리가 빠르게 닳기 때문입니다. 따로 할 일은 없습니다.
state 토픽에 connection:"offline" 이 뜹니다. SPOT 이 발행하는 게 아니라 브로커가
대신 발행합니다(MQTT LWT). 브로커가 알아채는 데 최대 60초 걸리므로 timestamp 를
같이 보고 판단해주세요.
| # | 항목 | 지금 | 물어보고 싶은 것 |
|---|---|---|---|
| 1 | 동시 발행 정리 | 태블릿·OC 서버 둘 다 robot/+/command 쓰기 권한 보유 (브로커 ACL 확인) |
SPOT 은 한 번에 하나만 실행하고, 실행 중 새 명령은 BUSY 로 거절합니다. 둘이 서로 모르는 채로 보내면 뒤엣것이 거절됩니다. 누가 순서를 관리할지 정해야 합니다 |
| 2 | 시나리오 목록 발행 주체 | 관리자 UI 가 scenarios 토픽(retained)으로 발행 |
서버가 시나리오를 만들거나 관리할 계획이 있다면 발행 주체를 옮겨야 합니다. 지금 계획을 알려주세요 |
안 해본 것을 했다고 적으면 그걸 전제로 개발하시게 되므로 나눠 적었습니다.
| 항목 | 상태 |
|---|---|
| 지점 이동 완주 | ✅ 2026-08-07, MQTT 경로로 웨이포인트 7개 통과 |
| 시나리오 실행 | ✅ 3스텝 전부 성공, session_id 그대로 되돌아옴 |
| 사람 추종 시작·정지 | ✅ |
| 추종 중 STOP | ✅ 1초 안에 정지 |
| 1Hz 상태 발행 | ✅ |
| 목적지 목록(retained) | ✅ |
state.commands_accepted (5절 제안) |
⬜ 제안 단계 — 미구현 |
| 충전 위치 복귀 | ⬜ 미검증 |
| 로봇팔 연동 전체 흐름 | ⬜ 미시험 |
- Google ADK 검토 (프레임워크·모델 비교)
- 페르소나 + 상황 카드 모델 (2차 시나리오 구동 방식)
- Mac Studio 로컬 LLM + Claude Opus 하이브리드 라우팅 전략
- 개발 일정·할 일 점검표 (단계별 진행 점검)
- 로봇 Adapter 개발 온보딩 (HA·MQTT 계정 등록, 토픽 적용, 테스트 송수신, 상태 확인)
- LG ThinQ 가전 연동 (HA 통합 · REST 데이터 취득 · 제어)
- 장소 도착 자동화 (태스크/이벤트/장소 규칙 → SPOT·로봇팔·반려로봇·Hub 자동 명령)
- 엔딩 화면 데이터 출처 점검 (차량 3필드 · 세션 종료 엔딩 5화면)