Orange Pi 視角
| 項目 | RPi5 | Orange Pi | Orin Nano | Thor T5000 |
|---|---|---|---|---|
| ISP 形態 | SoC 硬體 ISP | 感測器內建為主 | NVIDIA ISP | Blackwell+Holoscan |
| AE/AWB | libcamera ✅ | sensor ⚠️ | NVIDIA ✅✅ | NVIDIA ✅✅ |
| LSC | ✅ | ⚠️ 後處理 | ✅ | ✅ |
| NR/Sharpen | ✅ | ⚠️ 後處理 | ✅✅ | ✅✅ |
| HDR | ✅ | ⚠️ 依驅動 | ✅ | ✅✅ |
| 工具鏈 | 開源 | V4L2 陽春開放 | 封閉強 | 新 |
| 面向 | RPi5 | Orange Pi | Orin Nano | Thor |
|---|---|---|---|---|
| 感測器控制 | libcamera | V4L2 subdev | tegracam/Argus | tegracam/Holoscan |
| 曝光 | ExposureTime | exposure | SensorMode exp_time | SensorMode |
| 白平衡 | ColourGains | red/blue_balance | Argus AWB | Argus AWB |
| RAW | rpicam --raw | v4l2-ctl | argus raw | argus/Holoscan |
無論平台,OV 感測器 register(0x300A ID、0x3500 曝光、0x350A 增益)相同——平台差異只在「誰幫你寫」。
RPi5: i2ctransfer -y 22 w2@0x36 0x30 0x0a r1 Orange Pi: i2ctransfer -y 3 w2@0x3c 0x30 0x0a r1 Orin/Thor: i2ctransfer -y 0 w2@0x36 0x30 0x0a r1
下表再把「四平台操作」從介面層收斂到 register 層,方便直接對照:
| 面向 | RPi5 | Orange Pi | Orin Nano | Thor |
|---|---|---|---|---|
| 感測器控制 | libcamera | V4L2 subdev | tegracam/Argus | tegracam/Holoscan |
| 曝光 | ExposureTime | exposure | SensorMode exp_time | SensorMode |
| 白平衡 | ColourGains | red/blue_balance | Argus AWB | Argus AWB |
| RAW | rpicam --raw | v4l2-ctl | argus raw | argus/Holoscan |
四平台面對「同一顆感測器」時,硬體 register 完全相同——差異在抽象層。這源自各自的「控制模型」:
| 平台 | 控制模型 | 抽象層 | 誰寫 register |
|---|---|---|---|
| RPi5 | libcamera + 平台 ISP | 高(3A 全自動) | libcamera IPA |
| Orange Pi | V4L2 subdev | 低(直接 controls) | 使用者/驅動 |
| Orin Nano | tegracam + Argus | 高(封閉) | NVIDIA 驅動 |
| Thor T5000 | Holoscan + Argus | 最高(新) | NVIDIA 驅動 |
調校可攜性的關鍵:你在 Orange Pi 學到的「曝光三要素順序」「灰卡 AWB」「RAW 驗證」是感測器物理,與介面無關——搬到任何平台都成立。介面差異只是「怎麼把意圖翻譯成 register」。
任務:「把曝光鎖在固定值、關自動白平衡、取一幀 RAW」。
rpicam-still -o shot.jpg --immediate --raw --shutter 2000 \ --awbgains 1.4,1.1 --gain 1.0
v4l2-ctl -d /dev/v4l-subdev0 -c auto_exposure=0 -c exposure=2000 \ -c auto_n_white_balance=0 -c red_balance=140 -c blue_balance=110 v4l2-ctl -d /dev/video0 --set-fmt-video=pixelformat=SRGGB10 \ --stream-mmap=3 --stream-count=1 --stream-to=shot.raw
# argus_camera / libargus API 設定 SensorMode exp_time + AWB off gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! 'video/x-raw(memory:NVMM)' ! fakesink
# Holoscan SDK 的 GXF/operator 配置 sensor mode 與 AWB 設定
| 現象 | 方向 |
|---|---|
| 曝光值單位不同 | 各平台單位(µs/line/倍數)不同 → 對照 datasheet 轉換 |
| gain 定義不同 | 有的 1.0 基數、有的 0dB 基準 → 查 control 說明 |
| AWB 沒關就手動設 | auto 優先 → 先關 auto 再設手動 |
| RAW 格式名稱不同 | fourcc/名稱各平台異 → 統一用位元深 + order 描述 |
| 節點編號不同 | sensor-id / /dev/videoN 對應不同 → 先列 devices |
場景:在四個平台上分別把 OV5640 曝光鎖在 2000 lines,從使用者 API 追蹤到最終 register 寫入。
rpicam-still -o shot.jpg --immediate --shutter 2000
# libcamera → IPA → I2C → 0x3501=0x07, 0x3502=0xD0v4l2-ctl -d /dev/v4l-subdev0 -c exposure=2000
# V4L2 subdev → ov5640 driver → I2C → 0x3501=0x07, 0x3502=0xD0# Argus API → sensor_mode.exp_time=2000 → tegracam → I2C# Holoscan operator → GXF → sensor mode → I2C| 平台 | I2C bus(OV5640) | I2C 位址 | 速率 |
|---|---|---|---|
| RPi5 | bus 22(CSI0) | 0x3c | 100kHz |
| Orange Pi 5 | bus 3(CSI0) | 0x3c | 100kHz |
| Orin Nano | bus 0(CSI0) | 0x36 | 400kHz |
| Thor T5000 | bus 0(CSI0) | 0x36 | 400kHz |
容易忽略的邊界案例:Orin/Thor 的 OV 感測器位址是 0x36(不是 0x3c),這是因為 NVIDIA 平台的 OV 模組用不同的 address strap。如果你把 Orange Pi 的 i2cget 指令(0x3c)直接在 Orin 上跑,會讀不到 ID——必須先用 i2cdetect 確認實際位址。
| 症狀 | 可能原因 | 解決方案 |
|---|---|---|
| Orange Pi 的 exposure=2000 與 RPi5 的 shutter=2000 結果不同 | 單位不同(line vs µs) | 查 OV5640 datasheet:1 line ≈ 29.6 µs(1080p@30fps) |
| RPi5 的 awbgains=1.4,1.1 在 Orange Pi 上無效 | OV 用無號整數 gains,RPi 用浮點比值 | Orange Pi 用 red_balance=140(無號整數) |
| Orin 上 0x3c 讀不到 ID | Orin 的 OV 模組位址是 0x36 | 改用 i2cdetect 掃 bus 0 找實際位址 |
| 跨平台移植後格式名不同 | fourcc 命名差異 | 統一用「位元深 + Bayer order」描述(如 SRGGB10) |
| libcamera 的 ExposureTime 設定後 OV5640 不變 | libcamera 需要 IPA 模組且 auto 仍開 | 先關 auto exposure,再設 ExposureTime |
把單元 15 的跨平台知識做成完整的移植對照專案:選定一個調校任務(如「鎖曝光 2000、關 AWB、取 RAW」),在 Orange Pi 建立基準結果,再對照 RPi5 / NVIDIA 寫出等效設定並驗證。產出一份「移植對照文件」。
v4l2-ctl -d /dev/v4l-subdev0 -c auto_exposure=0 -c exposure=2000 \
-c auto_n_white_balance=0 -c red_balance=140 -c blue_balance=110
v4l2-ctl -d /dev/video0 --set-fmt-video=pixelformat=SRGGB10 \
--stream-mmap=3 --stream-count=1 --stream-to=baseline.raw
ls -l baseline.raw # 記錄 sizeimage 與亮度基準# Orange Pi(V4L2) v4l2-ctl -d /dev/v4l-subdev0 -c exposure=2000 -c auto_exposure=0 # RPi5(libcamera): shutter 2000µs + awbgains 固定 rpicam-still -o shot.jpg --shutter 2000 --awbgains 1.4,1.1 --gain 1.0 # Orin Nano(Argus): SensorMode exp_time + AWB off # Thor(Holoscan): sensor mode 參數設定
python3 - <<'EOF' row_us = 29.6 # OV5640 1080p@30fps 的 1-line 週期(µs) exposure_lines = 2000 exposure_us = exposure_lines * row_us print(f'Orange Pi exposure=2000 lines → {exposure_us:.0f} µs = RPi5 shutter') # gains: Orange Pi 整數 128=1.0×,RPi5 浮點 1.0× red_ratio = 140/128 print(f'red_balance=140 → {red_ratio:.2f}× (RPi5 的 ColourGains R)') EOF
# 移植對照.md 範例結構: # 任務 | Orange Pi | RPi5 | Orin | Thor | 單位/備註 # 曝光 | exposure=2000 | shutter=59000µs | exp_time=59000 | 同上 | 2000×29.6µs # AWB | red=140 blue=110 | awbgains 1.4,1.1 | AWB off+gains | 同上 | 128=1.0× # RAW | v4l2-ctl SRGGB10 | rpicam --raw | argus raw | capture | 同 10-bit
| 步驟 | 作法 | 通過判據 |
|---|---|---|
| 1. 建立基準 | Orange Pi 上完成任務並記錄結果 | 基準 RAW 與參數記錄 |
| 2. 寫等效設定 | 換算單位(lines↔µs、整數↔浮點) | 換算公式正確 |
| 3. 執行比較 | 第二平台跑相同任務 | 亮度/格式接近基準 |
| 4. 讀 register 驗證 | 兩平台都 i2cget 0x3501/0x3502 | register 值一致(同為 2000 lines) |
| 5. 差異記錄 | ISP 前端差異造成的亮度差 | 記錄並解釋差異來源 |
| 面向 | Orange Pi | RPi5 | Orin Nano | Thor |
|---|---|---|---|---|
| 抽象層 | 最低(V4L2 subdev) | 中(libcamera) | 高(Argus) | 最高(Holoscan) |
| 開放度 | 最高(全開放) | 開源 | 封閉 | 封閉 |
| 調校深度 | 低–中 | 高 | 高 | 高 |
| 工具鏈 | V4L2 + 自寫 Python | libcamera tools | NVIDIA tools | Holoscan SDK |
| 學習曲線 | 陡(要懂底層) | 中 | 中(封閉但強) | 中(新) |
| 適合 | 理解感測器 | 開源產品 | 量產畫質 | 多機/雲端 |
- [ ] 我能完成跨平台移植對照專案並產出文件。 - [ ] 我能換算 Orange Pi 的 lines 與 RPi5 的 µs 曝光單位。 - [ ] 我能換算整數 gains(128=1.0×)與浮點比值。 - [ ] 我知道 Orin/Thor 的 OV 位址是 0x36 而非 0x3c。 - [ ] 我理解「感測器物理可攜、介面不可攜」並能舉例。 - [ ] 我能用「感測器 register 最終值」驗證跨平台等效性。
跨平台移植的核心是「register 概念的對應」。以下是四平台的位元級比較:
| 面向 | Orange Pi (V4L2) | RPi5 (libcamera) | Orin Nano (NVIDIA) | Thor (Holoscan) |
|---|---|---|---|---|
| 曝光控制 | 0x3500~0x3502 (lines) | ExposureTime (µs) | NVIDIA AE (µs) | NVIDIA AE (µs) |
| 增益控制 | 0x350A (整數 128=1.0×) | AnalogueGain (浮點) | NVIDIA gain | NVIDIA gain |
| AWB 控制 | 0x5185/0x5187 (整數) | ColourGains (浮點) | NVIDIA AWB | NVIDIA AWB |
| I2C 位址 | 0x3c | 0x3c | 0x36 | 0x36 |
| format 控制 | media-ctl -V | libcamera format | NVIDIA format | Holoscan format |
決策樹 A:跨平台移植失敗
從 Orange Pi 移植到 RPi5 失敗? ├─ I2C 位址不同(0x3c vs 0x36) │ └─ 先 i2cdetect 確認位址 ├─ 曝光單位不同(lines vs µs) │ └─ 換算:lines × 29.6µs = µs ├─ 增益單位不同(整數 vs 浮點) │ └─ 換算:整數 / 128 = 浮點 ├─ format 描述不同 │ └─ 用「位元深 + Bayer order」統一描述 └─ 控制 API 不同 └─ V4L2_CID_* vs libcamera controls
決策樹 B:跨平台影像品質不一致
四平台影像品質不一致? ├─ 曝光設定不同 → 統一 exposure 值 ├─ AWB 設定不同 → 統一 gains 值 ├─ ISP 管線不同 → 確認各平台 ISP 差異 ├─ format 不同 → 統一 Bayer order + 位元深 └─ 後處理不同 → 確認各平台工具差異 └─ 用「感測器 register 最終值」驗證等效性
| 步驟 | 指令 | 預期輸出 | 判讀標準 |
|---|---|---|---|
| 1. Orange Pi 基準 | i2cget -y 3 0x3c 0x3500 | exposure 值 | 基準值 |
| 2. 換算 µs | lines × 29.6µs | µs 值 | RPi5/NVIDIA 用 |
| 3. RPi5 設定 | libcamera --set-ctrl=ExposureTime=XXX | µs 設定 | 等效曝光 |
| 4. 增益換算 | 整數 / 128 = 浮點 | 浮點值 | RPi5 用 |
| 5. 取幀對比 | 四平台各取一幀 | 四張影像 | 品質一致 |
| 6. 量測 Delta E | Python script | Delta E | < 3(一致) |
| 面向 | Orange Pi | RPi5 | Orin Nano | Thor | 推薦 |
|---|---|---|---|---|---|
| 代表 SoC | RK3588 / H618 | BCM2712 | Orin Nano | T5000 | 依需求 |
| 調校框架 | V4L2 + Python | libcamera | NVIDIA 工具 | Holoscan | 底層→V4L2 |
| 工具鏈 | V4L2 + 自寫 | libcamera tools | NVIDIA tools | Holoscan SDK | 學習→V4L2 |
| 學習曲線 | 陡(底層) | 中 | 中(封閉但強) | 中(新) | 底層→Orange Pi |
| 適合 | 理解感測器 | 開源產品 | 量產畫質 | 多機/雲端 | 依目標選 |
- [ ] 完成「跨平台移植對照」專案並產出文件 - [ ] 換算 Orange Pi 的 lines 與 RPi5 的 µs 曝光單位 - [ ] 換算整數 gains(128=1.0×)與浮點比值 - [ ] 確認 Orin/Thor 的 OV 位址是 0x36 而非 0x3c - [ ] 驗證「感測器物理可攜、介面不可攜」並舉例 - [ ] 用「感測器 register 最終值」驗證跨平台等效性 - [ ] 產出「cross-platform translation table」 - [ ] 用「位元深 + Bayer order」統一描述格式 - [ ] 產出「platform comparison report」(含數據) - [ ] 用「底層→開源→封閉」三分法選平台