0、写在前面
很高兴收到官方的OrangePi AIpro开发板测试邀请,在过去的几年中,我在自己的博客写了一系列有关搭载嵌入式Linux系统的SBC(单板计算机)的博文,包括树莓派4系列、2K1000龙芯教育派、Radxa Rock5B、BeagleBone等。
OrangePi AIpro开发板最吸引我的地方是它使用了华为昇腾的处理器和支持华为昇腾AI技术路线。
开发板本身质感满满,整体尺寸和Radxa Rock5B一致,板上接口丰富,有type-c电源接口、2*HDMI 2.0、音频接口、USB Type-C 3.0(非全功能)、千兆网口、Wi-Fi5&BT4.2模块(RTL8821)、TF插槽、eMMC模块接口、M.2插槽、40PIN引脚等。
本次测评中,我会从软硬件出发体验OrangePi AIpro开发板,针对开发板的优点和缺点给出自己的观点。
1、使用SSH和VNC连接开发板
得益于官方系统已经内置了SSH和VNC服务,在接通网线、电源之后,可以通过路由器后台管理界面获取OrangePi AIpro开发板的IP,同一网段下的电脑即可使用SSH或VNC远程控制香橙派 AIpro开发板。
官方系统具有两个账号:root / Mind@123 , HwHiAiUser / Mind@123;密码相同。
可以使用MobaXterm、Putty等软件或终端进行SSH远程连接,SSH端口为22。
我使用RealVNC Viewer远程连接香橙派 AIpro开发板桌面,VNC Server为IP::5901,点击OK之后点击新建的连接输入密码:Mind@123 。
完成上图所示操作后,即可进入桌面,默认用户为ROOT,VNC会方便我们进行一些可视化操作。
注意:如果VNC登录后出现卡顿情况或者无法操作,可以重启服务
# 停止正在运行的服务,-kill后面的数字可以在VNC远程连接窗口左上角查看
(base) root@orangepiaipro:~# vncserver -kill :1
Killing Xtightvnc process ID 917
# 重新启动刚才停止的服务
(base) root@orangepiaipro:~# vncserver :1
New 'X' desktop is orangepiaipro:1
Starting applications specified in /root/.vnc/xstartup
Log file is /root/.vnc/orangepiaipro:1.log
通过使用SSH和VNC两种方式,我们就可以把开发板放在合适的地方,通过自己的个人电脑进行后续的测试工作
2、使用SSD烧录Ubuntu系统镜像
虽然测试提供了安装好系统的32GB TF卡,但是可用空间已经比较小了,如下图所示,可用空间还剩下10几GB
出于空间和系统流畅性角度考虑,我将使用一块江波龙的64GB NVME协议 SSD固态硬盘作为系统盘。
开发板M.2接口在Linux系统中默认nvme协议,使用sata协议需要修改配置,在window系统中使用balenaEtcher进行烧录
把boot1拨到右端,boot2拨到左端后,上电成功进入系统,使用df -h
和lsblk
命令查看系统空间和磁盘情况
❗注意❗
在开发板用户手册中说明:NVMe SSD目前测试了樊想、金士顿和三星的,只有三星的NVMe SSD能稳 定运行Linux系统。
我这里使用的江波龙64GB Nvme SSD只是做个人测试使用。
3、OrangePi AIpro开发板功耗
这里我把TF和SSD区分开进行测试,功耗测试仪器为合宙IoT Power功耗测试仪。
3.1 使用TF的情况
刚上电开机时,功耗比较高,检测到的最高值在11.7W左右。
进入桌面后,在没有其他操作的情况下,功耗约为7.7W-8W,使用网页应用功耗在10.5W左右。
3.2 使用SSD的情况
刚上电开机时,功耗峰值在13W左右。
进入桌面后,在没有其他操作的情况下,功耗约为8.6W,使用网页应用功耗在11W左右。
3.3 分析
首先是开机时的功耗比较高,个人猜测是风扇的原因,上电到系统启动完成的这段时间风扇的转速很快,其他时间风扇转速比较平缓,以TF卡系统为例,风扇高速转动时和待机缓转时,总功耗差距4W左右。
其次是当打开软件,系统负载增加时,功耗也会有所增加;
最后根据固态硬盘额定功率的不同,开发板的总功耗也会相应增加,以我使用的江波龙64GB NVME SSD来说,对比TF卡,在上述三种场景下功耗增加分别在11.11%、11.68%、4.8%左右。
4、UnixBench跑分
UnixBench是一个广泛使用的基准测试工具,用于评估类Unix操作系统(如Linux、BSD等)的性能。它通过运行一系列的测试来测量系统的各种性能指标,包括CPU、内存、文件系统、图形和多任务处理能力。UnixBench的测试结果可以帮助系统管理员和开发人员了解其系统的性能水平,并与其他系统进行比较。
# 下载阿里云版本unixbench
wget https://github.com/aliyun/byte-unixbench/releases/download/v5.1.6/UnixBench-5.1.6.tar.gz
tar -zxvf UnixBench-5.1.6.tar.gz
cd UnixBench-5.1.6/UnixBench
./Run
分数仅供参考:单核776.5分,多核1641.1分,跑分结果截图如下:
在相同条件下,对比使用RK3588的Rock 5B开发板,如下图所示。昇腾310B是4核且默认情况还会分配一个AI CPU,RK3588是8核,比较多核性能意义不大,就我本次测试来说,单核两者相差约23.9%。
5、使用USB摄像头和安装OpenCV
这里使用的是UVC免驱USB摄像头,接入摄像头
# 检测外部摄像头设备的命令
ls /dev/video*
官方手册上说/dev/video1是来采集metadata的,那我们插入的设备为:/dev/video0
使用fswebcam软件,在安装fswebcam时发现系统已经安装过了
# 在/home/HwHiAiUser目录下生成一张当前摄像头拍摄到的实时照片
fswebcam -d /dev/video0 --no-banner -r 1920x1080 -S 10 /home/HwHiAiUser/image.jpg
在我执行pip3 list
时,发现系统已经安装了numpy 1.22.4,opencv-python-headless 4.9.0.80,opencv-python-headless是一个不带图形界面的版本的OpenCV,它可以用来进行图像处理和计算机视觉任务,但是不能用来显示图像或视频,这对于运行在无图形界面的服务器上的应用程序很方便,因为它可以节省资源。在Python程序中使用方式也是import cv2
。
下面我提供一个测试程序,处理视频流并保存为文件。
# -*- coding: utf-8 -*-
import cv2
import time
# 打开摄像头
cap = cv2.VideoCapture(0)
if not cap.isOpened():
print("Cannot open camera")
exit()
# 定义视频编码器和输出文件
fourcc = cv2.VideoWriter_fourcc(*'XVID')
out = cv2.VideoWriter('output.avi', fourcc, 20.0, (640, 480))
# 获取当前时间
start_time = time.time()
while True:
# 读取视频帧
ret, frame = cap.read()
if not ret:
print("Cannot read frame")
break
# 写入视频帧
out.write(frame)
# 检查是否时间已经超过5秒
if time.time() - start_time > 5:
print("Recorded 5 seconds, exiting")
break
# 释放摄像头和视频写入器
cap.release()
out.release()
sudo apt-get install mpv
安装mpv,mpv output.avi
进行视频播放。
如果你需要使用OpenCV的GUI功能,你应该安装完整的opencv-python
包,使用pip install opencv-python
进行安装。
6、使用开发板点亮RGB灯
OrangePi AIpro开发板具有40个Pin接口引脚,如下图所示。我将使用12、13、15三个GPIO引脚和14 GND 引脚进行简单的测试点亮RGB灯。
引脚 | 功能 | GPIO | GPIO序号 |
12 | GPIO7_03 | 227 | |
13 | GPIO1_06 | 38 | |
14 | GND | ||
15 | GPIO2_15 | 79 |
在系统中预装了gpio_operate工具可以读取、设置GPIO的输入输出方向和置0置1
# 切换root用户
su
# 获取12、13、15引脚GPIO方向,0:输入方向,1:输出方向
gpio_operate get_direction 7 3
gpio_operate get_direction 1 6
gpio_operate get_direction 2 15
设置12、13、15引脚GPIO方向为输出方向
gpio_operate set_direction 7 3 1
gpio_operate set_direction 1 6 1
gpio_operate set_direction 2 15 1
查询12、13、15引脚GPIO 电平,如下图所示,都为低电平。
gpio_operate get_value 7 3
gpio_operate get_value 1 6
gpio_operate get_value 2 15
R接12引脚、G接13引脚、B接15引脚,GND接14 GND。
# 设置12、13、15引脚GPIO 为高电平
gpio_operate set_value 7 3 1
gpio_operate set_value 1 6 1
gpio_operate set_value 2 15 1
# 设置12、13、15引脚GPIO 为低电平
gpio_operate set_value 7 3 0
gpio_operate set_value 1 6 0
gpio_operate set_value 2 15 0
编写shell脚本测试,给脚本添加可执行权限:chmod +x gpio_RGB.sh
#!/bin/bash
# 数组包含需要执行的命令
commands=(
"gpio_operate set_value 7 3 1"
"gpio_operate set_value 7 3 0"
"gpio_operate set_value 1 6 1"
"gpio_operate set_value 1 6 0"
"gpio_operate set_value 2 15 1"
"gpio_operate set_value 2 15 0"
)
# 无限循环执行命令,每隔0.5秒执行一条,ctrl+c结束执行
while true
do
for cmd in "${commands[@]}"
do
eval $cmd
sleep 0.5
done
done
7、使用Docker并配置开发板为 MQTT服务器
通过命令查询,发现系统已经默认安装了docker,并且有一个测试的hello-world镜像。
(base) root@orangepiaipro:/home/HwHiAiUser# docker --version
Docker version 25.0.3, build 4debf41
(base) root@orangepiaipro:/home/HwHiAiUser# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest ee301c921b8a 12 months ago 9.14kB
下载Docker 图形化web管理 portainer
#下载 Docker 图形化界面 portainer
sudo docker pull portainer/portainer
#创建 portainer 容器
sudo docker volume create portainer_data
#运行 portainer
sudo docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
运行之后在浏览器中输入IP:9000 进入界面。首次访问需要设定登录密码
配置EMQX 开源版,EMQX (Erlang/Enterprise/Elastic MQTT Broker)是基于 Erlang/OTP 平台开发的开源物联网 MQTT 消息服务器。
# 获取 Docker 镜像
docker pull emqx/emqx:5.6.1
# 启动 Docker 容器
docker run -d --name emqx -p 1883:1883 -p 8083:8083 -p 8084:8084 -p 8883:8883 -p 18083:18083 emqx/emqx:5.6.1
用IP:18083 进入EMQX服务器后台,默认账号:admin ,默认密码:public
测试代码-发布消息
import paho.mqtt.client as mqtt
import time
# 链接回调
def on_connect(client, userdata, flags, rc):
print ("链接")
print("Connected with result code: " + str(rc))
# 消息内容回调
def on_message(client, userdata, msg):
print("消息内容")
print(msg.topic + " " + str(msg.payload))
# 订阅回调
def on_subscribe(client, userdata, mid, granted_qos):
print("订阅")
print("On Subscribed: qos = %d" % granted_qos)
pass
# 取消订阅回调
def on_unsubscribe(client, userdata, mid, granted_qos):
print("取消订阅")
print("On unSubscribed: qos = %d" % granted_qos)
pass
# 发布消息回调
def on_publish(client, userdata, mid):
print("发布消息")
print("On onPublish: qos = %d" % mid)
pass
# 断开链接回调
def on_disconnect(client, userdata, rc):
print("断开链接")
print("Unexpected disconnection rc = " + str(rc))
pass
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.on_publish = on_publish
client.on_disconnect = on_disconnect
client.on_unsubscribe = on_unsubscribe
client.on_subscribe = on_subscribe
# keepalive 心跳间隔,单位是秒,如果 broker 和 client 在这段时间内没有任何通讯,client 会给 broker 发送一个 ping 消息
# retain 如果设为 Ture ,这条消息会被设为保留消息
client.connect('192.168.5.220', 1883, 60) # 60为keepalive的时间间隔
while True:
client.publish(topic='mqtt', payload='OrangePi AiPro', qos=0, retain=False)
time.sleep(5)
测试代码-接收消息
import paho.mqtt.client as mqtt
# 链接回调
def on_connect(client, userdata, flags, rc):
print("Connected with result code: " + str(rc))
# 消息信息回调
def on_message(client, userdata, msg):
print(msg.topic + " " + str(msg.payload))
# 订阅回调
def on_subscribe(client, userdata, mid, granted_qos):
print("On Subscribed: qos = %d" % granted_qos)
pass
# 取消订阅回调
def on_unsubscribe(client, userdata, mid):
print("取消订阅")
print("On unSubscribed: qos = %d" % mid)
pass
# 发布消息回调
def on_publish(client, userdata, mid):
print("发布消息")
print("On onPublish: qos = %d" % mid)
pass
# 断开链接回调
def on_disconnect(client, userdata, rc):
print("断开链接")
print("Unexpected disconnection rc = " + str(rc))
pass
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.on_publish = on_publish
client.on_disconnect = on_disconnect
client.on_unsubscribe = on_unsubscribe
client.on_subscribe = on_subscribe
client.connect('192.168.5.220', 1883, 60) # 60为keepalive的时间间隔
#当 qos>0 时,发送消息队列的最大值,默认是 0 ,表示无限制。当队列满时,旧消息会丢弃。
client.subscribe('mqtt', qos=0)
#loop_forever() => 该函数是保持永久连接, 阻塞式,可结合多线程或多进程的方式使用
client.loop_forever() # 保持连接
经过测试,我们的部署是没有问题的
8、昇腾310B独特的机制:AI CPU和Control CPU切换
npu-smi是昇腾AI处理器的系统管理工具,类似于NVIDIA GPU的 nvidia-smi,通过npu-smi info
命令我们可以查看到AI处理器名称为310B4(8T算力版本)。
根据开发手册所说:OrangePi AiPro使用的昇腾SOC总共有4个CPU,这4个CPU既可以设置为control CPU,也可以设置为AICPU。默认情况下,control CPU和AI CPU的分配数量为 3:1。
# 查看control CPU和AI CPU的分配数量
(base) root@orangepiaipro:/home/HwHiAiUser# npu-smi info -t cpu-num-cfg -i 0 -c 0
Current AI CPU number : 1
Current control CPU number : 3
Current data CPU number : 0
# 查询AI CPU占用率
(base) root@orangepiaipro:/home/HwHiAiUser# npu-smi info -t usages -i 0 -c 0
Memory Capacity(MB) : 7545
Memory Usage Rate(%) : 27
Hugepages Total(page) : 15
Hugepages Usage Rate(%) : 100
Aicore Usage Rate(%) : 0
Aicpu Usage Rate(%) : 0
Ctrlcpu Usage Rate(%) : 0
Memory Bandwidth Usage Rate(%) : 1
# 查询芯片的算力档位
(base) root@orangepiaipro:/home/HwHiAiUser# npu-smi info -t nve-level -i 0 -c 0
nve level : 8T_1.0GHz
# 设置AI CPU为0,最多可以设置3个AI CPU(3:1:0,最后的0为data CPU,固定配置为 0)
sudo npu-smi set -t cpu-num-cfg -i 0 -c 0 -v 0:4:0
查阅资料,我发现昇腾310有8核心版本和4核心版本,OrangePi AiPro搭载的是4核心版本。可以根据我们的实际需求,灵活切换control CPU和AI CPU的分配数量,最多可以设置3个AI CPU。
9、AI应用样例体验
OrangePi AiPro开发板系统提供了9个AI应用样例,我们可以使用Jupyter notebook快速体验。
9个AI样例分别是目标检测、文字识别、目标分类、图像曝光增强、卡通图像生成、蛋白质分类评估、细胞图像分割、人像分割与背景替换和语音识别。
我选取其中1个进行体验。启动Jupyter Lab,如下图所示:
复制地址在开发板浏览器中打开
点击左侧的01 yolov5后,双击打开main.ipynb。
首先就是对act工具转换模型为om模型的介绍,本展现了模型推理过程的代码。
点击红框内的箭头运行案例,得到一段识别后的视频,通过修改infer_mode可以选择图片、视频或摄像头。
在 infer_image
和infer_frame_with_vis
函数中添加时间记录,打印处理的时间
import time
def infer_image(img_path, model, class_names, cfg):
"""图片推理"""
# 记录开始时间
start_time = time.time()
# 图片载入
image = cv2.imread(img_path)
# 数据预处理
img, scale_ratio, pad_size = preprocess_image(image, cfg)
# 模型推理
output = model.infer([img])[0]
output = torch.tensor(output)
# 非极大值抑制后处理
boxout = nms(output, conf_thres=cfg["conf_thres"], iou_thres=cfg["iou_thres"])
pred_all = boxout[0].numpy()
# 预测坐标转换
scale_coords(cfg['input_shape'], pred_all[:, :4], image.shape, ratio_pad=(scale_ratio, pad_size))
# 图片预测结果可视化
draw_prediction(pred_all, image, class_names)
# 记录结束时间
end_time = time.time()
# 计算并输出推理时间
inference_time = end_time - start_time
print(f"Inference time: {inference_time:.4f} seconds")
def infer_frame_with_vis(image, model, labels_dict, cfg, bgr2rgb=True):
# 记录开始时间
start_time = time.time()
# 数据预处理
img, scale_ratio, pad_size = preprocess_image(image, cfg, bgr2rgb)
# 模型推理
output = model.infer([img])[0]
output = torch.tensor(output)
# 非极大值抑制后处理
boxout = nms(output, conf_thres=cfg["conf_thres"], iou_thres=cfg["iou_thres"])
pred_all = boxout[0].numpy()
# 预测坐标转换
scale_coords(cfg['input_shape'], pred_all[:, :4], image.shape, ratio_pad=(scale_ratio, pad_size))
# 图片预测结果可视化
img_vis = draw_bbox(pred_all, image, (0, 255, 0), 2, labels_dict)
# 记录结束时间
end_time = time.time()
# 计算并输出推理时间
inference_time = end_time - start_time
print(f"Inference time for frame: {inference_time:.4f} seconds")
return img_vis
此时打印了视频推理每一帧所用的时间,大约0.05S,每秒19fps左右
10、写在最后
在这几天的体验OrangePi AiPro开发板的过程中,上手体验非常好,优点如下:
-
官方提供的系统镜像已经做了很多预先的配置工作,可以更快上手。如默认开启的ssh、vnc服务等,内置的docker、conda、torch_npu、MindSpore等等,这对新手来说就少了很多配环境的折磨,可以更快的进入到AI应用的学习和实践。
-
对于发布半年左右的开发板,提供的开发资料非常详细。用户手册写的非常详细了,对 Linux 内核源码包和Linux 镜像编译脚本都做了详细的说明。
-
支持昇腾技术路线。昇腾从硬件底层到软件平台应用有一整套技术解决方案,有昇腾处理器、异构计算机构CANN、深度学习框架MindSpore等,OrangePi AiPro不单单是一个“树莓派”,更是帮助开发者去实践昇腾AI技术的高性价比载体。
-
OrangePi AiPro开发板背靠昇腾社区和香橙派社群,技术支持更多。昇腾社区提问帖子基本都有跟帖,香橙派目前在国内的口碑也非常不错,产品线和支持都很给力,在遇到问题的时候,更容易解决问题。
OrangePi AiPro开发板搭载的昇腾310B4芯片也给我很多惊喜,可以根据实际需求,灵活切换control CPU和AI CPU的分配数量。在最近,更是可以通过固件更新的方式,将频率从1.0Ghz提高到1.6Ghz,实现单核性能50%以上的提升。
但是在测评中,也有一些问题和相关的建议:
-
在当前系统使用中,HDMI0不能输出音频信号,HDMI1接口不能输出桌面视频信号。希望能在下个版本的系统中完成适配。
-
提供了一个USB3.0 Type-c接口,如果能在后续硬件版本中实现全功能Type-c功能就更好了。
-
目前的开发者手册虽然很详细,但是希望能增加一些昇腾相关内容,建议增加npu-smi工具使用和CANN、MindSpore相关内容。
总结一下,OrangePi AiPro是一块优秀的SBC,同时它的价格也会使它成为入门昇腾技术路线的最佳选择之一,非常适合学生学习和竞赛使用。