1. 从一块开发板说起:为什么我最终选了 BeagleY-AI
第一次拿到 BeagleY-AI 的时候,我其实没抱太大期望。市面上能跑 AI 推理的开发板太多了,从树莓派加加速棒到各种国产 SoC 方案,选择多到让人麻木。但真正上手用了一段时间之后,我发现这块板子的定位非常清晰——它不是那种"什么都能做但什么都做不精"的通用板,而是在 AI 推理、Python 开发和硬件扩展这三个方向上做了明确的取舍和优化。
BeagleY-AI 的核心是一颗集成了 AI 加速单元的处理器,配合足够大的内存和丰富的接口,让它能在不依赖云端的情况下完成图像分类、目标检测、语音识别等常见推理任务。对于做嵌入式 AI 项目的开发者来说,这意味着你可以把模型直接部署在设备端,不用担心网络延迟、数据隐私和持续的网络成本。
我写这个系列的目的很简单:把我从开箱到跑通第一个 AI 项目、再到接入传感器和外围硬件的完整过程记录下来。市面上很多教程要么只讲软件不讲硬件,要么只给代码不讲原理,中间踩坑的部分全靠自己摸索。我会尽量把每一步的"为什么"讲清楚,让你不仅知道怎么操作,还知道为什么这么做。
这篇文章适合几类人:一是刚接触嵌入式 AI 的开发者,想找一块门槛不高但功能够用的板子入门;二是有 Python 基础但没怎么碰过硬件的软件工程师,想拓展一下技能边界;三是做过一些单片机项目但想往 AI 方向靠的硬件爱好者。不管你属于哪一类,只要跟着走一遍,应该都能在自己的 BeagleY-AI 上跑出结果。
2. 开箱之后别急着上电:硬件接口与系统准备的几个关键决策
2.1 板载接口的布局逻辑与供电方案选择
BeagleY-AI 的接口布局乍一看和常见的单板计算机差不多,但仔细看会发现一些针对 AI 和硬件项目的专门设计。板子一侧是标准的 40 针 GPIO 排针,兼容常见的传感器和执行器模块;另一侧是 USB 接口、以太网口和显示输出。特别值得注意的是它单独引出的 CSI 摄像头接口和 DSI 显示接口,这两个接口在 AI 视觉项目里非常关键。
供电方面,官方推荐使用 5V/3A 的 USB-C 电源。我实测下来,如果你只是跑一些轻量级的推理任务,5V/2.5A 也能凑合,但一旦接上摄像头、显示屏或者多个传感器,供电不足的问题就会暴露出来——表现为系统随机重启或者 USB 设备频繁掉线。这不是板子的问题,而是电源功率不够导致的电压跌落。所以我的建议是一步到位,直接上一个质量靠谱的 5V/3A 电源,省得后面排查半天才发现是供电的锅。
注意:不要用那种十几块钱的廉价电源,空载电压可能标称 5V,但带载后跌到 4.6V 以下,AI 推理时处理器满载运行,电流波动很大,劣质电源根本扛不住。
散热也是容易被忽略的一点。BeagleY-AI 在跑推理任务时,处理器温度会明显上升。我建议至少贴一个铝制散热片,如果要做持续推理或者放在封闭外壳里,最好加一个小风扇。温度过高时处理器会降频,推理速度直接打对折,这个体验落差非常明显。
2.2 系统镜像的选择与烧录:别在第一步浪费时间
BeagleY-AI 支持从 microSD 卡启动,官方提供了基于 Debian 的系统镜像。下载镜像的时候要注意选择对应版本,别下成其他板子的镜像了——虽然名字很像,但设备树和驱动完全不同,烧进去也起不来。
烧录工具我用的是 balenaEtcher,跨平台,操作简单,选镜像、选卡、点烧录,三步搞定。烧录完成后,把卡插回板子,接上电源和网线,等待系统启动。第一次启动会比较慢,因为系统要做一些初始化配置,耐心等两三分钟。
这里有个小技巧:如果你没有显示器,可以通过串口或者 SSH 来访问。串口连接需要一根 USB 转 TTL 的线,接到板子对应的调试串口引脚上,波特率一般是 115200。SSH 的话需要你先知道板子的 IP 地址,可以通过路由器的管理界面查看,或者用网络扫描工具找一下。
提示:第一次启动后尽快修改默认密码,并配置好 SSH 密钥登录,后面用起来会方便很多。
系统起来之后,第一件事是更新软件源和已安装的包。这一步在国内网络环境下可能需要换源,否则下载速度会很慢。换源的方法和普通 Debian 系统一样,修改/etc/apt/sources.list文件,把官方源替换成国内镜像源即可。换完之后执行sudo apt update && sudo apt upgrade,把系统更新到最新状态。
2.3 Python 环境的隔离:为什么我不建议直接用系统 Python
系统自带的 Python 版本通常比较旧,而且直接在上面装包容易和系统工具产生依赖冲突。我的习惯是用虚拟环境来管理项目依赖,这样每个项目有自己独立的包目录,互不干扰。
创建虚拟环境的命令很简单:
sudo apt install python3-venv python3-pip python3 -m venv ~/projects/beagley-ai/venv source ~/projects/beagley-ai/venv/bin/activate激活虚拟环境后,命令行提示符前面会出现(venv)标识,这时候用 pip 安装的包都会装在这个虚拟环境里。退出虚拟环境用deactivate命令。
对于 AI 项目来说,常用的 Python 包包括 NumPy、OpenCV、Pillow 等。如果你要用到深度学习框架,可能还需要安装 ONNX Runtime 或者 TFLite Runtime 的 ARM 版本。这些包在 pip 上都有预编译的 aarch64 版本,直接 pip 安装即可,不需要自己编译。
注意:有些包在 ARM 平台上的预编译版本可能不是最新的,如果遇到兼容性问题,可以尝试指定版本号安装,或者从源码编译。源码编译比较耗时,建议优先找预编译版本。
3. 让板子"看见":摄像头接入与图像采集的完整链路
3.1 CSI 摄像头与 USB 摄像头的取舍
BeagleY-AI 支持两种摄像头接入方式:CSI 排线接口和 USB 接口。这两种方式各有优劣,选择哪种取决于你的具体需求。
CSI 摄像头直接连接到处理器的图像处理单元,延迟低、带宽高,适合需要高帧率或者高分辨率的场景。但 CSI 摄像头的兼容性是个问题,不是所有 CSI 摄像头都能直接用,需要驱动支持。官方推荐的摄像头模块兼容性最好,但价格通常比通用的 USB 摄像头贵一些。
USB 摄像头即插即用,兼容性好,随便一个 UVC 协议的摄像头插上就能用。但 USB 总线的带宽有限,高分辨率下帧率会受限,而且会占用一个 USB 接口。如果你只是做简单的图像分类或者二维码识别,USB 摄像头完全够用。
我自己的方案是:调试阶段用 USB 摄像头,快速验证代码逻辑;正式部署时换成 CSI 摄像头,获得更好的性能和更整洁的接线。
3.2 用 OpenCV 采集图像并验证摄像头工作状态
不管用哪种摄像头,第一步都是确认系统能识别到设备。对于 USB 摄像头,插入后执行ls /dev/video*,如果看到/dev/video0之类的设备节点,说明系统已经识别到了。对于 CSI 摄像头,可能需要加载对应的驱动模块,具体操作参考官方文档。
确认设备存在后,用 OpenCV 写一个最简单的采集程序来验证:
import cv2 cap = cv2.VideoCapture(0) if not cap.isOpened(): print("摄像头打开失败") exit() ret, frame = cap.read() if ret: cv2.imwrite("test_frame.jpg", frame) print(f"采集成功,图像尺寸:{frame.shape}") else: print("帧采集失败") cap.release()这段代码做了三件事:打开摄像头、读取一帧图像、保存为文件。如果运行后能看到test_frame.jpg文件并且图像内容正常,说明摄像头链路是通的。
提示:如果
cv2.VideoCapture(0)打不开,可以试试换成cv2.VideoCapture(0, cv2.CAP_V4L2),显式指定使用 V4L2 后端。在 Linux 系统上,V4L2 是标准的摄像头接口,兼容性最好。
采集到图像之后,你可以用 OpenCV 做各种预处理:缩放、裁剪、颜色空间转换、滤波去噪等等。这些操作在 AI 推理之前通常是必要的,因为模型对输入图像的尺寸和格式有特定要求。
3.3 图像预处理中的常见坑与性能优化
图像预处理看起来简单,但实际做项目时很容易在这里翻车。我踩过的几个坑值得说一下。
第一个坑是颜色空间搞混。OpenCV 默认用 BGR 顺序读取图像,但很多 AI 模型期望的是 RGB 顺序。如果你直接把 OpenCV 读到的图像喂给模型,颜色会偏得离谱,推理结果自然也不对。解决办法是在预处理阶段做一次cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)转换。
第二个坑是归一化参数不一致。不同的模型在训练时用的归一化方式可能不同,有的是除以 255,有的是减均值除标准差。如果你不确定模型期望的输入格式,最稳妥的办法是查模型的文档或者看训练代码。用错了归一化参数,模型精度会大幅下降。
第三个坑是预处理成了性能瓶颈。在嵌入式设备上,CPU 性能有限,如果预处理代码写得不够高效,可能比模型推理本身还慢。我的经验是尽量用 OpenCV 的向量化操作,避免 Python 层面的循环。比如缩放用cv2.resize,颜色转换用cv2.cvtColor,这些都是底层优化过的,比手写循环快得多。
如果预处理确实成了瓶颈,可以考虑用硬件加速。BeagleY-AI 的处理器通常带有图像处理单元或者 GPU,可以通过 OpenCL 或者专用 API 来加速图像操作。不过这部分的配置比较复杂,建议先把基础流程跑通,再考虑优化。
4. 跑通第一个 AI 推理:从模型选择到结果解读
4.1 在嵌入式设备上选模型的三个原则
在 BeagleY-AI 这种嵌入式设备上跑 AI 推理,模型选择和在服务器上完全不同。服务器上你可以随便上一个几百兆的大模型,推理慢一点无所谓。但在嵌入式设备上,内存有限、算力有限,模型选不好直接跑不起来。
我的选型原则有三条。第一,优先选轻量级网络。MobileNet、SqueezeNet、EfficientNet-Lite 这些专为移动端设计的网络,参数量小、计算量低,在嵌入式设备上跑起来比较流畅。第二,优先选量化过的模型。FP32 模型占内存大、计算慢,换成 INT8 量化模型后,内存占用减少四分之三,推理速度也能提升两三倍,精度损失通常在可接受范围内。第三,优先选有现成部署工具的模型。ONNX Runtime、TFLite、NCNN 这些推理框架都有各自的模型格式和转换工具,选一个你熟悉的框架,能省很多事。
以图像分类为例,我推荐从 MobileNetV2 开始。这个网络足够轻量,在 BeagleY-AI 上跑单张图片推理大概几十毫秒,精度也还不错。等跑通之后再尝试其他模型,对比一下速度和精度的权衡。
4.2 模型转换与部署:ONNX 路线的实操步骤
我选择 ONNX 作为模型部署的中间格式,因为 ONNX 的生态比较完善,从各种训练框架导出的模型都能转成 ONNX,然后 ONNX Runtime 在 ARM 平台上的支持也比较好。
假设你已经有一个训练好的 PyTorch 模型,转换步骤如下:
import torch import torch.onnx # 加载模型并设置为推理模式 model = MyModel() model.load_state_dict(torch.load("model.pth")) model.eval() # 构造一个示例输入 dummy_input = torch.randn(1, 3, 224, 224) # 导出为 ONNX torch.onnx.export( model, dummy_input, "model.onnx", input_names=["input"], output_names=["output"], dynamic_axes={"input": {0: "batch_size"}, "output": {0: "batch_size"}}, opset_version=11 )导出之后,可以用onnxruntime在 BeagleY-AI 上加载并推理:
import onnxruntime as ort import numpy as np session = ort.InferenceSession("model.onnx") input_name = session.get_inputs()[0].name # 构造输入数据 input_data = np.random.randn(1, 3, 224, 224).astype(np.float32) # 推理 outputs = session.run(None, {input_name: input_data}) print(outputs[0].shape)如果一切正常,你会看到输出张量的形状,比如(1, 1000)表示 1000 个类别的分类结果。
注意:ONNX Runtime 在 ARM 平台上默认使用 CPU 推理。如果你的模型比较大,推理速度慢,可以考虑用 ONNX Runtime 的 OpenVINO 或者 TensorRT 后端,但 BeagleY-AI 上是否支持这些后端需要查一下文档。
4.3 推理结果的解读与后处理
模型输出的原始张量通常不能直接使用,需要经过后处理才能得到人类可读的结果。以图像分类为例,输出是一个长度为 1000 的向量,每个元素对应一个类别的分数。你需要做的是:
- 对输出向量做 Softmax 归一化,得到每个类别的概率。
- 找出概率最高的几个类别。
- 根据类别索引查标签文件,得到类别名称。
def softmax(x): exp_x = np.exp(x - np.max(x)) return exp_x / exp_x.sum() probs = softmax(outputs[0][0]) top5_idx = np.argsort(probs)[-5:][::-1] for idx in top5_idx: print(f"类别 {idx}: 概率 {probs[idx]:.4f}")对于目标检测模型,后处理会更复杂一些,通常包括解码边界框、非极大值抑制等步骤。这些后处理逻辑在不同的模型之间差异很大,建议直接参考模型作者提供的示例代码。
后处理也是容易出问题的地方。我遇到过因为坐标缩放比例搞错,导致检测框位置完全偏移的情况。排查这类问题的办法是可视化——把检测框画到原图上,一眼就能看出对不对。
5. 从推理到控制:GPIO 与传感器接入的实战细节
5.1 GPIO 操作的安全规范与 Python 库选择
BeagleY-AI 的 40 针 GPIO 排针兼容常见的传感器模块,这为硬件项目提供了很大的便利。但 GPIO 操作有几个必须遵守的安全规范,否则可能烧毁引脚甚至整块板子。
第一,GPIO 引脚的工作电压通常是 3.3V,不要直接接 5V 的信号。如果你用的传感器输出是 5V 电平,需要加一个电平转换模块。第二,每个引脚的输出电流有限制,通常不超过 16mA,驱动 LED 或者小继电器没问题,但驱动电机必须用驱动模块。第三,配置引脚功能之前先查清楚引脚定义,别把电源引脚当成普通 IO 用了。
Python 操作 GPIO 常用的库有gpiod和libgpiod的 Python 绑定。较新的系统推荐用gpiod,因为旧的RPi.GPIO库主要是为树莓派设计的,在其他板子上兼容性不好。
import gpiod from gpiod.line import Direction, Value # 打开 GPIO 芯片 chip = gpiod.Chip("/dev/gpiochip0") # 配置引脚为输出模式 line = chip.get_line(17) line.request(consumer="led", type=gpiod.LINE_REQ_DIR_OUT) # 输出高电平 line.set_value(1)这段代码把 17 号引脚配置为输出并置高。实际操作时,引脚编号需要根据板子的引脚定义来确定,不同板子的编号方式可能不同。
5.2 接入温湿度传感器:I2C 通信的完整流程
I2C 是传感器接入中最常用的协议之一,接线简单,两根信号线加电源线就能通信。以常见的温湿度传感器为例,接入流程如下。
首先确认 I2C 总线已经启用。执行ls /dev/i2c-*,如果看到/dev/i2c-1之类的设备节点,说明 I2C 已经可用。然后用i2cdetect工具扫描总线上的设备:
sudo apt install i2c-tools sudo i2cdetect -y 1如果传感器连接正常,你会看到对应的地址被列出来,比如0x44或者0x76。
确认设备存在后,用 Python 读取数据。我通常用smbus2这个库,它比标准的smbus库更好用:
from smbus2 import SMBus bus = SMBus(1) address = 0x44 # 发送读取命令 bus.write_byte(address, 0x2C) # 读取 6 个字节的数据 data = bus.read_i2c_block_data(address, 0x00, 6) # 解析数据(具体解析方式取决于传感器型号) temp_raw = (data[0] << 8) | data[1] temp = -45 + 175 * temp_raw / 65535 print(f"温度:{temp:.2f} °C")提示:不同传感器的寄存器地址和数据格式不同,上面的代码只是示例。实际使用时一定要查传感器的数据手册,确认命令字节和数据解析方式。
I2C 通信中常见的问题是地址冲突和上拉电阻缺失。如果总线上挂了多个设备,地址不能重复。如果通信不稳定,可能是上拉电阻没接或者阻值不合适,通常 4.7kΩ 到 10kΩ 之间比较合适。
5.3 把 AI 推理结果和硬件控制串起来
单独跑 AI 推理或者单独控制硬件都不难,真正有意思的是把两者结合起来。比如做一个智能垃圾分类项目:摄像头采集图像,AI 模型识别垃圾类别,然后根据识别结果控制舵机把垃圾分到不同的桶里。
这个流程的代码结构大概是这样的:
import cv2 import onnxruntime as ort import gpiod # 初始化摄像头 cap = cv2.VideoCapture(0) # 初始化推理会话 session = ort.InferenceSession("garbage_classifier.onnx") # 初始化 GPIO chip = gpiod.Chip("/dev/gpiochip0") servo_line = chip.get_line(18) servo_line.request(consumer="servo", type=gpiod.LINE_REQ_DIR_OUT) while True: ret, frame = cap.read() if not ret: continue # 预处理 input_blob = preprocess(frame) # 推理 outputs = session.run(None, {"input": input_blob}) class_id = np.argmax(outputs[0]) # 根据类别控制舵机 if class_id == 0: set_servo_angle(servo_line, 0) elif class_id == 1: set_servo_angle(servo_line, 90) else: set_servo_angle(servo_line, 180)这个框架可以套用到很多场景:智能门禁(人脸识别控制电磁锁)、智能农业(识别病虫害控制喷药)、智能家居(手势识别控制灯光)等等。核心逻辑都是"感知-推理-决策-执行"这个闭环。
实际做项目时,实时性是个需要关注的问题。如果推理速度跟不上摄像头帧率,就需要跳帧处理,或者降低输入图像的分辨率。另外,GPIO 操作和推理最好放在不同的线程里,避免相互阻塞。
6. 调试与优化:那些文档里不会写的经验
6.1 系统卡顿和推理变慢的排查思路
用了一段时间之后,你可能会发现系统变慢了,推理时间从几十毫秒涨到几百毫秒。这种情况通常有几个原因。
最常见的是散热问题。处理器温度过高触发降频,性能直接打折。排查方法是查看处理器温度:
cat /sys/class/thermal/thermal_zone0/temp返回值除以 1000 就是摄氏度。如果超过 80°C,就需要加强散热了。
第二个原因是内存不足。AI 推理很吃内存,如果同时跑了其他占内存的服务,系统会频繁使用交换分区,速度自然就慢了。用free -h查看内存使用情况,如果可用内存很少,考虑关掉不必要的服务,或者换一块内存更大的板子。
第三个原因是后台进程占用 CPU。用top或者htop看看哪个进程在偷跑 CPU,把不需要的进程关掉。
6.2 模型推理速度优化的几个实用手段
如果排查完系统问题,推理速度还是不理想,可以从模型层面做优化。
第一个手段是量化。把 FP32 模型转成 INT8 模型,推理速度通常能提升两到三倍,模型体积也缩小到四分之一。ONNX Runtime 提供了量化工具,操作不算复杂:
from onnxruntime.quantization import quantize_dynamic, QuantType quantize_dynamic( "model.onnx", "model_quantized.onnx", weight_type=QuantType.QUInt8 )第二个手段是裁剪输入尺寸。如果你的模型输入是 224x224,但实际场景中 128x128 就够用,那就把输入改小。计算量通常和输入尺寸的平方成正比,从 224 降到 128,计算量减少到原来的三分之一左右。
第三个手段是使用多线程推理。ONNX Runtime 支持配置线程数:
options = ort.SessionOptions() options.intra_op_num_threads = 4 session = ort.InferenceSession("model.onnx", options)BeagleY-AI 通常有四个 CPU 核心,设置成 4 能充分利用多核性能。但也不是线程越多越好,线程太多反而会因为上下文切换开销导致性能下降,一般设置成物理核心数就行。
6.3 长时间运行项目的稳定性保障
做 Demo 和做产品是两回事。Demo 跑几分钟没问题,但产品需要连续运行几天甚至几个月不出故障。我在长时间运行的项目中总结了几条经验。
第一,加看门狗。BeagleY-AI 的处理器通常有硬件看门狗,可以在系统卡死时自动重启。配置看门狗需要写内核模块参数或者用systemd的看门狗功能,具体操作查一下系统文档。
第二,日志要写好。程序运行时的关键信息都要记日志,出问题时才有据可查。Python 的logging模块就够用了,配置好日志级别和输出文件,定期清理旧日志避免占满磁盘。
第三,异常处理要到位。摄像头掉线、传感器读取失败、推理出错,这些异常都要捕获并处理,不能让程序直接崩溃。我的习惯是在主循环外面包一层try-except,出错后记录日志、释放资源、等待几秒后重试。
第四,定期重启。如果程序有内存泄漏或者资源释放不干净的问题,定期重启是最简单有效的解决办法。可以用cron定时任务每天凌晨重启一次服务,对大多数项目来说影响可以忽略。
提示:如果你的项目对可用性要求很高,可以考虑双机热备方案,一台出问题另一台顶上。不过这会增加成本和复杂度,根据实际需求权衡。
7. 关于这块板子和这个系列,我的一些个人体会
BeagleY-AI 给我的感觉是一块"务实"的板子。它没有堆砌最顶级的硬件参数,而是在 AI 推理能力、Python 生态兼容性和硬件扩展性之间找到了一个不错的平衡点。对于想入门嵌入式 AI 的开发者来说,它的学习曲线比较平缓,社区文档也在逐步完善。
这个系列的第一篇主要覆盖了从开箱到跑通 AI 推理加硬件控制的完整链路。后面我计划继续写模型训练和部署的进阶内容、多传感器融合的案例、以及如何把项目从原型变成可以长期运行的产品。如果你跟着这篇文章走了一遍,应该已经能在自己的 BeagleY-AI 上跑出一些有意思的东西了。
最后分享一个我在嵌入式项目里一直坚持的习惯:每做一步都先验证再继续。不要一口气写完所有代码再运行,而是写一小段就测一小段。摄像头能出图了再写预处理,预处理对了再接模型,模型跑通了再加硬件控制。这样出问题时排查范围小,定位快,整体效率反而比"一口气写完再调试"高得多。