# ROS2 PC 이관 체크리스트

이 대시보드는 **Mac에서 만들고, 가짜(mock) rosbridge 서버로 검증**했습니다.
FAST-LIVO2가 실제로 도는 ROS 2 Humble PC로 옮겨서 마무리해야 할 것들을 정리합니다.

사용법 자체는 `PCD_Viewer_가이드.md`에 있습니다. 이 문서는 **이관과 남은 작업**만 다룹니다.

---

## 0. 지금 어디까지 확실한가

정직하게 갈라두면 실기에서 삽질이 줄어듭니다.

| 항목 | 상태 |
|---|---|
| UI·측정(거리/포지션)·파일 로드 | ✅ 실제 PCD로 확인 |
| rosbridge 프로토콜, 토픽 자동 바인딩, 누적, 카메라, 텔레메트리 | ⚠️ **목 서버로만 확인** — 실기 미검증 |
| 라이브 맵 위 측정 | ⚠️ 목 서버 데이터로 확인 |
| 복셀 다운샘플 누적 + 재색인 | ⚠️ 목 서버로 확인 (25초 세션에서 유지율 41%→20%로 수렴) |
| 오프라인(CDN 차단) 구동 | ✅ unpkg 차단 상태로 확인 (3절) |
| 실제 FAST-LIVO2 토픽 이름·타입·필드 | ❌ **미확인 — 4절에서 기록할 것** |
| 실제 환경에서의 복셀 유지율·적정 크기 | ❌ 미확인 — 실기에서 6절 보고 조정 |

---

## 1. 옮길 파일

```
pcd_viewer.html          ← 대시보드 본체 (이거 하나면 동작)
PCD_Viewer_가이드.md      ← 사용법
ROS2_이관_체크리스트.md    ← 이 문서
tools/mock-rosbridge.mjs ← 로봇 없이 테스트용 (선택, Node 필요)
```

`.pcd`는 옮길 필요 없습니다(용량만 큼). 실시간으로 볼 거고, 파일이 필요하면 그 PC에서 생성됩니다.

```bash
scp -r ~/Documents/"pcd viwer" user@ros2-pc:~/pcd_dashboard
```

---

## 2. 호스트 세팅

### 2-1. rosbridge
```bash
sudo apt install ros-humble-rosbridge-suite
ros2 launch rosbridge_server rosbridge_websocket_launch.xml     # :9090
```
- `rosapi` 노드가 함께 떠야 합니다(위 launch에 포함). 토픽 목록을 읽는 데 씁니다.
- 확인: `ros2 node list | grep -E "rosbridge|rosapi"`

### 2-2. 뷰어 서빙
```bash
cd ~/pcd_dashboard
python3 -m http.server 8000      # 0.0.0.0 바인딩(기본) → 다른 PC에서도 접속 가능
```

### 2-3. 다른 PC에서 볼 때
- 브라우저: `http://<호스트IP>:8000/pcd_viewer.html`
- LIVE 주소: `ws://<호스트IP>:9090` ← **localhost 아님**
- 방화벽: 8000, 9090 열기
  ```bash
  sudo ufw allow 8000/tcp && sudo ufw allow 9090/tcp
  ```

> **보안**: rosbridge는 인증이 없습니다. 붙는 사람이 토픽을 발행할 수도 있습니다.
> 신뢰된 LAN 안에서만 쓰고, 공인 IP로 열지 마세요.

---

## 3. 로봇 PC가 오프라인이면 (Three.js 로컬화)

기본값은 CDN(unpkg)에서 Three.js를 받습니다. 인터넷이 없으면 뷰어가 아예 안 뜹니다.
**아래 절차는 unpkg를 차단한 상태에서 실제로 검증했습니다.**

인터넷 되는 PC에서 받아서 같이 옮기면 됩니다:

```bash
cd ~/pcd_dashboard
mkdir -p vendor/three/controls vendor/three/loaders
curl -L -o vendor/three/three.module.js          https://unpkg.com/three@0.160.0/build/three.module.js
curl -L -o vendor/three/controls/OrbitControls.js https://unpkg.com/three@0.160.0/examples/jsm/controls/OrbitControls.js
curl -L -o vendor/three/loaders/PCDLoader.js      https://unpkg.com/three@0.160.0/examples/jsm/loaders/PCDLoader.js
```

`pcd_viewer.html`의 importmap을 이렇게 고칩니다 (디렉터리 구조를 지켜야 addon들이 `three`를 찾습니다):

```html
<script type="importmap">
{
  "imports": {
    "three": "./vendor/three/three.module.js",
    "three/addons/": "./vendor/three/"
  }
}
</script>
```

---

## 4. 첫 연결 — 순서와 기록할 것

### 4-1. 먼저 ROS 쪽에서 확인
```bash
ros2 topic list -t                       # 이름과 타입을 함께
ros2 topic hz /cloud_registered          # 발행 주파수
ros2 topic echo /cloud_registered --field fields --once   # x/y/z/rgb/intensity 구성
ros2 topic echo /cloud_registered --field width --once    # 스캔당 점 개수
```

### 4-2. 여기에 실제 값을 적어두세요 (지금은 추정)

| 슬롯 | 뷰어가 기대하는 타입 | 실제 토픽 이름 | 실제 타입 | 비고 |
|---|---|---|---|---|
| CLOUD | `sensor_msgs/msg/PointCloud2` | (기록) | | 점/스캔: ___ , Hz: ___ |
| ODOM | `nav_msgs/msg/Odometry` | (기록) | | |
| PATH | `nav_msgs/msg/Path` | (기록) | | 없을 수도 있음 |
| IMAGE | `sensor_msgs/msg/CompressedImage` | (기록) | | raw `Image`면 5-1 |

> 뷰어는 **이름이 아니라 타입으로** 토픽을 찾습니다. 이름이 달라도 타입만 맞으면 드롭다운에 뜹니다.
> 자동 선택이 틀리면 드롭다운에서 바꾸면 됩니다.

### 4-3. 대시보드 연결
1. 브라우저 → LIVE 칸에 `ws://localhost:9090` → `연결`
2. **토픽 4칸이 채워지는지** 확인
3. **TELEMETRY의 Hz가 뜨는지** 확인 (`—`면 그 토픽은 조용하다는 뜻)
4. 맵이 자라는지, `F`로 뷰가 맞는지
5. 거리 모드로 라이브 맵 위 두 점 측정

---

## 5. 실기에서 걸릴 만한 것들

### 5-1. 카메라가 안 뜬다 — 가능성 높음
지금은 `CompressedImage`만 받습니다. FAST-LIVO2는 `/origin_img`를 **raw `sensor_msgs/msg/Image`**로
낼 수 있고, 그러면 IMAGE 드롭다운이 비어 있습니다.

우회(권장 — 대역폭도 훨씬 유리):
```bash
ros2 run image_transport republish raw in:=/origin_img compressed out:=/origin_img/compressed
```
근본 해결: 뷰어에 raw Image 디코딩 추가 (7절).

### 5-2. 클라우드에 rgb가 없다
`rgb`가 없으면 `intensity`를 회색 계조로 씁니다. 둘 다 없으면 균일 회색입니다.
FAST-LIVO2는 컬러 맵을 내므로 보통 `rgb`가 있지만, 설정에 따라 다릅니다.

### 5-3. 대역폭
전송은 JSON + base64라 바이너리의 약 1.33배입니다. 점당 16바이트면 **점당 약 21바이트**.

```
대역폭 ≈ 점/스캔 × Hz × 21 B/점
예) 10,000 × 10 Hz × 21 B ≈ 2.1 MB/s ≈ 17 Mbps
    30,000 × 10 Hz × 21 B ≈ 6.4 MB/s ≈ 51 Mbps
```
같은 PC(localhost)나 유선 LAN이면 괜찮고, **Wi-Fi로 원격에서 보면 빠듯**합니다.

### 5-4. `rosapi 응답이 없습니다`
rosbridge는 떴는데 rosapi가 없는 경우입니다. launch 파일을 확인하거나
`ros2 run rosapi rosapi_node`를 따로 띄우세요.

---

## 6. 누적 버퍼와 복셀 크기 정하기

`/cloud_registered`는 **매 스캔을 통째로** 내보내고 스캔끼리 공간이 크게 겹칩니다.
그대로 쌓으면 6M 버퍼가 **1분 남짓**에 찹니다(1만 점 × 10Hz 기준).

그래서 **복셀 누적이 기본으로 켜져 있습니다**(5cm). 이미 점이 있는 복셀의 점은 버리므로,
누적량이 **돌린 시간이 아니라 본 공간 크기**에 비례합니다. 원리는 가이드 6-3절.

### 6-1. 실기에서 할 일: 유지율 보고 크기 정하기
TELEMETRY의 **복셀** 행에 `5cm · 유지 18.0%`처럼 나옵니다.

| 유지율이 | 뜻 | 조치 |
|---|---|---|
| 계속 50~100% | 복셀이 너무 작아 사실상 원본을 쌓는 중 | 크기를 키우세요 |
| 시간이 갈수록 하강·수렴 | 정상. 새로 보는 공간만 늘고 있음 | 그대로 |
| 5% 이하인데 맵이 성김 | 복셀이 너무 큼 | 줄이세요 |

크기를 바꾸면 **이미 쌓인 점도 즉시 재색인**됩니다(키우면 그 자리에서 솎임).
목 서버 기준 20cm → 50cm 재색인에서 108,690점 → 7,799점(7.2%)으로 줄었습니다.

### 6-2. 그래도 부족하면
```
버퍼가 차는 시간 ≈ LIVE_CAP / (점/스캔 × Hz × 유지율)
```
- **LIVE_CAP 상향**: `pcd_viewer.html`의 `const LIVE_CAP = 6_000_000;` → 예: `40_000_000`.
  메모리는 **점당 약 15바이트**(40M ≈ 600MB). 좋은 PC면 감당됩니다.
- **누적 맵 토픽 구독**: FAST-LIVO2가 누적 맵 토픽(`/cloud_map` 등)을 낸다면,
  그걸 물리고 **매번 통째로 교체**하는 방식이 더 쌀 수 있습니다. → 4-2에서 실제 토픽 확인.

> 복셀을 **끄면** 원본을 그대로 쌓습니다. 짧고 고밀도인 계측용입니다. 버퍼는 빨리 찹니다.
> 가득 차면 조용히 버리지 않고 **"가득 참"이라고 말하고 멈춥니다.**

---

## 7. 남은 개발 항목 (우선순위 순)

> **완료**: 복셀 다운샘플 누적(크기 슬라이더 + 재색인 포함). 6절 참고.
> 다만 복셀 인덱스는 `Set`이라 점 하나당 수십 바이트를 씁니다. 유지 점수가 수백만을
> 넘어가면 타입드 배열 해시로 바꾸는 게 다음 최적화입니다(지금은 필요 없을 가능성이 큼).

### 7-1. raw `sensor_msgs/msg/Image` 지원
- `CompressedImage`가 없는 환경 대비(5-1). rgb8/bgr8/mono8 → canvas ImageData.
- 대역폭이 크므로 throttle 필수.

### 7-2. CBOR 전송
- `subscribe`에 `compression: 'cbor'` + CBOR 디코더. base64 오버헤드(1.33배)를 없앱니다.
- 원격에서 볼 때만 의미 있음. localhost면 후순위.

### 7-3. 라이브 맵 저장
- 지금은 누적본을 **내보낼 수 없습니다**. FAST-LIVO2가 자체 저장하므로 필수는 아니지만,
  "지금 화면의 이 맵"을 `.pcd`로 떨구는 버튼이 있으면 계측 워크플로에 유용합니다.

### 7-4. GPS 지오레퍼런싱 (위경도 표시)
- 가이드 8절 참고. 실시간이 붙었으므로 `sensor_msgs/msg/NavSatFix` 슬롯을 하나 더 두면
  세션 중에 궤적↔GPS 정합을 계산할 수 있습니다.

### 7-5. 기타 후보
- 화면 하단 미니맵(위에서 본 궤적), 뷰 프리셋(Top/Front/Side)
- 여러 세션 비교(파일 + 라이브 동시 표시) — 지금은 활성 클라우드가 하나뿐입니다

---

## 8. 로봇 없이 테스트하기 (mock)

FAST-LIVO2를 안 켜고 대시보드만 확인할 때 씁니다. **Node 18+ 필요**(의존성 없음).

```bash
node tools/mock-rosbridge.mjs          # ws://localhost:9090
```

가짜로 내보내는 것: `/cloud_registered`(10Hz, 컬러 PointCloud2), `/aft_mapped_to_init`(20Hz),
`/path`(5Hz), `/origin_img`(5Hz, PNG). 뷰어에서 `ws://localhost:9090`으로 연결하면
실제와 같은 경로로 동작합니다.

> 이 목 서버는 **개발용**입니다. 실기 검증을 대신하지 못합니다 — 실제 토픽 이름·필드·주파수는
> 4절에서 반드시 확인하세요.

---

## 9. 이관 순서 요약

1. 파일 복사 (1절)
2. 오프라인이면 Three.js 로컬화 (3절)
3. rosbridge + http.server 실행 (2절)
4. `ros2 topic list -t`로 **실제 토픽 기록** (4-2)
5. 대시보드 연결 → 4칸·Hz·맵 성장 확인 (4-3)
6. 카메라 안 뜨면 republish (5-1)
7. **복셀 유지율 확인** → 크기 조정. 그래도 모자라면 LIVE_CAP 상향 (6절)
