在这里插入图片描述
注:本文是以瑞芯微RK3588作为硬件平台而进行的示例开发,其他Rock chip系列的产品如:RK3568, RV1126等;理论上示例的内容也同样可以作为参考;

相关学习参考资料网址:
Rockchip官方的模型转换工具下载地址:https://github.com/airockchip/rknn-toolkit2
Rockchip官方提供的模型示例下载地址:https://github.com/airockchip/rknn_model_zoo
PaddleOCR v4模型学习地址:https://github.com/PaddlePaddle/PaddleOCR
Openedv为正点官方网站,有丰富的嵌入式资料可以下载:http://www.openedv.com

应用程序下载:
本示例代码的github地址:https://github.com/Kingdomwhisky/ai_RK3588_project
如果只想下载可执行文件,也可以前往本人论坛下载:http://www.openedv.com/forum.php?mod=viewthread&tid=353840&extra=


前言

Rock chip这一系列的芯片,算是目前国内很流行的ARM芯片,目前其产品广泛应用于智能座舱、机器人、工业视觉、消费电子等多个领域;尤其是在当下AI这一时代的浪潮下,其高端的功能和应用也不断吸引着开发者去探索和创新;本文的目的之一就是想结合目前Rock chip官方提供的AI模型例程,再加上个人浅薄的理解,进行一些应用方面的拓展开发。希望本文给出的示例内容,能够给在嵌入式领域前行的各位带来或多或少的帮助或灵感。


1 相关算法模型

无论是何种AI模型,其都遵循着:模型训练 —> API接口调用模型 —> 编写应用程序 —> 经过交叉编译 —> 在硬件平台上实现运行

模型训练

API接口调用模型

编写应用程序

经过交叉编译

硬件平台上运行

若想在开发板上正常运行AI模型,那么大致需要满足以下条件:
1> 交叉编译工具:/opt/atk-dlrk3588-toolchain/bin/aarch64-buildroot-linux-gnu ; 用于编译C++程序的;

2> 模型转换工具: RKNN-Toollkit2 是基于 Python 语言实现的模型转换工具,可将其他训练框架导出的模型
转为 RKNN 模型,并提供较为有限的推理接口,协助用户测试模型转换效果。RKNPU2 是板端的组件,提供 NPU 驱动,并基于 C 语言提供模型加载、模型推理等功能。RKNPU2 具有一致的版本号。不同版本之间可能存在不兼容问题,为了避免造成不必要的麻烦,推荐用户使用同一版本的 RKNN-Toolkit2、RKNPU2;【下载地址见文章顶部,目前最新版本为2.3.2;本示例使用的是2.0.0-beta0版

3>部署到硬件平台: 下载模型(xxx.onnx),转换模型(xxx.rknn), 交叉编译出可执行文件(rknn_xxx_demo);


在这里插入图片描述
PaddleOCR v4 是一款基于百度飞桨(PaddlePaddle)深度学习框架开发的文字识别(OCR)工具。它继承了 PaddleOCR 系列模型的优势,并在性能和功能上进行了全面升级。其文字识别功能就是本示例的核心,利用其文字识别这一点来进行个性化的拓展应用;


2 应用程序功能介绍

在这里插入图片描述
将摄像头的数据作为输入传递给ppocr模型进行实时推理,mipi摄像头(imx415)通过ppocr的AI模型算法识别到的文字信息,将特定的信息作为相关的控制命令,从而达到文字识别控制系统这一目的;
目前已实现的功能:
1> 通过识别文字"ON" / “OFF” 来控制音乐的播放和结束;
2> 待开发(大家可自由发挥【狗头】)……

字符命令 响应操作
ON 开始播放音乐
OFF 结束音乐播放

3 调试中的问题与记录

3.1 问题点1

Question 1>
如何将模型的输出作为有效ID进行响应?

Reply 1:
编写相应的字符串转换处理函数,并与想要执行的操作对应;


3.2 问题点2

Question 2>
在原来的工程下新增一个media.c和media.h进去,运行build.sh脚本进行编译的时候,新增的两个文件没有参与到编译中?

Reply2:
修改CMakeLists.txt 文件内容,确保在add_executable()或add_library()命令中包含了新增的源文件。例如:

add_executable(your_target_name main.c media.c) # 假设你的可执行文件名为 your_target_name

3.3 问题点3

Question 3>
RK3588在代码方面可以通过system(“gst-play-1.0 ./music/boat.mp3”)成功播放音乐,但是摄像头画面会被卡住,音乐播放完却又能正常工作了?
Reply3:
播放音频时,若出现摄像头画面被卡住的现象,可能与以下原因有关:
1.‌资源竞争问题‌:
gst-play-1.0 是一个基于 GStreamer 的音频播放工具,它在播放音频时会占用一定的 CPU 资源和系统带宽。如果系统中同时运行了摄像头采集任务(如通过 V4L2 接口),那么当音频播放启动时,可能会导致 CPU 资源不足或系统调度冲突,从而影响到摄像头采集线程的正常运行。
2.‌GStreamer 线程调度影响‌:
GStreamer 播放器内部使用多线程处理音频解码和输出,如果在播放过程中没有正确设置线程优先级或资源隔离机制,可能导致摄像头采集线程被阻塞或调度延迟。
3.‌音频和视频处理共享硬件资源‌:
在 RK3588 上,音频和视频处理可能共享某些硬件资源(如内存带宽、DMA 控制器等),在高负载情况下,音频播放可能会影响视频采集的流畅性。
4.‌系统负载过高‌:
如果系统整体负载较高,例如同时运行多个高负载任务,gst-play-1.0 的启动和执行可能会进一步加剧系统资源紧张,进而影响摄像头采集线程的正常工作。

解决方案:

  • 优化线程优先级‌:确保摄像头采集线程具有较高的调度优先级,避免被音频播放线程抢占资源。

  • ‌使用独立线程播放音频‌:避免在主线程中调用 system(),改用独立线程执行 gst-play-1.0,减少对主流程的影响。
    (本人选用为Audio的动作响应函数创建一个独立的线程来解决同一进程下资源的抢占冲突,避免摄像头的处理过程中出现阻塞状态,导致画面卡住这一问题现象)


4 部分代码说明

对应的程序代码已上传至github网站上:https://github.com/Kingdomwhisky/ai_RK3588_project
各位可自行前往下载查看,如果觉得还不错的话请帮我点亮星星,让笔者也能star+1,嘿嘿……
如果只想下载可执行文件,当然也可以,可前往本人openedv论坛进行下载:openedv地址


main.cc

    //Change Camera devices num: /dev/video-camera0 -> video44
    cv::VideoCapture cap(44); //(KW 2026-01-18)  

这里是通过调用了opencv的函数来打开摄像头的,由于每个人平台的必定是会存在差异性的,要与自己设备实际的节点对应上才能正常打开摄像头;如果连摄像头都没打开,就别谈后续的识别处理及应用了
在这里插入图片描述


media.cc

/*************************************************************/
/*Define some charecter process function
/*Author: Kunwei He
/*Date: 2026-01-19
/*************************************************************/
unsigned char play_valid = 0x00;
int CMD_Audio = 0;

int ppocr_Charecter_convert_Commond(char *res_char , int res_score)
{

    //play_valid++;
    if(res_score < 60)
    {
        printf("[Score is: %d] < 60, not a useful CMD!\r\n", res_score);
        return 0xFF;
    }
    else
    {   //Score >= 60%
        printf("[Score is: %d], useful CMD!\r\n", res_score);
    }

    if(strcmp(res_char, "ON") == 0)
    {
        if(play_valid == 0x00)
        {
            play_valid++;
            if(play_valid >= 0xF0) play_valid = 0x01;  //Prevent data overflow (KW 2026-01-19)
            printf("Start play music!\r\n");
            return 1;
        }

    }
    else if(strcmp(res_char, "OFF") == 0)
    {
        if(play_valid != 0x00)
        {
            play_valid = 0x00;
            printf("Stop play music!\r\n");
            return 0;
        }

    }
 
    return 0xFF;
}

考虑到摄像头实时捕获处理数据的速度还是很快的,如果只是单纯地在收到对应的文字信息命令后就直接进行响应处理,那么其会带来这样一个问题:"摄像头每次识别到 “ON”“OFF” 都会进行动作响应,那对于本示例的而言就是会不断地执行打开或关闭动作,这对于一个控制系统而言肯定是不合理的;所以代码中增加了一个命令有效响应的标志位play_valid,参考MCU的按键有效检测的方式去模拟开关响应控制;


5 功能演示

调试终端下通过shell命令来运行目标程序:

cd "${程序存放的位置}"  #用cd命令进到对应的路径下,然后按如下格式运行C++应用程序
./rknn_ppocr_system_demo model/ppocrv4_det.rknn model/ppocrv4_rec.rknn

下面为笔者在MobaXterm的串口调试终端下的运行示范:
在这里插入图片描述

实际效果视频如下:
演示视频地址:https://www.bilibili.com/video/BV1PPzKBpEEw/?vd_source=744160e6008aa9d91be374ebcfc105da


6 总结

那么至此,本文也算是告一段落了。已经有很长一段时间没写过和技术相关的帖子了,好像自从毕业后就没再碰过了,开始工作后就老想着躺平了(哈哈~ )。说实话如果不是因为个人的变数,估计我也不会去主动学习RK3588;而在一开始学习3588的时候也挺迷茫的,里面不仅功能模块繁多,还分不同的大方向,一开始也是抱着能成功运行例程就算OK的心态进行下去的;在经过一段时间的摸索后,还是决定编写点个人的东西出来,也算是给自己当前阶段的学习成果做个总结了;当本示例编写出来后自身突然有种释然的感觉,也算是没太过虚度光阴了吧[Dog]……

由于本人水平有限,所以难免会有疏漏之处,欢迎大家一起交流讨论。如果大家能够通过本篇内容或多或少找到点启发的话那么本文也算是发挥其该有的价值了。最后,感谢各位阅读本文!

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐