Argus 曝光控制
| 要素 | 控制 | 注意 |
|---|---|---|
| 快門時間 | 感測器曝光 register | 太長模糊/banding |
| 類比增益 | 感測器 AGC | 太高雜訊 |
| 數位增益 | NVIDIA ISP | 最後手段 |
SensorMode ... exp_time = 20000 SensorMode ... gain = 2.0
v4l2-ctl -d /dev/v4l-subdev0 -C exposure
曝光值依感測器位元布局組合(單元 3 的 16-bit 位址規則)。正式流程用驅動/平台控制,這裡只是理解。
argus_camera SensorMode exp_time=20000
OV9281 的曝光時間以「行(line)」為單位:每行時間 = line_length_pclk / pclk。這是 register 與真實時間換算的關鍵。
| Register | 內容 | 範例值 |
|---|---|---|
| 0x3501/0x3502 | 曝光行數(高/低 8-bit) | 1000 = 0x03E8 |
| 0x350A/0x350B | 類比增益(整數 + 0.5 步進) | 2.0 = 0x04 / 0x00 |
假設 pclk=96 MHz,line_length=1688 pclk 每行時間 = 1688 / 96M ≈ 17.6 µs 曝光 1000 行 = 17.6 ms 假設目標曝光 20 ms: 行數 = 20000 µs / 17.6 µs ≈ 1136 行 → 寫 0x3501=0x04, 0x3502=0x70
1. 讀目前曝光與增益: v4l2-ctl -d /dev/v4l-subdev0 -C exposure v4l2-ctl -d /dev/v4l-subdev0 -C gain 2. 若 exposure 已達上限(如最大行數): → 光線不足,靠曝光救不回 → 補光 / 換鏡頭光圈 3. 若 gain 已達上限(如 8×)且雜訊明顯: → 增益撐到極限,品質崩壞 → 補光優先 4. 若兩者都沒到上限但畫面仍暗: → AE 統計/目標設定問題(不是光學問題)
過暗: ├─ AE 卡上限 → 補光/光圈 ├─ AE 統計錯誤 → 場景過暗或有遮罩 └─ 黑位錯 → 回 unit-08 過亮: ├─ AE 目標太高 → 調目標亮度 ├─ 曝光行數爆掉 → 查 max └─ 感測器飽和 → 縮光圈/曝光 banding(條紋): ├─ 日光燈 50/60Hz → 曝光時間為市電週期的整數倍 └─ 感測器讀出問題 → 查 clock
曝光不是孤立的 register。對每一個 sensor mode,都有 line length、frame length、pixel clock 與最大曝光行數。幀時間由 frame length × line time 決定;曝光越長,留給讀出與下一幀的餘裕越少。global shutter 解決的是逐列不同步,不會消除長曝光造成的 motion blur。
| 限制 | 結果 | 調整方向 |
|---|---|---|
| 曝光超過 frame margin | FPS 降低或 driver clamp | 查 frame length/max exposure |
| 曝光接近 10/20 ms 的非整數 | LED/市電 banding | 鎖定 anti-flicker 時間 |
| 運動速度高 | 模糊,即使 global shutter | 縮短 exposure、補光、提高 gain |
目標 FPS = 60 → frame interval = 16.67 ms 假設 line time = 17.6 µs 最大曝光行數(保留 8 行 margin) = floor(16,670 / 17.6) - 8 ≈ 939 lines 最大曝光時間 ≈ 939 × 17.6 µs = 16.53 ms 若 AE 要 20 ms: → 不能同時維持 60 fps,必須降 fps、提高補光或接受 gain 驗證:比較設定值、回讀值、metadata 中的實際 exposure。
1. requested 與 applied exposure 不同? ├─ 是 → 查 mode 上限、frame margin、單位換算 └─ 否 ─┐ 2. RAW histogram 是否隨曝光改變? ├─ 否 → 查 register latch、stream 狀態、sensor reset └─ 是 ─┐ 3. 亮度仍上下跳動? ├─ 是 → 查 AE target、ROI、統計延遲與 anti-flicker └─ 否 ─┐ 4. 亮度正常但影像糊/有條紋? └─ 查運動速度、光源頻率與曝光時間,不要先拉數位增益
場景:Thor T5000 搭載在 AGV(自動引導車)上,OV9281 @ 60 fps 做 SLAM。AGV 速度 2 m/s,目標清晰 SLAM 特徵點(motion blur < 1 pixel)。
# SLAM 要求:motion blur < 1 pixel # OV9281 像素尺寸 3.0 µm,鏡頭焦距 2.8 mm # 1 pixel 在物方的寬度 = 3.0 µm × (物距/焦距) # 物距 1 m → 1 pixel ≈ 1.07 mm # AGV 速度 2 m/s → 最大曝光 = 1.07 mm / 2 m/s = 0.535 ms # 60 fps → frame interval = 16.67 ms # 最大曝光 0.535 ms << 16.67 ms → 有充足時間 # 但曝光太短 → SNR 可能不足 # SNR 驗證( OV9281:full well 10000 e⁻, QE 60%) # 曝光 0.5 ms、場景 500 lux: # 光子數 ≈ 500 × 0.5 ms × 像素面積 × 120 lm/W ≈ 假設 800 光子 # 電子數 = 800 × 0.6 = 480 e⁻ # SNR = 20·log10(480/√480) ≈ 26.6 dB(偏低) # 解決方案: # 1. 提高增益 → 雜訊增加 → SNR 更差 # 2. 補光 → 光子數增加 → SNR 提升 → 推薦 # 3. 加大光圈 → 更多光子 → 同時景深縮小(SLAM 可能需要)
NVIDIA ISP 的 AE 支援 多區域統計(multi-zone statistics):把畫面分成 N×M 格子,每格獨立計算亮度。AE 演算法可以針對特定 ROI(Region of Interest)調整曝光,而非只看全畫面平均。這在「前景暗 + 背景亮」的場景中至關重要。
| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| AE 收斂後畫面仍過暗,gain 已達上限 | 曝光時間被 frame length clamp(上限卡住) | 讀回 applied exposure 與 max exposure;若已卡上限 → 補光或降 fps |
| 日光燈下畫面有水平亮暗帶 | 曝光時間非市電週期整數倍(50/60 Hz banding) | 啟用 anti-flicker 模式或手動設定曝光為 10 ms 整數倍 |
| ROI 外的主體過暗 | AE ROI 未覆蓋主體區域 | 重新設定 AE ROI;或用全畫面平均 AE + 手動微調 |
| 動態場景中曝光跳動 | AE 反應速度過快 / 統計延遲導致 overshoot | 降低 AE convergence speed;增加 temporal smoothing |
| 60 fps mode 下最大曝光 < 1 ms 但仍過亮 | 場景光線過強,即使最短曝光仍飽和 | 加入 ND filter 或縮小光圈;感測器端限制最大 analog gain |
場景:Thor 上的 SLAM 機器人,60 fps、會進出不同亮度環境(倉庫 / 戶外)、且常在日光燈下運作。專案目標:AE 在各種場景收斂快、無 banding、曝光不超過 motion blur 上限。
M1 曝光計算基礎 ├─ 算出 line time、最大曝光行數(unit-10.14) └─ 通過:requested = applied(回讀一致) M2 收斂測試 ├─ 場景快速切換(亮↔暗),觀察 AE 收斂幀數 └─ 通過:< 15 幀收斂、無 overshoot 跳動 M3 上限診斷 ├─ 低光:確認曝光/增益誰先到上限 └─ 通過:知道卡在哪、知道該補光或降 fps M4 anti-flicker ├─ 日光燈下測 50/60Hz banding ├─ 設定曝光為市電週期整數倍 └─ 通過:無水平亮暗帶 M5 ROI 策略 ├─ SLAM 場景定義 AE ROI └─ 通過:主體(前景)曝光優先 M6 回歸 └─ 通過:亮/暗/混合光源各場景全過 驗證: v4l2-ctl -d /dev/v4l-subdev0 -C exposure,gain # 比較 requested 與 applied
Step 1 讀目前值 v4l2-ctl -d /dev/v4l-subdev0 -C exposure,gain Step 2 手動設定並回讀 設定曝光 → 回讀確認 applied 一致 Step 3 單位換算驗證 曝光行數 × line time = 真實時間 Step 4 收斂測試 切換場景亮度,數 AE 收斂幀數 Step 5 banding 測試 日光燈下調整曝光為 50/60Hz 整數倍 Step 6 上限測試 低光下找出「曝光 or 增益先到上限」 判讀指標: requested ≠ applied → mode 上限 / 單位換算錯 收斂 > 30 幀 → 調 reaction speed banding 存在 → 曝光非市電週期整數倍
| 面向 | Thor T5000 | RPi5 | Orange Pi | Orin Nano |
|---|---|---|---|---|
| 控制介面 | SensorMode exp_time / V4L2 | ExposureTime | exposure(V4L2 ctrl) | SensorMode exp_time |
| AE 引擎 | NVIDIA 自動化 | libcamera IPA | 感測器內建 | NVIDIA 自動化 |
| anti-flicker | ✅ 支援 | ✅ 支援 | ⚠️ 少 | ✅ 支援 |
| AE ROI | ✅ 多區域統計 | ✅ libcamera | ⚠️ | ✅ |
| 曝光單位 | µs(Argus)→ 行數(register) | µs | 行數或 µs(依驅動) | µs(Argus)→ 行數 |
本單元涉及的關鍵 register,以及「讀→改→寫→驗證」的完整位元級操作序列:
| Register | 位址 | 功能 | Bit Field 說明 |
|---|---|---|---|
SENSOR_EXPOSURE_REG | 0x3500/0x3501/0x3502 (OV9281) | Exposure time | bit[19:16]=upper, bit[15:8]=mid, bit[7:0]=lower, 單位 line |
AE_CONVERGENCE_STATUS | 0x00100010 | AE 收斂狀態 | bit[0]=converged, bit[1]=over_exposed, bit[2]=under_exposed |
# Step 1: 讀取目前值 $ devmem2 0x3500/0x3501/0x3502 (OV9281) w # 記錄 current_value # Step 2: 計算新值(設定 bit[0]=1) $ new_value=$((current_value | 0x0001)) # Step 3: 寫入 $ devmem2 0x3500/0x3501/0x3502 (OV9281) w $new_value # Step 4: 驗證 $ devmem2 0x3500/0x3501/0x3502 (OV9281) w # 確認 bit[0] = 1,其餘 bit 不變 # Step 5: 進階 — bitmask 操作 $ read_val=$(devmem2 0x3500/0x3501/0x3502 (OV9281) w | grep "Read" | awk '{print $NF}') $ mask=0x0001 $ expected=0x0001 $ [ $(($read_val & $mask)) -eq $expected ] && echo "PASS" || echo "FAIL: bit[0] not set"
1. 曝光值不動? ├─ AE 被鎖定 → 檢查 `v4l2-ctl --set-ctrl=exposure_auto=1`(manual) └─ AE 正常但收斂慢 → 收斂速度參數太保守,調 AE speed factor 2. 曝光震盪(忽亮忽暗)? ├─ AE 步進太大 → 減小 step size └─ 目標亮度設定不當 → 調 bright target 值
1. 曝光時間 > frame duration? ├─ sensor 降為 partial exposure → 檢查 line_length 與 frame_length └─ 設定值超出 sensor range → clamp 到 max exposure 2. 曝光時間 = 0? ├─ AE 未啟動 → 確認 AE mode └─ 軟體 bug → 檢查 Argus 的 exposure 計算邏輯
AE 完整量測與調校 SOP:
| 步驟 | 動作 | 指令/方法 | 預期輸出 |
|---|---|---|---|
| Step 1 | 設定 baseline | 手動 exposure = 10ms, gain = 1× | 固定光源 D65 |
| Step 2 | 記錄 histogram | `v4l2-ctl -d /dev/video0 --list-ctrls` + dump frame | histogram 峰值在中間 |
| Step 3 | 啟用 AE | `v4l2-ctl --set-ctrl=exposure_auto=3`(aperture priority) | AE 開始收斂 |
| Step 4 | 監控收斂 | 每 100ms 記錄 exposure/gain 值 | 2–5 秒內收斂 |
| Step 5 | 驗證穩態 | 靜態場景持續 30 秒 | exposure 變化 < ±5% |
| Step 6 | 動態測試 | 突然遮擋 50% 畫面 | re-converge < 1 秒 |
| Step 7 | flicker 測試 | 100Hz 日光燈下 | 無 banding |
| 面向 | Thor T5000 | RPi5 | Orange Pi | Orin Nano |
|---|---|---|---|---|
| AE 實作 | Argus 3A (硬體加速) | libcamera 3A(軟體) | V4L2 auto exposure(有限) | Argus 3A |
| 曝光精度 | 1 line(~8.3μs @30fps) | 1 line | 1 line | 1 line |
| AE 收斂速度 | < 1 sec(典型) | 2–5 sec | 3–8 sec | 1–2 sec |
| Flicker 抗制 | 100/120Hz hardware detect | 軟體(有限) | ❌ | 100/120Hz |
| HDR 曝光控制 | Stagger 多曝光 | Single exposure | ❌ | Stagger 多曝光 |
| AE ROI 限制 | ✅ | ❌ | ❌ | ✅ |
針對「曝光與自動曝光(AE)」主題的完整 bring-up 步驟清單: