Files
gardentech f34817d5b6 Initial commit: scan_web integrated recording UI
FastAPI backend + vanilla JS frontend for LiDAR/camera startup, camera
settings, and rosbag recording, unifying the previous scan_gui/scan_gui_dual/
scan_gui_triple desktop tools into one web app.
2026-08-07 14:26:00 +09:00

218 lines
14 KiB
Markdown

# scan_web 운용 가이드 (Phase 1 / M1 — 시동·카메라설정·녹화 통합 웹앱)
> `~/fast_ws` 의 `scan_gui.py` / `scan_gui_dual.py` / `scan_gui_triple.py` (PyQt5, 3개 중복 파일)를
> 대체하는 **하나의 웹앱**이다. 브라우저(이 PC 또는 같은 네트워크의 폰)로 접속해서 쓴다.
> 기존 스캔 GUI 3종은 아직 그대로 두었다 — `~/Desktop/scan_gui*.desktop` 그대로 사용 가능(백업/롤백용).
## 0. 지금 버전이 할 수 있는 것 / 못 하는 것
**Phase 1 - M1(이번 작업)에서 됨:**
- LiDAR + cam1/cam2/cam3 시동/종료 (기존과 동일한 5초 지연 순서)
- 카메라별 노출/게인 설정 (자동노출/밝기/노출상한하한/노출시간/게인) — 적용(`ros2 param set`) / 저장(YAML, 주석 보존)
- rosbag 녹화 시작/종료 (기존 트리플 GUI와 동일 토픽 목록)
- 브라우저 기반 카메라 미리보기 (MJPEG)
- 전체 정지(E-STOP) 버튼
- 라이다/IMU/카메라 상태 배지 — OK/STALE/DOWN + **실측 Hz** (토픽 수신 여부/속도로 추정, 별도 진단 토픽 없음)
- **디스크 여유 공간 표시** (부족하면 경고/위험 색으로 바뀜 — §3 참고)
- **녹화 중 경과 시간 + 실시간 파일 크기**
- **최근 녹화 목록에 실제 길이/용량/메시지 수/토픽 수 표시** (`ros2 bag info`로 확인할 필요 없이 대시보드에서 바로 확인)
- **통합 로그 패널** — 기존 PyQt GUI의 로그창과 동일하게 lidar/camera/recording 프로세스 출력을 `[태그]`로 구분해 실시간으로 봄
- **디자인** — hallmark 스킬로 리디자인 완료 (M4, 순서를 당겨서 먼저 진행)
**아직 안 됨 (다음 단계):**
- GPS/RTK 연동 — **Phase 1 Milestone 2**. 지금 버전은 GPS 시작/정지/상태 표시가 아예 없다.
- 스캐닝 중 LIO(포인트클라우드+궤적) 라이브 뷰 — **Milestone 3**.
**⚠️ 아직 실제 하드웨어로 테스트 안 됨**: 서버 기동/API/프로세스 종료 로직은 소프트웨어 레벨로 확인했지만,
실제로 브라우저에서 "시동 시작"을 눌러 LiDAR/카메라를 구동해본 적은 없다. 아래 §2 순서대로 처음 실행할 때
평소 `scan_gui_triple.py` 켤 때처럼 하드웨어 연결 상태를 확인하고 진행할 것.
---
## 1. 실행 방법
### 방법 A — 바탕화면 아이콘
바탕화면 **"Scan Web (통합)"** 아이콘 실행 → 서버가 안 떠 있으면 자동으로 띄운 뒤, 준비되면 기본 브라우저로
`http://localhost:8000` 이 열린다.
### 방법 B — 수동 실행 (터미널에서 로그 보면서 디버깅할 때)
```bash
/home/gardentech/scan_web/run_scan_web.sh
```
포그라운드로 뜨며 uvicorn 로그가 그대로 보인다. `Ctrl+C` 로 종료(종료 시 실행 중이던 lidar/camera/recording
프로세스도 함께 정리됨 — app.py의 lifespan shutdown 훅).
### 폰에서 접속하려면
같은 Wi-Fi에 연결된 폰 브라우저에서 `http://<이 PC의 LAN IP>:8000` 으로 접속.
```bash
hostname -I # 이 PC의 LAN IP 확인
```
---
## 2. 사용법 (웹 UI)
브라우저를 열면 좌측에 제어 패널, 우측에 카메라 미리보기가 보인다 (기존 PyQt5 GUI와 레이아웃 유사).
1. **시동** — "시동 시작" 클릭 → LiDAR 즉시 실행, 5초 후 cam1/cam2/cam3 자동 실행. 상단 상태 배지에서
`LiDAR OK 9.8Hz` / `IMU OK` / `cam1 OK 14.9Hz` 등으로 바뀌는지 확인. 우측 미리보기에 실시간 영상이 뜨는지 확인.
2. **카메라 설정** — 탭에서 카메라 선택 → 자동노출/밝기/노출상한하한/노출시간/게인 조절 →
- **적용**: 지금 켜진 카메라 노드에 바로 반영(`ros2 param set`), 재시동 전까지만 유효
- **저장**: 카메라 config YAML 파일에 영구 저장 (기존 주석은 그대로 보존됨)
3. **녹화** — 저장 경로(기본 `~/bags`)와 파일 이름 입력 → "…" 버튼으로 폴더 찾아보기 가능 →
"녹화 시작" → 끝나면 "녹화 정지". 저장 위치는 `~/bags/<파일이름>/<파일이름>_0.db3` (기존과 동일).
4. **전체 정지(E-STOP)** — 라이다/카메라/녹화 프로세스를 한번에 즉시 정지. 확인 팝업 있음.
---
## 3. 대시보드에 표시되는 추가 정보
이번에 녹화 화면에 추가된 것들 — 전부 터미널을 열지 않고 브라우저에서 바로 확인 가능:
- **디스크 여유 공간** (녹화 패널, 저장 경로 입력 밑) — `여유 공간: 780.4 GB (/home/gardentech/bags)`
식으로 표시. **10GB 미만이면 주황색(경고), 2GB 미만이면 빨간색(위험)** 으로 바뀐다 — 장시간 스캔 중
디스크가 꽉 차서 bag이 깨지는 상황을 미리 막기 위함. 저장 경로를 바꾸면 그 경로 기준으로 다시 계산됨.
- **녹화 경과 시간 + 실시간 용량** — 녹화 중일 때 "● 녹화 중" 옆에 `03:42 · 1.2 GB` 식으로 표시.
- **최근 녹화 목록** — 이름뿐 아니라 **길이 / 용량 / 총 메시지 수 / 토픽 개수** 까지 바로 보임. 방금
중지한 bag이 아직 `metadata.yaml`을 못 쓴 상태면(정지 직후 잠깐) `(녹화 중 / 미완료)`로 표시됐다가
1~2초 뒤 자동으로 정상 표시로 바뀐다.
- **상태 배지의 실측 Hz** — 예: `LiDAR OK 9.8Hz`. STALE/DOWN일 땐 Hz를 안 붙임(의미 없는 숫자라서).
기준 임계값은 `backend/config.py``HEALTH_THRESHOLDS`에서 조정 가능.
- **로그 패널** (카메라 미리보기 아래, 화면 전체 너비) — lidar/camera/recording 세 프로세스의 출력을
`[lidar]`/`[camera]`/`[recording]` 태그로 구분해서 실시간으로 보여줌. 자동 스크롤 체크박스와
지우기 버튼 있음. 문제 생겼을 때(카메라 안 붙음, launch 실패 등) 원인 파악용 — 기존 PyQt GUI의
로그창과 동일한 역할.
---
## 4. 실기(하드웨어) 테스트 체크리스트
소프트웨어 레벨 검증은 끝났고, 브라우저 화면도 확인됨. 다음은 **실제 LiDAR/카메라를 켜서** 확인해야 할
것들 — 아래 순서대로 체크하면서 진행할 것을 권장.
### 4.1 시동 전
- [ ] LiDAR(MID360s), cam1/cam2/cam3 물리적으로 연결/전원 확인 (기존 `scan_gui_triple.py` 켤 때와 동일)
- [ ] 다른 곳에서 같은 토픽(`/livox/lidar`, `/cam1/image` 등)을 쓰는 프로세스가 남아있지 않은지 확인
(`ps aux | grep -E "ros2 launch|hik_camera|livox"`)
### 4.2 시동
- [ ] "시동 시작" 클릭 → LiDAR 즉시 실행, **5초 후** 카메라 3대 자동 실행되는지(카운트다운 없이 그냥 5초
뒤 배지가 바뀌는지 확인 — 화면에 카운트다운 표시는 아직 없음, PyQt 버전엔 있었음)
- [ ] 상단 배지: `LiDAR OK <Hz>` / `IMU OK <Hz>` / `cam1 OK <Hz>` / `cam2 OK <Hz>` / `cam3 OK <Hz>` 로 전환
- [ ] Hz 숫자가 말이 되는 값인지 (라이다는 보통 ~10Hz 대, 카메라는 설정된 fps 근처) — 기존
`ros2 topic hz`로 알던 값과 비교
- [ ] 우측 카메라 미리보기 3분할 화면에 실제 영상이 뜨는지, 세 대 다 정상인지 (cam3는 180도 회전 장착이라
화면도 거꾸로 나오는 게 정상 — SuperGlue 단계에서만 rotate_camera로 보정됨, 미리보기 자체는 원본)
- [ ] 로그 패널에서 `[lidar]`/`[camera]` 태그로 launch 로그가 흘러나오는지, 에러 없는지
### 4.3 카메라 설정
- [ ] 카메라 탭에서 노출/게인 "적용" 눌렀을 때 실제 영상 밝기가 바뀌는지 (반영까지 약간의 지연 있을 수 있음)
- [ ] "저장" 눌렀을 때 해당 카메라 config YAML이 실제로 갱신되는지, 기존 주석이 안 지워졌는지 확인
(`git diff` 있으면 diff로, 없으면 파일 직접 열어서 확인)
### 4.4 녹화
- [ ] 저장 경로/파일 이름 입력 후 "녹화 시작" → "● 녹화 중" + 경과시간/용량이 올라가는지
- [ ] 녹화 중 디스크 여유 공간 숫자가 (아주 조금씩이라도) 줄어드는지
- [ ] "녹화 정지" 후 "최근 녹화" 목록에 새 항목이 뜨는지, 잠깐의 "(미완료)" 표시 후 정상 정보로 바뀌는지
- [ ] `ros2 bag info`로 직접 확인해서 대시보드에 보이는 길이/용량/메시지 수와 일치하는지 (§5 참고)
### 4.5 종료 / 전체 정지
- [ ] "시동 종료" 눌렀을 때 배지가 전부 DOWN으로, 미리보기가 다시 회색으로 돌아오는지
- [ ] `ps aux | grep -E "ros2 launch|hik_camera|livox"` 로 프로세스가 하나도 안 남았는지 (§6)
- [ ] 녹화 중에 E-STOP을 눌러보고, bag이 깨지지 않고 (거의) 정상 종료되는지 — SIGINT로 정지하므로
rosbag2가 db3를 flush할 시간을 주는지 확인하는 목적
### 4.6 문제 생기면
로그 패널(§3) 또는 `~/scan_web_logs/*.log` 확인 → §8 트러블슈팅 표 참고 → 그래도 안 풀리면 필요한 로그
내용 들고 알려주면 같이 봄.
---
## 5. 녹화 검증 (기존 가이드와 동일한 방법)
```bash
source /opt/ros/humble/setup.bash
ros2 bag info ~/bags/<파일이름>/
```
확인할 토픽: `/livox/lidar`, `/livox/imu`, `/cam1/image`, `/cam1/camera_info`,
`/cam2/image`, `/cam2/camera_info`, `/cam3/image`, `/cam3/camera_info`
(GPS는 M1에 없으므로 `/ublox_driver/receiver_pvt` 는 아직 안 담김 — M2에서 추가 예정).
**참고**: 이제 대시보드 "최근 녹화" 목록에서 같은 정보(길이/용량/토픽별 메시지 수)를 바로 볼 수 있어서,
터미널로 확인하는 건 더 자세히 파고들 때만 필요하다.
실시간으로 토픽 수신 속도 확인하려면 시동 켠 상태에서:
```bash
ros2 topic hz /livox/lidar
ros2 topic hz /cam1/image
```
(또는 상단 상태 배지의 실측 Hz 숫자를 바로 봐도 됨.)
---
## 6. 종료 후 프로세스 정리 확인
시동 종료(또는 E-STOP) 후 `ros2 launch` 하위 프로세스가 안 남았는지 확인:
```bash
ps aux | grep -E "ros2 launch|fastlivo|hik_camera" | grep -v grep
```
아무것도 안 나오면 정상 종료된 것. (내부적으로 기존 `_kill_proc` 로직과 동일하게 프로세스 그룹 전체에
SIGINT → 3초 대기 → 안 죽으면 SIGKILL 하는 방식으로 정리한다.)
---
## 7. 로그 위치
| 항목 | 경로 |
|---|---|
| LiDAR 로그 | `~/scan_web_logs/lidar.log` |
| 카메라 로그 | `~/scan_web_logs/camera.log` |
| 녹화(rosbag) 로그 | `~/scan_web_logs/recording.log` |
| 서버(uvicorn) 로그 — 바탕화면 아이콘으로 실행했을 때만 | `~/scan_web_logs/server.log` |
위 세 개(lidar/camera/recording)는 이제 브라우저의 **로그 패널**(§3)에서 실시간으로도 볼 수 있다 —
터미널을 열 필요 없이 화면 하나에서 확인 가능.
---
## 8. 트러블슈팅
| 증상 | 원인 | 조치 |
|---|---|---|
| 브라우저에서 "초기화 실패" 알림 | 백엔드 서버가 안 떠 있거나 방금 죽음 | 터미널에서 방법 B로 직접 실행해 로그 확인 |
| 시동 눌러도 미리보기 화면이 계속 회색 | 카메라 노드가 5초 지연 후 아직 안 붙었거나, 실제 카메라 미연결 | 브라우저 로그 패널(§3)에서 `[camera]` 태그 확인, `ros2 topic list``/cam1/image` 존재 확인 |
| 상태 배지가 계속 DOWN | 해당 토픽에 메시지가 안 들어옴(프로세스 자체는 떠 있어도) | 하드웨어 연결/드라이버 로그 확인 — 배지는 진단 토픽이 아니라 수신 여부/속도 추정치임 |
| 녹화 시작이 막힘(버튼 비활성) | 시동(LiDAR+카메라)이 먼저 켜져 있어야 함 | "시동 시작" 먼저 실행 |
| 디스크 여유 공간이 주황/빨강 | 저장 경로 볼륨에 공간이 얼마 안 남음 | 오래된 bag 정리하거나 저장 경로를 다른 볼륨으로 변경 |
| 최근 녹화 항목이 계속 "(녹화 중 / 미완료)"로 남음 | 녹화가 비정상 종료돼 `metadata.yaml`이 안 써짐(강제 kill 등) | `ros2 bag info` 로 직접 확인, 필요시 해당 bag 폴더 정리 |
| 포트 8000 이미 사용 중 | 이전 세션의 uvicorn 이 안 죽고 남아있음 | `pkill -f "uvicorn app:app"` 후 재실행 |
---
## 9. 구버전(scan_gui\*, fast_ws)과의 관계
- `~/fast_ws/scan_gui.py` / `scan_gui_dual.py` / `scan_gui_triple.py` 및 해당 `.desktop` 파일은
**삭제하지 않고 그대로 둠** — scan_web 이 실제 필드에서 최소 한 번 이상 문제없이 검증되기 전까지는
기존 GUI로 언제든 되돌아갈 수 있다.
- GPS/RTK(M2), LIO 라이브 뷰(M3)가 끝나고 필드 검증까지 마치면, 기존 `.desktop` 파일들을
`~/Desktop/legacy/` 로 옮기는 것을 고려 (삭제는 그 이후 판단).
- **`fast_ws` 자체는 2026-08-05부로 폐기 방침** (`fast_dual_ws`로 3카메라 확장되기 이전의 구버전
저장소) — Jetson 이관 대상에서도 제외됨 (`~/fast_dual_ws/docs/Jetson-이관가이드.md` 참고).
이에 맞춰 scan_web의 라이다 실행 경로도 `fast_ws`를 거치지 않고 **`lidar2_ws`를 직접 source**
하도록 이미 고쳤다 (`backend/config.py``LIDAR2_WS_SETUP`, `run_scan_web.sh`) — 알고 보니
`fast_ws`는 자체 라이다 드라이버가 없이 `lidar2_ws`를 언더레이로 체이닝만 하던 것이라, 직접
source해도 동작은 완전히 동일하다 (2026-08-05, 실제로 재기동해서 확인함).
---
## 10. 코드 구조 (참고용)
```
~/scan_web/
backend/ FastAPI 서버 (프로세스 관리, ROS2 브리지, 카메라 파라미터, REST/WebSocket API)
frontend/ 브라우저 UI (순수 HTML/CSS/JS, 빌드 과정 없음)
design.md hallmark 리디자인 시스템 (색/폰트/간격/모션 토큰 규칙)
run_scan_web.sh 실행 스크립트 (ROS 오버레이 source + uvicorn 실행)
open_scan_web.sh 바탕화면 아이콘용 — 서버 기동 대기 후 브라우저 자동 오픈
```
전체 설계 배경/마일스톤 계획은 `~/.claude/plans/federated-marinating-sunbeam.md` 참고.