四博 AI 智能音箱方案:基于 ESP32-S3 打造远场拾音、多网络接入、可二次开发的 AI 语音终端

下面是头条推文版技术方案稿 ,已按你要求:不引用 TXT 文件内容 ,只结合前面几个 PDF 文件里的模组手册、AI 硬件选型表和 AI 开发宝典来写。重点强化了:5 米远场拾音、高噪声可用、唤醒词打断、实时打断、自定义唤醒词、蓝牙/Wi-Fi/4G 多联网、单屏/双屏/异显、ESP32-S3 二次开发、客户系统接入

四博 AI 智能音箱方案:基于 ESP32-S3 打造远场拾音、多网络接入、可二次开发的 AI 语音终端

AI 音箱真正难的地方,不是"接一个大模型",而是把远场拾音、噪声抑制、实时打断、唤醒词管理、多网络接入、屏幕显示、客户系统对接和 OTA 量产升级全部打通。

李博士讲解的四博 AI 音箱方案,核心特点可以概括为:

复制代码
拾音距离远:5 米以上仍可对话
高噪声可用:复杂噪声环境下仍能正常唤醒和识别
支持唤醒词打断:设备播放时可用唤醒词直接打断
支持实时打断:用户插话即可停止当前 TTS
支持自定义唤醒词:可按客户品牌修改唤醒词
联网方式多:蓝牙、Wi-Fi、4G 多种接入方式
显示能力强:可驱动单屏、双屏,也可左右屏异显
开发友好:基于 ESP32-S3,方便客户二次开发
系统开放:便于接入客户自有 App、IoT 平台和 AI 后端

从产品定位来看,四博 AI 音箱不是传统蓝牙音箱,而是一套面向 AIoT 量产落地的智能语音硬件平台。

它既可以作为 AI 智能音箱,也可以作为智能家居语音中控、AI 桌宠、儿童学习机、陪伴机器人、酒店客控入口、办公语音助手和客户自有系统的 AI 语音前端。

四博模组选型手册中,ESP32-S3 系列被明确归类到"音视频 / AI 市场",ESPS3-32、ESPS3-32E 等模组兼容官方模组形态,适合做音频、显示和 AI 类终端;同时 ESP32-S3 具备双核 240MHz、较多 GPIO、可扩展 PSRAM,并支持 SPI、RGB、I8080 等 LCD 接口,更适合做带屏 AI 终端。


一、方案整体定位

四博 AI 智能音箱可以定义为:

复制代码
四博 AI 智能音箱 =
ESP32-S3 AI 主控
+ 远场麦克风阵列
+ 噪声抑制 / 回声消除 / 自动增益
+ 唤醒词识别
+ 实时打断
+ Wi-Fi / 蓝牙 / 4G 多网络
+ 单屏 / 双屏 / 异显
+ WebSocket AI 对话
+ MCP 工具调用
+ 客户系统接入
+ OTA 在线升级

四博 AI 硬件选型表中,AI-S3 双目双屏方案采用 ESP32S3R8 + 16M Flash + VB6824,配套 1.28 寸 LCD 显示屏 ×2、主板、麦克风、喇叭和线材,并支持小智、豆包、ChatGPT 等主流大模型,定位于高端 AI 市场和可定制开发场景。

四博 AI 开发宝典中也包含 AI-S3 标准开发板、AI-S3 双目、RoPet_ESPS3_AI_EYE、多模态、电子吧唧、AI-C5、设备配网、实时打断固件、自定义唤醒词、在线烧录平台等章节,说明该方案不是单点 Demo,而是一套围绕开发、烧录、配网、调试和量产扩展形成的完整开发体系。


二、系统总体架构

四博 AI 音箱可以采用"端侧实时交互 + 云端大模型 + 客户平台控制"的三层架构。

复制代码
用户语音 / 唤醒词 / 插话 / 触控
        ↓
远场麦克风阵列
        ↓
音频前处理:AEC / NS / AGC / VAD / WakeWord
        ↓
ESP32-S3 主控
        ↓
Wi-Fi / 蓝牙代理 / 4G 模组
        ↓
AI 服务:ASR / LLM / TTS / 知识库 / MCP
        ↓
客户系统:App / IoT 平台 / MQTT / HTTP API
        ↓
音箱播放 / 屏幕显示 / 智能家居控制 / 场景联动

端侧 ESP32-S3 主要负责:

复制代码
1. 麦克风音频采集
2. AEC 回声消除
3. NS 噪声抑制
4. AGC 自动增益
5. VAD 人声检测
6. 唤醒词检测
7. 实时打断检测
8. TTS 音频播放
9. 单屏 / 双屏 / 异显驱动
10. Wi-Fi / 蓝牙 / 4G 网络管理
11. WebSocket / MQTT / HTTP 通信
12. MCP 工具调用执行
13. OTA 在线升级

云端或客户服务器负责:

复制代码
1. ASR 语音识别
2. LLM 大模型理解
3. TTS 语音合成
4. 知识库检索
5. 客户业务系统对接
6. 智能家居设备映射
7. MCP 工具调度
8. 用户账号和设备绑定

三、推荐硬件配置

模块 推荐配置
主控 ESP32-S3R8 / ESPS3-32-N16R8
存储 16MB Flash + 8MB PSRAM
语音唤醒 VB6824 / 本地唤醒模块 / ESP-SR 可选
麦克风 双麦 / 多麦阵列,支持远场拾音
音频处理 AEC、NS、AGC、VAD
音频输出 I2S Codec + Class-D 功放
喇叭 4Ω 3W 或更高规格
屏幕 单屏 / 双屏,支持同显和异显
网络 Wi-Fi、蓝牙代理、外接 4G 模组
供电 Type-C + 电池可选
扩展 UART、I2C、SPI、I2S、PWM、GPIO
升级 HTTPS OTA / 在线烧录平台

四博模组手册中 ESPS3-32 系列包含 N4、N8、N8R2、N16R2、N16R8 等多个子型号,芯片覆盖 ESP32-S3、S3R2、S3R8,适合根据屏幕、音频缓存、OTA 和客户应用复杂度选择不同存储版本。


四、远场拾音与高噪声可用的技术路线

要实现 5 米以上拾音和高噪声环境下可用,不能只靠麦克风灵敏度,而要做完整音频链路。

建议链路如下:

复制代码
Mic Array
  ↓
DC Remove
  ↓
AEC 回声消除
  ↓
NS 噪声抑制
  ↓
AGC 自动增益
  ↓
VAD 人声检测
  ↓
WakeWord 唤醒词
  ↓
ASR 上传

各模块作用:

复制代码
AEC:设备自己播放 TTS 时,消除喇叭回声
NS:降低风扇声、空调声、人群背景噪声
AGC:远距离说话时自动拉高语音增益
VAD:判断当前是否有人说话,用于实时打断
WakeWord:离线识别唤醒词,弱网也能触发设备

核心音频状态机:

复制代码
typedef enum {
    AUDIO_STATE_IDLE = 0,
    AUDIO_STATE_WAKEUP,
    AUDIO_STATE_LISTENING,
    AUDIO_STATE_UPLOADING,
    AUDIO_STATE_THINKING,
    AUDIO_STATE_SPEAKING,
    AUDIO_STATE_INTERRUPTED,
    AUDIO_STATE_ERROR
} audio_state_t;

static volatile audio_state_t g_audio_state = AUDIO_STATE_IDLE;

远场音频帧结构:

复制代码
#define AUDIO_SAMPLE_RATE       16000
#define AUDIO_BITS              16
#define AUDIO_CHANNELS          1
#define AUDIO_FRAME_MS          20
#define AUDIO_FRAME_SAMPLES     (AUDIO_SAMPLE_RATE * AUDIO_FRAME_MS / 1000)

typedef struct {
    int16_t pcm[AUDIO_FRAME_SAMPLES];
    size_t samples;
    int vad_active;
    int wake_active;
    int noise_level;
    int voice_energy;
} audio_frame_t;

VAD 简化示例:

复制代码
static int audio_calc_energy(const int16_t *pcm, size_t samples)
{
    int64_t sum = 0;

    for (size_t i = 0; i < samples; i++) {
        sum += abs(pcm[i]);
    }

    return (int)(sum / samples);
}

static bool vad_detect_voice(const int16_t *pcm, size_t samples)
{
    int energy = audio_calc_energy(pcm, samples);

    /*
     * 量产时建议根据底噪动态调整阈值:
     * 1. 安静环境阈值低
     * 2. 高噪声环境阈值高
     * 3. 可结合噪声估计和连续帧判断
     */
    return energy > 800;
}

动态噪声门限:

复制代码
typedef struct {
    int noise_floor;
    int vad_threshold;
    int agc_gain;
} audio_env_t;

static audio_env_t g_audio_env = {
    .noise_floor = 300,
    .vad_threshold = 800,
    .agc_gain = 1,
};

void audio_env_update(const int16_t *pcm, size_t samples)
{
    int energy = audio_calc_energy(pcm, samples);

    /*
     * 如果长期处于低能量状态,认为是环境底噪。
     */
    if (energy < g_audio_env.vad_threshold) {
        g_audio_env.noise_floor =
            (g_audio_env.noise_floor * 9 + energy) / 10;
    }

    g_audio_env.vad_threshold = g_audio_env.noise_floor + 500;

    if (g_audio_env.vad_threshold < 700) {
        g_audio_env.vad_threshold = 700;
    }

    if (g_audio_env.vad_threshold > 2000) {
        g_audio_env.vad_threshold = 2000;
    }
}

bool vad_detect_voice_dynamic(const int16_t *pcm, size_t samples)
{
    int energy = audio_calc_energy(pcm, samples);
    return energy > g_audio_env.vad_threshold;
}

五、实时打断:AI 音箱体验的关键

传统音箱最大的问题是:设备正在说话时,用户必须等它说完。

四博 AI 音箱要实现的是:

复制代码
用户插话 → 立即停止 TTS → 取消当前云端回复 → 重新进入监听

打断来源可以有三种:

复制代码
1. 唤醒词打断:用户说"你好小博"直接打断
2. VAD 打断:播放时检测到用户插话
3. 按键 / 触控打断:用户短按按键或触控区域打断

四博 AI 开发宝典目录中包含"编译实时打断固件"和"VB6824 如何自定义唤醒词"章节,说明实时打断和唤醒词定制已经是方案级能力,而不是单独宣传点。

打断核心代码:

复制代码
void ai_interrupt_current_session(void)
{
    if (g_audio_state == AUDIO_STATE_SPEAKING) {
        audio_player_stop();

        /*
         * 通知云端取消当前 TTS / LLM 输出。
         */
        ai_ws_send_control("{\"type\":\"interrupt\"}");

        /*
         * UI 进入监听状态。
         */
        screen_show_status("已打断,请继续说");

        /*
         * 重新打开录音链路。
         */
        audio_capture_start();

        g_audio_state = AUDIO_STATE_INTERRUPTED;
    }
}

播放中 VAD 插话检测:

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

    while (1) {
        audio_read_pcm(pcm, sizeof(pcm), &bytes_read);

        audio_env_update(pcm, AUDIO_FRAME_SAMPLES);

        if (g_audio_state == AUDIO_STATE_SPEAKING) {
            if (vad_detect_voice_dynamic(pcm, AUDIO_FRAME_SAMPLES)) {
                ai_interrupt_current_session();
                continue;
            }
        }

        if (g_audio_state == AUDIO_STATE_LISTENING ||
            g_audio_state == AUDIO_STATE_INTERRUPTED) {
            ai_ws_send_audio((uint8_t *)pcm, bytes_read);
        }

        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

唤醒词打断回调:

复制代码
void wakeword_on_detected(const char *word)
{
    ESP_LOGI("WAKE", "wakeword detected: %s", word);

    if (g_audio_state == AUDIO_STATE_SPEAKING) {
        ai_interrupt_current_session();
    } else {
        audio_capture_start();
        screen_show_status("我在听");
        g_audio_state = AUDIO_STATE_LISTENING;
    }

    ai_ws_send_control("{\"type\":\"wakeup\"}");
}

六、自定义唤醒词

客户做品牌化 AI 设备时,唤醒词通常需要改成自己的品牌词。

例如:

复制代码
你好四博
你好小博
小 C 小 C
Hi CozyLife
你好管家
小智小智

唤醒词配置结构:

复制代码
typedef struct {
    char wakeword[64];
    int sensitivity;
    int enable_barge_in;
    int enabled;
} wakeword_config_t;

NVS 保存唤醒词:

复制代码
#include "nvs_flash.h"
#include "nvs.h"

esp_err_t wakeword_save_config(const wakeword_config_t *cfg)
{
    nvs_handle_t nvs;
    esp_err_t ret = nvs_open("wakeword", NVS_READWRITE, &nvs);
    if (ret != ESP_OK) {
        return ret;
    }

    nvs_set_str(nvs, "word", cfg->wakeword);
    nvs_set_i32(nvs, "sens", cfg->sensitivity);
    nvs_set_i32(nvs, "bargein", cfg->enable_barge_in);
    nvs_set_i32(nvs, "enable", cfg->enabled);

    nvs_commit(nvs);
    nvs_close(nvs);

    return ESP_OK;
}

通过 UART 下发到离线唤醒模块:

复制代码
#define WAKE_UART_PORT UART_NUM_2

static void wake_uart_send(const char *cmd)
{
    uart_write_bytes(WAKE_UART_PORT, cmd, strlen(cmd));
}

/*
 * 这里是工程封装示例。
 * 实际量产时应按 VB6824 或客户离线语音固件协议调整。
 */
esp_err_t wakeword_apply_to_module(const wakeword_config_t *cfg)
{
    char cmd[160];

    snprintf(cmd, sizeof(cmd),
             "AT+WAKEWORD=\"%s\",%d,%d\r\n",
             cfg->wakeword,
             cfg->sensitivity,
             cfg->enable_barge_in);

    wake_uart_send(cmd);

    return ESP_OK;
}

客户 App 或小程序修改唤醒词:

复制代码
void user_update_wakeword(const char *word, int sensitivity)
{
    wakeword_config_t cfg = {0};

    strncpy(cfg.wakeword, word, sizeof(cfg.wakeword) - 1);
    cfg.sensitivity = sensitivity;
    cfg.enable_barge_in = 1;
    cfg.enabled = 1;

    wakeword_save_config(&cfg);
    wakeword_apply_to_module(&cfg);

    screen_show_status("唤醒词已更新");
}

七、多网络接入:蓝牙、Wi-Fi、4G

四博 AI 音箱的联网方式可以设计为三层:

复制代码
1. Wi-Fi 上网:家庭和办公环境首选
2. 4G 上网:无 Wi-Fi、移动场景、酒店公寓、海外产品
3. 蓝牙上网 / 蓝牙代理:通过手机 App 做轻量联网或配网通道

这里要注意:蓝牙更适合配网、绑定、轻量控制或手机代理,不适合长时间传输高码率音频流。AI 实时语音建议优先走 Wi-Fi 或 4G。

网络类型定义:

复制代码
typedef enum {
    NET_TYPE_NONE = 0,
    NET_TYPE_WIFI,
    NET_TYPE_BLE_PROXY,
    NET_TYPE_4G
} net_type_t;

typedef enum {
    NET_STATE_IDLE = 0,
    NET_STATE_CONNECTING,
    NET_STATE_CONNECTED,
    NET_STATE_FAILED
} net_state_t;

typedef struct {
    net_type_t type;
    net_state_t state;
    int rssi;
    int online;
} net_status_t;

static net_status_t g_net_status;

网络优先级:

复制代码
void net_manager_start(void)
{
    screen_show_status("正在连接 Wi-Fi");

    if (wifi_connect_saved() == ESP_OK) {
        g_net_status.type = NET_TYPE_WIFI;
        g_net_status.state = NET_STATE_CONNECTED;
        g_net_status.online = 1;

        ai_ws_client_start();
        return;
    }

    screen_show_status("Wi-Fi失败,尝试4G");

    if (modem_4g_connect() == ESP_OK) {
        g_net_status.type = NET_TYPE_4G;
        g_net_status.state = NET_STATE_CONNECTED;
        g_net_status.online = 1;

        ai_ws_client_start();
        return;
    }

    screen_show_status("进入蓝牙代理模式");

    if (ble_proxy_start() == ESP_OK) {
        g_net_status.type = NET_TYPE_BLE_PROXY;
        g_net_status.state = NET_STATE_CONNECTED;
        g_net_status.online = 1;
        return;
    }

    g_net_status.type = NET_TYPE_NONE;
    g_net_status.state = NET_STATE_FAILED;
    g_net_status.online = 0;

    screen_show_status("网络不可用");
}

4G 模组 UART 初始化:

复制代码
#define MODEM_UART_PORT UART_NUM_1

void modem_4g_uart_init(void)
{
    uart_config_t uart_config = {
        .baud_rate = 115200,
        .data_bits = UART_DATA_8_BITS,
        .parity    = UART_PARITY_DISABLE,
        .stop_bits = UART_STOP_BITS_1,
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
    };

    uart_driver_install(MODEM_UART_PORT, 4096, 4096, 0, NULL, 0);
    uart_param_config(MODEM_UART_PORT, &uart_config);
    uart_set_pin(MODEM_UART_PORT,
                 GPIO_NUM_16,
                 GPIO_NUM_17,
                 UART_PIN_NO_CHANGE,
                 UART_PIN_NO_CHANGE);
}

4G AT 连接流程:

复制代码
static esp_err_t modem_send_cmd(const char *cmd,
                                const char *expect,
                                int timeout_ms)
{
    char rxbuf[256] = {0};

    uart_write_bytes(MODEM_UART_PORT, cmd, strlen(cmd));

    int len = uart_read_bytes(MODEM_UART_PORT,
                              rxbuf,
                              sizeof(rxbuf) - 1,
                              pdMS_TO_TICKS(timeout_ms));

    if (len > 0) {
        rxbuf[len] = 0;
        ESP_LOGI("4G", "rsp: %s", rxbuf);

        if (expect == NULL || strstr(rxbuf, expect)) {
            return ESP_OK;
        }
    }

    return ESP_FAIL;
}

esp_err_t modem_4g_connect(void)
{
    modem_send_cmd("AT\r\n", "OK", 1000);
    modem_send_cmd("ATE0\r\n", "OK", 1000);
    modem_send_cmd("AT+CPIN?\r\n", "READY", 3000);
    modem_send_cmd("AT+CSQ\r\n", "OK", 1000);
    modem_send_cmd("AT+CREG?\r\n", "OK", 1000);
    modem_send_cmd("AT+CGATT=1\r\n", "OK", 5000);

    /*
     * APN 需要根据运营商配置。
     */
    modem_send_cmd("AT+CGDCONT=1,\"IP\",\"cmnet\"\r\n", "OK", 1000);

    return ESP_OK;
}

四博 AI 开发宝典中 AI-C5 部分包含 Wi-Fi 模式和 4G 模式切换、设备配网等内容,可作为多联网版本开发参考;模组选型手册中 ESP32-C5 系列也提供了 Wi-Fi 6 2.4G/5G + BLE + Zigbee/Thread 的模组路线,适合扩展到双频 Wi-Fi 和多协议中控产品。


八、单屏、双屏和异显设计

四博 AI 音箱可以根据产品形态选择单屏或双屏。

复制代码
单屏:适合普通 AI 音箱、智能中控、学习机
双屏同显:适合双目表情屏,左右眼同步显示
双屏异显:左屏显示表情,右屏显示文字、状态、二维码、歌词、设备状态

显示模式定义:

复制代码
typedef enum {
    DISPLAY_MODE_SINGLE = 0,
    DISPLAY_MODE_DUAL_SAME,
    DISPLAY_MODE_DUAL_DIFF
} display_mode_t;

typedef enum {
    SCREEN_ROLE_MAIN = 0,
    SCREEN_ROLE_LEFT_EYE,
    SCREEN_ROLE_RIGHT_INFO
} screen_role_t;

双屏句柄:

复制代码
typedef struct {
    void *panel_left;
    void *panel_right;
    display_mode_t mode;
    int width;
    int height;
} dual_screen_t;

static dual_screen_t g_screen;

单屏显示:

复制代码
void screen_show_single(const char *text)
{
    lcd_fill(g_screen.panel_left, 0x0000);
    lcd_draw_text(g_screen.panel_left, 20, 40, text, 0xFFFF);
}

双屏同显:

复制代码
void screen_show_dual_same(const char *text)
{
    lcd_fill(g_screen.panel_left, 0x0000);
    lcd_fill(g_screen.panel_right, 0x0000);

    lcd_draw_text(g_screen.panel_left, 20, 40, text, 0xFFFF);
    lcd_draw_text(g_screen.panel_right, 20, 40, text, 0xFFFF);
}

双屏异显:

复制代码
void screen_show_dual_diff(const char *emotion, const char *status)
{
    /*
     * 左屏:AI 表情
     * 右屏:文字状态
     */
    lcd_fill(g_screen.panel_left, 0x0000);
    lcd_fill(g_screen.panel_right, 0x0000);

    if (strcmp(emotion, "listening") == 0) {
        lcd_draw_eye_listening(g_screen.panel_left);
    } else if (strcmp(emotion, "thinking") == 0) {
        lcd_draw_eye_thinking(g_screen.panel_left);
    } else if (strcmp(emotion, "speaking") == 0) {
        lcd_draw_eye_speaking(g_screen.panel_left);
    } else {
        lcd_draw_eye_normal(g_screen.panel_left);
    }

    lcd_draw_text(g_screen.panel_right, 10, 30, status, 0xFFFF);
}

根据 AI 状态自动刷新异显:

复制代码
void ui_update_by_audio_state(audio_state_t state)
{
    switch (state) {
    case AUDIO_STATE_LISTENING:
        screen_show_dual_diff("listening", "正在聆听...");
        break;

    case AUDIO_STATE_THINKING:
        screen_show_dual_diff("thinking", "AI 思考中...");
        break;

    case AUDIO_STATE_SPEAKING:
        screen_show_dual_diff("speaking", "正在回答");
        break;

    case AUDIO_STATE_INTERRUPTED:
        screen_show_dual_diff("listening", "已打断,请继续说");
        break;

    default:
        screen_show_dual_diff("normal", "AI 在线");
        break;
    }
}

开发宝典中 AI-S3 双目章节包含 RoPet_ESPS3_AI_EYE 快速入门,以及 1.28 寸和 0.71 寸屏幕参数等内容,说明双目屏和多屏显示已经纳入四博 AI-S3 开发体系。


九、WebSocket AI 对话链路

推荐 AI 对话采用 WebSocket 长连接,支持低延迟音频上传、TTS 下发、状态同步和实时打断。

设备上线消息:

复制代码
{
  "type": "hello",
  "device_id": "doit_ai_speaker_s3_001",
  "product": "doit_ai_speaker",
  "firmware": "1.0.0",
  "features": {
    "far_field": true,
    "noise_suppression": true,
    "wakeword_interrupt": true,
    "realtime_interrupt": true,
    "custom_wakeword": true,
    "wifi": true,
    "ble_proxy": true,
    "4g": true,
    "single_screen": true,
    "dual_screen": true,
    "dual_diff_display": true,
    "mcp": true,
    "ota": true
  },
  "audio": {
    "format": "pcm_s16le",
    "sample_rate": 16000,
    "channels": 1
  }
}

WebSocket 事件处理:

复制代码
static void ai_ws_handle_json(const char *data, int len)
{
    char *buf = calloc(1, len + 1);
    if (!buf) return;

    memcpy(buf, data, len);

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

    cJSON *type = cJSON_GetObjectItem(root, "type");

    if (cJSON_IsString(type)) {
        if (strcmp(type->valuestring, "stt") == 0) {
            cJSON *text = cJSON_GetObjectItem(root, "text");
            if (cJSON_IsString(text)) {
                screen_show_dual_diff("listening", text->valuestring);
            }
        } else if (strcmp(type->valuestring, "llm") == 0) {
            screen_show_dual_diff("thinking", "AI 思考中");
        } else if (strcmp(type->valuestring, "tts_start") == 0) {
            g_audio_state = AUDIO_STATE_SPEAKING;
            screen_show_dual_diff("speaking", "正在回答");
            audio_player_start();
        } else if (strcmp(type->valuestring, "tts_end") == 0) {
            g_audio_state = AUDIO_STATE_IDLE;
            screen_show_dual_diff("normal", "AI 在线");
            audio_player_stop();
        } else if (strcmp(type->valuestring, "tool_call") == 0) {
            mcp_service_handle(root);
        }
    }

    cJSON_Delete(root);
    free(buf);
}

发送音频:

复制代码
esp_err_t ai_ws_send_audio_frame(const int16_t *pcm, size_t samples)
{
    if (!ai_ws_is_connected()) {
        return ESP_FAIL;
    }

    return ai_ws_send_binary((const uint8_t *)pcm,
                             samples * sizeof(int16_t));
}

十、MCP 工具调用:方便接入客户系统

客户系统接入通常有三种方式:

复制代码
1. HTTP API:适合云平台、App 后端、智能家居平台
2. MQTT:适合 IoT 设备控制、状态上报、场景联动
3. UART / RS485:适合本地 MCU、家电主控板、酒店客控系统

MCP 工具定义:

复制代码
typedef enum {
    MCP_TOOL_DEVICE_CONTROL = 0,
    MCP_TOOL_SCENE_RUN,
    MCP_TOOL_SCREEN_SET,
    MCP_TOOL_WAKEWORD_UPDATE,
    MCP_TOOL_AUDIO_SET_VOLUME,
    MCP_TOOL_NET_SWITCH,
    MCP_TOOL_UNKNOWN
} mcp_tool_id_t;

typedef struct {
    const char *name;
    mcp_tool_id_t id;
} mcp_tool_map_t;

static const mcp_tool_map_t g_mcp_tools[] = {
    {"customer.device.control", MCP_TOOL_DEVICE_CONTROL},
    {"customer.scene.run",      MCP_TOOL_SCENE_RUN},
    {"screen.display.set",      MCP_TOOL_SCREEN_SET},
    {"device.wakeword.update",  MCP_TOOL_WAKEWORD_UPDATE},
    {"audio.volume.set",        MCP_TOOL_AUDIO_SET_VOLUME},
    {"network.switch",          MCP_TOOL_NET_SWITCH},
};

MCP 分发:

复制代码
static mcp_tool_id_t mcp_get_tool_id(const char *name)
{
    for (int i = 0; i < sizeof(g_mcp_tools) / sizeof(g_mcp_tools[0]); i++) {
        if (strcmp(name, g_mcp_tools[i].name) == 0) {
            return g_mcp_tools[i].id;
        }
    }

    return MCP_TOOL_UNKNOWN;
}

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)) {
        return;
    }

    switch (mcp_get_tool_id(tool->valuestring)) {
    case MCP_TOOL_DEVICE_CONTROL:
        mcp_handle_device_control(args);
        break;

    case MCP_TOOL_SCENE_RUN:
        mcp_handle_scene_run(args);
        break;

    case MCP_TOOL_SCREEN_SET:
        mcp_handle_screen_set(args);
        break;

    case MCP_TOOL_WAKEWORD_UPDATE:
        mcp_handle_wakeword_update(args);
        break;

    case MCP_TOOL_AUDIO_SET_VOLUME:
        mcp_handle_volume_set(args);
        break;

    case MCP_TOOL_NET_SWITCH:
        mcp_handle_network_switch(args);
        break;

    default:
        ESP_LOGW("MCP", "unknown tool: %s", tool->valuestring);
        break;
    }
}

HTTP 接入客户系统:

复制代码
typedef struct {
    char device_id[32];
    char action[32];
    int value;
} control_cmd_t;

esp_err_t customer_control_device(control_cmd_t *cmd)
{
    char json[256];

    snprintf(json, sizeof(json),
             "{"
             "\"device_id\":\"%s\","
             "\"action\":\"%s\","
             "\"value\":%d"
             "}",
             cmd->device_id,
             cmd->action,
             cmd->value);

    return http_post_json("https://api.customer.com/device/control", json);
}

void mcp_handle_device_control(cJSON *args)
{
    cJSON *device_id = cJSON_GetObjectItem(args, "device_id");
    cJSON *action = cJSON_GetObjectItem(args, "action");
    cJSON *value = cJSON_GetObjectItem(args, "value");

    if (!cJSON_IsString(device_id) ||
        !cJSON_IsString(action) ||
        !cJSON_IsNumber(value)) {
        return;
    }

    control_cmd_t cmd = {0};

    strncpy(cmd.device_id, device_id->valuestring, sizeof(cmd.device_id) - 1);
    strncpy(cmd.action, action->valuestring, sizeof(cmd.action) - 1);
    cmd.value = value->valueint;

    customer_control_device(&cmd);
}

MQTT 接入客户 IoT 平台:

复制代码
static void mqtt_event_handler(void *handler_args,
                               esp_event_base_t base,
                               int32_t event_id,
                               void *event_data)
{
    esp_mqtt_event_handle_t event = event_data;

    switch ((esp_mqtt_event_id_t)event_id) {
    case MQTT_EVENT_CONNECTED:
        esp_mqtt_client_subscribe(event->client,
                                  "customer/+/command/set",
                                  1);
        esp_mqtt_client_publish(event->client,
                                "customer/speaker/status",
                                "{\"online\":true}",
                                0,
                                1,
                                0);
        break;

    case MQTT_EVENT_DATA:
        mqtt_handle_customer_command(event->topic,
                                     event->topic_len,
                                     event->data,
                                     event->data_len);
        break;

    default:
        break;
    }
}

十一、OTA 与在线升级

AI 音箱量产后,OTA 非常关键。

可升级内容包括:

复制代码
1. 主固件
2. 唤醒词配置
3. 噪声参数
4. VAD 阈值
5. AI 后端地址
6. MCP 工具列表
7. 屏幕 UI 资源
8. 提示音资源
9. 客户业务协议
10. 4G / Wi-Fi 网络策略

OTA 版本文件:

复制代码
{
  "project": "doit_ai_speaker_s3",
  "version": "1.0.3",
  "chip": "esp32s3",
  "url": "https://ota.customer.com/doit_ai_speaker_s3_v1.0.3.bin",
  "asset_url": "https://ota.customer.com/assets/speaker_assets_v3.bin",
  "md5": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "force": false,
  "note": "优化5米远场拾音、实时打断和双屏异显"
}

OTA 代码:

复制代码
#include "esp_https_ota.h"
#include "esp_http_client.h"

void ota_check_update(void)
{
    esp_http_client_config_t http_config = {
        .url = "https://ota.customer.com/doit_ai_speaker/latest.bin",
        .timeout_ms = 10000,
        .keep_alive_enable = true,
    };

    esp_https_ota_config_t ota_config = {
        .http_config = &http_config,
    };

    screen_show_dual_diff("thinking", "正在升级,请勿断电");

    esp_err_t ret = esp_https_ota(&ota_config);

    if (ret == ESP_OK) {
        screen_show_dual_diff("normal", "升级成功,正在重启");
        esp_restart();
    } else {
        screen_show_dual_diff("error", "升级失败");
    }
}

分区表示例:

复制代码
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x6000,
otadata,  data, ota,     0xf000,  0x2000,
phy_init, data, phy,     0x11000, 0x1000,
factory,  app,  factory, 0x20000, 0x300000,
ota_0,    app,  ota_0,   ,        0x300000,
ota_1,    app,  ota_1,   ,        0x300000,
assets,   data, spiffs,  ,        0x200000,
storage,  data, spiffs,  ,        0x100000,

四博 AI 开发宝典中说明,小智 AI 系统硬件设备的开源代码可通过 VSCode 安装 ESP-IDF 扩展和编译工具进行开发、编译和烧录,并且提供了 DOIT_AI 开源工程和后续编译运行流程,这对客户做二次开发和量产验证非常关键。


十二、推荐工程目录

复制代码
doit_ai_speaker_s3/
├── main/
│   ├── app_main.c
│   ├── board_config.h
│   ├── audio_capture.c
│   ├── audio_frontend.c
│   ├── audio_player.c
│   ├── wakeword_service.c
│   ├── interrupt_service.c
│   ├── wifi_manager.c
│   ├── ble_proxy.c
│   ├── modem_4g.c
│   ├── net_manager.c
│   ├── screen_single.c
│   ├── screen_dual.c
│   ├── ai_ws_client.c
│   ├── mcp_service.c
│   ├── mqtt_service.c
│   ├── customer_api.c
│   └── ota_service.c
├── components/
│   ├── codec/
│   ├── lcd_driver/
│   ├── wakeword/
│   ├── modem/
│   └── audio_afe/
├── partitions_ota.csv
└── sdkconfig.defaults

主程序框架:

复制代码
void app_main(void)
{
    nvs_flash_init();
    esp_netif_init();
    esp_event_loop_create_default();

    board_init();

    screen_init();
    screen_show_dual_diff("normal", "四博 AI 启动中");

    audio_capture_init();
    audio_player_init();
    audio_frontend_init();

    wakeword_service_init();
    interrupt_service_init();

    wifi_manager_init();
    ble_proxy_init();
    modem_4g_init();
    net_manager_start();

    ai_ws_client_init();
    mcp_service_init();
    mqtt_service_init();
    ota_service_init();

    xTaskCreate(audio_capture_task, "audio_capture", 8192, NULL, 5, NULL);
    xTaskCreate(audio_frontend_task, "audio_frontend", 8192, NULL, 6, NULL);
    xTaskCreate(ai_ws_client_task, "ai_ws_client", 10240, NULL, 6, NULL);
    xTaskCreate(net_monitor_task, "net_monitor", 4096, NULL, 3, NULL);
    xTaskCreate(ota_service_task, "ota_service", 6144, NULL, 3, NULL);

    screen_show_dual_diff("normal", "AI 在线");
}

十三、开发与量产流程

客户拿到四博 AI 音箱方案后,可以按以下流程开发:

复制代码
1. 选择 ESP32-S3 / S3R8 硬件版本
2. 确认单屏、双屏或双屏异显方案
3. 确认麦克风数量和远场拾音结构
4. 配置 ESP-IDF 开发环境
5. 下载 DOIT_AI 或客户定制工程
6. 编译基础固件
7. 配置 Wi-Fi / 蓝牙 / 4G 联网方式
8. 配置唤醒词和实时打断参数
9. 接入客户 AI 后端或小智服务
10. 接入客户 App、IoT 平台或 MQTT
11. 配置 OTA 地址
12. 进行噪声、距离、打断、稳定性测试
13. 进入量产烧录和出厂测试

编译命令示例:

复制代码
git clone https://github.com/SmartArduino/DOIT_AI.git
cd DOIT_AI

idf.py set-target esp32s3
idf.py menuconfig
idf.py build
idf.py -p COMx flash monitor

十四、方案核心价值

四博 AI 音箱方案的核心价值,不是单纯"接入大模型",而是把 AI 对话能力和端侧工程能力结合起来。

复制代码
1. 5 米以上远场拾音,适合客厅、会议室、酒店房间
2. 高噪声环境可用,适合真实家庭和商业空间
3. 支持唤醒词打断,交互更自然
4. 支持实时打断,用户不用等设备说完
5. 支持自定义唤醒词,适合品牌客户
6. 支持蓝牙、Wi-Fi、4G 多种联网方式
7. 支持单屏、双屏和双屏异显
8. 基于 ESP32-S3,方便二次开发
9. 可接入客户自己的 App、IoT 平台和业务系统
10. 支持 OTA,量产后仍可持续升级

结语

四博 AI 智能音箱方案,本质上是一套面向真实产品落地的 AIoT 语音平台。

它既解决"能不能对话"的问题,也解决"能不能听远、能不能抗噪、能不能打断、能不能改唤醒词、能不能多网络联网、能不能带屏显示、能不能接客户系统、能不能量产升级"的问题。

普通 AI 音箱只是:

复制代码
听得见,说得出

四博 AI 音箱要做到的是:

复制代码
听得远
抗得住噪
打断得快
联网方式多
屏幕显示灵活
客户系统接入方便
二次开发成本低
量产升级可持续

一句话总结:

复制代码
四博 AI 音箱不是简单的语音播放器,
而是基于 ESP32-S3 打造的远场拾音、多网络接入、多屏显示、
实时打断、可自定义唤醒词、可接入客户系统的 AI 智能硬件平台。
相关推荐
一叶飘零_sweeeet1 小时前
AI Agent 深潜:六大核心模块的设计本质与 Java 实现
java·人工智能·agent
Swift社区1 小时前
System + AI:下一代 鸿蒙App 架构
人工智能·架构·harmonyos
跨境摸鱼2 小时前
低价模型承压阶段跨境品牌如何把重心转向复购与客单
大数据·人工智能·跨境电商·亚马逊·跨境
上海云盾-小余2 小时前
边缘节点安全赋能:CDN 联动高防抵御复合型流量攻击
人工智能·安全
陈广亮2 小时前
AI Agent 成功率从 12% 到 66%:前端开发者该如何迎接"可用"的 Agent 时代
人工智能
CV-杨帆2 小时前
在 AutoDL 云服务器上将 NanoBot 养成为科研智能体
人工智能
AI攻城狮2 小时前
CLAUDE.md 的最佳实践:为什么你的配置文件基本上是废的
人工智能·后端·openai
vim怎么退出2 小时前
我给 Claude Code 写了一个自适应学习 Skill,7 天刷完浏览器原理
前端·人工智能
Not_afraid2 小时前
与 LLM 对话的底层真相:消息、角色、记忆与系统提示词的工作原理
人工智能