# KL630 Host Stream Firmware 即時影像語義分割系統,運行於 Kneron KL630 (Cortex-A7, uClibc)。 透過 IMX662 DOL-HDR 雙曝光攝影機進行 STDC 語義分割,並將結果以 RTSP 串流或 HDMI 輸出。 **技術細節 → [`docs/technical_report.md`](docs/technical_report.md)** --- ## 目錄結構 ``` kl630_build/ ├── web_serve.py # Web 控制台(主要使用) ├── build_and_serve.py # CLI 版本(不需要瀏覽器) ├── compile.sh # Docker 內 ARM 交叉編譯腳本 ├── Dockerfile # kl630-dev image 定義 ├── requirements.txt # Python 套件清單 │ ├── src/ │ ├── host_stream/ # 主程式(初始化、推論迴圈、結果處理) │ ├── app_flow/ # VMF pipeline 控制 │ ├── pre_post/ # YOLOv5 前後處理 │ └── stdc/ # STDC 語義分割後處理 │ ├── include/ │ ├── stdc/ # stdc_post_process.h(分析結果結構) │ └── fake/ # SDK 缺少時的 stub headers │ ├── ini/ │ └── host_stream.ini # 執行期設定(model、stream、ISP、FEC 參數) │ │ ├── lib/ # 裝置端 .so 函式庫(VMF SDK) ├── docs/ │ └── technical_report.md # 完整技術文件 └── build/ # 編譯輸出(由 compile.sh 產生) ``` --- ## 快速開始 ### 前置條件 - [Docker Desktop](https://www.docker.com/products/docker-desktop/) 已安裝並執行中 - Python 3.8+ ### 安裝 ```bash pip install -r requirements.txt ``` | 套件 | 用途 | |------|------| | `flask` | Web 控制台 + HTTP file server | | `opencv-python` | RTSP 串流預覽(內建 FFmpeg,無需另外安裝)| ### 啟動 ```bash python web_serve.py ``` 瀏覽器開啟 `http://localhost:8080/` --- ## 新機器首次設定 SOP 全新 KL630 裝置依序執行以下步驟: ### Step 1 — Compile 在 Web 控制台按 **Compile**。 - 自動建立 Docker image(若不存在) - 交叉編譯 ARM binary - 複製 binary / INI / 腳本到 `build/` > 若 binary 已是最新版本,可跳過此步驟直接從 Step 2 開始。 ### Step 2 — 設定 Output Mode 在 **INI Settings** 面板選擇輸出模式(預設 RTSP): | 組合 | RTSP | HDMI | 啟動腳本 | |------|------|------|---------| | RTSP 串流 | ON | OFF | `demo_rtsp.sh` | | HDMI 顯示 | OFF | ON | `demo_hdmi.sh` | | RTSP + HDMI 同時 | ON | ON | `demo_rtsp_hdmi.sh`(INI voc_enable=1)| | 純推論(無輸出) | OFF | OFF | 直接啟動 binary | ### Step 3 — Deploy to KL630 按 **Deploy to KL630**,自動透過 Telnet 完成: 1. 停止舊 firmware 2. 下載 binary、INI、NEF 模型 3. 下載 `demo_rtsp.sh`、`demo_hdmi.sh`、`demo_rtsp_hdmi.sh` 4. 設定 VOC 輸出模式 5. 啟動 firmware ### Step 4 — First-time ISP Setup 按 **First-time ISP Setup**。 寫入 DOL-HDR 所需的 flash 參數(`dwStatisticsSrcType=2`、`bGTREnable=1`), **只需執行一次**,設定永久保留在 flash,重新 Deploy 不會被覆蓋。 > 跳過此步驟影像會過暗或曝光不正確。 ### Step 5 — 魚眼鏡頭校正(FEC) 在 **INI Settings** 面板設定 Fish-Eye Correction: | 參數 | 推薦設定 | 說明 | |------|---------|------| | FEC | ON | 開啟魚眼校正 | | **Mode** | **4 — 180° Two Direction** | 天花板魚眼鏡頭推薦模式,同時展開水平與垂直方向 | | Install Type | 0 — Ceiling | 天花板安裝 | | EIS | 視需求 | 電子防手震 | 按 **Apply to Device + Restart** 套用並重啟 firmware。 --- ## Web 控制台功能說明 ### Network Config 設定 **Host IP**(這台 PC)、**KL630 IP**、**HTTP Port**、**Docker Image**。 按 Save 後自動更新 `deploy.sh` 的 `HOST_URL`。 ### HTTP Server Files 列出 `build/` 目錄下所有可下載的檔案,以及裝置端手動部署指令: ```sh wget http://:8080/deploy.sh -O /tmp/deploy.sh && sh /tmp/deploy.sh ``` ### RTSP Stream Preview 直接在網頁預覽 KL630 串流,不需要開 VLC。 按 **▶ Start Stream** 即可,連線失敗時 6 秒內回報錯誤。 --- ## Actions | 按鈕 | 說明 | |------|------| | **Compile** | Docker 交叉編譯 ARM binary,複製到 `build/` | | **Deploy to KL630** | Telnet 部署 binary / INI / NEF / 腳本,依 Output Mode 啟動 firmware | | **First-time ISP Setup** | 新機器一次性 ISP flash 設定(DOL-HDR 參數) | | **Write Autostart** | 寫入開機自動啟動腳本 `/etc/init.d/S99firmware` | --- ## INI Settings ### Fish-Eye Correction (FEC) | 參數 | 說明 | |------|------| | FEC ON/OFF | 開啟或關閉魚眼校正(`fec_mode = 0` 為關閉)| | Mode 1 | Single Region | | Mode 2 | 180° All Direction | | Mode 3 | 180° One Direction | | **Mode 4** | **180° Two Direction(推薦)** | | Mode 5 | PT Mode | | Install Type | Ceiling / Table / Wall(`initial_fec_app_type`)| | EIS | 電子防手震(`eis_enable`)| | DrawBox | H.264 burn-in 偵測框(`DrawBoxEnable`)| ### Output Mode | 選項 | 說明 | |------|------| | RTSP | H.264 RTSP 串流輸出,由 `demo_rtsp.sh` 管理 | | HDMI | VOC HDMI 顯示輸出,由 `demo_hdmi.sh` 管理 | - **Save INI(disk only)** — 更新本地 `ini/host_stream.ini`,下次 Deploy 時推送至裝置 - **Apply to Device + Restart** — 立即 Telnet 更新裝置 INI 並重啟 firmware ### Model Settings 切換推論模型(NEF 檔)、ModelId、JobId,支援上傳新 NEF。 **Apply to Device + Restart** 會下載 NEF 到裝置並依目前 Output Mode 重啟。 --- ## Terminal Output Log 下方有命令輸入列,可直接在網頁對 KL630 下指令: ```sh cat /tmp/fw.log # 查看 firmware 啟動 log cat /tmp/rtsp_demo.log # 查看 RTSP demo log ps | grep firmware # 確認 firmware 是否在執行 killall kp_firmware_host_stream ``` --- --- ## Web Server 命令行操作指南 若不喜歡 GUI,可透過指令和 API 完全控制 `web_serve.py`,不需要開瀏覽器。 ### 啟動 Web Server ```bash # 預設 port 8080 python web_serve.py # 指定端口 python web_serve.py --port 8080 python web_serve.py --port 9090 ``` Server 啟動後可用 `curl` 調用各項功能。 ### Web Server API 參考 #### 1. **查詢/保存設定** ```bash # 查看現在設定(Host IP、KL630 IP、HTTP Port、Docker Image) curl http://localhost:8080/api/config # 修改設定 curl -X POST http://localhost:8080/api/config \ -H "Content-Type: application/json" \ -d '{ "host_ip": "192.168.3.1", "kl630_ip": "192.168.3.10", "port": 8080, "docker_image": "kl630-dev" }' ``` #### 2. **查看 build/ 目錄下載文件列表** ```bash curl http://localhost:8080/api/files ``` 輸出示例: ```json [ {"name": "kp_firmware_host_stream", "size": 5242880}, {"name": "host_stream.ini", "size": 2048}, {"name": "demo_rtsp.sh", "size": 512}, {"name": "deploy.sh", "size": 1024} ] ``` #### 3. **編譯(Server-Sent Events 串流輸出)** ```bash # 啟動編譯,即時輸出編譯 log curl http://localhost:8080/api/compile/run # 搭配 jq 只看 error curl http://localhost:8080/api/compile/run | grep -o '"kind":"error"' | wc -l ``` 編譯 log 格式(SSE): ```json {"kind": "log", "text": "Starting cross-compile..."} {"kind": "ok", "text": "Compile SUCCESS"} {"kind": "error", "text": "Compile FAILED (exit 1)"} ``` #### 4. **部署到 KL630(Telnet)** ```bash # 執行完整部署流程(停止舊 firmware、下載 binary、啟動新 firmware) curl http://localhost:8080/api/deploy/run # 查看部署 log(最後 100 行)可透過網頁 Terminal 或直接用 tail ``` 部署流程等同於 Web UI 按下 **Deploy to KL630**。 #### 5. **ISP / Flash 一次性設定** ```bash # 一次性 ISP setup(DOL-HDR 參數) curl http://localhost:8080/api/spi_setup/run # 或藍牙相關設定 curl http://localhost:8080/api/bt_setup/run ``` #### 6. **INI 設定讀取/寫入** ```bash # 讀取目前 INI 設定 curl http://localhost:8080/api/ini # 修改 INI 並立即套用到裝置(等同 Web UI "Apply to Device + Restart") curl -X POST http://localhost:8080/api/ini/apply \ -H "Content-Type: application/json" \ -d '{ "fec_mode": 4, "DrawBoxEnable": 1, "voc_enable": 0 }' ``` 常見 INI 參數: - `fec_mode`: 0=關閉, 1-5=魚眼校正模式 - `DrawBoxEnable`: 0/1 — H.264 burn-in 偵測框 - `voc_enable`: 0/1 — HDMI VOC 輸出 - `ModelPath`, `ModelId`, `JobId`: 推論模型設定 #### 7. **RTSP 串流預覽 / 停止** ```bash # 啟動 RTSP 預覽(返回 MJPEG 影像串流) curl http://localhost:8080/api/stream/video > stream.mjpeg # 停止 RTSP 預覽 curl -X POST http://localhost:8080/api/stream/stop ``` #### 8. **STDC 推論統計** ```bash # 查看即時推論統計(幀率、語義分割百分比) curl http://localhost:8080/api/stdc/stats # 啟動推論 curl -X POST http://localhost:8080/api/stdc/start # 停止推論 curl -X POST http://localhost:8080/api/stdc/stop ``` 輸出示例: ```json { "frame": 42, "mov": 1, "diff": 4.2, "classes": { "bunker": 0.0, "car": 8.3, "grass": 0.0, "greenery": 12.1, "person": 0.0, "pond": 0.0, "road": 71.4, "tree": 8.2 } } ``` #### 9. **遠端執行指令(Telnet 到裝置)** ```bash # 在裝置上執行指令並取得輸出 curl -X POST http://localhost:8080/api/terminal/exec \ -H "Content-Type: application/json" \ -d '{"cmd": "ps | grep firmware"}' # 查看 firmware log curl -X POST http://localhost:8080/api/terminal/exec \ -H "Content-Type: application/json" \ -d '{"cmd": "cat /tmp/fw.log"}' # 查看可用模型 curl -X POST http://localhost:8080/api/terminal/exec \ -H "Content-Type: application/json" \ -d '{"cmd": "ls -lh /mnt/flash/vienna/nef/"}' ``` #### 10. **開機自動啟動設定** ```bash # 查看自動啟動腳本設定 curl http://localhost:8080/api/autostart/read # 寫入自動啟動腳本(`/etc/init.d/S99firmware`) curl -X POST http://localhost:8080/api/autostart/write \ -H "Content-Type: application/json" \ -d '{"autostart_mode": "rtsp"}' # or "hdmi", "rtsp_hdmi" ``` #### 11. **模型管理** ```bash # 查看可用模型列表 curl http://localhost:8080/api/model/list # 切換模型(需要指定 ModelId / JobId) curl -X POST http://localhost:8080/api/model \ -H "Content-Type: application/json" \ -d '{ "model_id": "100001", "job_id": 1 }' ``` ### 完整工作流示例(指令行完全不用 GUI) ```bash # 1. 設定網路(Host IP 和 KL630 IP) curl -X POST http://localhost:8080/api/config \ -H "Content-Type: application/json" \ -d '{"host_ip": "192.168.3.1", "kl630_ip": "192.168.3.10"}' # 2. 編譯 echo " Compiling..." curl http://localhost:8080/api/compile/run | grep '"kind"' | tail -1 # 3. 檢查生成的文件 echo " Build files:" curl http://localhost:8080/api/files | grep name # 4. 部署到裝置 echo " Deploying to KL630..." curl http://localhost:8080/api/deploy/run # 5. 查看推論統計 echo " STDC Stats:" curl http://localhost:8080/api/stdc/stats | python -m json.tool # 6. 設定魚眼校正(FEC Mode 4) curl -X POST http://localhost:8080/api/ini/apply \ -H "Content-Type: application/json" \ -d '{"fec_mode": 4}' ``` --- ## CLI 指令完整參考 完全不用瀏覽器,所有操作均可透過指令完成。 --- ### 1. 編譯(交叉編譯 ARM binary) **方法 A — `build_and_serve.py`(推薦)** ```bash # 完整流程:編譯 + 檢查 binary + 啟動 HTTP server python build_and_serve.py # 常用旗標 python build_and_serve.py --no-build # 跳過編譯,直接 serve(binary 已存在時) python build_and_serve.py --no-serve # 只編譯 + 檢查,不啟動 server python build_and_serve.py --port 9090 # 指定 HTTP server port(預設 8080) python build_and_serve.py --image my-kl630 # 指定 Docker image 名稱 python build_and_serve.py --no-copy # 不複製到網路資料夾 python build_and_serve.py --copy-dst /tmp/out # 指定複製目的地 ``` **方法 B — 直接 Docker** ```bash # 建立 Docker image(只需一次) docker build -t kl630-dev . # 交叉編譯 docker run --rm \ -v "$(pwd):/workspace/kl630_build" \ kl630-dev \ bash /workspace/kl630_build/compile.sh # 確認輸出 ls -lh build/kp_firmware_host_stream ``` --- ### 2. 啟動 HTTP File Server(裝置 wget 用) ```bash # 用 build_and_serve.py(推薦,自動 copy INI + deploy.sh) python build_and_serve.py --no-build --no-check --port 8080 # 或直接 Python 內建 server cd build && python -m http.server 8080 ``` --- ### 3. 部署到裝置(Telnet / 裝置端指令) 先確認 HTTP server 在 PC 端已啟動,再 Telnet 進裝置: ```bash telnet 192.168.3.10 ``` 在裝置端執行: ```sh # 一鍵下載並部署(最常用) wget http://192.168.3.1:8080/deploy.sh -O /tmp/deploy.sh && sh /tmp/deploy.sh # 或分步驟手動執行: # 停止舊 firmware killall -9 kp_firmware_host_stream 2>/dev/null; killall -9 rtsps 2>/dev/null sleep 1; rm -f /dev/shm/* # 下載 binary 和 INI wget http://192.168.3.1:8080/kp_firmware_host_stream -O /mnt/flash/vienna/kp_firmware_host_stream chmod +x /mnt/flash/vienna/kp_firmware_host_stream wget http://192.168.3.1:8080/host_stream.ini -O /mnt/flash/plus/kp_firmware/kp_firmware_0/kp_firmware/bin/ini/host_stream.ini # 下載並啟動 RTSP demo wget http://192.168.3.1:8080/demo_rtsp.sh -O /mnt/flash/plus/kp_firmware/kp_firmware_0/kp_firmware/bin/ini/demo_rtsp.sh chmod +x /mnt/flash/plus/kp_firmware/kp_firmware_0/kp_firmware/bin/ini/demo_rtsp.sh cd /mnt/flash/plus/kp_firmware/kp_firmware_0/kp_firmware/bin sh ./ini/demo_rtsp.sh ``` **新機器一次性 ISP 設定**(只需跑一次): ```sh wget http://192.168.3.1:8080/deploy.sh -O /tmp/deploy.sh && sh /tmp/deploy.sh --setup ``` --- ### 4. 裝置端常用指令 ```sh # 確認 firmware 是否在跑 ps | grep firmware # 查看 firmware log cat /tmp/fw.log tail -f /tmp/fw.log # 持續監看(BusyBox 無 -f,用 watch 替代) # 查看 RTSP demo log cat /tmp/rtsp_demo.log # 手動停止 firmware killall -9 kp_firmware_host_stream killall -9 rtsps # 直接啟動(指定模型) BIN_DIR=/mnt/flash/plus/kp_firmware/kp_firmware_0/kp_firmware/bin FW=/mnt/flash/vienna/kp_firmware_host_stream LD_LIBRARY_PATH=/mnt/flash/vienna/lib $FW \ -m nef/stdc_scnn_fp.nef \ -i 100001 -j 1 & # 切換輸出模式(不用重新 deploy) sh $BIN_DIR/ini/demo_rtsp.sh # RTSP 串流 sh $BIN_DIR/ini/demo_hdmi.sh # HDMI 顯示 sh $BIN_DIR/ini/demo_rtsp_hdmi.sh # RTSP + HDMI 同時 ``` --- ### 5. INI 設定(指令修改) 直接用 `sed` 修改裝置上的 INI,不需要重新 deploy: ```sh INI=/mnt/flash/plus/kp_firmware/kp_firmware_0/kp_firmware/bin/ini/host_stream.ini # 開啟 / 關閉魚眼校正 FEC sed -i 's/^fec_mode.*/fec_mode = 4/' $INI # Mode 4(180° Two Direction) sed -i 's/^fec_mode.*/fec_mode = 0/' $INI # 關閉 # 開啟 / 關閉 DrawBox(H.264 burn-in 框) sed -i 's/^DrawBoxEnable.*/DrawBoxEnable = 1/' $INI sed -i 's/^DrawBoxEnable.*/DrawBoxEnable = 0/' $INI # 開啟 HDMI / VOC 輸出 sed -i 's/^voc_enable.*/voc_enable = 1/' $INI # 查看目前設定 grep -E "fec_mode|DrawBoxEnable|voc_enable|ModelPath|ModelId" $INI ``` 修改 INI 後需重啟 firmware 才生效: ```sh killall -9 kp_firmware_host_stream 2>/dev/null sh /mnt/flash/plus/kp_firmware/kp_firmware_0/kp_firmware/bin/ini/demo_rtsp.sh ``` --- ### 6. Mock Server(事件測試) ```bash # 啟動 mock server(port 8081) python tools/mock_server/server.py # 開啟監控網頁 # http://localhost:8081/ ``` 用 `curl` 送測試事件(不用開網頁): ```bash # Channel A — 送即時事件(HTTP) curl -X POST http://localhost:8081/api/event \ -H "Content-Type: application/json" \ -d '{"response_type":"violation","content":{"id":"1","date":"2025-01-01T00:00:00+08:00","type":"road","level":2}}' # 常用事件類型:road / grass / hazard / person / bunker / pond / tree / car # level:0=解除, 1=警告, 2=嚴重, 3=緊急 # 查詢事件列表 curl http://localhost:8081/api/events # Channel C — 送 CAN 事件(測試 CAN bus TX) curl -X POST http://localhost:8081/api/can/send \ -H "Content-Type: application/json" \ -d '{"type":"hazard","level":1,"can_id":256}' # 送油門控制指令(CAN ID 0x75) curl -X POST http://localhost:8081/api/can/send_cmd \ -H "Content-Type: application/json" \ -d '{"cmd":128,"can_id":117}' # cmd: 0=關閉, 32/64/128/255=油門檔位 # 查詢 CAN bus 狀態 curl http://localhost:8081/api/can/status # 啟動 CAN interface(等同 UI Bring Up 按鈕) curl -X POST http://localhost:8081/api/can/bringup \ -H "Content-Type: application/json" \ -d '{"channel":"can0","bitrate":250000}' ``` --- ## BLE 指令協議(藍牙通訊) KL630 透過 DX-BT24 模組(UART `/dev/ttyS1` @ 115200)與 iPad / 手機 app 溝通。 所有訊息均為 UTF-8 JSON,無需 CRLF。 --- ### Command(App → KL630) #### 狀態確認 ```json {"command":"status_check"} ``` 回傳 Notify:`response_type=status_check` #### 查詢租借狀態 ```json {"command":"get_rent_status"} ``` 回傳 Notify:`response_type=rent_status` #### 租借 ```json {"command":"rent"} ``` 若目前 status=0 則轉為 1,其他狀態忽略。回傳 Notify:`response_type=rent_status` #### 歸還 ```json {"command":"return"} ``` 若目前 status=1 則轉為 0,其他狀態忽略。回傳 Notify:`response_type=rent_status` --- ### Notify(KL630 → App) #### 系統狀態(回應 status_check) ```json {"response_type":"status_check","content":{"ares_x_version":"1.0.0","bluetooth_peripheral_name":"BT-24","is_intervention_cart_control":false}} ``` | 欄位 | 說明 | |------|------| | `ares_x_version` | 韌體版本,由 INI `event:ares_version` 設定 | | `bluetooth_peripheral_name` | BLE 掃描名稱,由 INI `event:bt_name` 設定 | | `is_intervention_cart_control` | 是否正在介入車輛控制(CAN bus 活動中)| #### 租借狀態(回應 rent / return / get_rent_status) ```json {"response_type":"rent_status","content":{"status":0}} ``` | status | 說明 | |--------|------| | `0` | 未租借 | | `1` | 租借中 | | `2` | 管理模式 | #### 違規事件(由推論結果觸發) ```json {"response_type":"violation","content":{"id":"abcd-1234-0000-0000","date":"2025-12-08T06:08:49Z","type":"lane","level":2}} ``` | level | 說明 | |-------|------| | `0` | 解除 | | `1` | 違規發生 | | `2` | 違規持續 6 秒 | | `3` | 違規持續 10 秒 | #### 危險區域警告 ```json {"response_type":"alert","content":{"left_level":0,"right_level":1}} ``` 左右各獨立,`0`=無危險,`1`=有危險。 --- ### INI 設定(`ini/host_stream.ini` `[event]` 區段) ```ini bt_uart_dev = /dev/ttyS1 # UART 裝置路徑 bt_at_probe = 0 # 0: 正常啟動;1: 首次設定(9600→115200 升速) ares_version = 1.0.0 # 韌體版本字串 bt_name = BT-24 # BLE 掃描名稱 ``` --- ### 測試指令 #### 用 BLE app(nRF Connect 等)直接測試 複製以下 JSON 貼入 Write Characteristic 欄位送出: ``` {"command":"status_check"} ``` ``` {"command":"get_rent_status"} ``` ``` {"command":"rent"} ``` ``` {"command":"return"} ``` #### 用 Mock Server 模擬裝置回傳(curl) ```bash # 模擬違規事件通知 curl -X POST http://localhost:8081/api/event \ -H "Content-Type: application/json" \ -d '{"response_type":"violation","content":{"id":"test-001","date":"2026-04-22T00:00:00Z","type":"lane","level":1}}' # 模擬違規持續 6 秒 curl -X POST http://localhost:8081/api/event \ -H "Content-Type: application/json" \ -d '{"response_type":"violation","content":{"id":"test-001","date":"2026-04-22T00:00:00Z","type":"lane","level":2}}' # 模擬違規解除 curl -X POST http://localhost:8081/api/event \ -H "Content-Type: application/json" \ -d '{"response_type":"violation","content":{"id":"test-001","date":"2026-04-22T00:00:00Z","type":"lane","level":0}}' # 模擬危險區域警告(右側有危險) curl -X POST http://localhost:8081/api/event \ -H "Content-Type: application/json" \ -d '{"response_type":"alert","content":{"left_level":0,"right_level":1}}' # 模擬租借狀態更新 curl -X POST http://localhost:8081/api/event \ -H "Content-Type: application/json" \ -d '{"response_type":"rent_status","content":{"status":1}}' # 查看目前所有事件記錄 curl http://localhost:8081/api/events ``` --- ## Firmware 執行結果(console log) ``` [STDC] frame=42 mov=1 diff=4.2 bunker=0.0% car=8.3% grass=0.0% greenery=12.1% person=0.0% pond=0.0% road=71.4% tree=8.2% [STDC] ON ROAD [STDC WARN] CAR 8.3% ``` --- ## 詳細說明 IMX662 DOL-HDR 雙曝光設定、STDC 語義分割架構、新裝置部署 SOP、故障排查: **[`docs/technical_report.md`](docs/technical_report.md)**