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

14 KiB

scan_web 운용 가이드 (Phase 1 / M1 — 시동·카메라설정·녹화 통합 웹앱)

~/fast_wsscan_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와 레이아웃 유사).

  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.pyHEALTH_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.pyLIDAR2_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 참고.