4. 摄像头模组与驱动适配

在 Jetson 上做多摄像头同步采集,第一步不是写代码,而是把“物理摄像头”变成系统里一个可被稳定寻址、可被统一调度的视频节点。这条链路从 Sensor 选型开始,经过 CSI 接口、设备树、V4L2 驱动,最终由 Argus 或 GStreamer 暴露给应用层。任何一环不匹配,都会表现为“设备能枚举但出不了图”“出图但帧率不稳”“多路能开但时间戳对不齐”。本节按这条链路逐层展开。

Sensor 选型:先看接口与同步能力

Jetson 的摄像头接入主要走 MIPI CSI-2,模组通常由 Sensor + 镜头 + 供电/时钟电路组成。选型时优先确认四件事:一是 Sensor 型号是否在 Jetson 的 nvidia,camera 支持列表或社区驱动中已有参考实现,例如 IMX219、IMX477、IMX219 双路、OV5647 等;二是 CSI lane 数与 Jetson 模组可用 CSI 通道是否匹配,Orin Nano 与 Xavier NX 的 CSI 端口数量和 lane 分配不同;三是是否支持外部触发或 FSIN(Frame Sync Input),这是多路硬同步的关键;四是 I2C 地址是否可改,避免多路同型号 Sensor 地址冲突。

以 IMX219 为例,典型配置为 2-lane CSI、I2C 地址 0x10、最大 3280×2464。若要做 4 路同步,建议选择支持 FSIN 的模组,或使用带触发输入的转接板。若只做软同步,则需接受各 Sensor 独立曝光带来的时间偏差,后续在应用层用时间戳对齐。

设备树配置:把 Sensor 挂到 CSI 端口上

Jetson 的设备树决定了“哪个 I2C 地址上的 Sensor 接到哪个 CSI 端口、走几 lane、时钟多少”。以 Orin Nano 为例,摄像头相关节点通常位于 tegra-camera-platform 与 i2c@3180000 下。一个典型的 IMX219 节点片段如下:

i2c@3180000 {
  imx219_a@10 {
    compatible = "sony,imx219";
    reg = <0x10>;
    devnode = "video0";
    clocks = <&cam_i2c_mclk>;
    clock-names = "mclk";
    csi-port = <0>;
    num-lanes = <2>;
    mode0 {
      num-lanes = <2>;
      active_w = "3280";
      active_h = "2464";
      pixel_t = "bayer_rggb";
      mclk_khz = "24000";
      line_length = "3448";
      pix_clk_hz = "182400000";
    };
  };
};

关键字段含义:reg 是 I2C 地址,devnode 决定生成的 /dev/videoX 编号,csi-port 指定 CSI 端口,num-lanes 必须与硬件走线一致,pix_clk_hz 与 line_length 共同决定帧率。多路配置时,每路 Sensor 的 reg、csi-port、devnode 必须唯一。修改后需重新编译 DTB 并更新 /boot 下的设备树文件,重启后用 dmesg | grep imx219 确认驱动 probe 成功。

Jetson 摄像头驱动适配链路 Sensor 模组 IMX219 / IMX477 2-lane CSI-2 I2C 0x10 FSIN 可选 CSI 接口 MIPI CSI-2 csi-port 0/1/2 lane 数匹配 设备树 DTB i2c@3180000 reg / csi-port num-lanes / pix_clk devnode = video0 V4L2 驱动 /dev/video0 v4l2-ctl 枚举 格式/帧率设置 DMA 缓冲 Argus 库 libargus.so 多路同步采集 时间戳对齐 ISP 参数控制 GStreamer 管线 nvv4l2camerasrc nvvidconv / nvjpegenc appsink / filesink 多路 tee 分流 图:Sensor → CSI → 设备树 → V4L2 → Argus / GStreamer 的适配链路

V4L2 驱动:确认节点与格式

设备树生效后,驱动会创建 /dev/videoX。用 v4l2-ctl --list-devices 查看所有节点,再用 v4l2-ctl -d /dev/video0 --list-formats-ext 确认支持的分辨率与像素格式。IMX219 常见输出为 RG10(10-bit Bayer),需要 ISP 或软件 debayer 才能得到 RGB。若用 nvv4l2camerasrc,它可直接读取 Bayer 并交给 NVMM 处理。

多路场景下,建议为每路固定 devnode,例如 video0~video3,避免重启后编号漂移。可用 udev 规则按 devnode 或 I2C 地址建立稳定符号链接,如 /dev/cam0。测试单路出图:

gst-launch-1.0 nvv4l2camerasrc device=/dev/video0 ! \
  video/x-raw(memory:NVMM),width=1920,height=1080,framerate=30/1 ! \
  nvvidconv ! nvjpegenc ! filesink location=test0.jpg

若命令无报错且生成图片,说明 Sensor、设备树、V4L2 三层已通。若报 Failed to open,优先查 dmesg 中的 I2C 通信错误;若报格式协商失败,检查 --list-formats-ext 中的实际支持项。

Argus 与 GStreamer:应用层管线搭建

Argus 是 NVIDIA 提供的摄像头 API,优势在于多路同步、ISP 控制和低延迟。它通过 ICameraProvider 枚举设备,用 CaptureSession 同时启动多路流,并返回带硬件时间戳的帧。多路同步时,Argus 可配合 FSIN 实现帧级对齐;若 Sensor 不支持 FSIN,则只能依赖时间戳做软对齐。

GStreamer 更适合快速验证与管线拼接。多路采集常用 nvv4l2camerasrc 或 nvarguscamerasrc,前者走 V4L2 直通,后者走 Argus。典型四路管线可用 tee 分流到不同 sink,或分别启动四个独立管线。若要做同步,建议在应用层用 appsink 取帧,按 PTS 对齐后再融合。

选型建议:需要 ISP 精细控制与多路硬同步时优先 Argus;只需快速出图、做格式转换或推流时,GStreamer 管线更轻量。两者可共存,但同一 Sensor 不建议同时被 Argus 和 V4L2 独占打开。

常见问题与判断依据

  • 设备枚举不到:查 dmesg | grep -i imx219,确认 I2C 地址、供电、时钟是否正常。
  • 出图花屏或偏色:检查 pixel_t 是否与 Sensor 实际 Bayer 排列一致,RGGB 与 BGGR 写反会导致红蓝互换。
  • 帧率低于预期:核对 pix_clk_hz 与 line_length,并确认 CSI lane 数没有配少。
  • 多路时间戳偏差大:确认是否启用 FSIN;若没有,记录各路口 PTS 差值,评估是否满足应用容差。

完成本节后,应能独立完成“选 Sensor → 改设备树 → 验证 V4L2 → 搭 Argus/GStreamer 管线”的闭环,并能在多路场景下定位到具体是哪一层出了问题。