当前位置: 首页 > news >正文

【项目经验】小智ai源码学习记录

项目文件结构

拿到一个新的项目,要先了解文件结构,理清都有什么。
打开main文件夹能看到如下结构,其中,最重要的就是下方这四个文件。
在这里插入图片描述
main.cc是程序入口。
CMakeLists.txt是编译用到的配置文件,可以通过这个文件了解到项目都包含哪些文件。
idf_component.yml配置的是项目依赖的库,从下图能看到,编译后这些组件会被下载到managed_components文件夹下。
在这里插入图片描述
kconfig.projbuild是项目的配置文件,打开SDK配置编辑器就能看到相关的配置内容。
在这里插入图片描述

功能模块

就像分析一个函数一样,分析项目的功能也是类似的思路,先找到一个入口,不断深入,直到出口。小智ai接受一段音频,通过麦克风将数据给到esp32-s3,由esp32解析后通过协议发送到后端服务器,等接收到返回数据后再由喇叭和LCD屏幕输出。(也就是搞懂数据流)
在这里插入图片描述
我这里使用的是master分支(2025年7月16日)。基于面向对象的思想,整个项目被分为五大模块:板级模块boards、音频接受与发送audio_codecs、音频处理audio_processing、显示模块display和协议模块protocols。我们从主函数入手。

extern "C" void app_main(void)
{// Initialize the default event loopESP_ERROR_CHECK(esp_event_loop_create_default());// Initialize NVS flash for WiFi configurationesp_err_t ret = nvs_flash_init();if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {ESP_LOGW(TAG, "Erasing NVS flash to fix corruption");ESP_ERROR_CHECK(nvs_flash_erase());ret = nvs_flash_init();}ESP_ERROR_CHECK(ret);// Launch the applicationApplication::GetInstance().Start();

主函数很简洁,做了三件事,初始化事件循环event_loop,初始化nvs_flash,调用Application的start()函数。进入start函数,能看到先创建了一个board,再由board创建display和codec

void Application::Start() {auto& board = Board::GetInstance();SetDeviceState(kDeviceStateStarting);/* Setup the display */auto display = board.GetDisplay();/* Setup the audio codec */auto codec = board.GetAudioCodec();......
}

抽象类Board实现了开发板级的抽象,这里使用了工厂模式,可以通过配置来实现在编译时,创建不同的开发板对象。
GetInstance()调用create_board()来创建开发板对象。

public:static Board& GetInstance() {static Board* instance = static_cast<Board*>(create_board());return *instance;}

而create_board()则根据DECLARE_BOARD的配置,去new了一个对象。

#define DECLARE_BOARD(BOARD_CLASS_NAME) \
void* create_board() { \return new BOARD_CLASS_NAME(); \
}

打开SDK配置编辑器,找到Xiaozhi Assistant,修改Board Type选项,我这里选择的是面包板新版接线(WiFi),对应的是BOARD_TYPE_BREAD_COMPACT_WIFI。在Kconfig.projbuild文件能看到下面的内容。

choice BOARD_TYPEprompt "Board Type"default BOARD_TYPE_BREAD_COMPACT_WIFIhelpBoard type. 开发板类型config BOARD_TYPE_BREAD_COMPACT_WIFIbool "面包板新版接线(WiFi)"depends on IDF_TARGET_ESP32S3

之后在CMakeLists.txt文件内可以找到如下内容。

# 根据 BOARD_TYPE 配置添加对应的板级文件
if(CONFIG_BOARD_TYPE_BREAD_COMPACT_WIFI)set(BOARD_TYPE "bread-compact-wifi")

这里将BOARD_TYPE 配置成了bread-compact-wifi。我们可以到boards/bread-compact-wifi文件夹下的compact_wifi_board.cc文件内看到

DECLARE_BOARD(CompactWifiBoard);

再回到create_board(),就能知道这里执行的是new CompactWifiBoard(),创建了Board的实现类CompactWifiBoard。
后面创建codec和display都是执行的由CompactWifiBoard实现的方法。

    virtual AudioCodec* GetAudioCodec() override {
#ifdef AUDIO_I2S_METHOD_SIMPLEXstatic NoAudioCodecSimplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,AUDIO_I2S_SPK_GPIO_BCLK, AUDIO_I2S_SPK_GPIO_LRCK, AUDIO_I2S_SPK_GPIO_DOUT, AUDIO_I2S_MIC_GPIO_SCK, AUDIO_I2S_MIC_GPIO_WS, AUDIO_I2S_MIC_GPIO_DIN);
#elsestatic NoAudioCodecDuplex audio_codec(AUDIO_INPUT_SAMPLE_RATE, AUDIO_OUTPUT_SAMPLE_RATE,AUDIO_I2S_GPIO_BCLK, AUDIO_I2S_GPIO_WS, AUDIO_I2S_GPIO_DOUT, AUDIO_I2S_GPIO_DIN);
#endifreturn &audio_codec;}virtual Display* GetDisplay() override {return display_;}

先来看看GetAudioCodec(),这个函数返回了AudioCodec对象,也就NoAudioCodecSimplex的父类。在这个项目中,这种实现方式很常见,无论是board还是codec等,都是先创建了一个抽象类,再去实现具体子类,对应文件夹下有很多子类实现。这就是面向对象的编程思想,C语言没有类的概念,也就没有继承和多态,得益于esp32的高性能,可以使用C++来实现应用层代码,大大提高了开发效率和代码的复用能力,当我们需要适配自己的开发板和外设时,只需要实现对应的子类,再修改一下配置,上层的应用代码根本不需要修改。

类NoAudioCodecSimplex的构造函数就很简单了,配置了I2S,初始化了扬声器和麦克风。

未完待续…

http://www.lryc.cn/news/591068.html

相关文章:

  • Webpack5 新特性与详细配置指南
  • 基于LSTM的机场天气分析及模型预测
  • Python eval函数详解 - 用法、风险与安全替代方案
  • Go语言学习日志(一)
  • Python应用进阶DAY7--面向对象编程基本特性和super函数
  • 电子电路中的电压符号命名约定
  • FreeSWITCH配置文件解析(6) mod_format_cdr 话单中字段解析
  • 浅谈自动化设计最常用的三款软件catia,eplan,autocad
  • 云服务器如何设置防火墙和安全组规则?
  • Linux内核网络栈深度剖析:inet_connection_sock.c的服务器端套接字管理
  • 【算法训练营Day13】二叉树part3
  • 华为P30/pro (ELE-AL00) 鸿蒙4.2降级 EMUI 9
  • 服务器数据恢复—raid5磁盘阵列崩溃如何恢复数据?
  • 集群聊天服务器各个类进行详解
  • Cookie 与 Session概述
  • 【神经网络在MATLAB中是如何实现的?】
  • 构建可扩展的测试体系,从设计、优化到持续维护
  • 2D视觉系统标定流程与关键要求
  • VSCODE调教
  • 《前端基础核心知识笔记:HTML、CSS、JavaScript 及 BOM/DOM》
  • yolov8-pos/yolov11-pos 训练
  • 6、docker network
  • UE5 lumen
  • Linux搭建LAMP环境(CentOS 7 与 Ubuntu 双系统教程)
  • FastAdmin系统框架通用操作平滑迁移到新服务器的详细步骤-优雅草卓伊凡
  • lua(xlua)基础知识点记录二
  • STM32上移植Lua解析器
  • Android15系统实现刷机防呆功能
  • 【JVM】深入理解 JVM 类加载器
  • MySQL如何解决事务并发的幻读问题