Skip to content

MQTT_SCHEMA COMPANION_ROBOT

zero1ne-26 edited this page Oct 6, 2026 · 7 revisions

반려로봇 제어 MQTT 스키마

카이스트팀(REX) 작성. 모든 메시지는 CloudEvents 1.0 envelope으로 감싼다.


목차


개요

항목 내용
제공값 session_id (오케스트레이션 서버에서 발급)
작성 주체 카이스트팀
최종 수정일 2026-09-29
robot_id REX
envelope CloudEvents 1.0 (specversion, type, source, id, time, subject, data)

2026-09-29 변경 요약: 로봇을 바퀴 구동(주행) 으로 변경하고 REX가 실제 수행하는 capability만 유지하도록 정리했다. (1) capability를 say·goto·gesture(+안전 stop)로 제한(나머지 삭제), (2) 이족보행 전제였던 locomotion 채널을 폐기하고 물리적으로 분리된 base(바퀴 주행)·body(머리·상체 제스처)·audio(발화) 3채널로 재정의 — 채널 간 병렬 실행 (goto·gesture·say 동시 가능), (3) 이족보행 전용 항목(unstable_posture 사유, "전신 RL" 서술) 삭제, (4) say params에서 emotion·interrupt 제거, (5) 발화 화자를 세션 AI 페르소나 기준으로 결정(서버가 voice_id 주입). 빈/미지원 voice_id는 거절 없이 기본 화자 sohee로 발화한다.

토픽 목록

구분 Topic 방향 설명
REQUEST robot/REX/command 서버 → 반려로봇 반려로봇 제어 명령 전송
RESPONSE robot/REX/ack 반려로봇 → 서버 반려로봇 제어 결과 수신

채널 모델

반려로봇은 물리 자원을 3개 채널로 나누어 관리한다. capability 값에 따라 점유 채널이 결정되며, REQUEST 페이로드에 채널을 명시하지 않는다.

채널 물리 자원 사용 capability 동시 실행
base 바퀴 주행부 goto 채널 내 1개씩(순차)
body 머리·상체(제스처 모터) gesture 채널 내 1개씩(순차)
audio 스피커 say 병렬

서로 다른 채널은 병렬로 실행된다. 즉 주행(goto)·제스처(gesture)·발화(say)는 동시에 수행할 수 있고, 같은 채널에 들어온 명령만 순차 처리된다.

채널별 규칙

base — 주행 (채널 내 순차)

바퀴 주행부는 한 번에 한 목적지로 이동한다. 서버는 직전 goto의 completed 를 확인한 뒤 다음 goto를 보내는 것을 기본 흐름으로 한다. 수행 중 도착한 goto는 거절하지 않고 큐에 보관했다가 순차 실행하며, expires_at 이 경과하면 큐에서 꺼낼 때 rejected(expired) 로 회신한다. priority: safety 명령과 stop 은 진행 중 주행을 즉시 선점한다.

body — 제스처 (채널 내 순차)

머리·상체 제스처는 한 번에 하나씩 순차 실행한다. base 주행과는 독립 채널이므로 이동 중에도 제스처를 병렬로 수행할 수 있다.

audio — 발화 (병렬)

say 는 주행·제스처 중에도 병렬 수행 가능하다. 같은 채널에 say 가 겹쳐 도착하면 로봇 표현 계층이 결합 방식(순차·생략)을 자율 판단해 실행한다.


REQUEST

Topic: robot/REX/command

Payload

{
  "session_id": "string",
  "command_id": "string",
  "robot_id": "REX",
  "capability": "string",
  "params": {},
  "priority": "operator",
  "expires_at": "2026-08-22T10:17:30.000Z",
  "context": {
    "scenario_id": "string",
    "step_index": 0,
    "reason": "string",
    "utterance_hint": "string",
    "must_complete": true
  }
}
필드 타입 필수 설명
session_id string Y 오케스트레이션 서버에서 발급하는 세션 식별자
command_id string Y 서버가 부여하는 명령 식별자(ULID 권장). RESPONSE에 그대로 echo
robot_id string Y 대상 로봇. REX 고정. 불일치 시 rejected(robot_id_mismatch)
capability string Y 아래 whitelist 값. 미등록 시 rejected(capability_not_whitelisted:{name})
params object N capability별 파라미터
priority string N safety | operator (기본 operator). safety는 진행 중 동작을 선점
expires_at string N RFC3339 UTC. 큐에서 꺼낼 때 경과 시 rejected(expired)
context.scenario_id string N 시나리오 식별자
context.step_index number N 시나리오 내 스텝 순번
context.reason string N 명령 의도(로봇이 표현을 재해석하는 근거)
context.utterance_hint string N 발화 제안(say). 로봇이 그대로 읽지 않고 자기 말투로 재해석
context.must_complete boolean N true면 RESPONSE의 거절 사유표에서 허용된 사유 외에는 반드시 수행

capability whitelist

REX가 지원하는 capability는 아래 4개다. 실제 활성 목록은 robot/REX/capabilities(retained)에 선언되며, 시나리오는 해당 토픽에 선언된 값만 사용한다.

capability 채널 params 설명
stop 전 채널 channel, command_id, scenario_id (모두 선택) 정지·취소. 미지정 시 전 채널 중단 (안전상 항상 유효)
say audio text, voice_id 발화. 화자는 voice_id로 선택(§say voice 선택)
goto base x,y,yaw,velocity_max 또는 zone_id 지정 위치로 주행
gesture body name, repeat 제스처 재생

stop의 channel 은 base | body | audio 중 하나를 지정할 수 있고, 생략 시 전 채널을 중단한다.

say voice 선택

say 명령은 params.voice_id로 발화 화자를 선택한다. voice_id는 say capability에만 적용한다.

voice_id TTS speaker 설명
sohee Sohee Qwen CustomVoice Sohee (REX 현재 기본 화자)
serena Serena Qwen CustomVoice Serena
vivian Vivian Qwen CustomVoice Vivian
eric Eric Qwen CustomVoice Eric

화자 결정 방식 — 세션 AI 페르소나 기준. 한 세션에는 하나의 AI 페르소나 (orchestration/{sessionId}/me 의 ai_companion)가 매핑되며, 발화 화자는 그 페르소나에 따라 결정된다. 오케스트레이션 서버는 say 명령을 생성할 때 세션 페르소나의 화자를 params.voice_id 에 채워 전송한다.

voice_id 우선순위:

  1. 명령에 명시된 params.voice_id
  2. 세션 페르소나의 기본 voice_id
  3. REX 기본 화자 (현재 sohee)

REX는 받은 voice_id를 해당 say 명령에만 적용해 재생하며, 페르소나↔화자 매핑을 자체 보관하지 않는다(무상태). voice_id는 선택 필드이고 소문자로 보낸다. 비어 있거나 미지원 값이면 거절하지 않고 기본 화자(sohee)로 발화한다(값은 소문자로 정규화 후 비교). 화자 선택은 이후 명령의 기본 화자를 바꾸지 않는다.

페르소나별 voice_id 매핑값과 서버 주입 로직은 오케스트레이션 서버/페르소나 스키마 에서 관리한다(§확인 필요 사항). 현재 페르소나 객체(orchestration/ai-companion/list)에는 voice_id 필드가 없어 추가가 필요하다.

예시

{
  "session_id": "abc123",
  "command_id": "01K3QF8XW2N4V7B0YJ5R6T8ZAB",
  "robot_id": "REX",
  "capability": "gesture",
  "params": { "name": "강한 끄덕임", "repeat": 1 },
  "priority": "operator",
  "expires_at": "2026-08-22T10:17:30.000Z",
  "context": {
    "scenario_id": "SCN-WELCOME-03",
    "step_index": 2,
    "reason": "관람객 부스 진입",
    "must_complete": true
  }
}
say + voice_id 예시
{
  "session_id": "abc123",
  "command_id": "01KVOICE00000000000000001",
  "robot_id": "REX",
  "capability": "say",
  "params": {
    "text": "안녕하세요. 저는 REX예요!",
    "voice_id": "sohee"
  },
  "priority": "operator",
  "expires_at": "2026-09-20T07:00:00.000Z",
  "context": {
    "scenario_id": "SCN-VOICE-TEST-01",
    "step_index": 1,
    "reason": "REX 음성 화자 선택 테스트",
    "must_complete": true
  }
}

RESPONSE

Topic: robot/REX/ack

명령 1건당 최소 2회 발행한다(접수 + 종료).

Payload

{
  "session_id": "string",
  "command_id": "string",
  "robot_id": "REX",
  "status": "accepted",
  "reason": null,
  "result": null,
  "timestamp": "2026-08-22T10:16:00.220Z"
}
필드 타입 필수 설명
session_id string Y REQUEST의 값을 그대로 echo
command_id string Y REQUEST의 값을 그대로 echo
robot_id string Y REX
status string Y accepted | queued | started | completed | failed | rejected
reason string | null N failed / rejected 시 사유 코드
result object | null N completed 시 결과 (예: {"duration_s": 4.1})
timestamp string Y RFC3339 UTC, 밀리초

status

값 의미
accepted 명령 수신·큐 투입 (수신 후 200 ms 이내 발행)
queued 대상 채널(base·body)이 사용 중이라 대기열에 보관. 앞 동작 종료 후 started 발행
started 실제 실행 시작
completed 정상 완료. 같은 채널의 다음 명령 전송 트리거로 사용
failed 실행 중 실패
rejected 수행하지 않음

대상 채널이 비어 있으면 accepted → started → completed, 사용 중이면 accepted → queued → started → completed 순으로 발행된다.

reason (failed / rejected)

값 상황 must_complete 명령에 사용
schema_invalid 페이로드 규격 위반 가능
capability_not_whitelisted:{name} 미지원 capability 가능
robot_id_mismatch 대상 로봇 불일치 가능
expired expires_at 경과 (대기 중 만료 포함) 가능
queue_full:{channel} 해당 채널 대기열 초과 가능
estop_engaged / estop_fence 비상정지 상태 가능
unsafe_proximity 사람에 근접해 이동 불가 가능
obstacle_blocked 경로 물리적 차단 가능
low_battery 배터리 임계 이하 가능
preempted_by_safety priority: safety 명령에 선점됨 —
cancelled / cancelled_by_stop stop으로 취소됨 —

must_complete: true 명령은 위 표에서 "가능"으로 표시된 사유로만 거절한다. 관람객과 교감 중이라는 이유로는 거절하지 않으며, 현재 발화를 문장 단위로 마무리한 뒤(최대 3 s) started를 회신하고 수행한다.

예시

{
  "session_id": "abc123",
  "command_id": "01K3QF8XW2N4V7B0YJ5R6T8ZAB",
  "robot_id": "REX",
  "status": "completed",
  "reason": null,
  "result": { "duration_s": 4.1 },
  "timestamp": "2026-08-22T10:16:04.310Z"
}

QoS / 기타 설정

항목 내용
QoS REQUEST 1 / RESPONSE 1
Retain REQUEST false / RESPONSE false
세션 clean_session=false, client_id = rex-agent-REX (연결 단절 중 명령은 브로커가 보관)
응답 시간 command 수신 → accepted 200 ms 이내
중복 command_id 재실행하지 않고 현재 status를 ack로 재발행
중복 envelope id 전송 계층 중복으로 간주하고 무시 (최근 1024개 캐시)
명령 큐 채널별 독립 큐. 각 채널(base·body·audio)은 채널 내 순차, 채널 간 병렬. 각 큐 안에서 safety > operator
시간 표기 RFC3339 UTC, 밀리초, 명시적 Z
비-envelope 페이로드 파싱 실패로 drop, ack 하지 않음
인증 MQTT_USERNAME / MQTT_PASSWORD

비고

CloudEvents envelope

REQUEST·RESPONSE 모두 아래 형태로 감싼다. 구독 측은 data.*로 읽는다.

{
  "specversion": "1.0",
  "type": "robot.command",
  "source": "/services/orchestrator",
  "id": "01K3QF8XW2N4V7B0YJ5R6T8ZAC",
  "time": "2026-08-22T10:15:03.412Z",
  "subject": "robot/REX",
  "datacontenttype": "application/json",
  "data": { }
}
type 대상 토픽
robot.command robot/REX/command
robot.ack robot/REX/ack

연관 토픽

토픽 방향 QoS Retain 설명
robot/REX/state 발행 0 true 1 Hz 상태 스냅샷. 채널별(base·body·audio) 점유 상태(data.channels) 포함. availability는 data.connection(online/offline) + LWT로 표현
robot/REX/fault 발행 1 true 고장 발생/해소. critical 발생 시 진행·대기 명령을 정리해 회신
robot/REX/event 발행 1 false 로봇이 감지한 이벤트(터치·사용자 감지 등)
robot/REX/capabilities 발행 1 true 부팅 시 1회, 지원 capability와 채널 매핑 선언
safety/estop 구독 2 true 전역 비상정지. 거절 불가
system/heartbeat/rex-agent 발행 0 true 10 s 주기

확인 필요 사항

  • 페르소나별 화자(voice_id) 매핑을 오케스트레이션 서버에서 지원할지 확정. 필요 작업: (1) 페르소나 객체(orchestration/ai-companion/list, 세션 /me 의 ai_companion)에 voice_id 필드 추가(sohee|serena|vivian, 미지정 시 null → REX 기본 화자), (2) 서버가 say 생성 시 세션 페르소나의 voice_id를 params.voice_id에 주입(우선순위: 액션 지정값 > 페르소나 voice_id > REX 기본), (3) admin 페르소나 편집 화면에 화자 선택 UI 추가. 초기 매핑안: vivian ← 장난스러운친구·피카츄·알잘딱갈센, sohee ← 자상한연인, serena ← 어릴적 키우던 강아지·똑똑한 비서. (실제 주입은 페르소나 id(UUIDv7) 기준)
  • robot/{id}/command 토픽의 방향(중앙 → 로봇)이 오케스트레이션 서버 설계와 일치하는지 확인. 불일치 시 robot/REX/inbox로 분리 제안
  • zone_id 명명 규칙 확정 — goto params와 부스 존 이름이 같은 어휘를 사용해야 함
  • robot_id를 대문자 REX로 등록 가능한지 확인
  • 프로덕션 브로커 주소·인증 방식 확정

Clone this wiki locally