四博 AI 智能音箱 4G S3 版本技术方案
1. 产品定义
本方案面向一款 支持蓝牙、Wi-Fi、4G 三模联网的四博 AI 智能音箱。
核心能力包括:
1. AI 对话:
支持小智、豆包、ChatGPT、客户私有大模型。
2. 三模联网:
Wi-Fi 上网、4G 上网、蓝牙 PAN / BLE 配网。
3. 远场拾音:
支持 5 米范围远距离唤醒、打断和对话。
4. 高噪响应:
在空气炸锅、油烟机、电视背景声等高噪环境下稳定响应。
5. 实时打断:
AI 说话、TTS 播报、蓝牙音乐播放过程中可唤醒词打断。
6. 可改唤醒词:
支持 VB6824 唤醒词升级和客户定制唤醒词。
7. S3 二次开发:
基于 ESP32-S3,支持 ESP-IDF、DOIT_AI、AT+MCP、HTTP、MQTT、WebSocket。
8. 客户系统接入:
可对接客户 App、小程序、私有云、业务后台、智能家居平台。
推荐硬件配置:
主控:ESP32-S3R8 / ESPS3-32-N16R8
Flash:16MB
PSRAM:8MB
语音前端:VB6824
联网:Wi-Fi + BLE + 4G + 可选 7014 蓝牙 PAN
音频:麦克风 + AEC 回采 + I2S 功放 + 喇叭
显示:1.3 / 1.54 / 2.0 寸 LCD,可选
电源:Type-C + 电池 + 充电管理
系统:ESP-IDF + DOIT_AI + 小智协议 / 私有后端
扩展:UART / GPIO / I2C / SPI / MCP / MQTT / HTTP
AI 硬件选型资料中提到,ESP32-C2 / C3 / S3 加 VB6824 语音方案已经成熟应用于电子吧唧、S3 双目、S3 拍学机、地球仪、拍拍灯等产品;VB6824 完成音频编解码、AEC、语音唤醒、改唤醒词等功能,让主控芯片专注通信及 UI。
2. 整机系统架构
┌──────────────────────────────────────────────────────────────┐
│ 四博 AI 智能音箱 4G S3 版本 │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────────────┐ UART / I2C / GPIO │
│ │ VB6824 语音前端 │◄──────────────────────────────┐ │
│ │ - 离线唤醒 │ │ │
│ │ - 远距离拾音 │ │ │
│ │ - AEC 回声消除 │ │ │
│ │ - 高噪降噪 │ │ │
│ │ - 唤醒词打断 │ │ │
│ │ - 实时打断 │ │ │
│ │ - 改唤醒词 │ │ │
│ └─────────┬────────────┘ │ │
│ │ MIC / 回采音频 │ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ ESP32-S3R8 + 16M Flash + 8M PSRAM │ │
│ │ - Wi-Fi STA / SoftAP / BluFi │ │
│ │ - 4G PPP / ECM / RNDIS │ │
│ │ - 蓝牙 PAN / 蓝牙音箱,可选 7014 │ │
│ │ - WebSocket AI 对话 │ │
│ │ - OTA / NVS / 设备激活 │ │
│ │ - LCD / LED / 按键 / UI │ │
│ │ - MCP 工具调用 / 客户系统接入 │ │
│ └──────────────┬─────────────────┬──────────────────────┘ │
│ │ │ │
│ ┌─────────▼──────┐ ┌────────▼────────┐ │
│ │ 4G 通信模组 │ │ 7014 蓝牙模组 │ │
│ │ UART PPP / USB │ │ PAN / A2DP │ │
│ └─────────┬──────┘ └────────┬────────┘ │
│ │ │ │
│ SIM / 4G 天线 蓝牙天线 │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ LCD / RGB UI │ │ I2S AMP+SPK │ │ Battery / PMIC │ │
│ │ 状态显示 │ │ TTS / 音乐 │ │ 电池 / 充电管理 │ │
│ └──────────────┘ └──────────────┘ └────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
云端 / 私有化后端:
┌──────────────────────────────────────────────────────────────┐
│ OTA │ WebSocket │ ASR │ LLM │ TTS │ MCP │ 客户业务系统 │ 日志 │
└──────────────────────────────────────────────────────────────┘
这里建议采用 ESP32-S3 主控 + VB6824 语音前端 + 4G 模组 + 7014 蓝牙协处理器 的平台架构。ESP32-S3 负责联网、UI、AI 业务、WebSocket、OTA 和二次开发;VB6824 负责唤醒、降噪、AEC、打断和改唤醒词;4G 模组负责无 Wi-Fi 场景联网;7014 负责蓝牙 PAN 上网或蓝牙音箱模式。
需要注意:ESP32-S3 本身主要提供 Wi-Fi + BLE,若产品要求"经典蓝牙音箱 A2DP"或"手机蓝牙 PAN 上网",建议增加 7014 或独立蓝牙音频 / PAN 协处理器。AI 选型表中也单独给出了 7014 蓝牙 PAN AI 手机伴侣方案,特点是可通过手机网络通信,解决户外网络问题。
3. 硬件方案
3.1 主控:ESP32-S3 / ESPS3-32
推荐选型:
ESPS3-32-N16R8
或 ESPS3-32E-N16R8
配置建议:
| 模块 | 推荐配置 | 说明 |
|---|---|---|
| 主控 | ESP32-S3R8 | 双核 240MHz,适合 AI、UI、联网、音频流调度 |
| Flash | 16MB | 支持 OTA 双分区、资源、日志、配置 |
| PSRAM | 8MB | 支持 WebSocket buffer、UI buffer、音频 buffer |
| Wi-Fi | 2.4GHz | 家庭 / 办公 / 展厅主联网方式 |
| BLE | BluFi 配网 | 小程序 / App 配网 |
| GPIO | 充足 | 屏幕、功放、4G、按键、RGB、外设扩展 |
乐鑫系模组选型手册中,ESPS3-32 / ESPS3-32E 属于 ESP32-S3 系列,面向音视频 / AI 市场,ESPS3-32 尺寸为 18 × 25.5mm,ESPS3-32E 尺寸为 18 × 19.2mm,兼容 ESP32-S3-WROOM 系列模组。
3.2 语音前端:VB6824
VB6824 建议作为独立语音前端,负责:
1. 离线唤醒;
2. 远距离拾音;
3. AEC 回声消除;
4. 噪声抑制;
5. AI 播报中的实时打断;
6. 唤醒词升级;
7. 语音状态上报;
8. 与 ESP32-S3 通过 UART / GPIO 协同。
开发宝典中对 VB6824 的描述是:采用语音识别算法和语音降噪算法,支持更远距离唤醒、更低误唤醒率、更强抗噪音能力、更快响应识别时间,并支持免联网纯离线识别。
3.3 4G 模组
推荐两种接入方式:
方式 A:UART + PPPoS
优点:接线简单、软件成熟、适合语音流和控制流。
缺点:吞吐量较低。
方式 B:USB ECM / RNDIS
优点:吞吐量更高,适合图片、视频、资源下载。
缺点:USB Host 和驱动复杂度更高。
开发宝典中 AI-C5 章节说明,该开发板支持 2.4G / 5G Wi-Fi、4G 模组、喇叭、麦克风、电池和 2 寸屏幕;虽然 AI-C5 是 C5 架构,但其 4G 模组接入和 Wi-Fi / 4G 模式切换逻辑可以迁移到 S3 4G 音箱版本。
3.4 蓝牙能力
蓝牙建议拆成三层:
1. BLE 配网:
ESP32-S3 自带 BLE,可用于 BluFi 配网。
2. 蓝牙 PAN 上网:
建议外接 7014,通过手机网络给设备联网。
3. 蓝牙音箱:
如需 A2DP 蓝牙音乐播放,建议用 7014 或独立蓝牙音频芯片。
3.5 音频与声学结构
推荐音频链路:
MIC
↓
VB6824 语音前端
↓
ESP32-S3 AI 会话
↓
WebSocket / ASR / LLM / TTS
↓
I2S 功放
↓
喇叭
↓
AEC 回采
↓
VB6824
结构建议:
1. MIC 远离喇叭出音口和倒相孔;
2. MIC 孔避开空气流道和外壳振动位置;
3. 4G 天线、Wi-Fi 天线远离 MIC 走线和音频前级;
4. 功放电源与 4G 电源分区;
5. 4G 模组峰值电流要留足裕量;
6. 喇叭播放必须保留回采链路,用于 AEC 和实时打断;
7. 高噪场景下应单独调试唤醒阈值、AEC 参数和降噪参数。
4. 三模联网策略
4.1 联网优先级
建议默认优先级:
第一优先级:Wi-Fi
- 成本低
- 带宽稳定
- 适合家庭、办公室、展厅
- OTA 优先走 Wi-Fi
第二优先级:4G
- 户外、移动、无 Wi-Fi 场景
- 适合商用部署
- 需要做流量控制和弱网重连
第三优先级:蓝牙 PAN
- 手机伴侣场景
- 无 SIM 卡或 4G 弱信号时兜底
- 可作为临时联网方式
4.2 模式切换交互
开发宝典中给出的 4G / Wi-Fi 模式切换逻辑可以直接参考:在 4G 模式下重新开机,屏幕显示等待网络时双击 boot 键,可切换到 Wi-Fi 配网模式;在 Wi-Fi 配网模式界面双击 boot 键,可切换到 4G 模式并自动连接。
推荐扩展为:
开机:
1. 读取 NVS 中 last_link。
2. 优先尝试 Wi-Fi。
3. Wi-Fi 超时失败,启动 4G。
4. 4G 无卡 / 注册失败 / 信号弱,启动蓝牙 PAN。
5. 三路均不可用,进入 BluFi / SoftAP 配网。
运行中:
1. WebSocket 心跳失败 3 次,标记当前链路异常。
2. 后台预连接备用链路。
3. AI 正在录音或播放时不立即切网。
4. 当前轮对话结束后切换默认路由。
5. OTA 时优先 Wi-Fi,避免 4G 流量消耗。
5. 软件系统架构
建议基于 ESP-IDF + DOIT_AI 工程扩展。
main/
app_main.c
components/
board/
board_config.h
board_init.c
audio/
audio_focus.c
tts_player.c
wakeup_frontend.c
barge_in.c
network/
wifi_manager.c
lte_modem.c
bt_pan_manager.c
network_policy.c
ai/
websocket_client.c
ai_session.c
mcp_uart_bridge.c
ui/
display_manager.c
led_manager.c
key_manager.c
ota/
ota_manager.c
resource_ota.c
customer/
customer_http.c
customer_mqtt.c
customer_uart.c
factory/
factory_test.c
FreeRTOS 任务建议:
| 任务 | 优先级 | 作用 |
|---|---|---|
audio_frontend_task |
高 | 唤醒、打断、录音状态 |
ai_session_task |
高 | WebSocket 对话、TTS 播放 |
network_policy_task |
中高 | Wi-Fi / 4G / 蓝牙 PAN 链路选择 |
lte_modem_task |
中高 | 4G 注册、拨号、重连 |
mcp_uart_task |
中高 | AT+MCP 指令注册和帧解析 |
ui_task |
中 | 屏幕、LED、按键、状态显示 |
ota_task |
低 | 固件 OTA、资源 OTA |
factory_task |
低 | 产测、老化、SN 写入 |
6. 编译与开发流程
开发宝典说明,小智 AI 硬件设备的开源代码可以在 VSCode 中安装 ESP-IDF 扩展和编译工具进行编译和烧录;S3 相关工程需要设置目标芯片为 esp32s3,部分工程要求 ESP-IDF 版本大于等于 5.4.1。
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 /dev/ttyUSB0 flash monitor
推荐 menuconfig 配置项:
Xiaozhi Assistant
Board Type:
Sibo AI Speaker 4G S3
Network:
Wi-Fi Enable = y
BluFi Enable = y
LTE 4G Enable = y
Bluetooth PAN Enable = optional
Audio:
VB6824 Enable = y
USE_DEVICE_AEC = y
USE_SERVER_AEC = n
AI:
WebSocket Enable = y
MCP Enable = y
OTA:
OTA Enable = y
Resource OTA Enable = y
实时打断方面,开发宝典中说明可在 Kconfig.projbuild 中增加 USE_DEVICE_AEC 和 USE_SERVER_AEC 相关配置;USE_SERVER_AEC 需要服务器支持,如果服务器不支持,则选择 USE_DEVICE_AEC 后重新编译。
7. 关键代码示例
下面代码为工程框架级示例,GPIO 需要根据实际 PCB 修改。
7.1 板级配置 board_config.h
#pragma once
#include "driver/gpio.h"
#include "driver/uart.h"
#include "driver/spi_master.h"
/*
* 四博 AI 智能音箱 4G S3 版本
* ESP32-S3R8 + 16M Flash + 8M PSRAM + VB6824 + 4G + optional 7014
*/
#define BOARD_NAME "SIBO_AI_SPEAKER_4G_S3"
/* ---------- VB6824 / MCP UART ---------- */
#define AI_UART UART_NUM_1
#define AI_UART_BAUD 115200
#define AI_UART_TX_GPIO GPIO_NUM_17
#define AI_UART_RX_GPIO GPIO_NUM_18
#define AI_RESET_GPIO GPIO_NUM_21
/* ---------- 4G Modem UART ---------- */
#define LTE_UART UART_NUM_2
#define LTE_UART_BAUD 115200
#define LTE_TX_GPIO GPIO_NUM_39
#define LTE_RX_GPIO GPIO_NUM_40
#define LTE_PWRKEY_GPIO GPIO_NUM_41
#define LTE_RESET_GPIO GPIO_NUM_42
#define LTE_STATUS_GPIO GPIO_NUM_2
/* ---------- 7014 Bluetooth PAN / A2DP,可选 ---------- */
#define BT7014_UART UART_NUM_0
#define BT7014_TX_GPIO GPIO_NUM_43
#define BT7014_RX_GPIO GPIO_NUM_44
#define BT7014_EN_GPIO GPIO_NUM_45
/* ---------- I2S Speaker ---------- */
#define I2S_BCLK_GPIO GPIO_NUM_6
#define I2S_LRCK_GPIO GPIO_NUM_7
#define I2S_DOUT_GPIO GPIO_NUM_8
#define AMP_EN_GPIO GPIO_NUM_5
/* ---------- LCD,可选 ---------- */
#define LCD_SPI_HOST SPI2_HOST
#define LCD_CS_GPIO GPIO_NUM_10
#define LCD_DC_GPIO GPIO_NUM_11
#define LCD_RST_GPIO GPIO_NUM_12
#define LCD_BL_GPIO GPIO_NUM_13
/* ---------- Keys ---------- */
#define KEY_BOOT_GPIO GPIO_NUM_0
#define KEY_VOL_UP_GPIO GPIO_NUM_14
#define KEY_VOL_DOWN_GPIO GPIO_NUM_15
#define KEY_MUTE_GPIO GPIO_NUM_16
/* ---------- RGB LED ---------- */
#define RGB_LED_GPIO GPIO_NUM_38
/* ---------- Network Policy ---------- */
#define WIFI_CONNECT_TIMEOUT_MS 10000
#define LTE_CONNECT_TIMEOUT_MS 25000
#define BTPAN_CONNECT_TIMEOUT_MS 15000
#define WS_HEARTBEAT_TIMEOUT_MS 15000
#define NETWORK_FAILOVER_THRESHOLD 3
7.2 Kconfig:启用 S3 4G 板型与实时打断
menu "Sibo AI Speaker 4G S3"
config BOARD_SIBO_AI_SPEAKER_4G_S3
bool "Sibo AI Speaker 4G S3"
default y
help
ESP32-S3R8 + 16M Flash + VB6824 + 4G + optional 7014.
config USE_DEVICE_AEC
bool "Use device side AEC for real-time barge-in"
depends on BOARD_SIBO_AI_SPEAKER_4G_S3
default y
help
Enable device-side AEC for wake-word barge-in while TTS is playing.
config USE_SERVER_AEC
bool "Use server side AEC"
depends on BOARD_SIBO_AI_SPEAKER_4G_S3
default n
help
Enable only when the backend WebSocket server supports server-side AEC.
config LTE_ENABLE
bool "Enable 4G LTE network"
default y
config BT_PAN_ENABLE
bool "Enable Bluetooth PAN network"
default y
config MCP_ENABLE
bool "Enable AT+MCP UART bridge"
default y
endmenu
7.3 三模联网策略代码
#include <stdbool.h>
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define TAG "NET_POLICY"
typedef enum {
NET_LINK_NONE = 0,
NET_LINK_WIFI,
NET_LINK_LTE,
NET_LINK_BT_PAN,
} net_link_t;
typedef struct {
bool up;
int rssi;
int latency_ms;
int fail_count;
int priority;
int power_cost;
int traffic_cost;
} net_metric_t;
static net_link_t s_current_link = NET_LINK_NONE;
static net_link_t s_pending_link = NET_LINK_NONE;
static net_metric_t s_wifi = {
.up = false,
.rssi = -90,
.latency_ms = 999,
.priority = 3,
.power_cost = 1,
.traffic_cost = 0,
};
static net_metric_t s_lte = {
.up = false,
.rssi = -100,
.latency_ms = 999,
.priority = 2,
.power_cost = 4,
.traffic_cost = 4,
};
static net_metric_t s_btpan = {
.up = false,
.rssi = -90,
.latency_ms = 999,
.priority = 1,
.power_cost = 2,
.traffic_cost = 1,
};
static bool ai_session_is_busy(void)
{
/*
* TODO:
* 返回 true 表示正在录音、AI TTS 播放或 WebSocket 音频流传输。
* 对话中不强制切网,避免音频中断。
*/
return false;
}
static void wifi_update_metric(net_metric_t *m)
{
/*
* TODO:
* 1. esp_wifi_sta_get_ap_info 获取 RSSI。
* 2. ping AI gateway 获取 latency。
* 3. WebSocket 心跳失败则 fail_count++。
*/
m->up = true;
m->rssi = -55;
m->latency_ms = 35;
}
static void lte_update_metric(net_metric_t *m)
{
/*
* TODO:
* 1. AT+CSQ 获取信号。
* 2. AT+CREG? / AT+CEREG? 判断注册状态。
* 3. 判断 PPP netif 是否 up。
* 4. ping AI gateway。
*/
m->up = true;
m->rssi = -72;
m->latency_ms = 95;
}
static void btpan_update_metric(net_metric_t *m)
{
/*
* TODO:
* 1. 查询 7014 PAN 是否已连接手机。
* 2. 查询手机网络共享状态。
* 3. ping AI gateway。
*/
m->up = false;
m->rssi = -80;
m->latency_ms = 120;
}
static int calc_score(const net_metric_t *m)
{
if (!m->up) {
return -100000;
}
int score = 0;
score += m->priority * 1000;
score += m->rssi;
score -= m->latency_ms / 5;
score -= m->fail_count * 500;
score -= m->power_cost * 30;
score -= m->traffic_cost * 50;
return score;
}
static net_link_t choose_best_link(void)
{
int wifi_score = calc_score(&s_wifi);
int lte_score = calc_score(&s_lte);
int bt_score = calc_score(&s_btpan);
ESP_LOGI(TAG, "score wifi=%d lte=%d btpan=%d",
wifi_score, lte_score, bt_score);
if (wifi_score >= lte_score && wifi_score >= bt_score) {
return NET_LINK_WIFI;
}
if (lte_score >= wifi_score && lte_score >= bt_score) {
return NET_LINK_LTE;
}
if (bt_score >= wifi_score && bt_score >= lte_score) {
return NET_LINK_BT_PAN;
}
return NET_LINK_NONE;
}
static void set_default_link(net_link_t link)
{
switch (link) {
case NET_LINK_WIFI:
ESP_LOGI(TAG, "switch to Wi-Fi");
/*
* TODO:
* esp_netif_set_default_netif(wifi_netif);
* websocket_reconnect();
*/
break;
case NET_LINK_LTE:
ESP_LOGI(TAG, "switch to 4G LTE");
/*
* TODO:
* esp_netif_set_default_netif(ppp_netif);
* websocket_reconnect();
*/
break;
case NET_LINK_BT_PAN:
ESP_LOGI(TAG, "switch to Bluetooth PAN");
/*
* TODO:
* 通过 7014 建立 PAN 数据链路。
* websocket_reconnect();
*/
break;
default:
ESP_LOGW(TAG, "no network available, enter provisioning");
/*
* TODO:
* start_blufi_or_softap_provisioning();
*/
break;
}
s_current_link = link;
}
void network_policy_task(void *arg)
{
while (1) {
wifi_update_metric(&s_wifi);
lte_update_metric(&s_lte);
btpan_update_metric(&s_btpan);
net_link_t best = choose_best_link();
if (best != s_current_link) {
if (ai_session_is_busy()) {
s_pending_link = best;
ESP_LOGI(TAG, "AI busy, pending link=%d", best);
} else {
set_default_link(best);
s_pending_link = NET_LINK_NONE;
}
}
if (!ai_session_is_busy() && s_pending_link != NET_LINK_NONE) {
set_default_link(s_pending_link);
s_pending_link = NET_LINK_NONE;
}
vTaskDelay(pdMS_TO_TICKS(10000));
}
}
7.4 4G 模组 AT + PPP 初始化框架
#include <string.h>
#include "esp_log.h"
#include "esp_timer.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "board_config.h"
#define TAG "LTE"
static void modem_send_cmd(const char *cmd)
{
uart_write_bytes(LTE_UART, cmd, strlen(cmd));
uart_write_bytes(LTE_UART, "\r\n", 2);
ESP_LOGI(TAG, "MCU -> LTE: %s", cmd);
}
static bool modem_wait_keyword(const char *keyword, int timeout_ms)
{
uint8_t buf[256];
int total = 0;
int64_t start_ms = esp_timer_get_time() / 1000;
while ((esp_timer_get_time() / 1000 - start_ms) < timeout_ms) {
int n = uart_read_bytes(
LTE_UART,
buf + total,
sizeof(buf) - 1 - total,
pdMS_TO_TICKS(100)
);
if (n > 0) {
total += n;
buf[total] = 0;
if (strstr((char *)buf, keyword)) {
ESP_LOGI(TAG, "LTE <- %s", (char *)buf);
return true;
}
if (total > sizeof(buf) - 32) {
total = 0;
}
}
}
ESP_LOGW(TAG, "timeout waiting: %s", keyword);
return false;
}
static bool modem_at_ok(const char *cmd, int timeout_ms)
{
modem_send_cmd(cmd);
return modem_wait_keyword("OK", timeout_ms);
}
static void modem_power_on(void)
{
gpio_set_direction(LTE_PWRKEY_GPIO, GPIO_MODE_OUTPUT);
gpio_set_direction(LTE_RESET_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(LTE_RESET_GPIO, 1);
vTaskDelay(pdMS_TO_TICKS(100));
gpio_set_level(LTE_PWRKEY_GPIO, 1);
vTaskDelay(pdMS_TO_TICKS(1200));
gpio_set_level(LTE_PWRKEY_GPIO, 0);
vTaskDelay(pdMS_TO_TICKS(5000));
}
bool lte_modem_start_ppp(const char *apn)
{
char cmd[128];
modem_power_on();
for (int i = 0; i < 5; i++) {
if (modem_at_ok("AT", 1000)) {
break;
}
vTaskDelay(pdMS_TO_TICKS(1000));
}
modem_at_ok("ATE0", 1000);
modem_at_ok("AT+CPIN?", 1000);
modem_at_ok("AT+CSQ", 1000);
modem_at_ok("AT+CREG?", 1000);
modem_at_ok("AT+CEREG?", 1000);
modem_at_ok("AT+CGATT=1", 5000);
snprintf(cmd, sizeof(cmd), "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
modem_at_ok(cmd, 1000);
/*
* 不同 4G 模组拨号命令可能不同。
* 常见命令:ATD*99***1# 或 ATD*99#
*/
modem_send_cmd("ATD*99***1#");
if (!modem_wait_keyword("CONNECT", 10000)) {
ESP_LOGE(TAG, "PPP dial failed");
return false;
}
/*
* TODO:
* 收到 CONNECT 后,将 UART 交给 esp_modem / esp_netif PPP。
*/
ESP_LOGI(TAG, "PPP data mode entered");
return true;
}
7.5 AT+MCP:语音到设备控制
开发宝典中的 AT+MCP 适合把"自然语言"映射成 MCU 可执行的设备控制帧。协议默认 UART 为 115200, 8N1,所有 AT 指令以回车换行结束;AI 模组到 MCU 的帧格式为 0x55 0xAA LEN CMD DATA... 0xAA 0x55;当 MCU 收到 55 AA 01 FC AA 55 时,需要重启 AI 模组并重新发送 MCP 映射。
7.5.1 MCP 工具设计
set_speaker_volume 设置音量
set_lamp_color 设置 RGB 氛围灯
set_network_mode 切换 Wi-Fi / 4G / 蓝牙 PAN
enter_pairing 进入配网模式
play_local_prompt 播放提示音
customer_scene 接入客户业务系统
7.5.2 MCP UART 代码
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include "esp_log.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "board_config.h"
#define TAG "MCP"
#define FRAME_H1 0x55
#define FRAME_H2 0xAA
#define FRAME_T1 0xAA
#define FRAME_T2 0x55
#define CMD_STATUS 0xFF
#define CMD_RECOVER 0xFC
#define CMD_RGB 0xF1
#define CMD_VOLUME 0xF2
#define CMD_NET_MODE 0xF3
#define CMD_PAIRING 0xF4
#define CMD_CUSTOMER 0xF5
typedef enum {
AI_STARTING = 0x01,
AI_CONFIGURING = 0x02,
AI_IDLE = 0x03,
AI_CONNECTING = 0x04,
AI_LISTENING = 0x05,
AI_SPEAKING = 0x06,
AI_UPGRADING = 0x07,
AI_ACTIVATING = 0x08,
} ai_status_t;
static void ai_reset_module(void)
{
ESP_LOGW(TAG, "reset AI/VB6824 module");
gpio_set_direction(AI_RESET_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(AI_RESET_GPIO, 0);
vTaskDelay(pdMS_TO_TICKS(300));
gpio_set_level(AI_RESET_GPIO, 1);
vTaskDelay(pdMS_TO_TICKS(1500));
}
static void mcp_send_line(const char *line)
{
uart_write_bytes(AI_UART, line, strlen(line));
uart_write_bytes(AI_UART, "\r\n", 2);
ESP_LOGI(TAG, "MCU -> AI: %s", line);
}
static void ui_set_ai_status(ai_status_t status)
{
switch (status) {
case AI_STARTING:
ESP_LOGI(TAG, "AI starting");
break;
case AI_CONFIGURING:
ESP_LOGI(TAG, "AI configuring");
break;
case AI_IDLE:
ESP_LOGI(TAG, "AI idle");
break;
case AI_CONNECTING:
ESP_LOGI(TAG, "AI connecting");
break;
case AI_LISTENING:
ESP_LOGI(TAG, "AI listening");
break;
case AI_SPEAKING:
ESP_LOGI(TAG, "AI speaking");
break;
case AI_UPGRADING:
ESP_LOGI(TAG, "AI upgrading");
break;
case AI_ACTIVATING:
ESP_LOGI(TAG, "AI activating");
break;
default:
ESP_LOGW(TAG, "unknown AI status=0x%02X", status);
break;
}
}
static void speaker_set_rgb(uint8_t r, uint8_t g, uint8_t b)
{
ESP_LOGI(TAG, "RGB r=%u g=%u b=%u", r, g, b);
/*
* TODO:
* WS2812 用 RMT;
* 三路 PWM 灯用 LEDC。
*/
}
static void speaker_set_volume(uint8_t volume)
{
if (volume > 100) {
volume = 100;
}
ESP_LOGI(TAG, "volume=%u", volume);
/*
* TODO:
* 1. 设置播放器音量。
* 2. 设置功放或 Codec 音量。
* 3. 保存到 NVS。
*/
}
static void speaker_set_network_mode(uint8_t mode)
{
ESP_LOGI(TAG, "network mode=%u", mode);
/*
* mode:
* 0x01 Wi-Fi
* 0x02 4G
* 0x03 Bluetooth PAN
*/
}
static void speaker_enter_pairing(void)
{
ESP_LOGI(TAG, "enter pairing mode");
/*
* TODO:
* start_blufi_or_softap_provisioning();
*/
}
static void customer_scene_control(uint8_t scene_id, uint8_t action)
{
ESP_LOGI(TAG, "customer scene=%u action=%u", scene_id, action);
/*
* TODO:
* 1. MQTT 发布到客户平台;
* 2. HTTP 调客户 API;
* 3. UART / RS485 控制外部设备。
*/
}
static void mcp_register_tools(void)
{
mcp_send_line("AT");
mcp_send_line("AT+WIFICFG=0");
mcp_send_line("AT+CONNECT");
/*
* 用户:"把氛围灯调成红色"
*/
mcp_send_line(
"AT+ADDMCP=1,set_lamp_color,设置音箱氛围灯颜色,F1,3,R,G,B"
);
/*
* 用户:"音量调到 60"
*/
mcp_send_line(
"AT+ADDMCP=1,set_speaker_volume,设置音箱音量,F2,1,volume"
);
/*
* 用户:"切换到 4G 网络"
*/
mcp_send_line(
"AT+ADDMCP=1,set_network_mode,切换联网方式,F3,1,mode"
);
/*
* 用户:"重新配网"
*/
mcp_send_line(
"AT+ADDMCP=0,enter_pairing,让音箱进入配网模式,2,F4,01"
);
/*
* 用户:"打开客户系统的一号场景"
*/
mcp_send_line(
"AT+ADDMCP=1,customer_scene,控制客户业务系统,F5,2,scene_id,action"
);
}
static void mcp_handle_frame(uint8_t cmd, const uint8_t *data, uint8_t len)
{
if (cmd == CMD_RECOVER) {
ai_reset_module();
mcp_register_tools();
return;
}
if (cmd == CMD_STATUS && len >= 1) {
ui_set_ai_status((ai_status_t)data[0]);
return;
}
switch (cmd) {
case CMD_RGB:
if (len >= 3) {
speaker_set_rgb(data[0], data[1], data[2]);
}
break;
case CMD_VOLUME:
if (len >= 1) {
speaker_set_volume(data[0]);
}
break;
case CMD_NET_MODE:
if (len >= 1) {
speaker_set_network_mode(data[0]);
}
break;
case CMD_PAIRING:
speaker_enter_pairing();
break;
case CMD_CUSTOMER:
if (len >= 2) {
customer_scene_control(data[0], data[1]);
}
break;
default:
ESP_LOGW(TAG, "unknown MCP cmd=0x%02X len=%u", cmd, len);
break;
}
}
static void mcp_rx_task(void *arg)
{
uint8_t frame[160];
uint8_t pos = 0;
int expected = -1;
while (1) {
uint8_t b = 0;
int n = uart_read_bytes(AI_UART, &b, 1, pdMS_TO_TICKS(100));
if (n <= 0) {
continue;
}
if (pos == 0 && b != FRAME_H1) {
continue;
}
if (pos == 1 && b != FRAME_H2) {
pos = 0;
expected = -1;
continue;
}
frame[pos++] = b;
if (pos == 3) {
uint8_t len = frame[2];
if (len == 0 || len > 150) {
pos = 0;
expected = -1;
continue;
}
expected = 2 + 1 + len + 2;
}
if (expected > 0 && pos >= expected) {
uint8_t len = frame[2];
if (frame[3 + len] == FRAME_T1 &&
frame[4 + len] == FRAME_T2) {
uint8_t cmd = frame[3];
const uint8_t *data = &frame[4];
uint8_t data_len = len - 1;
mcp_handle_frame(cmd, data, data_len);
} else {
ESP_LOGW(TAG, "bad frame tail");
}
pos = 0;
expected = -1;
}
if (pos >= sizeof(frame)) {
pos = 0;
expected = -1;
}
}
}
void mcp_uart_bridge_start(void)
{
uart_config_t cfg = {
.baud_rate = AI_UART_BAUD,
.data_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
.source_clk = UART_SCLK_DEFAULT,
};
uart_driver_install(AI_UART, 2048, 2048, 0, NULL, 0);
uart_param_config(AI_UART, &cfg);
uart_set_pin(
AI_UART,
AI_UART_TX_GPIO,
AI_UART_RX_GPIO,
UART_PIN_NO_CHANGE,
UART_PIN_NO_CHANGE
);
ai_reset_module();
mcp_register_tools();
xTaskCreate(mcp_rx_task, "mcp_rx", 4096, NULL, 10, NULL);
}
7.6 音频焦点与实时打断
#include <stdbool.h>
#include "esp_log.h"
#define TAG "AUDIO_FOCUS"
typedef enum {
AUDIO_SRC_NONE = 0,
AUDIO_SRC_SYSTEM_ALERT,
AUDIO_SRC_AI_LISTENING,
AUDIO_SRC_AI_TTS,
AUDIO_SRC_ALARM,
AUDIO_SRC_BT_MUSIC,
AUDIO_SRC_UI_TONE,
} audio_source_t;
static audio_source_t s_current_audio = AUDIO_SRC_NONE;
static int audio_priority(audio_source_t src)
{
switch (src) {
case AUDIO_SRC_SYSTEM_ALERT: return 100;
case AUDIO_SRC_AI_LISTENING: return 90;
case AUDIO_SRC_AI_TTS: return 80;
case AUDIO_SRC_ALARM: return 70;
case AUDIO_SRC_BT_MUSIC: return 50;
case AUDIO_SRC_UI_TONE: return 30;
default: return 0;
}
}
static void stop_tts_player(void)
{
ESP_LOGI(TAG, "stop TTS");
/*
* TODO:
* 1. 停止 I2S 播放;
* 2. 清空 TTS ringbuffer;
* 3. 通知 WebSocket 当前 TTS 被打断。
*/
}
static void duck_bt_music(void)
{
ESP_LOGI(TAG, "duck Bluetooth music");
/*
* TODO:
* 通过 7014 或蓝牙音频芯片降低 A2DP 音量。
*/
}
bool audio_request_focus(audio_source_t src)
{
if (audio_priority(src) < audio_priority(s_current_audio)) {
return false;
}
if (s_current_audio == AUDIO_SRC_AI_TTS &&
src == AUDIO_SRC_AI_LISTENING) {
stop_tts_player();
}
if (s_current_audio == AUDIO_SRC_BT_MUSIC &&
src == AUDIO_SRC_AI_LISTENING) {
duck_bt_music();
}
s_current_audio = src;
return true;
}
void on_wakeup_word_detected(void)
{
ESP_LOGI(TAG, "wake word detected");
audio_request_focus(AUDIO_SRC_AI_LISTENING);
/*
* TODO:
* 1. 更新 UI 到 Listening;
* 2. 停止 TTS 或降低蓝牙音乐;
* 3. 打开上行音频流;
* 4. 通知 AI session 开始新一轮对话。
*/
}
void on_realtime_barge_in_detected(void)
{
ESP_LOGI(TAG, "real-time barge-in detected");
audio_request_focus(AUDIO_SRC_AI_LISTENING);
}
void on_ai_tts_start(void)
{
audio_request_focus(AUDIO_SRC_AI_TTS);
}
void on_ai_tts_finish(void)
{
s_current_audio = AUDIO_SRC_NONE;
}
VB6824 自定义唤醒词流程中,开发宝典说明升级完成后可以支持选定唤醒词,并且在 AI 说话过程中随时打断。
7.7 客户系统接入示例:MQTT / HTTP
MQTT 上报设备状态
#include <stdio.h>
#include "esp_log.h"
#define TAG "CUSTOMER_MQTT"
typedef struct {
int wifi_rssi;
int battery;
int volume;
int network_mode;
const char *ai_state;
const char *fw_version;
} device_shadow_t;
static void mqtt_publish_shadow(const char *payload)
{
/*
* TODO:
* esp_mqtt_client_publish(
* mqtt,
* "sibo/speaker/speaker_001/shadow/update",
* payload,
* 0,
* 1,
* 0
* );
*/
ESP_LOGI(TAG, "shadow=%s", payload);
}
void customer_upload_shadow(const device_shadow_t *s)
{
char payload[512];
snprintf(payload, sizeof(payload),
"{"
"\"fw_version\":\"%s\","
"\"wifi_rssi\":%d,"
"\"battery\":%d,"
"\"volume\":%d,"
"\"network_mode\":%d,"
"\"ai\":{\"state\":\"%s\"}"
"}",
s->fw_version,
s->wifi_rssi,
s->battery,
s->volume,
s->network_mode,
s->ai_state
);
mqtt_publish_shadow(payload);
}
HTTP 调客户场景接口
#include <stdio.h>
#include <string.h>
#include "esp_http_client.h"
#include "esp_log.h"
#define TAG "CUSTOMER_HTTP"
esp_err_t customer_http_call_scene(uint8_t scene_id, uint8_t action)
{
char body[128];
snprintf(body, sizeof(body),
"{\"device_id\":\"speaker_001\",\"scene_id\":%u,\"action\":%u}",
scene_id,
action);
esp_http_client_config_t config = {
.url = "https://api.customer.com/v1/scene/control",
.method = HTTP_METHOD_POST,
.timeout_ms = 8000,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_http_client_set_header(client, "Authorization", "Bearer ${token}");
esp_http_client_set_post_field(client, body, strlen(body));
esp_err_t err = esp_http_client_perform(client);
int status = esp_http_client_get_status_code(client);
ESP_LOGI(TAG, "customer api status=%d err=%s",
status,
esp_err_to_name(err));
esp_http_client_cleanup(client);
return err;
}
8. 私有化后端与 AI 链路
开发宝典中说明,设备默认可连接小智官方服务,也可以运行开源后端服务,让设备连接自己的后端;后端提供 OTA 接口和 WebSocket 接口,并可配置 LLM、TTS、人设等参数。
推荐后端结构:
Nginx / Caddy
├── HTTPS OTA
├── WSS WebSocket
├── Device Auth
├── ASR
├── LLM
├── TTS
├── MCP Tool Server
├── Customer API Gateway
└── Log / Device Shadow
配置示例:
server:
websocket_url: "wss://ai.customer.com/xiaozhi/v1/"
ota_url: "https://ai.customer.com/xiaozhi/ota/"
mqtt_uri: "mqtts://mqtt.customer.com"
device:
product_id: "sibo_ai_speaker_4g_s3"
auth_type: "token"
shadow_enable: true
log_upload_enable: true
ai:
ASR: "FunASR"
LLM: "CustomerLLM"
TTS: "DoubaoTTS"
Intent: "function_call"
capabilities:
- voice_wakeup
- realtime_barge_in
- wifi
- lte_4g
- bluetooth_pan
- bluetooth_speaker
- display
- mcp
- ota
- customer_api
9. OTA 与分区设计
推荐 16MB Flash 分区:
# Name, Type, SubType, Offset, Size
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, 0x320000, 0x300000
ota_1, app, ota_1, 0x620000, 0x300000
storage, data, fat, 0x920000, 0x500000
coredump, data, coredump,0xE20000, 0x100000
OTA 策略:
1. 主控固件 OTA:
ESP32-S3 双 OTA 分区,失败自动回滚。
2. 资源 OTA:
屏幕素材、提示音、默认配置、语音提示资源。
3. VB6824 固件:
单独走语音芯片升级流程,避免和主控 OTA 混淆。
4. 4G 流量控制:
4G 下只允许紧急升级或小版本补丁;
大版本升级建议提示用户切换 Wi-Fi。
5. 灰度发布:
按 product_id / batch_id / device_id 分批升级。
6. 安全:
HTTPS OTA、固件签名、NVS 加密保存 token。
10. 产测方案
10.1 工厂测试项目
主控:
- ESP32-S3 Flash / PSRAM 检测
- Wi-Fi MAC / BLE MAC
- SN 写入
- NVS 读写
- 固件版本读取
语音:
- VB6824 UART 通信
- MIC 电平
- 喇叭播放 1kHz
- 唤醒词测试
- TTS 播报中打断测试
- 高噪环境唤醒测试
网络:
- Wi-Fi 扫描
- Wi-Fi 连接
- 4G SIM 检测
- 4G CSQ
- 4G 注册
- PPP 拨号
- 蓝牙广播
- 蓝牙 PAN / A2DP 检测
UI:
- LCD 显示
- RGB LED
- 按键单击 / 双击 / 三击 / 长按
- 音量控制
云端:
- OTA 请求
- WebSocket 连接
- 设备激活
- MCP 指令闭环
- 客户 API 调用
10.2 产测命令建议
FACTORY ENTER
FACTORY SET_SN=SBOS3G20260001
FACTORY WIFI_SCAN
FACTORY WIFI_CONNECT=ssid,password
FACTORY LTE_CSQ
FACTORY LTE_DIAL
FACTORY BT_ADV
FACTORY MIC_LEVEL
FACTORY SPK_PLAY=1000HZ
FACTORY WAKE_TEST
FACTORY BARGE_IN_TEST
FACTORY LCD_TEST
FACTORY LED_RGB=255,0,0
FACTORY MQTT_CONNECT
FACTORY OTA_CHECK
FACTORY MCP_TEST
FACTORY EXIT
11. 推荐产品版本
11.1 标准 4G S3 音箱版
ESP32-S3R8 + 16M Flash + 8M PSRAM
VB6824
4G Cat.1 UART PPP
Wi-Fi + BLE BluFi
1.3 / 1.54 寸屏
3W / 4Ω 喇叭
单麦 / 双麦
电池 + Type-C
小智 / 豆包 / ChatGPT / 私有后端
AT+MCP 二次开发
适合:家庭音箱、儿童故事机、AI 桌面助手、商用语音终端。
11.2 增强三模版
ESP32-S3R8 + 16M Flash + 8M PSRAM
VB6824
4G Cat.1 / Cat.4
7014 蓝牙 PAN + 蓝牙音箱
Wi-Fi STA / SoftAP
BLE BluFi
LCD 屏幕
RGB 氛围灯
3W~5W 喇叭
实时打断
自定义唤醒词
OTA + 产测 + 私有化后端
适合:户外音箱、展厅导览、车载 AI 音箱、移动 AI 设备。
11.3 B 端客户系统版
ESP32-S3R8
VB6824
Wi-Fi / 4G / 蓝牙 PAN
客户私有 LLM
客户知识库
客户业务 API
MQTT / HTTP / WebSocket
远程运维
批量 OTA
日志上报
适合:酒店、门店、展厅、养老、教育、智能家居中控、行业私有化部署。
12. 方案总结
四博 AI 智能音箱 4G S3 版本建议采用 ESP32-S3R8 + 16M Flash + 8M PSRAM + VB6824 + 4G 模组 + 可选 7014 蓝牙协处理器 的平台化架构。
ESP32-S3 负责 Wi-Fi、BLE、4G 管理、屏幕 UI、WebSocket、OTA、MCP 和客户系统接入;VB6824 负责远距离拾音、离线唤醒、AEC、降噪、唤醒词打断和自定义唤醒词;4G 模组负责无 Wi-Fi 场景联网;7014 负责蓝牙 PAN 上网和蓝牙音箱能力。软件上基于 DOIT_AI、小智协议、AT+MCP、BluFi 配网、实时打断固件和私有化后端,可快速形成一套适合品牌客户、方案商客户和 B 端行业客户的可量产 AI 智能音箱方案。