因为研究生选择的是边缘计算方向,毕设也与此相关,老师给了我一块 Raspberry Pi 4 Model B,让我在上面运行基于光流法的运动检测。于是本文记录了我配置系统、搭建环境和运行代码时遇到的问题。

⚠️ 时间范围:本文记录的是 2022 年的软硬件环境,不代表 2026 年的当前支持状态。选择系统、安装镜像或处理相机兼容性问题时,请以 Raspberry Pi OS 下载页官方文档为准。

系统选择与安装

awesome raspberry pi 汇总了许多树莓派相关系统与工具,可供扩展阅读;这里仅讨论我实际尝试过的几个系统:

  • 官方 32 位系统。当时它的主要优势是设备兼容范围广,不能笼统地说它“不适合开发”:系统自带的 Python 版本取决于对应 Debian/Raspberry Pi OS 发行版,而不是由 32 位本身决定。不过,一些科学计算软件没有提供 armv7 预编译包,安装时可能需要源码构建;单个 32 位进程的可用虚拟地址空间也有限。选择前应逐项确认项目依赖。

  • 官方 64 位系统,推荐用于我当时的开发任务。Raspberry Pi OS 64-bit 在 2022 年 2 月正式发布,使用 Debian arm64 用户空间并运行于 AArch64。它能使用更多仅提供 arm64 构建的软件,也允许单个进程使用更大的地址空间;但性能收益取决于具体工作负载,不能概括为所有场景都比 32 位更快。本文后面提到的环境配置问题就是针对此系统。官方发布说明对两者的兼容性和内存差异有更完整的解释:Raspberry Pi OS (64-bit)

  • Kali Linux,美观炫酷,而且很适合网络安全。对于这个系统,我也只是简单尝试了一下,感觉很适合程序员日常使用,如果不是要搞毕设希望稳定一些,我想这或许是更好的选择。我当时用 apt upgrade 遇到过依赖问题,但不应把“先 dist-upgrade、再 upgrade”当成固定顺序。Kali 是滚动发行版,官方建议先执行 sudo apt update,检查变更后再执行 sudo apt full-upgrade,详见 Updating Kali

  • OPENFANS,树莓派爱好者基地系统,适合在没有显示器键盘等外设的情况下日常使用。可以说这个系统帮用户配好了绝大部分环境,可以直接在网页上访问 ssh 和 vnc,还能直接开启 docker 等,可以说是非常贴心。但是让人难受的一点是,它是中文系统,而且有些过于臃肿了,对程序员不太友好。

  • Ubuntu,没有特点就是最大的特点。可以说这是最常用的 Linux 系统,如果更习惯这个系统就可以去用。我也只是使用了这个系统很短的时间,总感觉有点高不成低不就的样子,或许这就是适合大众的代价吧。

当然,你甚至可以定制属于自己的树莓派操作系统,raspberry pi os是一个不错的学习资料。

系统安装通常可以直接使用 Raspberry Pi Imager。如果镜像支持 Imager 的系统自定义功能,可以在写卡前配置主机名、Wi-Fi、用户和 SSH,适合无屏幕部署;不支持这些选项的第三方镜像则应遵循它自己的文档。必要时可以在另一台计算机上挂载启动分区修改配置,并不限定必须使用 Linux。

环境配置

conda 的安装

虽然树莓派官方 64 位系统是 AArch64 架构,我当时安装 Miniconda 时仍遇到了命令无法执行的问题。由于没有保留完整的安装包版本和错误日志,无法把它归结为 Miniconda 对该架构的普遍缺陷。我的替代方案是 Miniforge,安装后可以正常使用。我修改 channel 配置后曾再次遇到求解或安装失败,这同样只是当时环境的现象;更稳妥的做法是保持 conda-forge 的一致优先级,避免混用 ABI 或依赖策略不兼容的软件源。

PyTorch 的安装

在 2022 年的环境里,PyTorch 官方安装入口没有为 Raspberry Pi 的 Linux AArch64 环境提供方便的 CPU 预编译包,我采用了第三方项目 pytorch-aarch64 提供的轮子,另一种选择是从源码构建。这只是当时的安装记录;官方二进制支持矩阵会变化,今天安装前应以 PyTorch 的当前发布支持说明和安装页为准,并确认 Python、glibc 与架构标签匹配。第三方轮子也应核对来源、版本和哈希。

Raspberry Pi 4 并非“没有 GPU”:其 BCM2711 包含 VideoCore VI 3D 图形核心,见官方数据表。准确的限制是它没有 NVIDIA CUDA GPU,常规 PyTorch 包也不会把 VideoCore VI 当作 CUDA 计算设备;没有另行适配的后端或推理运行时时,模型主要在 CPU 上执行,性能和内存容量都比较有限。

遇到的问题

VNC 无法连接,提示认证错误

一种方法是安装配套的 VNC Viewer,使用这个软件可以正常连接到树莓派。

另一种方式是修改树莓派端的 VNC 设置,这前提是你要有外设,连接树莓派后将 Authentication 从 UNIX password 改成 VNC password,之后就可以正常使用 Mobaxterm 等软件连接 VNC 了。

所以还是直接安装 VNC Viewer 更加方便,而且界面也还挺美观的。

VNC 显示 “Cannot Currently Show the Desktop”

这种情况出现在我从raspi-config打开了摄像头功能后,我认为这种联动是很离谱的事情,大致的影响过程好像是开启摄像头后,开机不会进入桌面,所以 VNC 无法连接过去。如果树莓派在开机过程中连接了屏幕,那之后使用 VNC 就正常了(但这又有什么用)。

国内的许多文章都说这种情况需要修改 VNC 分辨率或者重装 lxsession,我不知道这在以前的旧系统中能否解决,但在我这里毫无作用。

我当时在国外树莓派论坛看到并尝试的是下面一组针对 Bullseye、X11/LXDE 与特定 KMS 配置的规避方法。它不是适用于所有版本的通用方案;尤其不要在当前系统上不加核对地修改 /usr/bin 或禁用 KMS,现代 Raspberry Pi OS 的桌面栈、VNC 实现和启动分区路径都可能不同。

  1. Enable video without HDMI connected (aka headless), by adding video=HDMI-A-1:1920x1080@60D to /boot/cmdline.txt (hdmi_force_hotplug=1 in /boot/config.txt is no longer sufficient)

  2. Disable Mutter, otherwise your system will crawl to a halt. In /usr/bin/startlxde-pi, edit $TOTAL_MEM -ge 2048 to $TOTAL_MEM -ge 20480 and reboot.

  3. Disable the KMS Overlay in /boot/config.txt, to further increase performance. #dtoverlay=vc4-kms-v3d

虽然第一步中说将hdmi_force_hotplug=1解除注释已经不够了,但我使用这种方法可以解决问题,并没有修改 cmdline.txt 中的内容。

树莓派连接摄像头后无法使用

我给树莓派装的是官方的 camera module v2,但在一开始无法在树莓派访问摄像头。

当时很多教程仍使用 raspistill,但它被替换并不是因为 AArch64。Raspberry Pi OS 从 Bullseye 开始把默认相机栈从旧版 raspicam/MMAL 切换到 libcamera;当时的命令名是 libcamera-*。从 Bookworm 开始,官方又将应用重命名为 rpicam-*。版本沿革和当前命令见 Raspberry Pi 相机软件文档以及 Bullseye camera system

我进行的尝试有:

  1. /etc/modules-load.d/modules.conf 中添加bcm2835-v4l2

  2. sudo modprobe bcm2835-v4l2

  3. 当时曾通过 sudo rpi-update 更新测试固件后恢复。

前两个方法没有直接解决问题,我是在最后一步后恢复访问的。但 rpi-update 会安装测试版内核/固件,不适合作为常规排障步骤;现在应先使用 sudo apt update && sudo apt full-upgrade,并以 Raspberry Pi 官方相机文档和当前系统版本为准。只有在明确需要测试固件且能够回滚时才考虑 rpi-update

我也查到了一种本地更新的方式,但没有尝试,放在这里供大家参考:树莓派固件更新(rpi-update)的那些坑

OpenCV 无法访问摄像头

我的 OpenCV 版本是 4.5.5。在相机能被 libcamera 应用访问后,我尝试用 cap = cv2.VideoCapture(0)cap.read() 读取帧,但它一直返回 false。这里原先的“理论上可以”并不成立:0 只有在相机以 OpenCV 所用后端能够读取的 V4L2 capture 节点出现时才有效,libcamera 能识别相机并不保证这一点。

我当时在 raspi-config 中打开摄像头选项后恢复了读取;结合 Bullseye 的行为看,这更可能是在启用旧版相机兼容栈,因此只是特定系统镜像下的解决办法。Bullseye 的默认 libcamera 栈本身不需要再“开启相机接口”,当前系统也不应把切换 legacy camera 当成常规步骤。对于 Python 与 OpenCV,官方目前推荐用 Picamera2 获取帧,再按 NumPy/OpenCV 图像处理流程继续处理。

此外我还在论坛上看到说可以通过源码安装 OpenCV 的方法解决,但由于我的 OpenCV 是使用 conda 安装的,也不想折腾 OpenCV 了,就没尝试这种方法。