관제는 브로커에 오더와 instant action을 발행하고 상태를 되읽습니다. 로봇은 같은 JSON 스키마를 그대로 따릅니다.
어느 쪽도 상대의 구현을 알지 못하도록 만들었기 때문에, 양쪽 모두 같은 프로토콜을 말하는 다른 것으로 교체할 수 있습니다. 스키마는 고정(pinned)되어 있고, 저장소마다 각자 사본을 두고 각자 검증합니다 — 어느 저장소도 "다른 쪽이 확인했겠지"에 기대지 않습니다.
flowchart LR
UI["<b>r2bot-ui</b><br/>플릿 뷰 · 오퍼레이터 콘솔"]
ACS["<b>r2bot-acs</b><br/>관제"]
MQTT(("MQTT<br/>브로커"))
BRIDGE["<b>r2bot-robot</b><br/>VDA5050 브리지"]
NAV["Nav2 · ROS 2"]
UI <--> ACS
ACS <-->|VDA5050 3.0| MQTT
MQTT <-->|VDA5050 3.0| BRIDGE
BRIDGE <--> NAV
기능 단위로 나누어 관리합니다. 각 저장소는 자기 몫만 알고, 필요한 만큼만 서로를 참조합니다.
| 저장소 | 맡은 것 |
|---|---|
| r2bot-robot | ROS 2 · Nav2 주행, 그리고 오더를 goal로 바꾸는 VDA5050 브리지 |
| r2bot-acs | 관제 — 오더 배차, 스키마 검증, 플릿 API |
| r2bot-ui | 브라우저 — 플릿 뷰와 오퍼레이터 콘솔 |
| r2bot-docs | 둘 이상에 걸치는 설계·스펙과 프로토콜 계약 |
서비스 정의를 두 곳에 복사해 두지 않습니다. 여러 저장소에 걸친 테스트는 옆에 체크아웃된 저장소의 compose를 그대로 include 합니다 — 복사본 두 개가 어긋나는 것이야말로 피하려는 상황이기 때문입니다.
커밋은 왜인지를 남깁니다. 무엇이 바뀌었는지는 diff가 이미 말해 줍니다. 본문에는 무엇이 잘못됐고, 무엇을 측정했고, 무엇을 기각했는지를 씁니다. 형용사보다 숫자를 씁니다 — 다음 사람이 다시 확인할 수 있어야 하니까요.
테스트는 개발자와 CI가 같은 스크립트를 돌립니다. 저장소마다 tests/run.sh가
레이어로 나뉘어 있고, CI는 레이어를 이름으로 지정합니다. 그래야 레이어가 하나
늘었을 때 "CI가 감당할 수 있는가"를 누군가 판단하게 되고, CI가 조용히 빨개지지
않습니다.
어서션은 실제 효과를 봅니다. 로봇이 한 번도 움직이지 않아도 통과하는 테스트는 주행을 검증하는 테스트가 아닙니다.
개발은 headless Gazebo 시뮬레이션을 상대로 이루어집니다. 개별 저장소는 비공개입니다.