推荐软件产品
twitter,facebook,ins,youtube视频下载
磨针音视频转文字
磨针免费pdf转word
磨针微信定时发文件和消息
磨针c盘清理,任何场景都能释放几十G的空间

前言

最近突然心血来潮想玩玩树莓派,但估计是全球晶片荒的缘故,竟是一片难求。于是翻出多年前在课堂上购买的迷你树莓派,这颗树莓派的型号为Raspberry Pi Zero W Rev 1.1,单核CPU (ARMv6Z 32-Bit) 仅1 GHz 的时脉。记忆体的表定规格为512 MB,但实际上能用的大概400 MB 上下。这样的环境可说是十分凶险,在上面无论是开发或部署,都像是走钢索般,每步操作都如临深渊,一个不小心就会看到电源灯无情熄灭,只得拔线重来。之前工作上有接触到RPi3,虽然规格比Zero 好很多,但情况其实也没比较好。笔者在这边分享我跟这块树莓派相处的经验,给大家参考。

安装作业系统

笔者一般透过官方的RPi Imager安装作业系统,现在的RPi Imager 有很多不错的功能,例如在安装之前先设定好SSH 与WiFi 的设定,对于没有设定经验的使用者来说,实在方便很多。身为一个(自认为)硬派的Linux 使用者,这么小一块树莓派还要装桌面环境,实在痛苦。如果不是想要在树莓派上玩麦块或者做影像辨识之类的应用,建议安装没有桌面环境的Raspberry Pi OS Lite,透过SSH 为主进行远端操作。因为我这块比较古老,所以只能装32 位元。因为以SSH 远端操作为主的缘故,所以SSH 登入资讯与WiFi 网路连接一定要设定好。

开发环境

一开始没头没脑的,也不太确定要开发什么,不如我们这边先装个Py ... 不,千万不要。在这么严苛的环境做开发,已经是很想不开的行为了,别再做这种开发Python 的自杀举动。如果是开发一些微服务可能还OK,但笔者之前部署个Discord Bot 都觉得十分吃力。笔者这边为大家演示一下在这块小树莓派上跑Python 是个什么样子的想不开法:

pi@raspberrypi:~ $ time pip3 -V
pip 20.3.4 from /usr/lib/python3/dist-packages/pip (python 3.9)

real    0m23.613s
user    0m23.188s
sys     0m0.382s

诚如您所见,光是显示个pip 的版本,都要花你快半分钟。

在这种小型装置上,使用C 语言永远是个好伙伴。笔者帮自己设定的目标,是尝试在树莓派上跑个ONNX 模型的推论,虽然我没试过,也不确定是否真的可行,但达成这个目标最理想的做法,就是用C 来实现。

注:最近NSA 建议从程式语言层级确保记忆体安全,做为C 语言的替代选择,推荐使用Rust 做开发,但笔者对Rust 所学不多,是个需要继续修炼的课程。

所以我说那个开发环境

虽算说是用C 语言开发,难道用VSCode 的SSH Remote 套件不行吗?欸恭喜,问了就没有:

大概是因为我这块树莓派是32 位元的关系,之前用RPi3 是可以的,但基本上还是不太推荐这样直接Remote 过去,其实VSCode 的SSH Remote 是挺消耗资源的,对资源稀少的树莓派而言更是如此。

如果想要同时享有VSCode 带来的便利又想要进行远端开发,笔者推荐使用SSHFS (SSH Filesystem) 的方式,将树莓派里的专案资料夹挂在自己的系统里面。

如果作业系统是Windows 则可以使用WSL,不过建议把资料夹挂在 \\wsl.localhost\ 底下,运作效率会比较好一点,例如 \\wsl.localhost\Ubuntu\home\username\MyProject 之类的。

以下操作使用「Host 端」代表开发者的PC,「Remote 端」代表树莓派开发板:

  1. 首先在Host 端安装sshfs
    • sudo apt update
    • sudo apt install sshfs
  2. 在Host 端建立资料夹并进行挂载
    • mkdir RemoteProject
    • sshfs pi@@192.168.XXX.XXX:~/RPiProject RemoteProject
  3. 使用VSCode 快乐开启工作区
    • cd RemoteProject
    • code .

这样的做法有几个优点:

  1. 套件消耗的资源主要在Host 端,Remote 端基本上只需要负担网路传输。
  2. 可以同时进行Host 端与Remote 端的开发。

同时也有些缺点:

  1. 以VSCode 而言,你要常常去点重新整理的按钮才能看到档案的变动。
  2. 环境配置上主要还是看Host 端,若与Remote 端有差异,要到编译期间才看得出来。
  3. SSH 是会断线的,每次重开工作区都要重新挂载一次。

简单写个小程式

我们就来写个 Hello World! 吧:

// Main.c
#include <stdio.h>

int main() {
    printf("Hello, World!\n");
    return 0;
}

在撰写的过程应该能发现自动完成或错误波浪都有正常且快速的运作,如果用SSH Remote 进去通常不会这么快。

接下来在两边分别进行编译与执行:gcc Main.c -o Main && ./Main

可以善用VSCode 的分割Terminal 或者tmux 之类的工具来进行双边工作:

充满好奇心的各位,一定会想试试看在x64 上编译的程式,在ARM32 上执行会怎样:

$ ./Main
-bash: ./Main: cannot execute binary file: Exec format error

铁定是不给执行的,我们可以用 file 指令来看看两种编译出来的执行档有什么不一样:

$ file Main_x86-64
Main: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=c95fcb56d1a7f19bfafad22d97c41b4f7c1a4cab, for GNU/Linux 3.2.0, not stripped

$ file Main_armv6l
Main: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, BuildID[sha1]=d3e4234fa7a2d36d8f417cc58d34cdfa5971bfb3, for GNU/Linux 3.2.0, not stripped

从这些资讯可以看到两者在位元与CPU 架构上都不相同。在做跨平台开发的时候,若是管理不慎,自己被搞混的事情也是常常发生。笔者这边建议使用 uname -m 的指令,搭配常常用来与编译C 语言相伴的Makefile 来处理这个问题:

CC := @/usr/bin/gcc
Arch := $(shell uname -m)
BuildDir := Build/$(Arch)

all: Main.c
	@mkdir -p $(BuildDir)
	$(CC) Main.c -o $(BuildDir)/Main

在两端分别输入 make 指令进行编译,按几下VSCode 的重新整理后,可以看到工作区底下出现了一个 Build 资料夹,里面包含 armv6l 与 x86_64 两个资料夹,各自包含各自平台的执行档。

Makefile 除了可以当成进阶版的Shell Script 以外,还会自动帮你分析哪些档案需要重新编译。当程式码规模逐渐上升后,在RPi 上整个专案重新编译的时间就会越来越久,善用Makefile 可以替开发者节省不少时间。

注:如果当你的程式码规模已经大到树莓派上没编译个三天三夜编译不完的程度,建议改走Cross-Compile 这条路线。

结论

我们透过SSHFS 的方式,避免VSCode SSH Remote 带来的资源消耗,同时享受VSCode 带来的许多便利,并善用Makefile 区分两边平台的编译结果,希望这篇文章可以帮助到进行跨平台开发的各位。

补充

留言有网友提到若只是需要一个ARM32 的开发环境,用虚拟化技术不是更快吗?确实,如果要进行有规模的开发,采取虚拟化技术是必要的,这样的技术能够更充分的利用硬体效能,提高软体开发的效率。但有些时候虚拟机或容器可能没办法直接满足开发需求,例如:客户装置上的生产序号、装置上感应器的读取、或者像是外接麦克风实际录音等等。在虚拟机里面要实现这些情况,有时并不是那么容易,即便能够实现,也很可能会与实际情况有所落差。所以在实际装置上部署「最低限度」的开发环境,同样也是重要的课题。

而笔者手边只有这块迷你开发板,也不太可能直接拿客户的装置来写文章XD
在这块树莓派上,大多数操作都属于实验性质居多。这里使用SSHFS 只是作为一个概念性验证的手法。因此,在这篇文章并不是要强调它是唯一的方法,而是为了提供给有需要的人参考。

笔记

  • 确认树莓派型号
    • cat /sys/firmware/devicetree/base/model
    • cat /proc/cpuinfo

参考