大家好,今天给大分享一个OrangePi AIpro(20T)采用昇腾作为主控芯片的开发板,开箱以及对应功能的详细实现。

第一:板子基本介绍

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_嵌入式硬件

     接通电源给对应的开发板上电,观察其中的现象,如下:

      注意事项:开发板上有电源对应的Type-C接口,不要接错了。

     

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_#include_02

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_嵌入式硬件_03

1:控制启动设备3个拨码开关

      开发板的linux系统下支持从TF卡、EMMC和SSD启动,具体从哪个设备启动是通过3个拨码开关进行选择的,启动之前要检查一下。   

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_单片机_04

     从图上可以清晰的看出来对应系统的启动方式。

      注意事项:切换拨码开关后必须重新拔插电源上电才能启动设备选择生效。通过开发板复位按键来复位系统是不会让拨码开关设置配置生效的。

2:开发利用调试串口的方法 

      开发板默认使用uart0做为调试串口。需要注意的是,uart0的tx和rx引脚同时接到了两个地方,所以有两种使用调试串口的方法:

       第一种方法:

uart0 的 tx 和 rx 引脚接到了 40 pin 扩展接口中的 8 号和 10 号引脚,此种方式需要准备一个 3.3v 的 USB 转 TTL 模块和相应的杜邦线,然后才能正常使用开发板的调试串口功能。

                            

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_#include_05

        第二种方法:

uart0 的 tx 和 rx 引脚还接到了开发板的 CH343P 芯片上,再通过 CH343P 芯片引出到 Type-C USB 接口上。此种方式只需要一根 Type-C USB 接口的数据线将开发板连接到电脑的 USB 接口就可以开始使用开发板的调试串口功能了,无需购买 USB 转 TTL 模块。这种方法是推荐的方法。

                                 

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_#include_06

        注意事项:上面的两种方式只能二选一,请不要同时使用。

第二:环境搭建与测试

1:Windows平台使用调试串口方法

             1、直接安装对应的超级终端软件。

             2、选择串口波特率为115200.

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_开发板_07

             3、点击“OK”按钮后会进入下面的界面,此时启动开发板就能看到串口的输出信息了。

2:利用Windows PC将linux镜像烧写到TF卡的方法

      1、要有一张大容量的TF卡,TF 卡的传输速度必须为 class10 级或 class10 级以上,建议使用闪迪等品牌的 TF 卡。

      2、然后把 TF 卡插入读卡器,再把读卡器插入电脑。

      3、下载想要烧录的 Linux 镜像压缩包。

      4、下载用于烧录 Linux 镜像的软件——balenaEtcher,下载地址为:

              https://www.balena.io/etcher/

      5、进入 balenaEtcher 下载页面后,点击绿色的下载按钮会跳到软件下载的地方。

                         

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_单片机_08

选择下载 Portable 版本的 balenaEtcher,Portable 版本无需安装,双击打


开就可以使用。


                

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_单片机_09

              并进行双击打开。

              

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_嵌入式硬件_10

使用 balenaEtcher 烧录 Linux 镜像的具体步骤如下所示:


         a. 首先选择要烧录的 Linux 镜像文件的路径。


         b. 然后选择 TF 卡的盘符。


         c. 最后点击 Flash 就会开始烧录 Linux 镜像到 TF 卡中。


         

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_客户端_11

          

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_#include_12

成功烧录完成后 balenaEtcher 的显示界面如下图所示,如果显示绿色的指示图


标说明镜像烧录成功,此时就可以退出 balenaEtcher ,然后拔出 TF 卡插入到开发板的 TF 卡槽中使用了。


              

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_嵌入式硬件_13

注意事项:启动系统前请确保拨码开发拨到了TF卡启动的位置了。拨码开关的使用请参考说明。

3:Ubuntu Xfce桌面系统使用

进入 Ubuntu 镜像的下载链接后可以看到下图所示的两个 ubuntu 镜像,他们的


区别是:


         1) minimal 镜像是一个只有最基础功能的镜像,像 Linux 桌面、 CANN 和 AI 示例代码等都没有预装。此镜像只建议想自己从头定制安装 Linux 桌面和 AI 相关软件的开发者使用。


          2) desktop 镜像预装了 Linux 桌面、 CANN 、 AI 示例代码和一系列测试程序。如果想正常使用开发板的功能,请使用这个镜像。本章的内容都是基于 desktop 镜像编写的。


               

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_开发板_14

        Linux系统功能适配情况:

       

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_单片机_15

      

4:利用开发板无线连接

      1、使用 nmcli dev wifi 命令扫描周围的 WIFI 热点。

            命令:nmcli dev wifi

      2、然后使用 nmcli 命令连接扫描到的 WIFI 热点,其中:

      a. wifi_name 需要换成想连接的 WIFI 热点的名字。

       b. wifi_passwd 需要换成想连接的 WIFI 热点的密码。

            命令:sudo nmcli dev wifi connect wifi_name passwordwifi_passwd

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_#include_16

    开发板中使用的交叉编译工具链如下:

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_开发板_17

第三:香橙派开发板AI实现   

1、人工智能目标检测

     SSD(Single Shot MultiBox Detector)是一种流行且高效的单阶段目标检测算法,它在处理速度和检测精度之间取得了良好的平衡。与传统的两阶段方法(如 R-CNN 系列)不同,SSD 在单个网络前向传递中直接预测目标的边界框和类别,无需先生成候选区域。这种方法不仅加快了目标检测速度,而且简化了检测流程。

     将SSD人工智能算法(算法代码详见sample文件夹),放入欧拉实验平台,点击运行。

    

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_客户端_18

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_客户端_19

实现现象如下:

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_单片机_20

人工智能源码分析:

      要使用这个文件进行模型评估,你需要使用与该文件兼容的框架和API。以下是一个使用 MindSpore 读取 .mindrecord 文件的基本示例:

  1. 安装 MindSpore: 确保你的环境中安装了 MindSpore。你可以访问 MindSpore 的官方网站获取安装指导。
  2. 读取文件: 使用 MindSpore 提供的 API 读取 .mindrecord 文件,并将数据加载到模型中进行评估。
from mindspore import context
from mindspore.dataset import MindDataset

# 设置环境
context.set_context(mode=context.GRAPH_MODE, device_target="CPU")

# 创建数据集
dataset = MindDataset("path/to/ssd_eval.mindrecord0")

# 配置数据集,例如批处理大小等
dataset = dataset.batch(32)

# 使用数据集
for data in dataset.create_dict_iterator():
    images = data["image"]
    labels = data["label"]
    # 这里可以加入模型评估的代码
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
分析数据

在使用这种文件时,你可能需要了解数据的具体结构,比如数据中包含的标签、图像尺寸等。你可以使用 MindSpore 的数据集查看工具来检查 .mindrecord 文件中的内容,以便更好地理解和使用数据。

2、人工智能实现文字识别

        该人文字识别主要是将图像中的文字区域转化为字符信息,能够提取丰富的信息特征,采用ResNet算法模型,提取网络信息,其中包含转换后的om模型和测试图片,详细实现如下:

     找到源码,存放在欧拉平台,双击点开。

     

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_客户端_21

      打开图片文字转化代码,利用CNN网络提取丰富的特征信息,进行识别。

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_客户端_22

    提示编译成功的效果,注意观察启动的现象。

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_客户端_23

  最终成功输出的结果如下:

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_#include_24

文字识别现象解析:

要使用 ResNet 模型进行图片预测,你需要以下几步:

  1. 环境准备:确保 Python 环境中已安装必需的库,如 torch, torchvision
  2. 模型加载:加载预训练的 ResNet 模型。torchvision 提供了多种 ResNet 模型,如 ResNet-18, ResNet-50 等。
  3. 图片处理:将图片调整为模型所需的输入大小,并进行必要的预处理,比如标准化。
  4. 预测:将处理过的图片输入模型,获取预测结果

 基础案例实现:

import torch
from torchvision import models, transforms
from PIL import Image

# 加载预训练的 ResNet50 模型
model = models.resnet50(pretrained=True)
model.eval()  # 设置为评估模式

# 图片预处理
transform = transforms.Compose([
    transforms.Resize(256),
    transforms.CenterCrop(224),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

# 加载图片
img = Image.open("predict.png")  # 确保这里的路径与你的图片路径相对应
img_t = transform(img)
batch_t = torch.unsqueeze(img_t, 0)

# 进行预测
with torch.no_grad():
    output = model(batch_t)
    _, predicted = torch.max(output, 1)

# 获取类别标签
classes = [...]  # 这里需要一个类别列表,你可以从 ImageNet 的类别中获取
print("Predicted class:", classes[predicted.item()])
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.

3、人工智能远程聊天实现

       利用人工智能开发板作为服务器,收集远程客户端发送过来的信息,处理完毕之后也可以将对应的信息发送给客户端,实现远距离自由聊天功能。

      详细代码如下(欢迎评论区交流学习)

       服务器代码实现:

//服务器代码的具体实现
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <pthread.h>
#include <stdlib.h>

//1声明对应线程的个数
pthread_t pthread_max[5] = {0};

void *broadcast_clt(void *arg)
{
    int i;
	long a = (long )arg;
	char buf[100] = {0};
	
	printf("a = %ld\r\n",a);
	
	//获取客户端的clifd
	int clifd = pthread_max[a];
	
	printf("clifd = %d\r\n",clifd);
	
	//获取对应客户端发过来的信息
	while(1)
	{
		//获取内容recv
		recv(clifd,buf,100,0);
		printf("clifd = %d\r\n",clifd);
		
		//将获取到的内容转发给其他的客户端
		for(i = 0; i < 5; i++)
		{
			if((pthread_max[i] !=0) && (pthread_max[i] !=clifd))
			{
				//传输对应buf的内容
			    send(pthread_max[i],buf, 100, 0);
			}
		}
		
		usleep(500);	
	}
	
}




int main(int argc , char *argv[])
{
    //定义变量
     int clifd;
     socklen_t addrlen=sizeof(struct sockaddr);
     long i;
     pthread_t tid[10];
	
	//2 定义实现socket函数
	int serfd = -1;
    int new_sfd = -1;
    serfd = socket(AF_INET, SOCK_STREAM, 0);
    
	//3 定义实现bind函数
	#define SERVER_IP "192.168.1.111"
    #define PORT_NUM 1111

    typedef struct sockaddr SA;
    typedef struct sockaddr_in SIN; 

    SIN seraddr;
    SIN cliaddr;
    bzero(&seraddr,sizeof(SIN));  //功能类似memset()
    seraddr.sin_family=AF_INET;
    seraddr.sin_port=htons(PORT_NUM);
    seraddr.sin_addr.s_addr=inet_addr(SERVER_IP);  //对IP地址进行转化

    //将服务器地址信息与套接字进行绑定
	
	//实现本机地址重复使用
    int ret;
	int reuse = 1;
    ret = setsockopt(serfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse));
	
    ret = bind(serfd,(SA*)&seraddr,sizeof(SA));
    if(ret == -1)
    {
	  perror("connect failed\r\n");
	  exit(0);
    }
	
	//利用listen函数监听
	ret = listen(serfd,10);
    if(ret == -1)
    {
	perror("listen failed\r\n");
	exit(0);
    }
	
	while(1)
	{
	 //进入到循环函数里面完成通信
     clifd = accept(serfd,(SA*)&cliaddr,&addrlen);
     if(clifd == -1)
     {
	  perror("accept failed\r\n");
	  exit(0);
     }
	 
	 printf("accept success\r\n");
	 printf("clifd = %d\r\n",clifd);
	 
	 //保存一下对应的值
	 for(i = 0; i < 5; i++)
	 {
	     if(pthread_max[i] == 0)
	     {
	 	 pthread_max[i] = clifd;
	 	 pthread_create(&tid[i], NULL, broadcast_clt, (void *)i);
	     break;
	     }
	 }
      
      
	 }
	 //收回对应的文件描述符
	 close(serfd);
	 for(i = 0; i < 5; i++)
	 {
			if(pthread_max[i] > 0)
			{
				close(pthread_max[i]);
			}
	 }
	 
	 exit(0);

}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.

      客户端代码具体实现:

//客户端代码实现
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <string.h>
#include <semaphore.h>
#include <stdlib.h>


char send_buf[100] = {0};
char recv_buf[100] = {0};


void * send_srv(void *arg)
{
	long a = (long)arg;  //文件描述符
	int b = (int)a;
	
	int send_len;
	//发生数据
	while(1)
	{
	    scanf("%s",send_buf);
		
		//发送对应的字符串
        send_len = send(b,send_buf,sizeof(send_buf),0);
        if(send_len == -1)
        {
	     perror("failed\r\n");
	     exit(0);
        }
		
		printf("send success\r\n");
	
	}
	
	pthread_exit(NULL);
}


void *recv_srv(void *arg)
{
	long a = (long)arg;  //文件描述符
	int b = (int)a;
	
	//接受数据
	while(1)
	{
		recv(b,recv_buf,100,0);
		printf("recv_buf : %s\r\n",recv_buf);
	}
	pthread_exit(NULL);
}


int main(int argc , char *argv[])
{
    //定义变量
	pthread_t tid1,tid2;


	//建立通信端口socket
	int serfd;
    serfd = socket(AF_INET,SOCK_STREAM,0);
    if(serfd == -1)
    {
	perror("socket failed\r\n");
	exit(0);
    }
	
	//绑定对应的地址信息connect
	#define SERVER_IP "192.168.1.111"
    #define PORT_NUM 1111

    typedef struct sockaddr SA;
    typedef struct sockaddr_in SIN; 

    SIN seraddr;
    bzero(&seraddr,sizeof(SIN));  //功能类似memset()
    seraddr.sin_family=AF_INET;
    seraddr.sin_port=htons(PORT_NUM);
    seraddr.sin_addr.s_addr=inet_addr(SERVER_IP);  //对IP地址进行转化

    //将服务器地址信息与套接字进行绑定
    int ret;
    ret = connect(serfd,(SA*)&seraddr,sizeof(SA));
    if(ret == -1)
    {
	  perror("connect failed\r\n");
	  exit(0);
    }
	
	//提示一下客户端创建成功
	printf("connect success\r\n");
	
	
	long send_cfd = (long )serfd;
	
	pthread_create(&tid1, NULL, send_srv, (void *)send_cfd);
	pthread_create(&tid2, NULL, recv_srv, (void *)send_cfd);
	
	//等待对应的线程运行结束
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	
	exit(0);
	
	
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.
  • 110.
  • 111.
  • 112.
  • 113.
  • 114.
 第一步:利用ubuntu中的sftp通信传输AI开发板

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_嵌入式硬件_25

第二步:在AI开发板上编译服务器代码

         开发板上的编译命令:

         aarch64-linux-gnu-gcc -pthread service.c -o ser  

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_开发板_26

第三步:在个人电脑上实现客户端代码编译

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_开发板_27

第四:任意聊天具体实验现象

嵌入式香橙派人工智能AI开发板详细操作与远程聊天实现_开发板_28

第四:性能分析

    1、负载
      能够使用20G左右的模型,进行编译,能够实时进行推理60FPS的视频,同时推理一张640*640的图像大约只要15-20ms,目前没有做量化设计,精度还是fioat16,做完In量化后,应该还可以进一步提升。
    2、散热
Orange AlPro 在散热方面还是做的比较好的,配备了散热风扇,运行3个小时后,板子的温度还是处于一个较低的温度,个人觉得散热效果还是比较让人满意的。
     3、噪音
     这几天下来,只有在开机启动的时候大约有6~10s左右比较大的声音,但也在可接受范围内,平时运行各种AI模型都是静默的,几乎感受不到风扇的声音存在。     

      开发板Orange PiAPro 性能稳定,主打一个性价比!搭载的华为昇腾A!处理器,以 8TOPS 的INT8 算力和 4 TFLOPS FP16 的浮点运算能力,为复杂AI模型提供了强大的计算支撑。我在8G版本的 Orange PiAlPro上成功的运行了 MusicGen模型,其模型参数大小为 2.2G这对于 8G 版本的 Orange PiAIPro 来说,无疑是一个极大的挑战。板子在运行时内存使用超 90%,但是散热真的很好,风扇噪音较小,整块处理器的问题摸起来并不烫手,即使在满载的情况下运行半小时左右,处理器的温度略高于手指温度。

第五:产品评价

       经过这两天操作香橙派开发板,感触颇深,硬件和系统的稳定性还是非常好的,基本上这块板子的所有外设和人工智能的实例都操作完了,还是非常容易上手的,开发文档比较齐全。

       可以使用的操作系统也非常丰富,香橙派AiPro支持Ubuntu、openEuler等操作系统,这为用户提供了更多的选择空间,同时也方便了用户根据自己的需求进行开发和部署。

      总体感受:香橙派开发板性能优越,易于上手,各种开发工具包齐全,非常适合新手,后期将继续分享优秀的人工智能项目,欢迎大家评论和相互交流学习。