元器件 · 传感器

树莓派相机模块

插在树莓派 CSI 排线接口而不是 USB 上的相机:独立的数据通道、自动对焦,也是大多数机器人视觉代码默认使用的传感器。

它是什么

经扁平排线连到树莓派 CSI 口的小传感器板——一个专用的相机接口,不是 USB。这个区别就是它存在的全部理由。机器人上的树莓派,USB 总线上一般已经挂着 Wi-Fi、通往电机控制的串口,可能还有存储;而相机再往同一条总线上推 1080p,事情就到此为止了。

对机器人,相机是改变可能性的传感器。本站其他传感器都报一个数——距离、角度、反射率。相机报一个场景,机器人才能认出东西是什么,而不只知道有东西。

树莓派相机模块标注图:方形小 PCB,中央黑色镜筒盖在图像传感器上,扁平排线从底边连进树莓派 CSI 口,四角安装孔,标注镜头、CSI-2 排线和背面传感器触点。
相机板大半是镜头和传感器:图像数据经 CSI-2 排线走自己的通道,不碰机器人其他设备用的 USB 总线。 下载 SVG

工作原理

光照到传感器上,传感器经 MIPI CSI-2(一条高速短距串行链路)把原始行数据送进树莓派的图像管线。树莓派把这些原始行变成可用的图像:去马赛克、白平衡、曝光、镜头暗角校正。在当前的 Raspberry Pi OS 上,这套工作由 libcamera 负责,命令行工具是 rpicam-apps,Python 里则是 Picamera2。

两件事对机器人要紧:

**管线花时间。**帧不是曝光瞬间就有的。代码看到它时几十毫秒过去,动的车已经动了。视觉闭环必须按这个延迟设计。

**曝光默认是自动的,除非你把它关掉。**自动曝光会很乐意在两帧之间改变你场景的亮度——拍照这样没问题,但对一个按亮度做阈值判断的视觉算法却是灾难。光线稳定之后,就把曝光和增益锁定。

什么时候用它

机器人要回答标量传感器答不了的问题时请相机:

  • 基准标记——ArUco 标签从单帧就能给出完整的 3D 位姿,这是让机器人获得一次真实位置修正最便宜的办法。
  • 现实世界循迹——相机看到几米外的线,反射阵列只看到正下方。
  • 物体识别——分出椅子和墙,而不是对两个都读 40 cm。
  • 视觉 SLAM——只用图像建图。

别为了避障去加一台相机。VL53L0X 用三行代码、20 ms 就能回答“有多远”;相机回答得一样的问题,既更差、更慢,又要多花上百倍的努力。

接线与坑

  • **排线是有方向的。**银色触点要朝向板子连接器的触点——在树莓派上就是蓝色背胶朝向 USB/网口那一侧。插反了相机根本不会被识别,而且不会损坏任何东西。
  • **先挑起连接器卡扣。**把塑料卡环轻轻挑起,让排线端端正正地插到底,再把卡扣压回去。排线如果只是斜着插进去,枚举就会时断时续,看起来像是相机坏了。
  • **树莓派 5 和 Zero 需要 22 针排线。**相机是同一个,连接器更窄。下单前先确认。
  • **让排线远离电机走线。**这是一条没有屏蔽的高速链路,就跑在你塞满底盘的其它线路旁边;串进来的电机噪声表现为画面损坏。
  • **电源预算要留够。**除了树莓派自身的消耗外大约还要 250 mA,而且必须来自同一路供电——在这路供电上省钱,就会欠压并损坏 SD 卡。
  • **对焦是一个设置项,不只是一个对焦环。**在三代模块上,画面反差低时自动对焦会来回搜索。对一台总是看差不多距离的机器人,设定一个固定的对焦位置,别让它在机动到一半时来回搜索。

选哪个模块

模块 传感器 分辨率 对焦 对机器人的意义
二代 IMX219 8 MP 定焦(可手动调) 便宜、可预测,不会自动对焦来回搜索
三代 IMX708 11.9 MP 自动对焦 通用最优;机器人用锁对焦
三代广角 IMX708 11.9 MP 自动对焦 102° 视场——导航好得多
HQ IMX477 12.3 MP C/CS 镜头座 要特定镜头或远距离
全局快门 IMX296 1.6 MP C/CS 镜头座 动的机器人最要紧的那款

全局快门值得好好解释,因为卷帘快门是机器人视觉最被低估的问题。

卷帘快门传感器逐行曝光而不是一起,帧顶比帧底早拍几毫秒。相机静止看不见。90°/s 转弯的机器人上,帧顶帧底是不同角度拍的,直竖线出来歪的。

对标记位姿管线来说,这不是个表面问题。ArUco 标签的角点被用来解算它的位姿,如果这四个角点是在机器人略有差别的四个朝向下拍到的,算出来的位姿就是错的,而且再怎么标定也纠正不过来。如果你的机器人要一边走一边看,全局快门传感器就是解法,代价是分辨率降低,这值得。

让图像可用的设置

自动曝光、增益和白平衡对摄影来说非常好,对视觉算法却主动有害。它们会在帧与帧之间改变你的阈值所依赖的数值,而这与场景本身无关。

from picamera2 import Picamera2
import time

picam = Picamera2()

# Small frames. 640x480 is plenty for markers and lines, and the pipeline
# cost scales with pixel count.
config = picam.create_video_configuration(
    main={"size": (640, 480), "format": "RGB888"},
    controls={"FrameDurationLimits": (33333, 33333)},   # lock to 30 fps
)
picam.configure(config)
picam.start()

# Let auto-exposure settle on the real scene, then freeze it.
time.sleep(2)
metadata = picam.capture_metadata()
picam.set_controls({
    "AeEnable": False,
    "AwbEnable": False,
    "ExposureTime": metadata["ExposureTime"],
    "AnalogueGain": metadata["AnalogueGain"],
    "AfMode": 0,                 # manual focus
    "LensPosition": 2.0,         # dioptres: 1/distance_in_metres
})

while True:
    frame = picam.capture_array()
    # ... your processing here

LensPosition 的单位是屈光度——也就是对焦距离(以米计)的倒数。看约 50 cm 处的物体要设 2.0;看一米处设 1.0;无穷远是 0.0。显式设定它可以避免自动对焦在机动途中来回搜索——在一台运动着的机器人上,这会在最不该出现的时刻糊上一两秒画面。

分辨率、帧率和延迟

分辨率是大家留太高、代价超预期的设置。

分辨率 像素 相对算力 适合
320×240 77 k 1× 循迹、色块跟踪
640×480 307 k 4× ArUco 标记,大多数机器人视觉
1280×720 922 k 12× 小的或较远的标记
1920×1080 2.07 M 27× 录像,实时控制很少

树莓派 4 在 640×480 下跑 ArUco 检测,能轻松维持 30 fps。同样这套流程在 1920×1080 下会掉到个位数帧率,而且每帧在处理完时都已经过期。用能分辨你所关心特征的最小分辨率,同时记住检测距离是随分辨率变化的——如果标记在远处检测不到,那么提高分辨率确实有用,代价照付。

延迟预算

这就是视觉控制难的原因,值得写出来:

阶段 典型
曝光 10–30 ms
传感器读出和 CSI 传输 5–15 ms
ISP 管线(去马赛克、白平衡) 5–10 ms
你的处理 10–50 ms
图像到决策合计 30–105 ms

0.3 m/s 的车这窗口走 1–3 cm;90°/s 转弯转 3–9°。视觉闭环作用的是车刚才在哪,按实时测量调参必振荡。

实践答案和别处一样:视觉环跑得比控制环慢,用它修正更快的航位推算,或按已知延迟前向预测再用。这正是路径跟踪给 GPS 搭的结构,原因一样。

装到车上

**刚性。**相机标定产出内参——焦距、主点、畸变——是那台相机在那个支架上的属性。车一加速就晃的支架让标定持续失效,位姿估计无故漂。

**远离电机线。**CSI 排线是无屏蔽高速差分链路。挨着电机线跑,开关噪声耦合进去就是花帧或相机间歇消失。

**排线做应力释放。**扁线连接器不为反复弯折设计,车还一直振。两端附近把排线贴住,别让振动把连接器晃松。

朝下偏一点(地面车)。指地平线的相机大半像素拍天花板。下偏十到二十度,有用的场景——前面地面和上面的东西——进画面中央。

故障排查

现象 可能原因 解决
相机完全认不出 排线插反 银触点对板子触点
时认时不认 排线没插到底摆正 挑起卡扣重插到底压好
树莓派 5 上 No cameras available 线宽错 树莓派 5 和 Zero 要 22-pin 线
花帧撕裂 电机噪声上排线 远离电机线走;做应力释放
逐帧亮度变 自动曝光还开着 静置后锁曝光增益
机动途中画面变糊 自动对焦来回搜索 设 AfMode: 0 并固定 LensPosition
转弯竖线歪 卷帘快门 转慢点,或全局快门模块
负载一高帧率就崩 分辨率太高 降到 640×480;查是否过热降频
位姿估计无缘无故漂移 相机支架在晃动 刚性安装;重新标定
相机一开树莓派就重启 电源扛不住多出的约 250 mA 换更好的电源——这会损坏 SD 卡

相机还是测距传感器?

相机 VL53L0X / HC-SR04
回答 那里有什么、在哪、什么朝向 最近的东西多远
延迟 30–100 ms 20–60 ms,无处理
代码 一整条视觉管线 三行
算力 树莓派级处理器 任何单片机
失效 黑、逆光、运动模糊 特定表面(见各页)
成本 $25–50 加树莓派 $2–5

说句实在话:**别为了避障去加相机。**测距传感器回答这个问题更快、更便宜、也更可靠,而花在让相机干这件事上的每一小时,都是从只有相机才能干的事情上挪走的。

需要知道某个东西是什么、或者自己在哪的时候,就该加一台相机——识别物体、读取基准标记以获得一次绝对位姿修正,或者跟着一条机器人能提前几米看到的线,而不是只看着脚下。这些事情用标量传感器确实做不到,而它们值得你搭起整条管线。

探索关联图谱

用到它的搭建

包含 树莓派相机模块 的项目、学习路线和模拟器。

问题

树莓派相机模块 常见问题

做机器人,树莓派相机比 USB 摄像头更好吗?

对机器人来说通常是的,原因在于接口而不是画质。CSI 相机有一条直通树莓派图像管线的专用数据通道,所以它不会和 Wi-Fi 适配器或串口链路争抢 USB 带宽,帧时序也可预测得多。只有在你需要长线缆的时候——CSI 排线又短又脆弱——或者希望相机不作任何改动就能在笔记本电脑上使用时,USB 摄像头才是更好的选择。

做机器人该买哪款树莓派相机?

大多数机器人选三代相机模块——有自动对焦,有广角版可选,而且有最新的软件支持。如果机器人需要看到离自己很近的东西,就选广角(102°)版,而做导航时几乎总是如此。如果机器人要一边快速移动一边观察,就改选全局快门相机;如果需要特定的镜头,就选 HQ 相机。如果定焦能满足需要,二代相机模块依然够用,而且更便宜。

为什么机器人转弯时相机画面会歪斜?

这是卷帘快门造成的。传感器是一行一行读出的,而不是一次性捕获整帧,所以在读出期间移动的东西,在每一行上被记录的位置都略有不同——转弯会把直线剪切成斜线。这之所以要紧,是因为位姿估计假设每一帧对应同一个瞬间。可以缩短曝光时间,测量时让机器人放慢速度,或者使用一次性捕获所有行的全局快门相机。

树莓派 5 用的是同一种相机排线吗?

不是,而且这一点几乎把所有人都坑过。树莓派 5 和 Zero 系列使用更窄的 22 针连接器,而树莓派 4 及更早的型号使用大多数相机随附的 15 针连接器。相机本身是一样的;你需要合适的排线或转接头。树莓派 5 还有两个相机接口,所以可以接一对双目相机。

我还该用 picamera 库吗?

不该——原来的 picamera 模块是基于一套在当前 Raspberry Pi OS 上已经不存在的相机软件栈编写的。请使用 Picamera2(其底层是 libcamera),或者在相机作为 V4L2 设备出现后通过 OpenCV 采集图像。大多数几年前的教程都是为这个已经废弃的 API 写的,这也是复制来的代码片段在全新安装的系统上立刻报错的常见原因。

延伸阅读

参考资料