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.
14 KiB
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 — 수동 실행 (터미널에서 로그 보면서 디버깅할 때)
/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 으로 접속.
hostname -I # 이 PC의 LAN IP 확인
2. 사용법 (웹 UI)
브라우저를 열면 좌측에 제어 패널, 우측에 카메라 미리보기가 보인다 (기존 PyQt5 GUI와 레이아웃 유사).
- 시동 — "시동 시작" 클릭 → LiDAR 즉시 실행, 5초 후 cam1/cam2/cam3 자동 실행. 상단 상태 배지에서
LiDAR OK 9.8Hz/IMU OK/cam1 OK 14.9Hz등으로 바뀌는지 확인. 우측 미리보기에 실시간 영상이 뜨는지 확인. - 카메라 설정 — 탭에서 카메라 선택 → 자동노출/밝기/노출상한하한/노출시간/게인 조절 →
- 적용: 지금 켜진 카메라 노드에 바로 반영(
ros2 param set), 재시동 전까지만 유효 - 저장: 카메라 config YAML 파일에 영구 저장 (기존 주석은 그대로 보존됨)
- 적용: 지금 켜진 카메라 노드에 바로 반영(
- 녹화 — 저장 경로(기본
~/bags)와 파일 이름 입력 → "…" 버튼으로 폴더 찾아보기 가능 → "녹화 시작" → 끝나면 "녹화 정지". 저장 위치는~/bags/<파일이름>/<파일이름>_0.db3(기존과 동일). - 전체 정지(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. 녹화 검증 (기존 가이드와 동일한 방법)
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에서 추가 예정).
참고: 이제 대시보드 "최근 녹화" 목록에서 같은 정보(길이/용량/토픽별 메시지 수)를 바로 볼 수 있어서,
터미널로 확인하는 건 더 자세히 파고들 때만 필요하다.
실시간으로 토픽 수신 속도 확인하려면 시동 켠 상태에서:
ros2 topic hz /livox/lidar
ros2 topic hz /cam1/image
(또는 상단 상태 배지의 실측 Hz 숫자를 바로 봐도 됨.)
6. 종료 후 프로세스 정리 확인
시동 종료(또는 E-STOP) 후 ros2 launch 하위 프로세스가 안 남았는지 확인:
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 참고.