엣지 AI 기반 통학 시간대
교통 위험 모니터링 시스템 구축 및 인식 개선 — 프로젝트 개요
문제: 등교 시간 교문 앞 도로의 과속 · 정차 구역 밖 정차 · 횡단 학생 근접은 체감과 민원만 있고 숫자가 없음. 해법: 창 안쪽 엣지 디바이스(Jetson Orin Nano)가 영상을 저장하지 않고 통행을 세어 지표 3개(K1~K3)를 만들고, 위험 이벤트 순간에만 시각-언어 모델(VLM)이 "그 정차가 무엇이었는가"를 한 줄 태그로 붙여 오탐을 줄임. 숫자는 안내판 · 규범 메시지 · 건의서로 돌아가 운전자 · 학부모의 행동과 지자체의 결정을 바꿈. 연구: 같은 이벤트에 YOLO 단독 · VLM 단독 · 하이브리드 판정을 나란히 기록해 8GB 엣지 보드에서 하이브리드가 무엇을 더 주고 무엇을 비용으로 치르는지(fps · 지연 · 메모리 · 전력) 실측함. 증명: 개입 전 2주와 개입 후를 같은 요일 · 시간대로 비교해 공개함.
이 문서의 모든 절은 이 여섯 마디 중 하나에 속함. 절 3 이후의 지도는 파이프라인 마디(CAM · DET · TRK · VLM · DB · ANL · MSG)로 바뀌어 다시 나타남. 이 문서는 docs/index.html로 저장소에 들어가 GitHub Pages의 "프로젝트개요"가 됨.
0-1두 문서가 만나는 자리 — 문제 우선 위에 연구 트랙을 얹는다
"모델이 확실히 잴 수 있는 것만 지표로" · 프레임 무저장 · 가상선 · 호모그래피 · 5분 버킷 · QC · 수동 대조 GATE · 검토 큐 · 규범 메시지 · 전후 비교. 이 뼈대는 VLM이 없어도 그대로 돌아가야 하며, VLM이 죽어도 K1~K3는 나온다가 설계의 첫 조건.
추가하는 것 (연구 계획서)위험 이벤트 순간에만 도는 Slow Loop(VLM) · YOLO / VLM / HYBRID 3중 기록 · 자원(FPS · 지연 · 메모리 · 전력) 실측 · 안전 지수 · 학술 벤치마크. 계획서의 "동시 적재 가능 · 5.2 GB · 30→24 fps · 오탐 60%↓ · Recall 95%"는 실측 전 가정이므로 이 개요에서는 전부 가설(R1~R3)과 측정 프로토콜로 바꿈.
무엇을 바꾸려는가학교가 직접 제어할 장치는 없음. 바꿀 수 있는 것은 운전자 · 학부모의 행동(정보 · 규범 메시지)과 지자체의 결정(정확도가 붙은 건의서). 시스템의 출력은 알림과 리포트이고, 성공은 K1~K3의 변화 + 벤치마크 표 1장으로 정의함.
| 가설 | 내용 | 지표 · 검증 |
|---|---|---|
| H1 | 등교 시간대 통과 차량 상당수가 30 km/h를 초과한다 | K1 |
| H2 | 정차 구역 밖 정차가 시야를 가려 횡단 위험을 만든다 | K2 |
| H3 | 횡단과 차량 통과가 겹치는 순간이 특정 15분에 집중된다 | K3 |
| R1 | VLM 태그를 붙이면 "정차 = 위험"으로 세던 오탐(승하차 · 대기 등 정상 정차)이 줄어든다 | C1 · 사람 라벨 대비 FPR |
| R2 | Slow Loop가 돌 때 Fast Loop fps 저하가 QC 임계(15 fps) 안에 머문다 | fps · tegrastats |
| R3 | 8GB 통합 메모리에서 YOLO + 2~3B VLM Q4 동시 상주가 스왑 없이 유지된다 | mem · swap · 온도 |
0-2범위 — 무엇을 하고, 무엇을 주장하지 않는가
| # | 쟁점 | 계획서 | 카운터 매뉴얼 | 확인된 사실 · 이 개요의 결정 |
|---|---|---|---|---|
| 1 | Camera Module 3를 Jetson에 | RTSP 1080p30 카메라 가정 | Pi 5 + CM3 (picamera2 · 22핀) | CM3(IMX708)는 Jetson 공식 지원 센서가 아님. 커뮤니티 드라이버(RidgeRun)가 있으나 JetPack 5.1.1 / 6.0 커널 패치 기준이고 단일 모드(4608×2592 @ 14 fps)만 제공 → 현재 보드의 JetPack 7.2.1(커널 6.8)에는 그대로 적용되지 않을 가능성이 큼. 결정: Jetson 트랙은 USB UVC 카메라(무드라이버 · 1080p30 · 오토포커스 끔) 또는 IMX477 / IMX219 CSI(네이티브 드라이버)로 시작하고, CM3는 Pi 트랙 전용. CM3를 Jetson에 반드시 써야 한다면 R1에서 1일 한도로 시도하고 실패 시 되돌림. |
| 2 | JetPack 버전 | "JetPack 6 세팅, NanoLLM" | — | 보유 보드는 JetPack 7.2.1(L4T r39.2.1 · Ubuntu 24.04 · CUDA 13 · TensorRT 10.x · Python 3.12)이 이미 설치됨. JetPack 6 시대 자료(jetson-containers · NanoLLM · cu126 휠)는 그대로 쓰이지 않고, TensorRT 엔진은 보드에서 다시 빌드해야 함. 결정: 계획서의 1단계 "OS 세팅"을 "JetPack 7.2.1 위에서 툴체인 검증"으로 바꾸고 R1에 1주를 줌. VLM 런타임은 NanoLLM 대신 llama.cpp(CUDA 빌드)를 1순위, Ollama(arm64 CUDA)를 2순위로 실측 후 선택. |
| 3 | 수치의 출처 | 5.2 GB 점유 · 30→24 fps · GPU 42→85% · FPR 60%↓ · Recall ≥ 95% | "수동 대조 ≤ 10% 통과 뒤에만 보고" | 계획서 수치는 어느 것도 이 보드에서 잰 값이 아님(문헌 · 추정치). 8GB는 OS · 데스크톱 · CUDA 컨텍스트 · 카메라 버퍼와 공유되므로 "모델 파일 크기의 합"으로 판단할 수 없음. 결정: 모두 절 4의 실측 프로토콜로 대체. 목표치는 "Fast Loop ≥ 15 fps(QC 임계) · 스왑 0 · VLM 이벤트당 ≤ 4 s · 정상 정차 오탐 감소를 사람 라벨로 확인"으로 낮춰 잡음. 95% Recall은 목표가 아니라 측정 결과임. |
| 4 | 스몸비 · 승하차 지도 · 사각지대 궤적 | VLM이 정황 판정 (핵심 위험 트리거) | "모델이 확실히 잴 수 있는 것만" | 2~3층 창에서 본 보행자의 "고개 숙임 · 스마트폰"은 원경 · 저해상(얼굴 판독 불가 거리)이라는 프라이버시 전제와 정면 충돌하고 측정 가능성 등급이 낮음. 결정: 스몸비 · 어린이 관련 판정은 제외. VLM의 역할은 K2 정차 이벤트의 사유 태그(C1) 하나로 좁힘 — 고정 선택지 boarding · waiting · delivery · other. 사각지대 궤적은 K3 기하(거리 · 시간)로만 다룸. |
| 5 | 2안 · 원본 영상 녹화 후 순차 벤치마크 | RTSP → NVMe에 H.264 저장, 3회 재실행 | 영상 · 이미지 파일 저장 금지 (디버그 포함) | 학교 창에서 공공 도로를 녹화해 보관하는 것은 GATE 0 자체를 통과하지 못할 가능성이 큼. 결정: 운영 카메라로는 어떤 모드에서도 녹화 없음. 순차 벤치마크가 필요하면 (a) 교직원 · 학생 자원자가 연출한 통제 세션(학교 안 도로 · 참여 동의 · 암호화 · 세션 후 30일 폐기)이나 (b) 공개 교통 영상 데이터셋으로만 함. 1안(섀도 로깅)이 기본이며, 이것만으로 3중 기록이 되므로 2안 없이도 논문 표는 채워짐(자원 경합이 있는 상태의 벤치라는 것을 명시). |
| 6 | VLM 묘사 텍스트 | "한국어 정황 묘사"를 DB에 저장 · CQA 점수 평가 | "특정 차량 · 특정 사람 언급 없음" | 자유 문장은 색 · 차종 · 인상착의 · 연령 추정을 담기 쉬워 텍스트여도 식별 정보가 됨. 결정: VLM 출력은 JSON 고정 선택지만 저장(tag · confidence · door_open · person_near). 자유 묘사는 개발 중 화면 확인용으로만 쓰고 DB에 넣지 않음. 금칙어 필터(색상 · 차종 · 성별 · 연령 · 번호판 패턴)를 PARSE에 둠. |
| 7 | 일정에 게이트가 없음 | 10주 · 1~5단계 직선 | 12주 · GATE 0/1/2 · 실패 시 되돌아감 | VLM 판정을 사람 라벨과 대조하는 절차가 계획서에 없고(is_ground_truth_hazard만 NULLABLE로 존재), 그것 없이는 FPR · Recall을 계산할 수 없음. 결정: 게이트를 4개로(G0 협의 · G1 수동 대조 · G2 VLM 판정 검증 · G3 발송 승인) 늘리고 14주로 다시 짬. 사람 라벨은 창가 실시간 육안 기록으로 만듦(영상 없이도 가능한 유일한 방법). |
| 8 | 단일 테이블 | traffic_monitoring_events 한 장에 모델별 행 | 10개 테이블 · 5분 버킷 · 이벤트 · QC · 검증 · 검토 큐 | 한 이벤트에 3개 모델 결과와 사람 라벨이 붙으므로 "이벤트"와 "추론"과 "라벨"은 다른 표여야 조인이 됨. 결정: 카운터의 10개 표를 그대로 두고 inferences · labels · bench_runs 3개를 추가(절 5). 계획서의 단일 표는 VIEW로 제공해 분석 코드의 편의는 유지. |
| 9 | 설치 지점의 기하 (사진 확인 후 추가) | RTSP 카메라 위치 미정 | 2~3층 창 · 20~40° 사선 · 8~15 m 가상선 구간 | 항공사진으로 보면 카메라(3층 중앙탑 창)는 교문 정면 축 위에 있고 도로는 교문 너머 좌우 방향. 사진 축척 추정으로 교문까지 30~40 m, 도로 중심까지 45~55 m로 진술(20 m)과 차이가 크며, 시선 각은 약 11°로 권장보다 얕음. 교문 기둥과 담장 가로수가 좌우 도로를 가려 도로는 교문 틈(11~15 m)으로만 보이고, 두 횡단보도는 축에서 비켜 가로수 뒤일 가능성. 결정: ① 거리를 지도 거리 재기로 실측한 뒤 렌즈 초점거리 확정(절 H-04) ② 가림 없는 교내 진입로를 K2와 교문 통과 차량 수(C2)의 주 관측 구간으로 승격 ③ K1 가상선은 교문 틈 안에 ④ K3는 R1 시험 캡처에서 횡단보도 가시성을 확인한 뒤 채택/보류를 결정. |
상자 안은 코드명, 이름은 상자 바깥. 회색 점선 = 엣지 보드 한 대 안(Jetson 또는 Pi), 붉은 점선 = 영상이 존재하는 두 구간(프레임 · 크롭, 모두 메모리). 카운터 매뉴얼의 지도에 QUE · VLM · MON 세 상자와 inferences 층이 추가된 것이 전부이며, 초록 경로만으로도 K1~K3가 나옴.
컴포넌트 설명표 (지도의 코드명 순)
| 코드 | 이름 | 역할 | Jetson 트랙 | Pi 트랙 | 산출물 (저장되는 것) |
|---|---|---|---|---|---|
| CAM | 카메라 · 창 안쪽 | 2~3층 창 안쪽 사선 구도, 1280×720 · 15~30 fps, 프레임은 메모리에서만 | USB UVC(V4L2) 또는 IMX477/219(nvarguscamerasrc) | Camera Module 3 (picamera2) | 없음 |
| DET | 검출 | YOLO11n/s · COCO 6종 → veh4 · two_wheel · person 묶음 | TensorRT FP16 .engine (ultralytics export, 보드에서 빌드) | Hailo-10H .hef | 상자 + 클래스 (메모리) |
| TRK | 추적 · 가상선 · 이벤트 | ByteTrack · 호모그래피 · 가상선 A/B · dwell/conflict 판정 · 이벤트 시 크롭을 큐로 | 공통 Python (trafficsvc/counter) — 백엔드 무관 | 이벤트 · 5분 누적기 | |
| QUE | 비동기 큐 | 이벤트 크롭 + 메타를 상한 8개까지 보관, 넘치면 오래된 것부터 버림(dropped 카운트) | 공통 (asyncio.Queue / 스레드) | 없음 (드롭 수만 QC에) | |
| VLM | 맥락 판정 | 크롭 1장 + 고정 프롬프트 → JSON 태그. 처리 후 크롭 폐기 | Qwen2.5-VL 3B / Qwen3-VL 2B GGUF Q4 · llama.cpp(CUDA) 서버 | Hailo GenAI VLM (지원 시) 또는 CPU llama.cpp (배치) | inferences 행 (텍스트) |
| MON | 자원 계측 | 1 Hz로 GPU · RAM · 스왑 · 전력 · 온도 · 콜백 fps를 읽어 5분 QC 행과 벤치 실행 행에 붙임 | tegrastats / jtop | vcgencmd · hailortcli monitor | qc_5min · bench_runs |
| ACC | 5분 집계 · QC | 버킷 flush, 표본 < 5면 null, calib_ver · qc 비트 | 공통 | counts_5min · ped_5min · events · qc_5min | |
| DB | traffic.db | 카운터 10개 표 + inferences · labels · bench_runs · VIEW | SQLite WAL (단일 writer = trafficsvc) | 표 13개 (절 5) | |
| EXT | 외부 데이터 | 기상청 강수 · 기온, 학사일정 | API · 수기 캘린더 (timer) | ext_wx · school_cal | |
| ANL | 배치 분석 · 벤치 | M0~M4(카운터) + B1 혼동행렬 · B2 자원 곡선 · 안전지수 | systemd timer (야간) | analysis · 주간 집계 JSON | |
| LLM | 로컬 LLM | 집계 JSON → 리포트 문장 초안 · 숫자 검증기 | 같은 llama.cpp 서버의 텍스트 모델 (야간) | Hailo GenAI 또는 CPU | outbox draft |
| WEB | FastAPI + React | 공개 카드 · 차트 · 벤치 뷰 · 검토 큐 · 라벨 입력 · PDF | 공개 포트 / 관리 포트 분리 (Mealboard 규칙) | — | |
| MSG | 발송 | outbox status = approved 만 채널별 발송 | 텔레그램 봇 · 안내판 텍스트 · PDF | 발송 로그 | |
| PPL | 이해관계자 | 운전자 · 학부모 · 학생안전부 · 지자체 · 경찰 — 숫자를 받아 행동 · 결정을 바꾸는 사람 | — | 피드백 (전후 비교 대상) | |
detect/(TensorRT vs Hailo)와 vlm/(llama.cpp vs Hailo GenAI) 두 패키지의 백엔드 클래스뿐. 카메라는 OpenCV/GStreamer/picamera2 소스를 capture/에서 같은 제너레이터 인터페이스로 감쌈. 나머지(추적 · 지표 · 집계 · DB · 웹 · 배치)는 한 벌.문제 확인(1주 관찰)이 맨 앞에 오고, GATE 0 GATE 1 GATE 2 GATE 3 네 곳은 사람이 통과를 결정함. 카운터 매뉴얼의 게이트 3개에 GATE 2 · VLM 판정 검증이 끼어든 것이 차이. VLM 트랙(R5)은 GATE 1을 지난 뒤에만 시작 — 지표가 먼저, 연구가 그 위에.
| 단계 | 주차 | 산출물 | 완료 기준 | 절 |
|---|---|---|---|---|
| 문제 확인 | 1 | 1주 관찰 로그 · 가설 H1~H3 · R1~R3 확정 · 카메라 결정(쟁점 1) | 문제 진술 1장에 담당 교사 서명 | 0 · ! |
| 준비 · GATE 0 | 1~2 | 승인 문서 · 안내문 · JetPack 7.2.1 툴체인 검증 · 창 조준 | GATE 0 통과 · 30분 무저장 실행 로그 · TensorRT 엔진 빌드 성공 | H · R1 |
| 구현 + 검증 | 3~6 | 검출 · 추적 · 가상선 · 속도 · 5분 집계 · 수동 대조표 | Fast Loop ≥ 15 fps · 속도 ±3 km/h · GATE 1 통과 | R2 · R3 · R4 |
| 연구 트랙 | 6~9 | Slow Loop · 자원 실측표 · 육안 라벨 60건 · 혼동행렬 | GATE 2 통과 · 벤치 표 초안 | R5 |
| 운영 + 전달 | 8~14 | baseline 2주 · 대시보드 · 배치 · 알림 · LLM 리포트 · 개입 2회 | 주간 리포트 3회 · 전후 비교 1건 · 건의서 초안 · 벤치 표 공개 | R6 · R7 · FX |
| 이식 (선택) | 12~14 | Pi 5 + AI HAT+ 2 백엔드 · 같은 DB · 같은 UI | 같은 통제 세션에서 두 보드 벤치 표 1장 | R8 |
detect/ · vlm/ · capture/)를 코드에 그어 둠. 아래 표의 "실측"은 R1에서 채움.01트랙 비교표
| 항목 | Jetson 트랙 (본 프로젝트) | Pi 트랙 (이식) | 비고 |
|---|---|---|---|
| 보드 | Jetson Orin Nano Super 8GB 개발킷 · NVMe 부팅 · JetPack 7.2.1 | Raspberry Pi 5 8GB + AI HAT+ 2 (Hailo-10H, 8GB) · Trixie · hailo-h10-all | Pi는 운영 중인 Mealboard Pi와 별도 장비 |
| 메모리 | 8GB LPDDR5 통합 — OS · CUDA 컨텍스트 · 카메라 버퍼 · 두 모델이 한 풀을 나눔 | Pi RAM 8GB + HAT 전용 8GB — 검출/LLM은 HAT 메모리, 파이썬은 Pi RAM | Jetson은 데스크톱을 끄고(multi-user.target) 실측 시작 |
| 검출 | YOLO11n/s → ONNX → TensorRT FP16 .engine (보드에서 빌드, JetPack 버전 종속) | Model Zoo YOLOv8/11 .hef | 커스텀 학습은 마지막에 |
| 추적 | ByteTrack (supervision) — 공통 | track 단위 카운트 | |
| VLM | Qwen2.5-VL-3B 또는 Qwen3-VL-2B GGUF Q4 · llama.cpp CUDA 서버(llama-server --mmproj) · 대안 Ollama | Hailo GenAI VLM (지원 모델 한정) 또는 CPU llama.cpp 야간 배치 | 실측 tok/s · 이벤트당 ms 로 결정 |
| 텍스트 LLM | Qwen2.5 1.5B/3B Q4 · 같은 llama.cpp (야간) | Hailo GenAI 또는 Ollama CPU | 카운터 매뉴얼 절 4 계승 |
| 카메라 | ELP AR0234 2.3MP 컬러 글로벌 셔터 USB (UVC · MJPEG) + 2.8-12mm CS 가변 렌즈 — 실측 거리에 맞춰 초점거리 고정 후 링 나사 잠금. CM3 비권장 | Camera Module 3 (22핀 mini FPC) | 쟁점 1 · 9 · 절 H-04 |
| 전력 · 발열 | 25 W 모드(MAXN SUPER) · 팬 상시 · tegrastats로 전력 읽기 | 27 W PD · Active Cooler | 발열 throttling은 QC 비트 |
| 저장 | NVMe (DB · 모델 · 로그) — 영상 없음 | microSD 64GB A2 | find 결과 항상 0건 |
| 원격 | SSH (Tailscale 노드 추가) · Claude Code 원격 세션 | SSH (기존 rspi 방식 · 학교망 제약은 Mealboard CLAUDE.md 참고) | 절 7 |
02Jetson 런타임 세팅 (R1 · 문서 순서대로)
scripts/setup_jetson.sh · 핵심만 (sudo 는 사람이)# 0) 현재 상태 확인 — 계획서의 "JetPack 6" 가정을 여기서 깸
cat /etc/nv_tegra_release # R39 (rel 39.2.x) 이면 JetPack 7.2.x
apt list --installed 2>/dev/null | grep -E "nvidia-jetpack|tensorrt|cuda-toolkit"
python3 --version # 3.12
# 1) 전력 모드 · 데스크톱 끄기 · 계측 도구
sudo nvpmodel -q ; sudo nvpmodel -m 0 ; sudo jetson_clocks # MAXN SUPER 여부는 -q 출력에서 확인
sudo systemctl set-default multi-user.target && sudo reboot # GUI 메모리 반환 (필요 시 graphical 로 복귀)
sudo pip3 install -U jetson-stats && jtop # 메모리 · 전력 · 온도 한눈에
# 2) 프로젝트 venv (시스템 site-packages 상속 — CUDA · OpenCV 접근)
curl -LsSf https://astral.sh/uv/install.sh | sh
git clone https://github.com/xparapx/<REPO>.git ~/traffic && cd ~/traffic
uv venv --system-site-packages && uv sync
# 3) PyTorch/TensorRT 휠 — JetPack 7.2 (CUDA 13) 용 aarch64 휠을 NVIDIA PyPI(jp7) 또는 검증된 릴리스에서. cu126 휠은 동작하지 않음
# 4) YOLO11 → TensorRT 엔진 (보드에서, 30분 내외)
uv run yolo export model=yolo11n.pt format=engine half=True imgsz=640 device=0 # → yolo11n.engine (models/ · git 제외)
# 5) llama.cpp CUDA 빌드 · VLM 서버 (모델 파일은 git 제외)
git clone https://github.com/ggml-org/llama.cpp && cd llama.cpp && cmake -B build -DGGML_CUDA=ON && cmake --build build -j
./build/bin/llama-server -m models/qwen2.5-vl-3b-q4_k_m.gguf --mmproj models/mmproj-qwen2.5-vl-3b-f16.gguf -ngl 99 -c 2048 --port 8090
# 6) 카메라 확인
v4l2-ctl --list-devices ; v4l2-ctl -d /dev/video0 --list-formats-ext # ELP: MJPG 1920x1200 @30 확인
v4l2-ctl -d /dev/video0 -c exposure_auto=1 -c exposure_absolute=150 # 수동 노출 고정 (역광 대비)
gst-launch-1.0 v4l2src device=/dev/video0 ! image/jpeg,width=1920,height=1080,framerate=30/1 ! nvv4l2decoder mjpeg=1 ! nvvidconv ! video/x-raw,format=BGRx ! fakesink -v
gst-launch-1.0 nvarguscamerasrc ! nvvidconv ! fakesink # CSI (IMX477/219)
# 7) 원격
curl -fsSL https://tailscale.com/install.sh | sh && sudo tailscale up
free -h와 tegrastats를 같이 봄. ④ 카메라 모듈 3는 절 !의 쟁점 1 — R1의 1일 한도 시도 후 되돌림. ⑤ 헤드리스로 바꾼 뒤 조준은 MJPEG 미리보기(카운터 매뉴얼 P1)로.setup.sh(Trixie · hailo-h10-all · hailortcli fw-control identify)를 그대로 씀. 이 저장소에서는 scripts/setup_pi.sh로 두고, 백엔드 선택은 data/config.json의 "backend": "tensorrt" | "hailo".03백엔드 경계 — 코드에 그어 두는 두 줄
edge/trafficsvc/detect/__init__.py · 핵심만from typing import Protocol, Iterator
import numpy as np
class Detection: # 정규화 좌표 · 원 라벨 · 신뢰도 — 백엔드가 무엇이든 같은 모양
__slots__ = ("label", "conf", "x1", "y1", "x2", "y2")
class Detector(Protocol):
def infer(self, frame_bgr: np.ndarray) -> list[Detection]: ...
def stats(self) -> dict: ... # {"infer_ms": .., "backend": "tensorrt"}
def load(cfg: dict) -> Detector:
if cfg["backend"] == "tensorrt":
from .tensorrt_yolo import TensorRTYolo # ultralytics YOLO("yolo11n.engine")
return TensorRTYolo(cfg["engine"], conf=0.40, classes=[0, 1, 2, 3, 5, 7])
if cfg["backend"] == "hailo":
from .hailo_yolo import HailoYolo # HailoRT .hef + 후처리
return HailoYolo(cfg["hef"], conf=0.40)
raise ValueError(cfg["backend"])
# vlm/__init__.py 도 같은 꼴: class Tagger(Protocol): def tag(self, crop_bgr, meta) -> dict
# llama_cpp 백엔드 = HTTP(localhost:8090, OpenAI 호환) · hailo 백엔드 = GenAI SDK
04현장 기하 검토 — 3층 중앙탑 창에서 교문 · 도로까지 (사진 기반 추정 · 실측 전)
항공사진의 화살표 시작점(본관 3층 중앙탑 창)을 기준으로 시야 · 가림 · 거리 · 렌즈를 검토함. 아래 수치는 사진 축척 추정이며, R0에서 지도 거리 재기(네이버 · 카카오맵)와 창 높이 실측으로 바꿔 넣은 뒤 렌즈를 확정함.
| 항목 | 사진 추정 | 영향 | 대응 |
|---|---|---|---|
| 카메라 → 교문 거리 | 30~40 m (진술 20 m) | 렌즈 초점거리 · 픽셀당 크기가 2배 차이 | 지도 거리 재기로 실측 후 렌즈 확정. 20 m면 5~6 mm, 45~55 m면 10~12 mm |
| 카메라 → 도로 중심 | 45~55 m | 시선 각 ≈ 11° (권장 20~40°보다 얕음) → 밀집 시 차량 겹침 · 바닥점 오차 | 12 mm에서 1 px ≈ 1.2 cm, 보행자 ≈ 130 px로 검출은 충분. 겹침은 수동 대조(G1)에서 밀집 시간대 오차로 드러냄 |
| 교문 기둥 (4~5 m) · 담장 가로수 (10 m급) | 기둥 뒤 · 가로수 뒤 도로는 보이지 않음 | 도로 가시 구간이 교문 틈 폭 11~15 m로 제한 | 가상선 A·B(8~12 m)를 교문 틈 안에 배치. 구간이 8 m 미만이면 K1은 p85 대신 "통과 시간" 프록시로 강등 |
| 중앙 수목 (건물 앞 15 m · 높이 6~8 m) | 시선 높이 7 m와 겹칠 수 있음 | 여름철 잎이 도로 하단을 가릴 가능성 | R1 시험 캡처에서 확인 · 가리면 창을 한 층 위(옥상 탑) 또는 좌우 창으로 검토 |
| 횡단보도 2곳 | 축에서 좌 · 우 15 m 이상 · 가로수 뒤 가능성 | K3(횡단 중 근접)의 ROI를 못 잡을 수 있음 | 시험 캡처에서 횡단보도 다각형이 그려지면 채택, 안 되면 K3 보류 + 문제 진술에 명시 (스코프 축소는 실패가 아님) |
| 교내 진입로 (교문 ↔ 건물) | 가림 없음 · 10~35 m · 붉은 포장 | 가장 잘 보이는 구간이며 학부모 차량 정차 · 진입이 실제로 일어나는 곳 | K2 정차 구역 다각형과 교문 통과 차량 수(C2, 진입/진출)의 주 관측 구간으로 승격. 이곳은 사유지라 안내문 게시가 곧 근거 |
| 태양 방향 | 미상 (건물이 남향이면 카메라는 남향 → 등교 시간 역광) | 08:00 전후 자동 노출 흔들림 · 유리 반사 | R1 첫 날 07:40~08:30 시험 캡처로 확인 · 수동 노출 고정 · 후드 밀착 · 하늘을 화면 밖으로 |
| 도로 중심까지 | 권장 초점거리 | 수평 화각 · 커버 폭 | 1 px ≈ | 보행자 (px) | 번호판 글자 (px) |
|---|---|---|---|---|---|
| 20~25 m | 5~6 mm | 51~58° · 20~25 m | 1.1~1.3 cm | 130~160 | 8~10 (판독 불가) |
| 35~40 m | 8 mm | 40° · 26~29 m | 1.1~1.2 cm | 140~150 | 9~10 (판독 불가) |
| 45~55 m | 10~12 mm | 27~32° · 24~30 m | 1.2~1.4 cm | 120~140 | 8~9 (판독 불가) |
거리가 멀수록 초점거리를 올려도 번호판 글자가 10 px를 넘지 않으므로 "판독 불가" 원칙은 어느 행에서도 유지됨. 2.8-12 mm 가변 렌즈로 세 행을 모두 덮고, 확정 후 링 나사를 잠그고 마커 선을 그음(12 mm 이상은 이 프로젝트에서 쓰지 않음).
카운터 매뉴얼 절 K(사선 구도 · 프레임 미저장 · track_id · 가상선 · 호모그래피 · p85 · 5분 버킷 · QC · ORB · 기준 프로파일 · 규범 메시지 · 검토 큐 · systemd)는 그대로 전제. 여기는 이 프로젝트에서 새로 나오는 말만.
CPU와 GPU가 같은 8GB를 씀. "VRAM 5.2 GB"라는 표현은 Jetson에서 성립하지 않고, OS · 버퍼 · 모델이 한 풀에서 경합함. 스왑이 생기면 fps가 급락.
ONNX 모델을 특정 GPU · JetPack 버전에 맞게 컴파일한 파일. FP16이면 정확도 손실 거의 없이 2배 안팎 빠름. 다른 보드 · 버전에서는 못 씀.
Fast = 전 프레임에 도는 검출 · 추적 · 지표(동기). Slow = 이벤트당 한 번 도는 VLM(비동기). 둘은 큐 하나로만 만나고, Slow가 죽어도 Fast는 돔.
이벤트가 VLM 처리보다 빨리 오면 쌓임. 상한(8)을 두고 넘치면 오래된 것부터 버리며 dropped를 QC에 기록 — 무한히 쌓여 메모리를 먹는 것을 막음.
이미지 + 텍스트 프롬프트 → 텍스트. 여기서는 "묘사"가 아니라 고정 선택지 분류기로만 씀. 2~3B · Q4 양자화면 Jetson에서 이벤트당 수 초.
가중치를 4비트로 줄인 형식(GGUF). VLM은 언어 모델 GGUF + 비전 인코더(mmproj) 두 파일. -ngl 99로 전 레이어를 GPU에.
실시간 관제를 유지한 채 백그라운드에서 다른 모델의 판정을 "그림자처럼" 함께 기록. 같은 이벤트 키에 YOLO · VLM · HYBRID 3행이 붙음.
VLM이 GPU를 쓰는 순간 YOLO의 fps가 떨어짐. 그 상태에서 잰 fps는 "경합 있는 벤치"이며, 그렇게 표기하면 논문에 쓸 수 있음 — 숨기면 오염.
사람이 판정한 정답. 영상을 저장하지 않으므로 이벤트 발생 순간 창가에서 육안으로 기록하는 것이 이 프로젝트의 유일한 정답 생성법.
FPR = 정상 정차를 위험으로 부른 비율. Recall = 진짜 위험을 놓치지 않은 비율. 정밀도 = 위험이라 부른 것 중 진짜 비율. 셋 다 라벨이 있어야 계산됨.
K1~K3를 baseline 대비 정규화해 100점으로 합친 표시용 값. 지표가 아니라 커뮤니케이션 장치이며, 리포트에는 항상 K1~K3 원값과 함께.
Jetson의 RAM · GPU 사용률 · 전력(mW) · 온도를 1초마다 찍는 도구. 벤치 표의 MB · W 열은 여기서 옴.
01후보 변수 측정 가능성 등급 (카운터 표 + VLM 후보)
| 후보 변수 | 모델이 재는 방법 | 주요 오차 원인 | 등급 | 채택 |
|---|---|---|---|---|
| 4륜 통과 수 · 방향 · 속도 | veh4 track이 가상선 A·B 통과 · 시간차 × 실거리 | 겹침 · 가림 · 15 fps 타이밍 | 높음 · 중상 | 핵심 (K1) |
| 정차 (≥ 20 s · 구역 밖) | 같은 track 20 s 이동 < 1 m · 다각형 안 | 구역 경계 · track 단절 | 높음 | 핵심 (K2) · Slow Loop 트리거 |
| 횡단 중 차량 근접 | crosswalk 안 person 존재 중 veh4 최근접 < 2 m ≥ 1 s | 바닥점 · 원근 · 군집 | 중 | 핵심 (K3) · 프록시 명시 + 육안 대조 |
| 정차 사유 태그 (boarding · waiting · delivery · other) | K2 이벤트 크롭 1장 → VLM 고정 선택지 | 원경 · 문 열림 가림 · 모델 편향 · 프롬프트 민감성 | 중 (실측 전) | 연구 변수 C1 · G2 통과 후만 리포트 |
| 정차 중 문 열림 · 사람 접근 (보조 신호) | VLM boolean 2개 (door_open · person_near) | 위와 같음 | 중 | C1 보조 · 결합 규칙 입력 |
| 스마트폰 보행 (스몸비) | 보행자 크롭 → VLM | 원경 · 저해상 전제와 충돌, 자세 판독 불가 | 낮음 | 제외 (쟁점 4) |
| 어린이 · 학생 · 학부모 여부 | — | 식별 · 연령 추정 = 설계상 하지 않음 | 불가 | 제외 |
| 통학버스 사각지대 궤적 | bus 라벨 정차 중 person track이 차량 전방 2 m 진입 | 버스 ↔ 트럭 혼동 · 가림 | 중 | K3의 변형으로만 기록 (zone = bus_front) · 리포트 보류 |
| 교문 통과 차량 수 · 방향 (진입 / 진출) | 교내 진입로에 가상선 1개 — veh4 track 통과 · 순서 | 거의 없음 (가림 없는 구간) | 높음 | 맥락 변수 C2 · "등교 시간 교내 진입 n대"로 K2와 함께 리포트 |
| 추론 지연 · 메모리 · 전력 · fps | MON 1 Hz + 이벤트별 타이머 | 계측 오버헤드 · 온도 | 높음 | 연구 변수 R (벤치 표) |
02정의 (등교 시간대 = 등교 시각 − 40분 ~ 등교 시각)
K2 = Σ dwell(veh4, duration ≥ 20 s, zone = no_stop) / 등교일 수
K3 = Σ conflict(person ∈ crosswalk, min dist(veh4) < 2 m, ≥ 1 s) / 등교일 수 (프록시)
C2 = Σ 교내 진입로 가상선 통과(veh4, 방향별) / 등교일 수 (가림 없는 구간 · 오차 최소)
C1 = K2 이벤트별 tag 분포 {boarding, waiting, delivery, other, unknown} · G2 통과 후 · "정상 정차로 재분류된 비율"을 함께 표기
R = 모델별 (fps_fast, latency_ms, mem_mb, power_w, FPR, Recall, precision) — 같은 event_id 기준, 라벨 있는 이벤트만
학교 기여분 = 지표(등교 시간대) − 지표(같은 요일 10:00~11:00)
01하는 것 · 하지 않는 것 (VLM 추가분)
하는 것
- K2 이벤트 순간 차량 상자 주변 크롭 1장(448 px, 여백 20%)을 메모리에서 VLM에 전달, 응답 즉시
del - VLM 출력은 고정 선택지 JSON만 저장:
tag · conf · door_open · person_near · latency_ms - 사람 라벨은 창가 육안 기록 (시각 · 태그 · 라벨러) — 텍스트만
- 벤치마크는 1안 섀도 로깅(운영 중 자동) + 필요 시 통제 세션 · 공개 데이터셋
- 모델 · 프롬프트 버전을 모든 추론 행에 기록 (재현성)
하지 않는 것
- 운영 카메라의 영상 · 프레임 · 크롭 파일 저장 (어느 모드 · 디버그 포함)
- VLM 자유 묘사 문장 저장 · 색상 · 차종 · 성별 · 연령 · 인상착의 · 번호판 질의
- 보행자 얼굴 · 자세 · 스마트폰 판정 (스몸비)
- 클라우드 API로 이미지 전송 (모든 추론은 보드 안)
- VLM 태그의 자동 발송 · 자동 리포트 (G2 · G3 전에는 화면에도 안 나감)
02통제 세션 규칙 (2안이 필요할 때만)
| 항목 | 규칙 |
|---|---|
| 장소 · 시간 | 학교 부지 안 도로 또는 주차장, 수업 외 시간, 안내 표지 설치 |
| 참여자 | 교직원 · 자원 학생(보호자 동의) · 교직원 차량. 외부 통행이 섞이지 않는 구간 |
| 내용 | 정상 정차 시나리오(승하차 · 대기 · 배송 흉내) × n회, 위험 시나리오(정차 구역 밖 장기 정차 · 횡단 중 근접)를 안전 속도로 연출 |
| 저장 | 별도 NVMe 디렉터리, LUKS 암호화, data/sessions/<date>/ — 운영 파이프라인이 읽지 못하는 경로. 세션 종료 30일 후 삭제 로그 남김 |
| 용도 | run.py --source file --mode YOLO_ONLY | VLM_ONLY | HYBRID 순차 벤치 (자원 경합 0). 라벨은 시나리오 대본이 곧 정답 |
- 학교 개인정보 보호 담당자에게 설계서(절 1 · 2 · 3) 제출 · 확인 — VLM 크롭 처리 · 텍스트 저장 범위 · 통제 세션 여부 명시
- 교육청 영상정보처리기기 · 개인정보 지침 해당 여부 확인 (문의 기록)
- 학교장 · 학생안전부 승인 · 학부모회 사전 설명 (VLM은 "정차 사유 태그"로만 설명)
- 안내문 게시 (창 안쪽 · 교문) 후 카메라 전원 ON
- CLAUDE.md 프라이버시 조항 v1: "이미지 파일 쓰기 코드 금지 · VLM 출력은 enum JSON만 · 금칙어 필터 통과 전 DB 기록 금지"
--log-disable 또는 로그 경로 tmpfs, 설치 직후 확인. ② 개발 중 "VLM이 뭘 보는지" 확인하려고 크롭을 cv2.imwrite하는 습관 → 화면 표시(imshow)만, 그것도 개발 플래그 뒤에. ③ 프롬프트에 "묘사하라"가 들어가면 모델은 색 · 차종을 씀 → 선택지만 묻고 JSON 외 출력은 버림.01트리거 · 크롭 · 프롬프트 · 결합 규칙
| 단계 | 규칙 | 비고 |
|---|---|---|
| 트리거 | K2 dwell 이벤트가 20 s 조건을 만족하는 순간 1회 (track당 1회). conflict(K3)는 트리거하지 않음 | 이벤트 빈도 ≈ 하루 10~30건 → VLM 부하 작음 |
| 크롭 | 차량 상자 + 여백 20%, 긴 변 448 px로 축소, BGR→RGB, 메모리 버퍼 | 얼굴 · 번호판이 판독되는 해상도가 아님을 G0 시험 캡처로 확인 |
| 프롬프트 | 고정 템플릿 v1 + 선택지 4개 + JSON 스키마. 온도 0. max_tokens 64 | prompt_ver를 추론 행에 기록 |
| 파싱 | JSON 파싱 실패 · enum 외 값 · 금칙어 포함 → tag=unknown, 원문 폐기 | unknown 비율도 벤치 지표 |
| 결합 (HYBRID) | YOLO_ONLY: dwell(no_stop) = DANGER · VLM_ONLY: tag 만으로 · HYBRID: dwell ∧ (tag ∈ {other, unknown} ∨ person_near ∧ zone = no_stop) = DANGER, tag ∈ {boarding, waiting, delivery} ∧ duration < 60 s = WARNING, 그 외 SAFE | 규칙은 hybrid_rules.py 한 파일 · 버전 기록 |
| 기록 | inferences에 3행 (model_type × 같은 event_id), 각 행에 latency · mem · power · model_ver · prompt_ver | 절 5 |
import asyncio, time, json, re, numpy as np
from .vlm import load as load_tagger # llama_cpp | hailo 백엔드
ENUM = {"boarding", "waiting", "delivery", "other"}
BAN = re.compile(r"(색|흰|검정|빨간|파란|승용|SUV|승합|트럭|남성|여성|아이|어린이|노인|\d{2,3}[가-힣]\d{4})")
class SlowLoop:
def __init__(s, cfg, db, mon):
s.q = asyncio.Queue(maxsize=cfg.get("queue_max", 8)); s.tagger = load_tagger(cfg); s.db, s.mon = db, mon; s.dropped = 0
def submit(s, event_id, crop_rgb, meta): # Fast Loop 스레드에서 호출 · 절대 블록하지 않음
try: s.q.put_nowait((event_id, crop_rgb, meta))
except asyncio.QueueFull:
s.q.get_nowait(); s.q.put_nowait((event_id, crop_rgb, meta)); s.dropped += 1
async def run(s):
while True:
event_id, crop, meta = await s.q.get(); t0 = time.time(); m0 = s.mon.snapshot()
try: out = s.tagger.tag(crop, meta) # dict 또는 예외
except Exception as e: out = {"tag": "unknown", "err": type(e).__name__}
finally: del crop # 크롭은 여기서 끝
tag = out.get("tag") if out.get("tag") in ENUM and not BAN.search(json.dumps(out, ensure_ascii=False)) else "unknown"
row = {"event_id": event_id, "model_type": "VLM_ONLY", "tag": tag, "door_open": bool(out.get("door_open")),
"person_near": bool(out.get("person_near")), "conf": out.get("conf"),
"latency_ms": int((time.time() - t0) * 1000), **s.mon.delta(m0)} # mem_mb · power_w · gpu_pct
s.db.insert_inference(row); s.db.insert_inference(hybrid(meta, row)) # HYBRID 행 · YOLO_ONLY 행은 Fast Loop이 이미 씀
submit이 블록되면 Fast Loop fps가 떨어짐 — put_nowait만. ② VLM 서버 워밍업(첫 요청 10 s+)은 서비스 시작 시 더미 요청으로 미리. ③ llama.cpp 서버는 동시 요청 1로 고정(--parallel 1) — KV 캐시 중복 할당 방지. ④ 온도 throttling이 오면 latency가 2~3배 뛰고 그것이 곧 R2 · R3의 데이터임 — 숨기지 말고 QC 비트로.01대안 비교 · 이 개요의 결정
| 대안 | 동작 | 얻는 것 | 비용 · 위험 | 결정 |
|---|---|---|---|---|
| 1안 섀도 로깅 (실시간 비동기) | YOLO 상시 + VLM 상주, 이벤트 시 큐 → 같은 event_id에 3행 | 운영 · 알림 · 연구 데이터가 한 번의 가동으로 | 이벤트 순간 GPU 경합 → fps 순간 저하 (실측 대상) | 기본. Fast ≥ 15 fps · 스왑 0 이면 채택 |
| 2안 순차 벤치 (파일 재실행) | 같은 파일에 --mode 3회 | 경합 0의 순수 벤치 | 운영 카메라 녹화 불가 (쟁점 5) | 통제 세션 · 공개 데이터셋에서만 |
| 3안 동적 스위칭 | 피크 시간대에만 VLM 로드/언로드 | 비피크 전력 · 발열 감소 | 로드 지연 3~10 s · 복잡도 · 첫 이벤트 놓침 | 1안이 메모리 · 발열에서 실패할 때의 대체안. 구현은 systemctl start vlm@peak 타이머 수준으로 단순하게 |
02메모리 예산 — 가정을 적고 실측으로 지움
| 항목 | 가정 (착수 전) | 실측 (R1 · R5에서 채움) | 측정 방법 |
|---|---|---|---|
| OS + 서비스 (헤드리스) | ~1.0 GB | __ GB | free -h 부팅 직후 |
| CUDA 컨텍스트 + TensorRT YOLO11n FP16 + 카메라 버퍼 | ~1.0 GB | __ GB | Fast Loop만 10분 · tegrastats RAM 열 |
| VLM 2~3B Q4 + mmproj + KV(2048) | ~2.5~3.5 GB | __ GB | llama-server 기동 후 · 첫 요청 후 |
| Python 런타임 (추적 · 웹 · DB) | ~0.5 GB | __ GB | 서비스별 RSS |
| 합계 · 여유 | ~5~6 GB · 여유 2 GB | __ GB · 스왑 __ | zramctl · swap used 가 0을 벗어나면 R3 실패 |
03실측 프로토콜 (R5 · 통제 세션 또는 등교 3일)
Fast Loop만 30분. fps(콜백) · RAM · GPU% · 전력 · 온도 1 Hz. → bench_runs(mode='YOLO_ONLY')
VLM 서버를 띄우되 요청 없음, 30분. 상주 비용(메모리 · 유휴 전력)을 분리.
1안 그대로 등교 3일. 이벤트 순간 ±10 s 창의 fps 최저값 · 회복 시간 · VLM latency 분포(p50 · p95). → 계획서의 "30→24 fps" 자리에 실측값.
통제 세션에서 이벤트를 1분에 4회로 몰아 큐 드롭 · 온도 throttling 발생점을 찾음. 이 값이 3안으로 갈지 결정.
통제 세션 파일로 --mode 3회. 경합 0 조건의 latency · 정확도. B2와 나란히 표에.
import subprocess, re, time, threading
PAT = re.compile(r"RAM (\d+)/(\d+)MB.*?SWAP (\d+)/(\d+)MB.*?GR3D_FREQ (\d+)%.*?(?:VDD_IN|VIN_SYS_5V0) (\d+)mW.*?(?:gpu|GPU)@([\d.]+)C")
class Mon: # tegrastats 1 Hz 를 파싱해 최신값 유지 (Pi 백엔드는 vcgencmd)
def __init__(s): s.v = {}; threading.Thread(target=s._loop, daemon=True).start()
def _loop(s):
p = subprocess.Popen(["tegrastats", "--interval", "1000"], stdout=subprocess.PIPE, text=True)
for line in p.stdout:
m = PAT.search(line)
if m: s.v = dict(ts=time.time(), ram_mb=int(m[1]), swap_mb=int(m[3]), gpu_pct=int(m[5]), power_w=int(m[6]) / 1000, temp_c=float(m[7]))
def snapshot(s): return dict(s.v)
def delta(s, m0): now = s.v; return dict(mem_mb=now.get("ram_mb"), power_w=now.get("power_w"), gpu_pct=now.get("gpu_pct"), swap_mb=now.get("swap_mb"))
# 정규식은 보드의 실제 tegrastats 한 줄로 R1 에서 맞춤 — 필드명이 JetPack 버전마다 다름
counts_5min · ped_5min · events · qc_5min · calib · ext_wx · school_cal · validation · analysis · outbox는 그대로. 연구를 위해 "한 이벤트에 여러 판정과 라벨이 붙는" 구조 세 장을 더함. 계획서의 단일 표는 VIEW로 남겨 분석 코드가 한 번에 읽게 함.-- events 확장: Slow Loop 대상인지 · 최종 risk 는 HYBRID 행에서 가져오되 표시용으로 캐시
ALTER TABLE events ADD COLUMN event_id TEXT; -- UUID v4 · 3표 조인 키 (id 는 로컬 정수 유지)
ALTER TABLE events ADD COLUMN risk_level TEXT; -- SAFE | WARNING | DANGER (HYBRID 기준 캐시)
ALTER TABLE qc_5min ADD COLUMN vlm_dropped INTEGER; -- 큐 드롭 수
ALTER TABLE qc_5min ADD COLUMN power_w REAL; -- 5분 평균 전력 (MON)
ALTER TABLE qc_5min ADD COLUMN mem_mb INTEGER; -- 5분 최대 RAM
ALTER TABLE qc_5min ADD COLUMN throttle INTEGER; -- 온도 throttling 비트
-- 판정: 같은 event_id 에 model_type 별 1행 (섀도 로깅)
CREATE TABLE inferences(
id INTEGER PRIMARY KEY, event_id TEXT NOT NULL, ts TEXT NOT NULL,
model_type TEXT NOT NULL, -- YOLO_ONLY | VLM_ONLY | HYBRID
risk_level TEXT NOT NULL, -- SAFE | WARNING | DANGER
tag TEXT, door_open INTEGER, person_near INTEGER, conf REAL, -- VLM 출력 (enum 만 · 자유 문장 없음)
latency_ms INTEGER, mem_mb INTEGER, power_w REAL, gpu_pct INTEGER, swap_mb INTEGER,
model_ver TEXT, prompt_ver TEXT, rules_ver TEXT, backend TEXT, -- 재현성 (yolo11n-fp16-trt10 · qwen2.5vl-3b-q4 · p1 · h1 · tensorrt|hailo)
UNIQUE(event_id, model_type));
-- 사람 라벨: 창가 실시간 육안 기록 · 통제 세션 대본 — 이미지 없이 만드는 유일한 정답
CREATE TABLE labels(
id INTEGER PRIMARY KEY, event_id TEXT NOT NULL, ts TEXT NOT NULL,
hazard INTEGER NOT NULL, -- 1 = 실제 위험 정차 (구역 밖 · 시야 가림) · 0 = 정상
tag TEXT, -- boarding | waiting | delivery | other (사람 판정)
labeler TEXT NOT NULL, source TEXT NOT NULL, -- live | session
note TEXT);
-- 벤치 실행: B0~B4 각 실행의 요약 (초 단위 시계열은 qc_5min · inferences 에 이미 있음)
CREATE TABLE bench_runs(
id INTEGER PRIMARY KEY, started TEXT, ended TEXT, board TEXT, mode TEXT, -- jetson|pi · YOLO_ONLY|SHADOW|SEQ_*
fps_med REAL, fps_p05 REAL, lat_p50_ms INTEGER, lat_p95_ms INTEGER, mem_max_mb INTEGER,
swap_max_mb INTEGER, power_avg_w REAL, temp_max_c REAL, n_events INTEGER, n_dropped INTEGER, note TEXT);
-- 계획서 호환 뷰: 단일 표처럼 읽기
CREATE VIEW traffic_monitoring_events AS
SELECT i.event_id, i.ts AS timestamp, i.model_type, i.risk_level, i.tag AS context_tag,
i.latency_ms AS inference_latency_ms, i.mem_mb AS gpu_mem_used_mb, i.power_w AS power_draw_w,
l.hazard AS is_ground_truth_hazard, l.tag AS gt_tag, e.zone, e.duration_s
FROM inferences i JOIN events e ON e.event_id = i.event_id LEFT JOIN labels l ON l.event_id = i.event_id;
CREATE INDEX ix_inf_event ON inferences(event_id); CREATE INDEX ix_lab_event ON labels(event_id);
01수집 페이로드 — 누가 어느 표에 쓰는가
| 쓰는 쪽 | 표 | 주기 | 비고 |
|---|---|---|---|
| Fast Loop (ACC) | counts_5min · ped_5min · qc_5min | 5분 | 표본 < 5 → null · calib_ver · qc 비트 · MON 요약 |
| Fast Loop (EVT) | events (+ event_id) · inferences(YOLO_ONLY) | 이벤트 | dwell 판정 즉시 YOLO_ONLY 행 기록 → 큐 submit |
| Slow Loop | inferences(VLM_ONLY · HYBRID) · events.risk_level | 이벤트 + 1~4 s | 실패 시 tag=unknown 행이라도 남김 (결측 ≠ 미실행) |
| 라벨 화면 (관리 포트) | labels | 이벤트 순간 · 세션 | 라벨러는 태그 알림을 받고 60 s 안에 입력 · 늦으면 note='late' |
| 배치 (ANL) | analysis · bench_runs · outbox(draft) | 매일 22:00 · 주간 | M0~M4 + B1 혼동행렬 + 안전지수 |
| 사람 (검토) | outbox(approved) · validation | — | 승인은 관리 포트에서만 |
model_ver · prompt_ver · rules_ver · backend. ④ 라벨이 없는 이벤트는 FPR · Recall 계산에서 빠지고, "라벨 있는 이벤트 수"를 벤치 표에 함께 적음.01인사이트 → 알림 매핑 (카운터 표 + 추가 3행)
| 인사이트 | 입력 | 모델 · 방법 | 알림 형태 · 수신자 | 기대하는 인식 · 행동 변화 |
|---|---|---|---|---|
| K1 30 km/h 초과 비율 | counts_5min(veh4) · school_cal | 주 단위 비율 + M2 추세 · 전후 검정 | 안내판 · 주간 메시지 · 건의서 | 운전자 감속 · 단속 건의 |
| K2 정차 구역 밖 정차 | events(dwell, no_stop) | 일 단위 건수 + M3 군집(핫스팟) | 안내판 · 학부모 규범 메시지 | 하차는 드롭존에서 · 정차 시간 단축 |
| K3 횡단 중 차량 근접 | events(conflict) · cross_n | 일 단위 건수 + M4 위험 시간대 | 주간 리포트 · 건의서 | 안전요원 배치 시간 · 보행 신호 검토 |
| C1 정차 사유 분포 (G2 후) | inferences(HYBRID) · labels | 태그 비율 + "정상 정차로 재분류된 비율" | 주간 리포트 (학부모회) · 드롭존 설계 근거 | "정차의 70%가 승하차 → 드롭존 위치 · 길이 조정"처럼 비난 없는 시설 제안 |
| 안전 지수 (표시용) | K1~K3 · baseline | 100 − Σ w·clip((K − K_base)/K_base) · w = (0.4, 0.3, 0.3) · 주 단위 | 정문 모니터 · PWA 카드 | 한눈에 보는 추세. 원값 K1~K3 없이 단독 표기 금지 |
| 벤치 표 (연구) | inferences · labels · bench_runs | B1 혼동행렬(모델별 FPR · Recall · 정밀도) · B2 자원 곡선(fps · ms · MB · W) | 관리 포트 벤치 뷰 · 보고서 부록 | "하이브리드가 무엇을 주고 무엇을 치르는가"를 한 장으로 |
| 오늘의 이상 · 학교 기여분 · 개입 효과 · 내일 예보 | 카운터 매뉴얼 절 3의 매핑 그대로 (M1 · M2 · M5) | |||
02UI 설계 — 화면 · 포트 · 데이터 원천
Plant_Growth_Monitoring_Demo의 web/(React · Vite · Tailwind v4 · ECharts · PWA · 목 데이터 모드)를 셸로 가져오고, 페이지만 바꿈. 공개 포트는 analysis만 읽고, 이미지 · 라이브 프리뷰는 어느 포트에도 없음.
| 페이지 | 포트 | 내용 | 읽는 표 |
|---|---|---|---|
오늘 / | 공개 | 아침 카드: 오늘 K1 · K2 · K3 잠정값 · 안전 지수 게이지 · 현재 5분 통행 · QC 통과율 · "자동 카운트 · 수동 대조 오차 ±n%" | analysis · counts_5min · qc_5min |
프로파일 /profile | 공개 | 요일 기준 프로파일 + 오늘 곡선 · 이상 마커 | analysis(M1) |
속도 /speed | 공개 | 주간 p85 · 초과율 · 추세 · 개입 표시선 | analysis(M2) |
정차 /dwell | 공개 | 도로 평면 정차 히트맵(군집 3) · G2 통과 후 사유 태그 도넛 | analysis(M3) · inferences |
벤치 /bench | 관리 | 모델별 혼동행렬 · fps / latency / mem / power 시계열 · 이벤트 ±10 s fps 창 · B0~B4 요약 표 · 보드(jetson · pi) 토글 | bench_runs · inferences · qc_5min · labels |
라벨 /label | 관리 (모바일) | 이벤트 알림 → 60 s 카운트다운 → hazard · tag 4버튼 · 라벨러 이름. 이미지 없음, 이벤트 시각 · 구역 · 지속시간만 표시 | events → labels |
검토 큐 /outbox | 관리 | 초안 목록 · 수정 · 승인 · 반려 · 검증기 결과 · 모델 버전 | outbox |
시스템 /system | 관리 | 서비스 4개 상태 · tegrastats 현재값 · 디스크 · DB 행 수 · config.json 편집 · "이미지 파일 0건" 검사 버튼 | MON · config |
월간 PDF /report/monthly.pdf | 관리 | K1~K3 · 정확도 부록 · (G2 후) C1 · 벤치 표 1장 | Playwright 렌더 |
┌──────────────────────────────┐ │ 교문 앞 통행 · 오늘 09/15(화) │ │ 안전 지수 ▮▮▮▮▮▮▮░░░ 72 (▲3) │ │ K1 초과율 24% │ K2 6건 │ K3 3건 │ │ 지금 5분: 차 14 · 이륜 3 · 보행 22│ │ QC 통과 91% · 수동 대조 ±8% │ │ [지난주 리포트] [프로파일] [정차]│ └──────────────────────────────┘
┌──────────────────────────────┐ │ 이벤트 08:21:14 · no_stop · 27 s │ │ 남은 시간 ●●●●○○ 41 s │ │ 위험한 정차였나요? [예] [아니오] │ │ 사유 [승하차][대기][배송][기타] │ │ 라벨러: 김○○ [저장] │ │ (이미지 없음 · 창가에서 보고 입력)│ └──────────────────────────────┘
03인식 개선 루프 · 알림 규칙
GATE 1 통과 직후. 알림 없이 측정만. 이 기간의 프로파일 · p85 · 정차 건수가 비교 기준. Slow Loop는 돌지만 결과는 화면에 안 나감.
PWA 카드 · 교문 안내판에 지난주 K1 · K2 게시. 2주.
"지난주 정차의 78%가 드롭존 안이었습니다"처럼 다수의 행동을 숫자로. G2를 통과했으면 C1로 "정차의 대부분은 승하차 → 드롭존 안내"까지. 2주.
같은 요일 · 시간대 짝지어 순열 검정. 효과 없음도 공개. 지자체 · 경찰에 월간 PDF(정확도 부록 + 벤치 표).
git push → 기기 git pull --ff-only · deploy.ps1 한 번 · 기기 작업트리 항상 clean)를 그대로 씀. 기기가 둘(Jetson · Pi)이라도 저장소는 하나, 다른 것은 config.json의 backend와 설치 스크립트뿐. Claude Code는 로컬 세션이 주가 되고, 기기 위 확인은 SSH 원격 세션에서.01운영 구조
| 자리 | 역할 | 도구 · 규칙 |
|---|---|---|
| 로컬 PC 작업 폴더 (집 · 학교 · 노트북) | 모든 편집 · 커밋 · 테스트(TRAFFIC_FAKE_HW=1) · 웹 빌드 | Claude Code + GitHub. 다른 PC는 같은 저장소 clone 또는 Claude Code 원격제어. 기기에서 직접 편집 금지 |
GitHub xparapx/<REPO> | 단일 진실 · main 하나 · GitHub Pages(docs/) · 웹 릴리스 tarball | 모델 가중치 · DB · .env · 세션 데이터는 .gitignore |
Jetson (~/traffic) | 서비스 4개 실행 · 엔진 빌드(보드 종속) · 실측 | scripts/deploy.ps1 -Target jetson → push · pull · install.sh --update · 헬스체크. sudo · 발송은 사람 |
Pi (~/traffic, 이식 단계) | 같은 서비스 · Hailo 백엔드 | deploy.ps1 -Target pi. 학교망 제약(Tailscale 차단)은 Mealboard CLAUDE.md의 Cloudflare 경로 참고 |
| Claude Code 원격 세션 (SSH) | 기기 위 확인 · 로그 · doctor · 실측 스크립트 실행 | 편집은 하지 않음 — 고칠 것이 보이면 로컬에서 고쳐 push |
02저장소 구조 (Plant_Growth_Monitoring_Demo 포맷)
<REPO>/ # 예: SchoolZone_Edge_Traffic_Demo
edge/trafficsvc/ # 패키지 (Plant 의 hub/plantsvc 대응): settings · schema · config · db
capture/ # uvc.py · csi_argus.py · picam.py — 같은 제너레이터 인터페이스 (프레임 파일 쓰기 없음)
detect/ # __init__.py(Protocol) · tensorrt_yolo.py · hailo_yolo.py
counter/ # tracker.py(ByteTrack) · geo.py(호모그래피·가상선) · counter.py · acc.py · drift.py(ORB)
vlm/ # __init__.py(Protocol) · llama_cpp.py · hailo_genai.py · prompts/p1.txt · hybrid_rules.py
slowloop.py · fastloop.py · mon.py · qc.py · api.py(공개/관리) · cli.py(serve·doctor·seed·bench·session) · doctor.py
analysis/ # run_daily.py · run_weekly.py · m0_calib.py … m4_conflict.py · b1_confusion.py · b2_resource.py · safety_score.py
llm/ # weekly_draft.py · validate.py · prompts/weekly_ko.txt
notify/ # dispatch.py (approved 만)
web/ # React + Vite + TS + Tailwind v4 + ECharts (src/features/{today,profile,speed,dwell,bench,label,outbox,system})
deploy/systemd/ # traffic-fast.service.tmpl · traffic-vlm.service.tmpl · traffic-web.service.tmpl · traffic-analysis.timer.tmpl
scripts/ # setup_jetson.sh · setup_pi.sh · install.sh · deploy.ps1 · bench.sh · session.sh · rollback.sh
models/ # export_trt.sh · fetch_gguf.sh · README (가중치 · 엔진은 git 제외)
tests/ # pytest — 합성 궤적 · 큐 드롭 · 검증기 · dispatch(draft 무시) · 스키마 (하드웨어 없이)
docs/ # index.html(이 문서) · manual.html(구축 매뉴얼 · 카운터 P1~P7 계승) · WORKLOG.md · GATES.md
data/ # traffic.db · config.json · calib/ · sessions/ (전부 git 제외 · 이미지 없음)
CLAUDE.md README.md pyproject.toml .gitignore
03CLAUDE.md 필수 조항 (첫 커밋에)
- 이미지 · 영상 파일을 쓰는 코드(
imwrite · VideoWriter · save) 금지. 디버그는--show플래그 뒤 화면 표시만 - VLM 출력은 enum JSON만 DB에. 자유 문장 · 색 · 차종 · 성별 · 연령 · 번호판 필드 없음
- 통제 세션 파일은
data/sessions/에만, 운영 파이프라인이 읽지 못함 - 리포트 · 알림의 주어에 "어린이 · 학생 · 학부모" 금지
- 기기 작업트리 clean ·
main하나 ·deploy.ps1만으로 배포 - 완료 기준: 절 8 각 단계의 ①~④를 그대로 복사
- 확인된 함정: JetPack 7.2.1 휠 · CM3 드라이버 · 엔진 이식 불가 · tegrastats 필드명 · llama-server 로그 · PowerShell 5.1
&&없음 - 검증:
uv run pytest -q·cd web && npm run lint && npm run build·TRAFFIC_FAKE_HW=1 uv run trafficsvc serve
PLANT_FAKE_HW처럼 TRAFFIC_FAKE_HW=1이면 합성 궤적 생성기가 Fast Loop를 대신하고 VLM은 규칙 기반 가짜 태거가 됨. 노드 · 카메라 없이 전 화면과 배치가 돌고, 화면에 DUMMY DATA 배지. 학교 PC에서 UI를 다듬을 때 기기가 필요 없음.각 단계는 카운터 매뉴얼의 P1~P7에 대응하고(괄호), 상세 실습 절차는 docs/manual.html로 옮김. 여기는 무엇을 · 언제 · 어디까지와 위임 프롬프트의 컨텍스트 블록만. 프롬프트의 [컨텍스트]에 있는 것 이상을 Claude Code에 요구하지 않음 — 그것이 곧 CLAUDE.md의 현재 상태.
R0문제 확인 · GATE 0 · 저장소 생성 (카운터 절 0 · 2) · 1~2주차
1주 관찰 로그 · 문제 진술 1장(H1~H3 · R1~R3 · K1~K3 · C1 · C2 · 목표치) · 거리 · 창 높이 실측 → 렌즈 초점거리 확정(절 H-04) · 카메라 · 렌즈 주문(ELP AR0234 + 2.8-12mm) · 승인 문서 · 안내문 · 저장소(구조 · CLAUDE.md · pyproject · 더미 모드 · 스키마 · 테스트 뼈대)
① 담당 교사 서명 ② GATE 0 문서 보관 ③ TRAFFIC_FAKE_HW=1로 서비스 기동 · 8 페이지 렌더 ④ pytest 통과 · GitHub Pages에 이 문서 게시
R1Jetson 런타임 · 카메라 · 미저장 캡처 (H · P1) · 2주차
JetPack 7.2.1 툴체인 검증 로그 · yolo11n.engine 빌드 · llama-server 기동 · ELP UVC(MJPEG → nvv4l2decoder) 캡처 확인 · 창 조준(MJPEG 미리보기) · 07:40~08:30 역광 시험 캡처 · 교문 틈 도로 폭 · 횡단보도 가시성 · 중앙 수목 가림 확인 → K1 · K3 채택/보류 판정 · ORB 기준점 · B0 · B1 기준선 · 메모리 예산 실측 열
① 30분 캡처 루프 fps ≥ 15 · 이미지 파일 0건 ② 엔진 단독 추론 ≤ 15 ms/frame (640) ③ VLM 서버 더미 요청 응답 · 상주 메모리 기록 ④ 절 4-02 표의 실측 열 채움 · 스왑 0
R2검출 · 추적 · 가상선 · 속도 · 정차 · 근접 (P2 · P3) · 3~4주차
tensorrt_yolo.py(ultralytics engine 로드 · 6종 · conf 0.40 · 묶음) · ByteTrack · 호모그래피 4점 실측 · counter.py(카운터 매뉴얼 P3 이식) · 이벤트에 event_id · YOLO_ONLY 추론 행
① 콜백 fps ≥ 15 · track_id 유지(10대) ② 4점 재투영 < 0.3 m · 자전거 속도 ±3 km/h ③ 합성 궤적 pytest(직진 · 정차 30 s · 횡단 중 근접) ④ dwell 판정 시 inferences(YOLO_ONLY) 1행 · 파일 저장 없음
R35분 집계 · QC · MON · 서비스 등록 (P4) · 4~5주차
acc.py(카운터 P4) + mon.py(tegrastats 파서) → qc_5min에 power · mem · throttle · vlm_dropped · systemd 유닛 4개 템플릿 · install.sh · deploy.ps1
① 등교일 하루 주간 버킷 132개 · qc=0 ≥ 80% ② 표본 부족 버킷 null ③ 재부팅 후 4 서비스 자동 복구 ④ deploy.ps1 한 번으로 push → pull → update → 헬스체크
R4수동 대조 GATE 1 (P5) · 5~6주차
카운터 P5 그대로: 15분 × 10회, 학생 2인 클리커 + 1인 근접 육안 기록. 추가: 같은 시간에 /label 화면을 처음 써 보며 정차 이벤트가 오면 hazard · tag를 입력(G2용 라벨 축적 시작).
veh4 오차 ≤ 10% · 속도 ±3 km/h · conflict 정밀도 ≥ 0.7 · 카운터 간 일치 ≥ 95% · 정확도 표 작성. 통과 시점부터 baseline 2주 시작, VLM 트랙(R5) 착수.
R5Slow Loop · 자원 실측 · 라벨 60건 GATE 2 (신규) · 6~9주차
vlm/llama_cpp.py(OpenAI 호환 HTTP · 이미지 base64 · 온도 0 · JSON 스키마) · slowloop.py · hybrid_rules.py · 프롬프트 p1 · B2 · B3 실측(등교 3일 + 통제 세션 1회) · /label 실운영 · b1_confusion.py · b2_resource.py · 벤치 뷰
① 이벤트당 latency p95 ≤ 4 s · 이벤트 순간 fps 최저 ≥ 15 · 스왑 0 ② 라벨 ≥ 60건 · unknown ≤ 15% ③ HYBRID 정밀도 ≥ 0.7 · YOLO_ONLY 대비 FPR 감소를 수치로(감소 폭은 결과) ④ 절 4 표 완성. 미달이면 p2 프롬프트 · 모델 교체(Qwen3-VL 2B ↔ Qwen2.5-VL 3B) 후 재시도, 2회 실패 시 C1은 "연구 결과: 미달"로 보고하고 운영 리포트에서 제외
R6대시보드 · 배치 · 알림 · 검토 큐 (P6) · 8~11주차
공개 페이지 4 + 관리 페이지 4 · run_daily.py(M0~M4 + 안전지수) · dispatch.py · 개입 1 · 2 문안 · 월간 PDF(정확도 부록 + 벤치 표)
① 공개 카드 QR · QC 통과율 표시 ② 매일 배치가 analysis · outbox(draft) 채움 ③ draft 상태 발송 0건(테스트) ④ 주간 리포트 1회 실제 발송 · C1은 G2 통과 시에만 노출
R7로컬 LLM 리포트 · 전후 비교 · 건의 GATE 3 (P7) · 11~14주차
주간 집계 JSON → llama.cpp 텍스트 모델 → 검증기 → outbox · 톤 3안 · 전후 비교(순열 검정) · 월간 건의 PDF · 학생 발표 자료 · 벤치 표 공개
① 초안 2분 내 · 검증기 통과 · 숫자 변조 초안 rejected ② 주간 리포트 3회 발송(승인 로그) ③ 개입 2회 + 전후 비교 1건 공개(효과 없음 포함) ④ 건의서 1건 제출 또는 제출 준비
R8Pi 5 + AI HAT+ 2 이식 (선택 · 12~14주차)
capture/picam.py(CM3) · detect/hailo_yolo.py · vlm/hailo_genai.py 또는 CPU 배치 · setup_pi.sh · 같은 통제 세션 파일로 B4 재실행
① 같은 DB 스키마 · 같은 UI에 board='pi' 벤치 행 ② 두 보드 벤치 표 1장(fps · ms · MB · W · FPR · Recall) ③ 이식에 바뀐 파일이 capture/ · detect/ · vlm/ · scripts/ 밖에 없음을 git diff --stat으로 확인
14주 일정 (주차 격자 · 1주차 = 9/14 주)
| 작업 | 주차 |
|---|---|
| R0 문제 확인 · GATE 0 · 저장소 · 카메라 결정 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
| R1 JetPack 7.2.1 런타임 · 카메라 · 캡처 · B0/B1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
| R2 검출 · 추적 · 가상선 · 속도 · 이벤트 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
| R3 5분 집계 · QC · MON · 서비스 · deploy.ps1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
| R4 수동 대조 · GATE 1 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
| baseline 2주 (측정만 · Slow Loop 섀도) | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
| R5 Slow Loop · 자원 실측 · 라벨 60건 · GATE 2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
| R6 대시보드 · 배치 · 알림 · 개입 1 · 2 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
| R7 로컬 LLM 리포트 · GATE 3 · 전후 비교 · 건의 · 발표 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
| R8 Pi 5 + AI HAT+ 2 이식 (선택) | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
역할 (팀 5명 기준 · 겸임 가능)
창 거치, 4점 실측, 속도 검증 주행, 통제 세션 연출, 청소 · 이동 점검 로그
런타임 검증, 검출 백엔드, Counter, 누적기, 서비스. Claude Code 위임 프롬프트 작성 · 검수
프롬프트 · 결합 규칙 · 실측 프로토콜 · 혼동행렬 · 자원 곡선 · 벤치 표. 라벨 캠페인 조직
수동 대조 설계, 정확도 표, 기준 프로파일, 전후 검정, 안전지수
알림 문안, 규범 메시지 3안, UI 문구, 학부모회 · 지자체 대응, 발표
협의 · 승인, 검증 판정, VLM 판정 검증 판정, 발송 승인. sudo 와 발송은 교사가
프로젝트 완료 기준 (전부 체크되면 종료)
- 문제 진술 1장(H1~H3 · R1~R3 · K1~K3 · C1 · 목표치)에 담당 교사 서명
- GATE 0 문서(확인 · 승인 · 안내문 사진 · VLM 처리 방식 명시) 보관
- 이미지 · 영상 파일 0건 — 저장소 · Jetson · Pi 전체 검색 결과 첨부 (통제 세션 디렉터리는 별도 삭제 로그)
- 등교일 20일 이상 5분 버킷, qc=0 ≥ 80%
- GATE 1 정확도 표 — 차량류 오차 ≤ 10%
- GATE 2 결과 — 라벨 ≥ 60건, 모델별 혼동행렬, 자원 실측표(절 4) 완성 (통과 여부와 무관하게 공개)
- K1 · K2 · K3 baseline 2주 + 개입 2회 + 전후 비교 결과 공개 (효과 없음 포함)
- 주간 리포트 3회 발송(승인 로그) · 로컬 LLM 실측표
- 월간 건의 리포트 PDF 1건(정확도 부록 + 벤치 표) 제출 또는 제출 준비
- 벤치 표 1장: YOLO / VLM / HYBRID × (FPR · Recall · 정밀도 · fps · ms · MB · W) — 계획서의 가정 열과 실측 열 나란히
- 학생 발표: "우리 데이터로 무엇이 바뀌었고, 하이브리드는 무엇을 주고 무엇을 치렀는가"
명령 (Jetson)
cat /etc/nv_tegra_release # JetPack 7.2.x = R39
jtop / tegrastats --interval 1000 # RAM · GPU · 전력 · 온도
sudo nvpmodel -q ; sudo jetson_clocks # 전력 모드 확인 · 클럭 고정
v4l2-ctl --list-devices # 카메라
systemctl status traffic-fast traffic-vlm traffic-web ; journalctl -u traffic-fast -f
systemctl list-timers | grep traffic # 배치
curl -s localhost:8090/health # llama-server
sqlite3 data/traffic.db "SELECT model_type, COUNT(*) FROM inferences GROUP BY 1;"
sqlite3 data/traffic.db "SELECT * FROM bench_runs ORDER BY id DESC LIMIT 5;"
find ~/traffic -name "*.jpg" -o -name "*.png" -o -name "*.mp4" -o -name "*.h264" # 항상 0건 (data/sessions 제외)
tailscale status
참고 자료
Jetson ISO 설치 · L4T r39.2.x · Ubuntu 24.04 · CUDA 13. docs.nvidia.com/jetson/orin-nano-devkit · 포럼 "JetPack 7.2 Getting Started" 스레드
RidgeRun IMX708 커뮤니티 드라이버(JetPack 5.1.1 / 6.0 패치 · 단일 모드 4608×2592@14). developer.ridgerun.com · 7.2.1 적용 여부 미확인 → 1일 한도
UVC · MJPEG 1920×1200/1080 @30 · 수동 노출 · 2.8-12mm 가변 렌즈 확정 후 잠금. Jetson: v4l2src ! image/jpeg ! nvv4l2decoder mjpeg=1 ! nvvidconv
yolo export format=engine half=True · Jetson 가이드 · 엔진은 보드에서 빌드
github.com/roboflow/supervision · 카운터 매뉴얼 P2 경로 B
github.com/ggml-org/llama.cpp · llama-server --mmproj · OpenAI 호환 API · --log-disable
qwen2.5vl · qwen3-vl 태그 · JetPack 7 지원 여부를 설치 전 확인
Hailo-10H · Trixie · hailo-h10-all · GenAI 예제. 카운터 매뉴얼 절 H · P2
창문 안쪽 시민과학 교통 카운터 · 영상 미저장 · EU WeCount. telraam.net
Plant_Growth_Monitoring_Demo(저장소 구조 · uv · deploy.ps1 · 더미 모드 · React 셸), Mealboard(FastAPI · PWA · Funnel · Playwright PDF · 포트 분리), multinode_aq(5분 버킷 · analysis · CLAUDE.md 관행), 스쿨존 교통카운터 매뉴얼(P1~P7 · 게이트 · 규범 메시지)
글꼴 IBM Plex Sans KR / Mono · 색 토큰은 대시보드 hub/web/app.css와 동일(라이트 기본, 다크 토글) · 세 지도는 archify 규약(상자 안 코드명 · 이름은 바깥 · 큰 글꼴)으로 작성한 인라인 SVG · 이 파일은 외부 의존성 없이 단독 열림(글꼴만 온라인) · 원본: 스쿨존_교통카운터.html(v0.2) + 스쿨존_교통_위험_연구_계획서.html · 확인 기준일 2026-09-14