四博 AI 智能音箱方案基于四博 ESP32-S3 AI-Speaker 核心方案

四博 AI 智能音箱方案

基于四博 ESP32-S3 AI-Speaker 核心方案

1. 方案概述

四博 AI 智能音箱是一套基于 ESP32-S3 / 四博 AI-Speaker 开发板 打造的智能语音硬件方案,面向 AI 陪伴、学习问答、家庭助手、儿童故事机、桌面智能终端、AI 玩具、AI 音响等场景。

方案以 ESP32-S3R8 高性能主控 + 麦克风采集 + 喇叭播放 + LCD 显示 + Wi-Fi/BLE 联网 + 云端/本地智能体接入 为核心,实现语音唤醒、实时语音对话、知识库问答、声音克隆、MCP 工具调用、OTA 升级、素材在线更新等能力。

四博 AI-Speaker 开发板本身为全开源方案,带 240×240 分辨率 1.3 寸屏幕,支持"四博小助手"小程序,支持声音克隆、知识库、自建大模型和 MCP 扩展能力,源码基于 DOIT_AI 工程。


2. 核心硬件选型

2.1 主控方案

推荐主控:

模块 推荐型号 说明
主控 SoC ESP32-S3R8 / ESPS3-32-N16R8 双核 240MHz,适合 AI 音频、LCD、联网、UI
存储 16MB Flash + 8MB PSRAM 支持音频缓存、UI 资源、OTA、协议栈
网络 2.4GHz Wi-Fi + BLE 支持 Wi-Fi 联网、BLE/BluFi 配网
显示 1.3 寸 240×240 或 1.54 寸 LCD 显示表情、状态、歌词、学习卡片
音频 ES8311 Codec / I2S Mic / VB6824 可选 支持采音、播放、离线唤醒
功放 NS4150B / MAX98357A / Class-D 功放 驱动 4Ω/3W 或 8Ω/1W 喇叭
电源 Type-C 5V + 锂电池可选 支持桌面供电或便携式

四博选型资料中,ESP32-S3 系列定位于音视频 / AI 市场,ESPS3-32、ESPS3-32E 系列兼容乐鑫官方模组封装;S3 系列可选 S3R2、S3R8 等规格,适合做通用 AI 方案。

ESP32-S3 相比 C2/C3 更适合 AI 智能音箱,因为它具备双核 240MHz、更多 GPIO、较大的 SRAM/PSRAM 扩展能力,并支持 LCD SPI/RGB/I8080 等显示接口。


3. 产品功能定义

3.1 基础 AI 音箱功能

  1. 语音唤醒

    支持本地唤醒词,例如"小智小智""你好四博"等。

    可选方案:

    • ESP-SR 本地唤醒;

    • VB6824 离线语音芯片唤醒;

    • 按键唤醒;

    • 触摸唤醒。

  2. 实时语音对话

    麦克风采集用户语音,ESP32-S3 通过 WebSocket / HTTP 上传音频流,由云端完成 ASR、LLM、TTS,再回传语音流播放。

  3. AI 学习问答

    支持百科问答、英语口语陪练、古诗词讲解、数学题讲解、亲子故事、课程知识库问答等。

  4. 专业知识库接入

    通过"四博小助手"或后台绑定自定义知识库,让音箱回答指定资料中的内容,例如产品手册、课件、说明书、企业资料。

  5. 声音克隆

    用户录制少量语音后,可生成专属音色,让设备用指定声音播报。四博 AI-S3 方案资料中明确提到可通过小助手实现声音克隆、知识库接入、MCP 扩展和素材/固件在线更新。

  6. MCP 工具调用

    通过大模型工具调用机制,实现"语音控制设备"。例如:

    • "把音量调到 60%"

    • "打开小夜灯"

    • "播放英语单词练习"

    • "切换成睡眠模式"

    • "查询今天的课程表"

  7. 趣味游戏娱乐

    支持成语接龙、猜谜语、口算训练、英语单词闯关、故事续写、角色扮演等。

  8. OTA 升级

    支持固件在线升级、提示音资源更新、UI 素材更新、参数远程配置。开发宝典中 DOIT_AI 工程示例包含 OTA URL 配置项。


4. 系统架构

复制代码
┌──────────────────────────────┐
│        云端 AI 服务平台        │
│ ASR / LLM / TTS / 知识库 / MCP │
└──────────────┬───────────────┘
               │ WebSocket / HTTPS
┌──────────────▼───────────────┐
│        ESP32-S3 AI 主控        │
│ Wi-Fi / BLE / 音频 / LCD / OTA │
├──────────────┬───────────────┤
│              │               │
│          音频系统             │
│  Mic → I2S/Codec → S3 → Amp   │
│              │               │
├──────────────┼───────────────┤
│ LCD UI        │ 按键/触摸/灯效 │
│ 表情/状态/字幕 │ 音量/唤醒/模式 │
└──────────────┴───────────────┘

ESP32-S3 不建议直接在本地运行完整大语言模型。更合理的分工是:

  • ESP32-S3 负责: 音频采集、音频播放、Wi-Fi/BLE、LCD UI、按键、灯效、OTA、协议通信、缓存管理。

  • 云端或局域网服务负责: ASR、LLM 推理、TTS、知识库检索、声音克隆、复杂 MCP 工具编排。

  • 离线语音芯片或 ESP-SR 负责: 唤醒词、简单离线命令、弱网兜底控制。


5. 开发环境

开发环境建议:

项目 建议配置
IDE VSCode
SDK ESP-IDF 5.4.1 / 5.5.x
工程 SmartArduino/DOIT_AI
目标芯片 esp32s3
配网方式 SoftAP / BluFi / 四博小助手
编译方式 idf.py 或 VSCode ESP-IDF 插件

开发宝典中,四博 AI 系统硬件设备开源代码可在 VSCode 中安装 ESP-IDF 扩展和编译工具进行编译烧录;文档示例中安装 ESP-IDF 时选择 v5.5,AI-Speaker S3 编译教程使用 esp-idf 5.4.1。

开发宝典还明确说明,S3 开源工程推荐 ESP-IDF 版本不低于 5.4.0,C5 则需要不低于 5.5.0。


6. 工程配置示例

基于 DOIT_AI 工程,可在:

复制代码
DOIT_AI/main/boards/doit-ai-speaker/sdkconfig.defaults.board

加入或确认类似配置:

复制代码
# 目标芯片
CONFIG_IDF_TARGET="esp32s3"

# Wi-Fi / BLE
CONFIG_BT_ENABLED=y
CONFIG_USE_BLUFI_NET_CONFIGURING=y

# OTA 地址,实际量产时换成自己的 OTA 服务器
CONFIG_OTA_URL="https://your-domain.com/v1/ota/"

# PSRAM,S3R8 建议打开
CONFIG_SPIRAM=y
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384

# FreeRTOS Tick,音频场景建议 1000Hz
CONFIG_FREERTOS_HZ=1000

# 日志级别
CONFIG_LOG_DEFAULT_LEVEL_INFO=y

# WebSocket / HTTPS
CONFIG_ESP_TLS_USING_MBEDTLS=y
CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y

# 分区表建议使用 OTA 分区
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_ota.csv"

编译命令示例:

复制代码
cd DOIT_AI

# 导入 ESP-IDF 环境
. $IDF_PATH/export.sh

# 设置目标芯片
idf.py @main/boards/doit-ai-speaker/build.cfg set-target esp32s3

# 编译
idf.py @main/boards/doit-ai-speaker/build.cfg build

# 合并固件
idf.py @main/boards/doit-ai-speaker/build.cfg merge-bin

# 烧录和监视
idf.py -p COMx flash monitor

开发宝典中给出的 S3 AI-Speaker 编译流程包括克隆 DOIT_AI、配置 doit-ai-speaker 板级配置、设置 esp32s3 目标、执行 build 和 merge-bin。


7. 软件任务设计

建议软件分为 8 个核心任务:

任务 作用
wifi_task Wi-Fi 连接、断线重连、配网
audio_capture_task 麦克风采集、VAD、上传音频
audio_play_task TTS 播放、提示音播放
ai_session_task WebSocket 长连接、AI 会话状态机
ui_task LCD 表情、字幕、状态显示
button_task 按键、音量、打断、配网触发
ota_task 版本检测、固件升级
mcp_task 工具调用、外设控制、学习应用逻辑

状态机建议:

复制代码
BOOT
  ↓
INIT_AUDIO / INIT_LCD / INIT_WIFI
  ↓
PROVISIONING 配网
  ↓
IDLE 待机
  ↓ 唤醒词 / 按键
LISTENING 录音
  ↓
THINKING AI 推理中
  ↓
SPEAKING 播放回复
  ↓ 用户打断
INTERRUPTED
  ↓
LISTENING

8. 关键代码示例

下面代码是基于 ESP-IDF 的技术骨架,实际引脚需要按照四博 AI-Speaker 原理图替换。


8.1 板级配置 board_config.h

复制代码
#pragma once

#include "driver/gpio.h"
#include "driver/spi_master.h"

/*
 * 注意:
 * 下面引脚仅为工程模板示例。
 * 量产时请按四博 AI-Speaker / AI-S3 原理图修改。
 */

#define BOARD_NAME                  "DOIT_AI_SPEAKER_S3"

/* I2S 音频 */
#define PIN_I2S_BCLK                GPIO_NUM_4
#define PIN_I2S_WS                  GPIO_NUM_5
#define PIN_I2S_DIN                 GPIO_NUM_6    // Mic / Codec ADC data
#define PIN_I2S_DOUT                GPIO_NUM_7    // DAC / Amp data
#define PIN_I2S_MCLK                GPIO_NUM_16

/* I2C Codec,例如 ES8311 */
#define PIN_I2C_SDA                 GPIO_NUM_8
#define PIN_I2C_SCL                 GPIO_NUM_9
#define I2C_PORT_AUDIO              I2C_NUM_0

/* LCD SPI */
#define LCD_HOST                    SPI2_HOST
#define PIN_LCD_MOSI                GPIO_NUM_11
#define PIN_LCD_SCLK                GPIO_NUM_12
#define PIN_LCD_CS                  GPIO_NUM_10
#define PIN_LCD_DC                  GPIO_NUM_13
#define PIN_LCD_RST                 GPIO_NUM_14
#define PIN_LCD_BL                  GPIO_NUM_15

/* 按键 */
#define PIN_KEY_WAKE                GPIO_NUM_0
#define PIN_KEY_VOL_UP              GPIO_NUM_1
#define PIN_KEY_VOL_DOWN            GPIO_NUM_2

/* 功放使能 */
#define PIN_AMP_EN                  GPIO_NUM_17

/* 指示灯 */
#define PIN_RGB_LED                 GPIO_NUM_48

/* 音频参数 */
#define AUDIO_SAMPLE_RATE           16000
#define AUDIO_BITS_PER_SAMPLE       16
#define AUDIO_CHANNELS              1
#define AUDIO_FRAME_MS              20
#define AUDIO_FRAME_SAMPLES         (AUDIO_SAMPLE_RATE * AUDIO_FRAME_MS / 1000)

8.2 主程序 app_main.c

复制代码
#include <stdio.h>
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"

#include "board_config.h"
#include "wifi_manager.h"
#include "audio_capture.h"
#include "audio_player.h"
#include "ai_ws_client.h"
#include "ui_display.h"
#include "button_service.h"
#include "ota_service.h"
#include "mcp_service.h"

static const char *TAG = "AI_SPEAKER";

void app_main(void)
{
    ESP_LOGI(TAG, "启动 %s", BOARD_NAME);

    /* 1. NVS 初始化 */
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES ||
        ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ESP_ERROR_CHECK(nvs_flash_init());
    }

    /* 2. 系统事件和网络栈 */
    ESP_ERROR_CHECK(esp_netif_init());
    ESP_ERROR_CHECK(esp_event_loop_create_default());

    /* 3. 外设初始化 */
    ui_display_init();
    ui_display_show_text("四博AI音箱启动中...");

    button_service_init();
    audio_player_init();
    audio_capture_init();
    mcp_service_init();

    /* 4. Wi-Fi / BluFi 配网 */
    wifi_manager_init();
    wifi_manager_start();

    /* 5. AI WebSocket 会话 */
    ai_ws_client_init();

    /* 6. OTA */
    ota_service_init();

    /* 7. 启动任务 */
    xTaskCreatePinnedToCore(audio_capture_task,
                            "audio_capture",
                            8192,
                            NULL,
                            5,
                            NULL,
                            0);

    xTaskCreatePinnedToCore(audio_player_task,
                            "audio_player",
                            8192,
                            NULL,
                            5,
                            NULL,
                            1);

    xTaskCreatePinnedToCore(ai_ws_client_task,
                            "ai_ws_client",
                            10240,
                            NULL,
                            6,
                            NULL,
                            1);

    xTaskCreatePinnedToCore(ota_service_task,
                            "ota_service",
                            6144,
                            NULL,
                            3,
                            NULL,
                            0);

    ui_display_show_text("等待配网/唤醒");
    ESP_LOGI(TAG, "系统初始化完成");
}

8.3 I2S 麦克风采集 audio_capture.c

复制代码
#include <string.h>
#include "esp_log.h"
#include "driver/i2s_std.h"
#include "board_config.h"
#include "ai_ws_client.h"
#include "audio_capture.h"

static const char *TAG = "AUDIO_CAPTURE";

static i2s_chan_handle_t rx_chan = NULL;
static volatile bool g_capture_enabled = false;

void audio_capture_start(void)
{
    g_capture_enabled = true;
}

void audio_capture_stop(void)
{
    g_capture_enabled = false;
}

esp_err_t audio_capture_init(void)
{
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0,
                                                            I2S_ROLE_MASTER);

    ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, NULL, &rx_chan));

    i2s_std_config_t std_cfg = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(AUDIO_SAMPLE_RATE),
        .slot_cfg = I2S_STD_MSB_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT,
                                                    I2S_SLOT_MODE_MONO),
        .gpio_cfg = {
            .mclk = PIN_I2S_MCLK,
            .bclk = PIN_I2S_BCLK,
            .ws   = PIN_I2S_WS,
            .dout = I2S_GPIO_UNUSED,
            .din  = PIN_I2S_DIN,
            .invert_flags = {
                .mclk_inv = false,
                .bclk_inv = false,
                .ws_inv   = false,
            },
        },
    };

    ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &std_cfg));
    ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));

    ESP_LOGI(TAG, "I2S 采集初始化完成: %dHz, %dbit, mono",
             AUDIO_SAMPLE_RATE, AUDIO_BITS_PER_SAMPLE);

    return ESP_OK;
}

void audio_capture_task(void *arg)
{
    int16_t pcm[AUDIO_FRAME_SAMPLES];
    size_t bytes_read = 0;

    while (1) {
        if (!g_capture_enabled) {
            vTaskDelay(pdMS_TO_TICKS(20));
            continue;
        }

        esp_err_t ret = i2s_channel_read(rx_chan,
                                         pcm,
                                         sizeof(pcm),
                                         &bytes_read,
                                         pdMS_TO_TICKS(100));

        if (ret == ESP_OK && bytes_read > 0) {
            /*
             * 可在这里加入:
             * 1. VAD 检测
             * 2. AEC 回声消除
             * 3. AGC 自动增益
             * 4. OPUS 编码
             */
            ai_ws_send_audio((const uint8_t *)pcm, bytes_read);
        } else {
            ESP_LOGW(TAG, "I2S read failed: %s", esp_err_to_name(ret));
        }
    }
}

8.4 AI WebSocket 通信 ai_ws_client.c

复制代码
#include <string.h>
#include "esp_log.h"
#include "esp_websocket_client.h"
#include "cJSON.h"

#include "ai_ws_client.h"
#include "audio_player.h"
#include "ui_display.h"
#include "mcp_service.h"

static const char *TAG = "AI_WS";

#define AI_WS_URL "wss://your-ai-server.com/v1/audio/chat"

static esp_websocket_client_handle_t client = NULL;
static volatile bool ws_connected = false;

static void ai_ws_send_hello(void)
{
    cJSON *root = cJSON_CreateObject();
    cJSON_AddStringToObject(root, "type", "hello");
    cJSON_AddStringToObject(root, "device", "doit_ai_speaker_s3");
    cJSON_AddStringToObject(root, "audio_format", "pcm_s16le");
    cJSON_AddNumberToObject(root, "sample_rate", 16000);
    cJSON_AddNumberToObject(root, "channels", 1);

    char *json = cJSON_PrintUnformatted(root);
    esp_websocket_client_send_text(client, json, strlen(json), portMAX_DELAY);

    cJSON_free(json);
    cJSON_Delete(root);
}

static void handle_json_message(const char *json, int len)
{
    char *buf = calloc(1, len + 1);
    if (!buf) return;

    memcpy(buf, json, len);

    cJSON *root = cJSON_Parse(buf);
    if (!root) {
        free(buf);
        return;
    }

    cJSON *type = cJSON_GetObjectItem(root, "type");
    if (!cJSON_IsString(type)) {
        cJSON_Delete(root);
        free(buf);
        return;
    }

    if (strcmp(type->valuestring, "stt") == 0) {
        cJSON *text = cJSON_GetObjectItem(root, "text");
        if (cJSON_IsString(text)) {
            ui_display_show_text(text->valuestring);
            ESP_LOGI(TAG, "用户说: %s", text->valuestring);
        }
    } else if (strcmp(type->valuestring, "llm") == 0) {
        cJSON *text = cJSON_GetObjectItem(root, "text");
        if (cJSON_IsString(text)) {
            ui_display_show_text(text->valuestring);
            ESP_LOGI(TAG, "AI回答: %s", text->valuestring);
        }
    } else if (strcmp(type->valuestring, "tts_start") == 0) {
        ui_display_show_text("AI正在说话...");
        audio_player_start();
    } else if (strcmp(type->valuestring, "tts_end") == 0) {
        audio_player_stop();
        ui_display_show_text("等待唤醒");
    } else if (strcmp(type->valuestring, "mcp") == 0) {
        mcp_service_handle(root);
    }

    cJSON_Delete(root);
    free(buf);
}

static void websocket_event_handler(void *handler_args,
                                    esp_event_base_t base,
                                    int32_t event_id,
                                    void *event_data)
{
    esp_websocket_event_data_t *data = (esp_websocket_event_data_t *)event_data;

    switch (event_id) {
    case WEBSOCKET_EVENT_CONNECTED:
        ws_connected = true;
        ESP_LOGI(TAG, "WebSocket 已连接");
        ui_display_show_text("AI服务已连接");
        ai_ws_send_hello();
        break;

    case WEBSOCKET_EVENT_DISCONNECTED:
        ws_connected = false;
        ESP_LOGW(TAG, "WebSocket 已断开");
        ui_display_show_text("AI服务断开,重连中");
        break;

    case WEBSOCKET_EVENT_DATA:
        if (data->op_code == 0x1) {
            handle_json_message(data->data_ptr, data->data_len);
        } else if (data->op_code == 0x2) {
            /*
             * 二进制数据作为 TTS 音频流。
             * 格式可以是 PCM / OPUS / MP3,按服务端约定处理。
             */
            audio_player_feed((const uint8_t *)data->data_ptr, data->data_len);
        }
        break;

    case WEBSOCKET_EVENT_ERROR:
        ESP_LOGE(TAG, "WebSocket 错误");
        break;

    default:
        break;
    }
}

esp_err_t ai_ws_client_init(void)
{
    esp_websocket_client_config_t cfg = {
        .uri = AI_WS_URL,
        .buffer_size = 4096,
        .network_timeout_ms = 10000,
        .reconnect_timeout_ms = 3000,
    };

    client = esp_websocket_client_init(&cfg);
    if (!client) {
        return ESP_FAIL;
    }

    esp_websocket_register_events(client,
                                  WEBSOCKET_EVENT_ANY,
                                  websocket_event_handler,
                                  NULL);

    return ESP_OK;
}

void ai_ws_client_task(void *arg)
{
    esp_websocket_client_start(client);

    while (1) {
        /*
         * 这里可以加入心跳、token刷新、断线重连、状态上报。
         */
        if (ws_connected) {
            const char *ping = "{\"type\":\"ping\"}";
            esp_websocket_client_send_text(client,
                                           ping,
                                           strlen(ping),
                                           pdMS_TO_TICKS(1000));
        }

        vTaskDelay(pdMS_TO_TICKS(15000));
    }
}

esp_err_t ai_ws_send_audio(const uint8_t *data, size_t len)
{
    if (!ws_connected || !client || !data || len == 0) {
        return ESP_FAIL;
    }

    int ret = esp_websocket_client_send_bin(client,
                                            (const char *)data,
                                            len,
                                            pdMS_TO_TICKS(100));

    return ret > 0 ? ESP_OK : ESP_FAIL;
}

8.5 按键唤醒与实时打断

复制代码
#include "esp_log.h"
#include "driver/gpio.h"
#include "audio_capture.h"
#include "audio_player.h"
#include "ai_ws_client.h"
#include "ui_display.h"
#include "board_config.h"

static const char *TAG = "BUTTON";

static void IRAM_ATTR key_isr_handler(void *arg)
{
    uint32_t gpio_num = (uint32_t)arg;

    if (gpio_num == PIN_KEY_WAKE) {
        /*
         * 真实项目中不要在 ISR 里直接处理复杂逻辑,
         * 建议投递到队列,这里为了说明简化。
         */
    }
}

void button_service_init(void)
{
    gpio_config_t io_conf = {
        .pin_bit_mask = (1ULL << PIN_KEY_WAKE) |
                        (1ULL << PIN_KEY_VOL_UP) |
                        (1ULL << PIN_KEY_VOL_DOWN),
        .mode = GPIO_MODE_INPUT,
        .pull_up_en = GPIO_PULLUP_ENABLE,
        .pull_down_en = GPIO_PULLDOWN_DISABLE,
        .intr_type = GPIO_INTR_NEGEDGE,
    };

    gpio_config(&io_conf);
    gpio_install_isr_service(0);
    gpio_isr_handler_add(PIN_KEY_WAKE, key_isr_handler, (void *)PIN_KEY_WAKE);
}

/*
 * 建议由 button_task 判断短按、长按、三击:
 * 短按:开始对话 / 打断 TTS
 * 长按:进入配网
 * 三击:恢复出厂或重新配网
 */
void button_on_wake_pressed(void)
{
    ESP_LOGI(TAG, "唤醒键触发");

    /*
     * 如果 AI 正在说话,用户按键表示打断。
     */
    audio_player_stop();
    ai_ws_send_control("{\"type\":\"interrupt\"}");

    ui_display_show_text("请说话...");
    audio_capture_start();
}

开发宝典中 S3 双目板的 QA 也提到,烧录后进入配网状态,可通过三次点按按键进入配网流程;这类按键逻辑可以复用到 AI 音箱方案中。


8.6 MCP 工具调用示例

云端大模型返回:

复制代码
{
  "type": "mcp",
  "tool": "speaker.set_volume",
  "arguments": {
    "volume": 70
  }
}

设备端解析:

复制代码
#include <string.h>
#include "esp_log.h"
#include "cJSON.h"
#include "audio_player.h"
#include "ui_display.h"
#include "mcp_service.h"

static const char *TAG = "MCP";

void mcp_service_init(void)
{
    ESP_LOGI(TAG, "MCP 服务初始化完成");
}

void mcp_service_handle(cJSON *root)
{
    cJSON *tool = cJSON_GetObjectItem(root, "tool");
    cJSON *args = cJSON_GetObjectItem(root, "arguments");

    if (!cJSON_IsString(tool) || !cJSON_IsObject(args)) {
        ESP_LOGW(TAG, "MCP 参数错误");
        return;
    }

    if (strcmp(tool->valuestring, "speaker.set_volume") == 0) {
        cJSON *volume = cJSON_GetObjectItem(args, "volume");
        if (cJSON_IsNumber(volume)) {
            int vol = volume->valueint;
            if (vol < 0) vol = 0;
            if (vol > 100) vol = 100;

            audio_player_set_volume(vol);

            char text[64];
            snprintf(text, sizeof(text), "音量已设置为 %d%%", vol);
            ui_display_show_text(text);

            ESP_LOGI(TAG, "设置音量: %d", vol);
        }
    } else if (strcmp(tool->valuestring, "speaker.play_story") == 0) {
        cJSON *name = cJSON_GetObjectItem(args, "name");
        if (cJSON_IsString(name)) {
            ui_display_show_text("正在播放故事");
            ESP_LOGI(TAG, "播放故事: %s", name->valuestring);
            /*
             * 这里可以请求云端生成故事 TTS,
             * 或播放本地 LittleFS / SD 卡中的音频资源。
             */
        }
    } else if (strcmp(tool->valuestring, "speaker.set_light") == 0) {
        cJSON *mode = cJSON_GetObjectItem(args, "mode");
        if (cJSON_IsString(mode)) {
            ESP_LOGI(TAG, "切换灯效: %s", mode->valuestring);
            /*
             * 例如:
             * mode = sleep / rainbow / breathing / off
             */
        }
    } else {
        ESP_LOGW(TAG, "未知 MCP 工具: %s", tool->valuestring);
    }
}

开发宝典中 AT+MCP 部分提到,四博 AI-01 AT+MCP 固件可以通过 UART AT 指令把"人话"映射为 MCU 能执行的控制帧,并且可用于开灯、调温、拉窗帘等语义控制场景;同样思想可以迁移到 S3 AI 音箱,用 JSON/WebSocket 或 UART 方式实现工具调用。


8.7 OTA 版本检测示例

复制代码
#include "esp_log.h"
#include "esp_http_client.h"
#include "esp_ota_ops.h"
#include "esp_https_ota.h"
#include "ota_service.h"

static const char *TAG = "OTA";

#define OTA_FIRMWARE_URL "https://your-domain.com/firmware/ai_speaker_s3.bin"

void ota_service_init(void)
{
    ESP_LOGI(TAG, "OTA 服务初始化");
}

void ota_service_task(void *arg)
{
    while (1) {
        /*
         * 量产版本建议:
         * 1. 先请求 version.json
         * 2. 对比 version / project_name / chip / md5
         * 3. 确认需要升级后再执行 OTA
         */
        vTaskDelay(pdMS_TO_TICKS(3600 * 1000));
    }
}

esp_err_t ota_start_upgrade(void)
{
    esp_http_client_config_t http_cfg = {
        .url = OTA_FIRMWARE_URL,
        .timeout_ms = 15000,
    };

    esp_https_ota_config_t ota_cfg = {
        .http_config = &http_cfg,
    };

    ESP_LOGI(TAG, "开始 OTA: %s", OTA_FIRMWARE_URL);

    esp_err_t ret = esp_https_ota(&ota_cfg);
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "OTA 成功,准备重启");
        esp_restart();
    } else {
        ESP_LOGE(TAG, "OTA 失败: %s", esp_err_to_name(ret));
    }

    return ret;
}

9. 云端接口建议

9.1 设备上线

复制代码
{
  "type": "hello",
  "device_id": "DOIT-S3-000001",
  "model": "doit_ai_speaker_s3",
  "firmware": "1.0.0",
  "audio": {
    "format": "pcm_s16le",
    "sample_rate": 16000,
    "channels": 1
  },
  "features": {
    "interrupt": true,
    "mcp": true,
    "knowledge_base": true,
    "voice_clone": true
  }
}

9.2 音频上传

复制代码
WebSocket Binary Frame:
PCM 16kHz / 16bit / mono / 20ms frame

9.3 云端下发 TTS

复制代码
WebSocket Binary Frame:
PCM / OPUS / MP3

9.4 云端下发字幕

复制代码
{
  "type": "llm",
  "text": "这个问题可以这样理解..."
}

9.5 云端下发工具调用

复制代码
{
  "type": "mcp",
  "tool": "speaker.set_light",
  "arguments": {
    "mode": "sleep"
  }
}

10. AI 智能音箱应用场景

10.1 儿童学习音箱

  • 英语单词跟读

  • 古诗词背诵

  • 数学口算训练

  • 作文素材启发

  • 百科问答

  • 睡前故事

10.2 桌面 AI 助手

  • 日程提醒

  • 天气播报

  • 语音备忘

  • 智能问答

  • 会议摘要播放

  • 设备控制入口

10.3 AI 陪伴音箱

  • 角色扮演

  • 情绪陪伴

  • 声音克隆

  • 专属人格设定

  • 长期记忆

  • 对话背景音乐

10.4 智能家居语音中控

  • 灯光控制

  • 空调控制

  • 插座控制

  • 窗帘控制

  • 场景模式控制

  • 通过 MCP / UART / MQTT 对接外部 MCU 或网关


11. 量产建议

11.1 硬件建议

模块 建议
麦克风 单麦可做入门款,双麦可做降噪和远场增强
Codec 推荐 ES8311,便于 I2S 录放一体化
功放 3W Class-D,预留 EN 脚做静音控制
屏幕 1.3 寸 240×240 做状态屏,1.54 寸可做高级版本
存储 16MB Flash + 8MB PSRAM 更适合 OTA 和资源缓存
电源 桌面款 Type-C 5V,便携款增加锂电池和充电管理
结构 喇叭腔体与麦克风隔离,减少回声和啸叫

11.2 软件建议

  1. 量产必须做设备唯一 ID

    用 MAC / SN / 证书绑定云端账号。

  2. 音频链路必须支持打断

    用户说话时应立即停止 TTS 播放,切换到录音状态。

  3. 弱网必须做重连和本地提示

    Wi-Fi 断开、AI 服务断开时,LCD 和语音都要提示。

  4. OTA 必须做版本回滚

    使用 A/B 分区,升级失败自动回退。

  5. 隐私设计必须明确

    本地唤醒后才上传音频;可以增加物理静音键。

  6. MCP 工具必须做白名单

    只允许模型调用已注册工具,避免生成非法控制指令。


12. 对外宣传版描述

四博 AI 智能音箱基于 ESP32-S3 高性能 AIoT 核心平台打造,集语音交互、智能问答、学习陪伴、知识库接入、声音克隆、屏幕显示、MCP 工具调用和 OTA 在线升级于一体。设备支持 Wi-Fi/BLE 联网,可通过"四博小助手"完成配网、智能体配置、知识库管理、音色设置和固件更新。凭借 ESP32-S3 双核处理能力、丰富外设接口和四博成熟 AI 硬件开发生态,该方案可快速应用于儿童学习机、AI 故事机、桌面音箱、智能玩具、智能家居语音中控和品牌定制 AI 终端等场景。

相关推荐
学术头条1 小时前
Springer Nature直播预告 | 无人系统集群协同与工程挑战
人工智能·科技·机器学习·ai·agi
@不误正业1 小时前
HarmonyOS-6.0-AI全栈能力解析-Data-Augmentation-Kit到智能体开发实战
人工智能·华为·harmonyos·开源鸿蒙
HackTorjan2 小时前
深度解析雪花算法及其高性能优化策略
人工智能·深度学习·算法·性能优化·dreamweaver
无忧智库2 小时前
碳电融合时代的数字化破局:某能源集团“十五五“VPP与碳交易联动运营系统深度解析(WORD)
大数据·人工智能·能源
果汁华2 小时前
LlamaIndex:连接私有数据与 LLM 的数据框架
人工智能·知识图谱
高工智能汽车2 小时前
从芯片到场景:联发科发布主动式智能体座舱,按下AI汽车进化加速键
人工智能·汽车
元宇宙时间2 小时前
全球信息聚合市场迎来爆发拐点:从边缘实验走向主流基础设施
人工智能
189228048612 小时前
EMMC32G-M525闪存EMMC32G-T527
网络·人工智能
暗夜猎手-大魔王2 小时前
转载--AI Agent 架构设计:工具系统设计(OpenClaw、Claude Code、Hermes Agent 对比)
人工智能