1단계 명세(PHASE-1-DATA-FORMAT, v1.0.0)는 청소 로봇이 주고받는 데이터를 표현하는 공통 형식을 정한다. 대상은 로봇 식별 정보, 로봇 상태, 지도, 청소 세션 기록, 센서 데이터, 이벤트, 명령이다. 명세는 모든 데이터가 의미적 상호운용성을 위해 JSON-LD 형식을 사용해야 한다(MUST)고 규정한다.
JSON-LD는 일반 JSON 문서에 @context와 @type 같은 키워드를 더해, 각 필드가 무엇을 뜻하는지 기계가 해석할 수 있게 하는 W3C 표준 형식이다. WIA-ROB-011 문서의 @context는 https://wiastandards.com/rob-011/v1이며, @type은 문서가 어떤 종류의 데이터인지 나타낸다. 이 장에서 다루는 주요 타입은 다음과 같다.
@type | 내용 | 명세 절 |
|---|---|---|
CleaningRobot | 로봇 식별 정보 | 2.1 |
RobotState | 배터리·위치·동작 모드·센서 상태 | 2.2 |
OccupancyGrid | 점유 격자 지도, 방, 진입 금지 구역, 도크 위치 | 2.3 |
CleaningSession | 청소 세션 기록과 통계 | 2.4 |
LidarScan, CameraImage | 센서 데이터 | 3.1, 3.2 |
RobotEvent | 정보·경고·오류 이벤트 | 4 |
RobotCommand | 로봇에 보내는 명령 | 5 |
CleaningRobot)로봇 식별 정보는 제조사, 모델, 일련번호, 펌웨어·하드웨어 버전, 제조일, 지원 기능 목록을 담는다. 펌웨어 버전은 유의적 버전(semver) 형식으로 적는다.
{
"@context": "https://wiastandards.com/rob-011/v1",
"@type": "CleaningRobot",
"robotId": "ROB-2025-XXXX-YYYY",
"manufacturer": "string",
"model": "string",
"serialNumber": "string",
"firmwareVersion": "semver",
"hardwareVersion": "string",
"manufactureDate": "ISO8601 date",
"capabilities": ["array", "of", "capability", "strings"]
}
capabilities는 문자열 배열이다. 명세는 기능 이름의 목록을 따로 고정하지 않지만, 3단계의 mDNS 광고 예시에서는 slam, camera, mopping 같은 값을 사용한다(제6장 참조).
RobotState)로봇 상태는 특정 시각의 배터리, 자세(pose), 동작 모드, 청소 설정, 센서 값을 하나의 문서로 표현한다.
{
"@type": "RobotState",
"timestamp": "ISO8601 datetime",
"battery": {
"percentage": 0-100,
"voltage": "float (V)",
"current": "float (A)",
"temperature": "float (°C)",
"health": 0-100,
"cycleCount": "integer"
},
"pose": {
"x": "float (meters)",
"y": "float (meters)",
"theta": "float (radians)",
"floor": "integer",
"confidence": 0-1
},
"mode": "idle|cleaning|charging|returning|error",
"cleaningMode": "auto|spot|edge|zigzag|spiral",
"suctionPower": 0-100,
"brushSpeed": 0-100,
"waterFlow": 0-100,
"sensors": {
"lidar": "SensorReading",
"camera": "SensorReading",
"cliff": ["boolean", "array"],
"bumper": "boolean",
"dirtLevel": 0-100
}
}
mode는 로봇이 지금 무엇을 하고 있는지를, cleaningMode는 청소 중일 때 어떤 방식으로 청소하는지를 나타낸다. 두 필드 모두 열거형(enum)이며, 명세는 열거값이 명세와 정확히 일치해야 한다고 규정한다.
| 필드 | 값 | 의미 |
|---|---|---|
mode | idle | 대기 |
cleaning | 청소 중 | |
charging | 충전 중 | |
returning | 도크로 복귀 중 | |
error | 오류 상태 | |
cleaningMode | auto | 자동 청소 |
spot | 국소 청소 | |
edge | 가장자리 청소 | |
zigzag | 지그재그 경로 | |
spiral | 나선형 경로 |
suctionPower, brushSpeed, waterFlow, battery.percentage, battery.health, sensors.dirtLevel은 0~100 범위의 값이고, pose.confidence는 0~1 범위의 위치 추정 신뢰도다. 위치 좌표는 미터, 방향 theta는 라디안 단위를 쓴다.
OccupancyGrid)지도는 점유 격자(occupancy grid) 방식으로 표현한다. 공간을 일정한 크기의 칸으로 나누고 각 칸이 비어 있는지, 장애물로 막혀 있는지를 값으로 기록하는 방식이다. 격자 데이터 자체는 uint8 배열을 base64로 인코딩해 data 필드에 담는다.
{
"@type": "OccupancyGrid",
"resolution": 0.05,
"width": "integer (cells)",
"height": "integer (cells)",
"origin": {
"x": "float (meters)",
"y": "float (meters)",
"theta": "float (radians)"
},
"data": "base64 encoded uint8 array",
"rooms": [
{
"id": "UUID",
"name": "string",
"polygon": [[x, y], ...],
"surfaceType": "hardwood|tile|carpet|vinyl|marble",
"lastCleaned": "ISO8601 datetime",
"cleanCount": "integer"
}
],
"noGoZones": [
{
"id": "UUID",
"polygon": [[x, y], ...],
"type": "no_go|restricted"
}
],
"dockLocation": { "x": "float", "y": "float", "theta": "float" }
}
resolution은 한 칸의 크기(미터)로, 명세 예시의 0.05는 한 칸이 5cm라는 뜻이다. 따라서 지도의 실제 크기는 width × resolution, height × resolution미터가 된다. 예를 들어 폭 200칸, 높이 160칸이면 10m × 8m 공간이다. 방(rooms)과 진입 금지 구역(noGoZones)은 다각형 꼭짓점 목록으로 표현하며, 이 좌표는 지도 범위 안에 있어야 한다. 방마다 바닥 재질(surfaceType)을 기록해 로봇이 재질에 맞게 흡입력이나 물 공급량을 조절할 수 있게 한다.
작성 시 주의: 다각형 좌표와 도크 위치는 격자 칸 번호가 아니라 미터 단위 좌표다. 칸 번호로 적으면 다른 시스템이 지도를 가져올 때 방 경계가 크게 어긋난다. 명세의 유효성 규칙 2(SI 단위 사용)가 이를 요구한다.
CleaningSession)청소 세션 기록은 한 번의 청소 작업에 대한 시작·종료 시각, 소요 시간, 청소 면적, 이동 거리, 소비 에너지, 청소한 방, 중단 내역, 통계를 담는다.
{
"@type": "CleaningSession",
"sessionId": "UUID",
"startTime": "ISO8601 datetime",
"endTime": "ISO8601 datetime",
"duration": "integer (seconds)",
"areaCleaned": "float (m²)",
"distanceTraveled": "float (m)",
"batteryConsumed": "float (Wh)",
"cleaningMode": "string",
"rooms": ["room_id", "array"],
"interruptions": [
{
"timestamp": "ISO8601 datetime",
"reason": "stuck|battery_low|manual_stop|error",
"duration": "integer (seconds)"
}
],
"statistics": {
"avgSpeed": "float (m/s)",
"avgSuction": "float (%)",
"dirtCollected": "float (g)",
"coverage": "float (%)"
}
}
중단 사유(reason)는 끼임(stuck), 배터리 부족(battery_low), 사용자 정지(manual_stop), 오류(error) 네 가지다. 세션 기록은 2단계 API의 청소 이력 조회(GET /robot/history)가 돌려주는 기본 단위이기도 하다.
LidarScan)LiDAR 스캔은 측정 각도 범위와 간격, 측정 가능 거리 범위, 거리 측정값 배열로 이루어진다. 반사 강도(intensities)는 선택 항목이다.
{
"@type": "LidarScan",
"timestamp": "ISO8601 datetime",
"angleMin": "float (radians)",
"angleMax": "float (radians)",
"angleIncrement": "float (radians)",
"rangeMin": "float (meters)",
"rangeMax": "float (meters)",
"ranges": ["float", "array"],
"intensities": ["float", "array (optional)"]
}
CameraImage)카메라 이미지는 크기, 인코딩(rgb8, bgr8, jpeg, png), base64 이미지 데이터와 함께, 로봇이 인식한 물체 목록(detectedObjects)을 분류명·신뢰도·경계 상자로 담는다. 카메라 이미지는 개인정보에 민감한 데이터이므로 전송과 저장에 3단계의 보안 요구 사항을 적용해야 한다.
RobotEvent)
{
"@type": "RobotEvent",
"eventId": "UUID",
"timestamp": "ISO8601 datetime",
"type": "info|warning|error|critical",
"category": "navigation|cleaning|battery|sensor|communication",
"message": "string",
"details": { "arbitrary": "key-value pairs" }
}
이벤트는 심각도(type) 네 단계와 분류(category) 다섯 가지로 구분한다. details에는 이벤트별 부가 정보를 키-값 쌍으로 자유롭게 넣는다.
RobotCommand)
{
"@type": "RobotCommand",
"commandId": "UUID",
"timestamp": "ISO8601 datetime",
"action": "start|stop|pause|resume|dock|set_mode",
"parameters": {
"mode": "string (optional)",
"rooms": ["array (optional)"],
"powerLevel": "integer (optional)"
}
}
명령의 동작(action)은 시작, 정지, 일시 정지, 재개, 도크 복귀, 모드 설정 여섯 가지다. 같은 명령을 2단계 REST API로 보낼 때는 POST /robot/clean, POST /robot/stop, POST /robot/dock 같은 엔드포인트를 사용하고, MQTT로 보낼 때는 wia/rob/{robot_id}/command 토픽을 사용한다(제5장, 제6장 참조).
명세 6절은 모든 1단계 데이터가 지켜야 할 규칙 여섯 가지를 정한다.
2025-12-26T14:30:00Z).제3장에서 본 적합성 등급 Tier 1은 JSON Schema 검증 보고서를 필수 산출물로 요구한다. 따라서 구현팀은 위 규칙을 JSON Schema로 옮겨 자동 검증에 사용하는 것이 실무적으로 유리하다.
x_)구현체는 x_ 접두사를 붙인 사용자 정의 필드를 추가할 수 있다(MAY). 접두사 덕분에 제조사 고유 필드가 향후 표준에 추가될 필드와 충돌하지 않는다. 바닥 청소 이외의 로봇 유형이 고유 정보를 표현할 때도 이 방식을 쓴다(제3장 참조).
{
"@type": "RobotState",
"battery": 75,
"x_customField": "vendor-specific data"
}
위 예시는 명세 7절의 원문을 그대로 옮긴 것으로, 확장 필드의 형태만 보여 준다. 실제 문서에서 battery는 4.3절의 객체 구조를 따라야 한다.
모든 데이터 형식에는 하위 호환성을 위한 버전 정보가 들어간다.
{
"@context": "https://wiastandards.com/rob-011/v1",
"@version": "1.0.0",
"schemaVersion": "1.0.0"
}
명세의 마이그레이션 지침은 다음과 같다. 부 버전 사이에서는 하위 호환성을 유지하고, 주 버전을 바꿀 때는 마이그레이션 도구를 제공하며, 호환성을 깨는 변경은 모두 문서화하고, 전환 기간에는 여러 버전을 함께 지원한다.
다음은 명세 9절의 로봇 상태 예시다. 청소 중인 로봇의 배터리가 75%, 0번 층(floor: 0)의 (2.5m, 3.1m) 위치에서 약 90도(1.57rad) 방향을 향하고 있다.
{
"@context": "https://wiastandards.com/rob-011/v1",
"@type": "RobotState",
"timestamp": "2025-12-26T14:30:00Z",
"battery": {
"percentage": 75,
"voltage": 14.8,
"current": 2.5,
"temperature": 35.2,
"health": 95,
"cycleCount": 245,
"charging": false,
"timeToEmpty": 3600
},
"pose": { "x": 2.5, "y": 3.1, "theta": 1.57, "floor": 0, "confidence": 0.95 },
"mode": "cleaning",
"cleaningMode": "auto",
"suctionPower": 80,
"brushSpeed": 100,
"sensors": {
"lidar": { "timestamp": "2025-12-26T14:30:00Z", "ranges": [1.2, 1.5, 2.0] },
"cliff": [false, false, false, false],
"bumper": false,
"dirtLevel": 45
}
}
예시의 charging과 timeToEmpty(남은 사용 시간, 초)는 4.3절의 기본 구조에는 없는 필드로, 명세 예시가 배터리 객체에 추가 정보를 담을 수 있음을 보여 준다.
@context는 https://wiastandards.com/rob-011/v1이다CleaningRobot, RobotState, OccupancyGrid, CleaningSession, LidarScan, CameraImage, RobotEvent, RobotCommand다idle, cleaning, charging, returning, error 다섯 가지다x_ 확장 필드로, 호환성은 @version과 schemaVersion으로 관리한다mode와 cleaningMode는 각각 무엇을 나타내는가?x_ 확장 필드는 어떤 문제를 해결하는가?