四博 AI 智能拍学机 / AI 智能音箱技术方案

下面是一套偏 工程落地 / 技术评审 / 客户方案书 风格的"四博 AI 智能拍学机 / AI 智能音箱一体化方案"。这里把"AI 智能拍学机"定义为:AI 智能音箱 + 摄像头拍题学习 + 屏幕交互 + 学习游戏 + 大模型辅导 + 远程管理 + 客户系统接入

方案基于你上传的《四博智联 AI 开发宝典》《深圳四博智联 AI 硬件选型表 2026》和《2026 年四博智联模组选型手册-乐鑫系》。资料中明确提到,ESP32-C2 / C3 / S3 加 VB6824 语音方案已经成熟应用于电子吧唧、S3 双目、S3 拍学机、地球仪、拍拍灯等方向;VB6824 可完成音频编解码、AEC、语音唤醒、改唤醒词等功能,让主控芯片专注通信和 UI。

四博 AI 智能拍学机 / AI 智能音箱技术方案

1. 产品定位

本方案面向一款儿童学习类 AI 硬件,产品形态可以是:

复制代码
AI 智能拍学机
= AI 智能音箱
+ 摄像头拍题
+ 屏幕显示
+ 学习辅导
+ 互动游戏
+ 语音对话
+ 本地内容
+ 远程管理
+ 客户系统接入

核心功能包括:

复制代码
1. AI 对话:
   语音唤醒、连续对话、知识问答、百科解释、故事陪伴。

2. 拍照学习:
   拍题识别、OCR、错题讲解、英语单词识别、绘本识别、口算批改。

3. 学习模式:
   语文、数学、英语、百科、绘本阅读、单词记忆、每日学习任务。

4. 游戏模式:
   口算闯关、单词消消乐、成语接龙、记忆训练、听音辨词、AI 猜谜。

5. 远程管理:
   家长端管理、内容下发、学习报告、OTA、参数配置、日志诊断。

6. 二次开发:
   支持 ESP-IDF、DOIT_AI、小智协议、AT+MCP、HTTP、MQTT、WebSocket。

硬件建议采用 ESP32-S3R8 + 16M Flash + 8M PSRAM + VB6824 + 摄像头 + 屏幕 + 麦克风 + 喇叭。四博选型资料中,AI 智能相机形态已经包含 2.0 寸屏、4G 选配、存储卡选配、摄像头、镜片、主板、麦克风、电池包、喇叭和线材,主控为 ESP32S3R8 + 16M Flash + VB6824,可选小智、豆包、ChatGPT 等大模型,适合品牌 B 端客户或方案商客户定制。


2. 推荐硬件架构

2.1 整体框图

复制代码
┌──────────────────────────────────────────────────────────────┐
│                  四博 AI 智能拍学机 / AI 音箱                 │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  ┌──────────────────────┐       UART / GPIO                  │
│  │ VB6824 语音前端       │◄─────────────────────────────┐     │
│  │ - 离线唤醒             │                              │     │
│  │ - AEC 回声消除         │                              │     │
│  │ - 降噪                 │                              │     │
│  │ - 唤醒词打断           │                              │     │
│  │ - 改唤醒词             │                              │     │
│  └─────────┬────────────┘                              │     │
│            │ MIC / 回采音频                             │     │
│                                                         ▼     │
│  ┌────────────────────────────────────────────────────────┐   │
│  │ ESP32-S3R8 + 16M Flash + 8M PSRAM                     │   │
│  │ - Wi-Fi / BLE BluFi                                   │   │
│  │ - WebSocket AI 对话                                   │   │
│  │ - 摄像头采集 / JPEG 编码                              │   │
│  │ - OCR / VLM / 拍题后端请求                            │   │
│  │ - LCD UI / 游戏界面                                   │   │
│  │ - 本地学习游戏引擎                                    │   │
│  │ - SD 卡 / Flash 内容缓存,可选                         │   │
│  │ - OTA / 远程管理 / 日志                               │   │
│  │ - MCP 工具调用 / 客户系统接入                         │   │
│  └───────┬───────────────┬───────────────┬────────────────┘   │
│          │               │               │                    │
│  ┌───────▼──────┐ ┌──────▼──────┐ ┌──────▼────────┐           │
│  │ Camera        │ │ LCD / Touch │ │ I2S AMP+SPK   │           │
│  │ 拍题 / 识物    │ │ 学习/游戏UI │ │ TTS/提示音     │           │
│  └──────────────┘ └─────────────┘ └───────────────┘           │
│                                                              │
│  可选扩展:4G 模组 / 7014 蓝牙 PAN / SD 卡 / IMU / 触摸按键    │
└──────────────────────────────────────────────────────────────┘

云端 / 私有化后端:
┌──────────────────────────────────────────────────────────────┐
│ OTA │ WebSocket │ ASR │ LLM │ TTS │ OCR │ VLM │ 题库 │ 家长后台 │
└──────────────────────────────────────────────────────────────┘

3. 主控选型

推荐使用四博 ESPS3-32-N16R8 / ESPS3-32E-N16R8

根据乐鑫系模组选型手册,ESPS3-32 系列支持 ESP32-S3 / S3R2 / S3R8,提供 N4、N8、N8R2、N16R2、N16R8 等子型号,18 × 25.5mm 通用模组,兼容 ESP32-S3-WROOM-1 系列;ESPS3-32E 为 18 × 19.2mm,兼容 ESP32-S3-WROOM-1U 系列。

推荐配置:

复制代码
主控:ESP32-S3R8
Flash:16MB
PSRAM:8MB
无线:2.4GHz Wi-Fi + BLE
显示:SPI / RGB / I8080 LCD
摄像头:DVP Camera
音频:I2S 输出 + MIC / VB6824

选择 ESP32-S3 的原因:

复制代码
1. 适合音视频 / AI 市场;
2. 支持摄像头 DVP;
3. 支持 LCD 屏幕;
4. PSRAM 可承载 JPEG buffer、UI buffer、WebSocket buffer;
5. ESP-IDF 生态成熟;
6. 适合客户二次开发和量产。

开发宝典中的多模态方案 DOIT_ESPS3_AI_EYE_Vision 就是基于 ESP32-S3,集摄像头、双目显示和触摸交互于一体,硬件与软件全开源,可直接用于二次开发或量产制造。


4. 功能架构

4.1 AI 音箱能力

复制代码
用户:"你好小智,帮我讲一个恐龙故事。"
  ↓
VB6824 唤醒
  ↓
ESP32-S3 建立 AI 会话
  ↓
WebSocket 上传音频
  ↓
ASR + LLM + TTS
  ↓
喇叭播放 + 屏幕显示文字 / 表情

支持能力:

复制代码
1. 唤醒词唤醒;
2. 按键唤醒;
3. AI 多轮对话;
4. TTS 播报;
5. 声音克隆;
6. 知识库问答;
7. MCP 工具扩展;
8. 客户自有大模型接入。

4.2 拍题学习能力

复制代码
用户:"小博,帮我看一下这道题。"
  ↓
摄像头拍照
  ↓
JPEG 压缩
  ↓
上传 OCR / VLM / 拍题服务
  ↓
返回题目文本、答案、步骤、知识点
  ↓
LLM 生成儿童友好解释
  ↓
屏幕显示步骤 + TTS 讲解

典型学习场景:

复制代码
数学:
  - 口算批改
  - 应用题讲解
  - 竖式计算识别
  - 错题归因

语文:
  - 生字解释
  - 拼音纠错
  - 课文朗读
  - 成语解释

英语:
  - 单词识别
  - 跟读评分
  - 中英互译
  - 情景对话

绘本:
  - 拍图讲故事
  - 识别画面内容
  - 提问互动

4.3 游戏能力

游戏不建议做复杂 3D,而建议做 轻量级学习游戏

复制代码
1. 口算闯关;
2. 单词选择;
3. 成语接龙;
4. 听音辨词;
5. 看图猜物;
6. 记忆翻牌;
7. 学习打卡;
8. 积分成长系统。

游戏逻辑本地运行,题库和成长数据可云端同步:

复制代码
本地:
  - UI 渲染
  - 按键 / 触摸输入
  - 计时
  - 分数
  - 简单题库

云端:
  - 学习报告
  - 个性化推荐
  - 错题本
  - 家长端任务
  - 排行榜,可选

AI 硬件选型表中提到 ESP32-S3 + 7014 + 摄像头 + 4G 高端方案具有开发者生态好、可多模态、可以玩游戏、可以当蓝牙音箱等特点,这类能力非常适合扩展成 AI 拍学机。


5. 软件系统设计

5.1 组件划分

复制代码
main/
  app_main.c

components/
  board/
    board_config.h
    board_init.c

  audio/
    audio_focus.c
    tts_player.c
    wakeup_frontend.c

  ai/
    ai_session.c
    websocket_client.c
    mcp_uart_bridge.c

  camera/
    camera_service.c
    image_capture.c

  learning/
    study_session.c
    ocr_client.c
    vlm_client.c
    homework_solver.c
    wrong_book.c

  game/
    game_engine.c
    math_quiz.c
    word_game.c
    idiom_game.c

  ui/
    display_manager.c
    screen_learning.c
    screen_game.c
    screen_status.c

  remote/
    remote_manager.c
    mqtt_shadow.c
    ota_manager.c

  customer/
    customer_http.c
    customer_mqtt.c

5.2 FreeRTOS 任务

任务 优先级 作用
audio_frontend_task 唤醒、打断、录音状态
ai_session_task AI WebSocket、ASR、LLM、TTS
camera_task 中高 拍照、JPEG buffer 管理
learning_task 中高 拍题、OCR、VLM、学习结果处理
game_task 学习游戏状态机
ui_task 屏幕刷新、学习界面、游戏界面
remote_task 远程管理、家长端命令、状态上报
mcp_uart_task 中高 AT+MCP 语音工具调用
ota_task 固件 OTA、资源 OTA
log_task 学习日志、错误日志上传

6. 开发环境与工程编译

开发宝典说明,小智 AI 硬件设备的开源代码可在 VSCode 中安装 ESP-IDF 扩展和编译工具进行编译烧录;多模态工程使用 VSCode 打开,ESP-IDF 版本需大于等于 5.3.2,并设置目标芯片为 esp32s3

6.1 DOIT_AI 基础工程

复制代码
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

6.2 多模态视觉工程

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

idf.py set-target esp32s3
idf.py menuconfig
idf.py build
idf.py -p /dev/ttyUSB0 flash monitor
复制代码
Board Type:
  Sibo AI Study Camera Speaker S3

Audio:
  VB6824 Enable = y
  USE_DEVICE_AEC = y

Camera:
  Enable Camera = y
  Pixel Format = JPEG
  Frame Size = VGA / SVGA

Display:
  LCD Enable = y
  Study UI = y
  Game UI = y

Network:
  Wi-Fi = y
  BluFi Provisioning = y
  4G Optional = n / y

AI:
  Xiaozhi WebSocket = y
  MCP Enable = y
  Vision Tool = y

Learning:
  OCR Enable = y
  Homework Solver Enable = y
  Local Game Engine = y

Remote:
  MQTT Shadow = y
  OTA = y
  Log Upload = y

7. 关键代码示例

下面代码为工程骨架示例,可直接作为 ESP-IDF 组件起点。GPIO、屏幕驱动、摄像头型号、后端接口 URL 需要按实际 PCB 和客户平台调整。


7.1 板级配置 board_config.h

复制代码
#pragma once

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

/*
 * 四博 AI 智能拍学机 / AI 智能音箱
 * ESP32-S3R8 + 16M Flash + 8M PSRAM + VB6824 + Camera + LCD
 */

#define BOARD_NAME                      "SIBO_AI_STUDY_CAMERA_S3"

/* ---------- AI / VB6824 UART ---------- */
#define AI_UART                         UART_NUM_1
#define AI_UART_BAUD                    115200
#define AI_UART_TX_GPIO                 GPIO_NUM_42
#define AI_UART_RX_GPIO                 GPIO_NUM_41
#define AI_RESET_GPIO                   GPIO_NUM_40

/* ---------- Camera DVP,示例,量产需按 PCB 修改 ---------- */
#define CAM_PIN_PWDN                    GPIO_NUM_NC
#define CAM_PIN_RESET                   GPIO_NUM_NC
#define CAM_PIN_XCLK                    GPIO_NUM_15
#define CAM_PIN_SIOD                    GPIO_NUM_4
#define CAM_PIN_SIOC                    GPIO_NUM_5
#define CAM_PIN_D0                      GPIO_NUM_11
#define CAM_PIN_D1                      GPIO_NUM_9
#define CAM_PIN_D2                      GPIO_NUM_8
#define CAM_PIN_D3                      GPIO_NUM_10
#define CAM_PIN_D4                      GPIO_NUM_12
#define CAM_PIN_D5                      GPIO_NUM_13
#define CAM_PIN_D6                      GPIO_NUM_14
#define CAM_PIN_D7                      GPIO_NUM_16
#define CAM_PIN_VSYNC                   GPIO_NUM_6
#define CAM_PIN_HREF                    GPIO_NUM_7
#define CAM_PIN_PCLK                    GPIO_NUM_21

/* ---------- LCD SPI ---------- */
#define LCD_SPI_HOST                    SPI2_HOST
#define LCD_SPI_SCLK_GPIO               GPIO_NUM_35
#define LCD_SPI_MOSI_GPIO               GPIO_NUM_36
#define LCD_CS_GPIO                     GPIO_NUM_37
#define LCD_DC_GPIO                     GPIO_NUM_38
#define LCD_RST_GPIO                    GPIO_NUM_39
#define LCD_BL_GPIO                     GPIO_NUM_45

/* ---------- I2S Speaker ---------- */
#define I2S_BCLK_GPIO                   GPIO_NUM_1
#define I2S_LRCK_GPIO                   GPIO_NUM_2
#define I2S_DOUT_GPIO                   GPIO_NUM_3
#define AMP_EN_GPIO                     GPIO_NUM_46

/* ---------- Keys / Touch ---------- */
#define KEY_BOOT_GPIO                   GPIO_NUM_0
#define KEY_CAPTURE_GPIO                GPIO_NUM_47
#define KEY_GAME_GPIO                   GPIO_NUM_48

/* ---------- Remote / Backend ---------- */
#define AI_WS_URL                       "wss://ai.customer.com/xiaozhi/v1/"
#define OTA_URL                         "https://ota.customer.com/study_camera/ota/"
#define OCR_API_URL                     "https://api.customer.com/v1/ocr"
#define VLM_API_URL                     "https://api.customer.com/v1/vision"
#define STUDY_API_URL                   "https://api.customer.com/v1/study/solve"
#define MQTT_URI                        "mqtts://mqtt.customer.com"

7.2 摄像头初始化与拍照

复制代码
#include "esp_log.h"
#include "esp_camera.h"
#include "board_config.h"

#define TAG "CAMERA"

static camera_fb_t *s_last_fb = NULL;

esp_err_t camera_service_init(void)
{
    camera_config_t config = {
        .pin_pwdn = CAM_PIN_PWDN,
        .pin_reset = CAM_PIN_RESET,
        .pin_xclk = CAM_PIN_XCLK,
        .pin_sccb_sda = CAM_PIN_SIOD,
        .pin_sccb_scl = CAM_PIN_SIOC,

        .pin_d7 = CAM_PIN_D7,
        .pin_d6 = CAM_PIN_D6,
        .pin_d5 = CAM_PIN_D5,
        .pin_d4 = CAM_PIN_D4,
        .pin_d3 = CAM_PIN_D3,
        .pin_d2 = CAM_PIN_D2,
        .pin_d1 = CAM_PIN_D1,
        .pin_d0 = CAM_PIN_D0,

        .pin_vsync = CAM_PIN_VSYNC,
        .pin_href = CAM_PIN_HREF,
        .pin_pclk = CAM_PIN_PCLK,

        .xclk_freq_hz = 20000000,
        .ledc_timer = LEDC_TIMER_2,
        .ledc_channel = LEDC_CHANNEL_5,

        .pixel_format = PIXFORMAT_JPEG,
        .frame_size = FRAMESIZE_VGA,
        .jpeg_quality = 12,
        .fb_count = 2,
        .fb_location = CAMERA_FB_IN_PSRAM,
        .grab_mode = CAMERA_GRAB_LATEST,
    };

    esp_err_t err = esp_camera_init(&config);
    if (err != ESP_OK) {
        ESP_LOGE(TAG, "camera init failed: 0x%x", err);
        return err;
    }

    ESP_LOGI(TAG, "camera init done");
    return ESP_OK;
}

camera_fb_t *camera_capture_jpeg(void)
{
    if (s_last_fb) {
        esp_camera_fb_return(s_last_fb);
        s_last_fb = NULL;
    }

    s_last_fb = esp_camera_fb_get();
    if (!s_last_fb) {
        ESP_LOGE(TAG, "capture failed");
        return NULL;
    }

    ESP_LOGI(TAG, "capture jpeg len=%u", s_last_fb->len);
    return s_last_fb;
}

void camera_release_last(void)
{
    if (s_last_fb) {
        esp_camera_fb_return(s_last_fb);
        s_last_fb = NULL;
    }
}

7.3 拍题识别客户端

这个模块负责把摄像头图片上传给后端 OCR / VLM / 拍题服务,并接收解析结果。

复制代码
#include <stdio.h>
#include <string.h>
#include "esp_log.h"
#include "esp_http_client.h"
#include "esp_camera.h"
#include "board_config.h"

#define TAG "STUDY_SOLVER"

typedef enum {
    STUDY_SUBJECT_UNKNOWN = 0,
    STUDY_SUBJECT_MATH,
    STUDY_SUBJECT_CHINESE,
    STUDY_SUBJECT_ENGLISH,
    STUDY_SUBJECT_GENERAL,
} study_subject_t;

typedef struct {
    study_subject_t subject;
    char question[512];
    char answer[512];
    char steps[1024];
    char knowledge[256];
    int confidence;
} study_result_t;

extern camera_fb_t *camera_capture_jpeg(void);
extern void camera_release_last(void);
extern void display_show_study_result(const study_result_t *result);
extern void ai_tts_speak_text(const char *text);

static esp_err_t upload_homework_image(camera_fb_t *fb,
                                       study_subject_t subject,
                                       study_result_t *out)
{
    if (!fb || !out) {
        return ESP_ERR_INVALID_ARG;
    }

    char subject_header[16];

    switch (subject) {
    case STUDY_SUBJECT_MATH:
        snprintf(subject_header, sizeof(subject_header), "math");
        break;
    case STUDY_SUBJECT_CHINESE:
        snprintf(subject_header, sizeof(subject_header), "chinese");
        break;
    case STUDY_SUBJECT_ENGLISH:
        snprintf(subject_header, sizeof(subject_header), "english");
        break;
    default:
        snprintf(subject_header, sizeof(subject_header), "auto");
        break;
    }

    esp_http_client_config_t config = {
        .url = STUDY_API_URL,
        .method = HTTP_METHOD_POST,
        .timeout_ms = 20000,
        .buffer_size = 4096,
    };

    esp_http_client_handle_t client = esp_http_client_init(&config);

    esp_http_client_set_header(client, "Content-Type", "image/jpeg");
    esp_http_client_set_header(client, "X-Device-Id", "study_camera_001");
    esp_http_client_set_header(client, "X-Subject", subject_header);
    esp_http_client_set_post_field(client, (const char *)fb->buf, fb->len);

    esp_err_t err = esp_http_client_perform(client);
    int status = esp_http_client_get_status_code(client);

    ESP_LOGI(TAG, "study api status=%d err=%s", status, esp_err_to_name(err));

    /*
     * 量产工程中这里应读取 HTTP response body 并解析 JSON。
     * 示例返回:
     * {
     *   "subject": "math",
     *   "question": "12 + 35 = ?",
     *   "answer": "47",
     *   "steps": "先算个位 2+5=7,再算十位 1+3=4,所以结果是47。",
     *   "knowledge": "两位数加法",
     *   "confidence": 92
     * }
     */

    out->subject = subject;
    snprintf(out->question, sizeof(out->question), "12 + 35 = ?");
    snprintf(out->answer, sizeof(out->answer), "47");
    snprintf(out->steps, sizeof(out->steps),
             "先算个位:2 加 5 等于 7;再算十位:1 加 3 等于 4,所以答案是 47。");
    snprintf(out->knowledge, sizeof(out->knowledge), "两位数加法");
    out->confidence = 92;

    esp_http_client_cleanup(client);
    return err;
}

void study_capture_and_solve(study_subject_t subject)
{
    ai_tts_speak_text("好的,我来帮你看一下这道题。");

    camera_fb_t *fb = camera_capture_jpeg();
    if (!fb) {
        ai_tts_speak_text("摄像头打开失败,请检查摄像头连接。");
        return;
    }

    study_result_t result = {0};
    esp_err_t err = upload_homework_image(fb, subject, &result);

    camera_release_last();

    if (err != ESP_OK) {
        ai_tts_speak_text("题目识别失败,请稍后再试。");
        return;
    }

    display_show_study_result(&result);
    ai_tts_speak_text(result.steps);

    /*
     * TODO:
     * 1. 保存到错题本;
     * 2. 上传学习记录;
     * 3. 推荐相似题;
     * 4. 给家长端推送学习报告。
     */
}

7.4 本地学习游戏引擎

这里给一个轻量级"口算闯关"游戏框架。真实产品可以扩展英语单词、成语接龙、记忆训练等模式。

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "esp_log.h"

#define TAG "GAME"

typedef enum {
    GAME_NONE = 0,
    GAME_MATH_QUIZ,
    GAME_WORD_SELECT,
    GAME_IDIOM_CHAIN,
} game_type_t;

typedef struct {
    int a;
    int b;
    char op;
    int answer;
    int options[4];
    int correct_index;
} math_question_t;

typedef struct {
    game_type_t type;
    int level;
    int score;
    int combo;
    int question_index;
    math_question_t current_math;
} game_session_t;

static game_session_t s_game = {0};

extern void display_game_question(const math_question_t *q, int score, int level);
extern void display_game_result(bool correct, int score);
extern void ai_tts_speak_text(const char *text);

static int rand_range(int min, int max)
{
    return min + rand() % (max - min + 1);
}

static void generate_math_question(int level, math_question_t *q)
{
    int max = 10 + level * 5;

    q->a = rand_range(1, max);
    q->b = rand_range(1, max);
    q->op = '+';
    q->answer = q->a + q->b;

    q->correct_index = rand_range(0, 3);

    for (int i = 0; i < 4; i++) {
        if (i == q->correct_index) {
            q->options[i] = q->answer;
        } else {
            int delta = rand_range(-5, 5);
            if (delta == 0) {
                delta = 3;
            }
            q->options[i] = q->answer + delta;
        }
    }
}

void game_start_math_quiz(int level)
{
    if (level < 1) {
        level = 1;
    }

    s_game.type = GAME_MATH_QUIZ;
    s_game.level = level;
    s_game.score = 0;
    s_game.combo = 0;
    s_game.question_index = 0;

    generate_math_question(level, &s_game.current_math);

    display_game_question(&s_game.current_math, s_game.score, s_game.level);
    ai_tts_speak_text("口算闯关开始,请选择正确答案。");
}

void game_answer_option(int option_index)
{
    if (s_game.type != GAME_MATH_QUIZ) {
        return;
    }

    bool correct = option_index == s_game.current_math.correct_index;

    if (correct) {
        s_game.combo++;
        s_game.score += 10 + s_game.combo;
        ai_tts_speak_text("回答正确,继续加油。");
    } else {
        s_game.combo = 0;
        ai_tts_speak_text("这题不对,我们再试一题。");
    }

    display_game_result(correct, s_game.score);

    s_game.question_index++;

    /*
     * 每 5 题升一级。
     */
    if (s_game.question_index > 0 && s_game.question_index % 5 == 0) {
        s_game.level++;
        ai_tts_speak_text("恭喜升级,难度提高了。");
    }

    generate_math_question(s_game.level, &s_game.current_math);
    display_game_question(&s_game.current_math, s_game.score, s_game.level);
}

void game_stop(void)
{
    s_game.type = GAME_NONE;
    ai_tts_speak_text("游戏结束,学习也要注意休息。");

    /*
     * TODO:
     * 上传游戏成绩:
     * device_id、user_id、game_type、score、level、duration。
     */
}

7.5 AT+MCP:语音控制拍题、学习和游戏

开发宝典中的 AT+MCP 非常适合做二次开发。协议使用标准 UART,默认 115200, 8N1;通过 AT+ADDMCP 可以把"人话"映射为 MCU 可执行的二进制控制帧;AI 模组还会主动上报开机、配网、联网、监听、说话、升级、激活等状态。

7.5.1 MCP 命令定义

复制代码
CMD_CAPTURE_SOLVE       0xF1  拍照解题
CMD_START_GAME          0xF2  开始学习游戏
CMD_ANSWER_GAME         0xF3  回答游戏选项
CMD_SET_STUDY_MODE      0xF4  切换学习模式
CMD_SHOW_WRONG_BOOK     0xF5  查看错题本
CMD_PARENT_REPORT       0xF6  上传 / 查询学习报告
CMD_CUSTOMER_API        0xF7  接入客户系统

7.5.2 MCP 注册与解析代码

复制代码
#include <stdio.h>
#include <string.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_CAPTURE_SOLVE       0xF1
#define CMD_START_GAME          0xF2
#define CMD_ANSWER_GAME         0xF3
#define CMD_SET_STUDY_MODE      0xF4
#define CMD_SHOW_WRONG_BOOK     0xF5
#define CMD_PARENT_REPORT       0xF6
#define CMD_CUSTOMER_API        0xF7

typedef enum {
    STUDY_SUBJECT_UNKNOWN = 0,
    STUDY_SUBJECT_MATH    = 1,
    STUDY_SUBJECT_CHINESE = 2,
    STUDY_SUBJECT_ENGLISH = 3,
    STUDY_SUBJECT_GENERAL = 4,
} study_subject_t;

extern void study_capture_and_solve(study_subject_t subject);
extern void game_start_math_quiz(int level);
extern void game_answer_option(int option_index);
extern void wrong_book_show(void);
extern void report_upload_now(void);
extern void customer_scene_control(uint8_t scene_id, uint8_t action);

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 ai_reset_module(void)
{
    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_register_tools(void)
{
    mcp_send_line("AT");
    mcp_send_line("AT+WIFICFG=0");
    mcp_send_line("AT+CONNECT");

    /*
     * 用户:"帮我看一下这道数学题"
     * AI -> MCU: 55 AA 02 F1 01 AA 55
     * data[0] = subject
     */
    mcp_send_line(
        "AT+ADDMCP=1,capture_solve,拍照识别并讲解题目,F1,1,subject"
    );

    /*
     * 用户:"开始口算游戏,难度二"
     */
    mcp_send_line(
        "AT+ADDMCP=1,start_math_game,开始口算闯关游戏,F2,1,level"
    );

    /*
     * 用户:"我选第三个"
     */
    mcp_send_line(
        "AT+ADDMCP=1,answer_game,回答当前游戏选项,F3,1,option"
    );

    /*
     * 用户:"切换到英语学习模式"
     */
    mcp_send_line(
        "AT+ADDMCP=1,set_study_mode,切换学习科目模式,F4,1,subject"
    );

    /*
     * 用户:"查看我的错题本"
     */
    mcp_send_line(
        "AT+ADDMCP=0,show_wrong_book,查看错题本,2,F5,01"
    );

    /*
     * 用户:"把今天的学习报告发给家长"
     */
    mcp_send_line(
        "AT+ADDMCP=0,parent_report,上传或查询学习报告,2,F6,01"
    );

    /*
     * 用户:"打开客户平台的一号课程"
     */
    mcp_send_line(
        "AT+ADDMCP=1,customer_api,调用客户学习平台接口,F7,2,scene_id,action"
    );
}

static void handle_ai_status(uint8_t status)
{
    switch (status) {
    case 0x01:
        ESP_LOGI(TAG, "AI starting");
        break;
    case 0x02:
        ESP_LOGI(TAG, "AI configuring");
        break;
    case 0x03:
        ESP_LOGI(TAG, "AI idle");
        break;
    case 0x04:
        ESP_LOGI(TAG, "AI connecting");
        break;
    case 0x05:
        ESP_LOGI(TAG, "AI listening");
        break;
    case 0x06:
        ESP_LOGI(TAG, "AI speaking");
        break;
    case 0x07:
        ESP_LOGI(TAG, "AI upgrading");
        break;
    case 0x08:
        ESP_LOGI(TAG, "AI activating");
        break;
    default:
        ESP_LOGW(TAG, "unknown AI status=0x%02X", status);
        break;
    }
}

static void mcp_handle_frame(uint8_t cmd, const uint8_t *data, uint8_t len)
{
    if (cmd == CMD_RECOVER) {
        /*
         * 开发宝典要求:
         * 收到 55 AA 01 FC AA 55 后,MCU 重启 AI 模组并重新发送 MCP 映射。
         */
        ai_reset_module();
        mcp_register_tools();
        return;
    }

    if (cmd == CMD_STATUS && len >= 1) {
        handle_ai_status(data[0]);
        return;
    }

    switch (cmd) {
    case CMD_CAPTURE_SOLVE:
        if (len >= 1) {
            study_capture_and_solve((study_subject_t)data[0]);
        } else {
            study_capture_and_solve(STUDY_SUBJECT_UNKNOWN);
        }
        break;

    case CMD_START_GAME:
        if (len >= 1) {
            game_start_math_quiz(data[0]);
        } else {
            game_start_math_quiz(1);
        }
        break;

    case CMD_ANSWER_GAME:
        if (len >= 1) {
            /*
             * 语音传 1~4,内部转 0~3。
             */
            int option = data[0] > 0 ? data[0] - 1 : 0;
            game_answer_option(option);
        }
        break;

    case CMD_SET_STUDY_MODE:
        if (len >= 1) {
            ESP_LOGI(TAG, "set study mode=%u", data[0]);
            /*
             * TODO:
             * study_set_subject(data[0]);
             * display_show_subject(data[0]);
             */
        }
        break;

    case CMD_SHOW_WRONG_BOOK:
        wrong_book_show();
        break;

    case CMD_PARENT_REPORT:
        report_upload_now();
        break;

    case CMD_CUSTOMER_API:
        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);
            }

            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 远程管理:设备影子与学习报告

设备状态 JSON

复制代码
{
  "device_id": "study_camera_001",
  "fw_version": "1.0.0",
  "wifi_rssi": -55,
  "battery": 82,
  "ai_state": "idle",
  "camera_ready": true,
  "study_mode": "math",
  "today": {
    "study_minutes": 35,
    "questions": 18,
    "correct": 15,
    "wrong": 3,
    "game_score": 260
  }
}

上报代码

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

#define TAG "STUDY_REPORT"

typedef struct {
    int study_minutes;
    int questions;
    int correct;
    int wrong;
    int game_score;
} study_daily_report_t;

static void mqtt_publish(const char *topic, const char *payload)
{
    /*
     * TODO:
     * esp_mqtt_client_publish(client, topic, payload, 0, 1, 0);
     */
    ESP_LOGI(TAG, "MQTT %s => %s", topic, payload);
}

void report_upload_daily(const study_daily_report_t *r)
{
    char payload[512];

    snprintf(payload, sizeof(payload),
        "{"
        "\"device_id\":\"study_camera_001\","
        "\"study_minutes\":%d,"
        "\"questions\":%d,"
        "\"correct\":%d,"
        "\"wrong\":%d,"
        "\"game_score\":%d"
        "}",
        r->study_minutes,
        r->questions,
        r->correct,
        r->wrong,
        r->game_score
    );

    mqtt_publish("sibo/study_camera/study_camera_001/report/daily", payload);
}

void report_upload_now(void)
{
    study_daily_report_t report = {
        .study_minutes = 35,
        .questions = 18,
        .correct = 15,
        .wrong = 3,
        .game_score = 260,
    };

    report_upload_daily(&report);
}

7.7 客户系统接入示例

客户可以把拍学机接入自己的教育平台、题库平台、家长端 APP 或小程序。

复制代码
#include <stdio.h>
#include <string.h>
#include "esp_http_client.h"
#include "esp_log.h"

#define TAG "CUSTOMER_API"

esp_err_t customer_scene_control(uint8_t scene_id, uint8_t action)
{
    char body[128];

    snprintf(body, sizeof(body),
             "{\"device_id\":\"study_camera_001\",\"scene_id\":%u,\"action\":%u}",
             scene_id,
             action);

    esp_http_client_config_t config = {
        .url = "https://customer.example.com/api/v1/device/scene",
        .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. 后端服务设计

建议后端拆成以下服务:

复制代码
1. AI WebSocket Gateway:
   负责设备端语音对话、ASR、LLM、TTS。

2. OCR / VLM Service:
   负责拍题识别、绘本识别、看图问答。

3. Study Engine:
   负责错题本、学习计划、知识点推荐、题库匹配。

4. Game Service:
   负责游戏题库、排行榜、成长积分、奖励策略。

5. Parent Admin:
   家长端管理、学习报告、设备限制、内容管控。

6. OTA Service:
   固件 OTA、资源 OTA、灰度升级。

7. Device Management:
   设备绑定、设备影子、日志、远程诊断。

8. Customer API Gateway:
   对接客户教育平台、App、小程序、私有化系统。

开发宝典中说明,设备默认可连接小智官方服务,也可以运行开源后端服务,让设备连接到自己的后端;后端包含 OTA 接口和 WebSocket 接口,并可配置 LLM、TTS、人设等参数。

后端配置示例:

复制代码
server:
  websocket_url: "wss://ai.customer.com/xiaozhi/v1/"
  ota_url: "https://ai.customer.com/xiaozhi/ota/"
  mqtt_uri: "mqtts://mqtt.customer.com"

ai:
  ASR: "FunASR"
  LLM: "CustomerLLM"
  TTS: "DoubaoTTS"
  VLM: "CustomerVisionModel"
  Intent: "function_call"

study:
  ocr_url: "https://api.customer.com/v1/ocr"
  solve_url: "https://api.customer.com/v1/study/solve"
  wrong_book_enable: true
  parent_report_enable: true

game:
  local_game_enable: true
  cloud_rank_enable: false
  daily_task_enable: true

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

资源管理建议:

复制代码
storage/
  prompt/         提示音
  avatar/         AI 形象素材
  game/           本地游戏资源
  study/          本地题库 / 单词表
  cache/          TTS 缓存
  log/            日志

OTA 策略:

复制代码
1. 主控固件 OTA:
   ESP32-S3 双 OTA 分区,失败回滚。

2. 资源 OTA:
   游戏题库、提示音、表情动画、单词表单独更新。

3. AI 参数 OTA:
   大模型地址、人设、TTS 音色、学习策略远程下发。

4. 灰度升级:
   按 project_id / batch_id / device_id 分批升级。

5. 安全:
   HTTPS OTA + 固件签名 + token 鉴权。

10. 产测方案

10.1 工厂测试项目

复制代码
主控:
  - ESP32-S3 Flash / PSRAM 检测
  - Wi-Fi MAC / BLE MAC
  - NVS SN 写入
  - 固件版本读取

语音:
  - VB6824 UART 通信
  - 麦克风电平
  - 喇叭播放
  - 唤醒词测试
  - 播放中打断测试

摄像头:
  - 摄像头初始化
  - 拍照 JPEG 大小检测
  - 图像方向检测
  - 亮度检测
  - 后端上传测试

屏幕:
  - 白屏 / 黑屏 / RGB 纯色
  - 背光 PWM
  - 学习 UI 显示
  - 游戏 UI 显示

学习:
  - 拍题上传
  - OCR 返回
  - 题目讲解
  - 错题本写入

游戏:
  - 按键输入
  - 题目生成
  - 计分逻辑
  - 音效播放

远程:
  - MQTT 连接
  - 学习报告上报
  - OTA 检查
  - 日志上传

10.2 产测命令建议

复制代码
FACTORY ENTER
FACTORY SET_SN=SBOSTUDY20260001
FACTORY WIFI_SCAN
FACTORY WIFI_CONNECT=ssid,password
FACTORY MIC_LEVEL
FACTORY SPK_PLAY=1000HZ
FACTORY WAKE_TEST
FACTORY CAMERA_CAPTURE
FACTORY OCR_TEST
FACTORY LCD_TEST
FACTORY GAME_TEST
FACTORY MQTT_CONNECT
FACTORY REPORT_UPLOAD
FACTORY OTA_CHECK
FACTORY EXIT

11. 推荐产品版本

11.1 基础 AI 学习音箱版

复制代码
ESP32-S3R8 + 16M Flash
VB6824
麦克风 + 喇叭
1.54 寸屏
Wi-Fi + BLE BluFi
AI 问答
故事机
口算游戏
远程 OTA

适合:AI 故事机、儿童学习音箱、桌面陪伴设备。

11.2 AI 智能拍学机标准版

复制代码
ESP32-S3R8 + 16M Flash + 8M PSRAM
VB6824
摄像头
2.0 寸屏
麦克风 + 喇叭
电池
Wi-Fi
拍题识别
OCR / VLM
学习游戏
错题本
家长端报告

适合:儿童拍题机、学习机、教育硬件、绘本助手。

11.3 高端多模态游戏学习版

复制代码
ESP32-S3R8 + 16M Flash + 8M PSRAM
VB6824
摄像头
2.0 / 4.75 寸高清屏
触摸 / 按键
SD 卡
4G 选配
7014 蓝牙 PAN 选配
AI 对话
拍题讲解
绘本识别
学习游戏
声音克隆
知识库
MCP 工具
客户私有后端

适合:品牌 B 端客户、教育机构、方案商客户、海外 AI 学习产品。


12. 方案总结

四博 AI 智能拍学机建议采用 ESP32-S3R8 + 16M Flash + 8M PSRAM + VB6824 + 摄像头 + 屏幕 + 麦克风 + 喇叭 的平台化架构。

ESP32-S3 负责摄像头、屏幕、联网、AI WebSocket、学习游戏、远程管理和客户系统接入;VB6824 负责离线唤醒、AEC、降噪、语音唤醒、改唤醒词和打断;摄像头负责拍题、绘本识别和看图问答;屏幕负责题目步骤、游戏界面和学习反馈;后端负责 OCR、VLM、大模型讲解、错题本、家长报告和 OTA。

这套方案既可以做 AI 智能音箱 ,也可以升级成 AI 拍学机、AI 学习机、AI 游戏学习终端、AI 绘本助手,并且支持 ESP-IDF、DOIT_AI、AT+MCP、HTTP、MQTT、WebSocket 等多种二次开发路径,适合客户快速打样、定制和量产。

相关推荐
Gh0st_Lx2 小时前
【6】持续学习方法概述:在数据集 B 上变强了,在数据集 A 上却暴跌?
人工智能·语言模型·transformer
前端摸鱼匠2 小时前
【AI大模型春招面试题27】字节对编码(BPE)的分词过程?如何处理未登录词(OOV)?
人工智能·ai·面试·大模型·求职招聘
全模态研习社2 小时前
深入探讨OpenAI ChatGPT 4o图像API的运用与操作
人工智能
MediaTea2 小时前
AI 术语通俗词典:召回率(分类)
人工智能·算法·机器学习·分类·数据挖掘
ECT-OS-JiuHuaShan2 小时前
哲学的本质,是递归因果
java·开发语言·人工智能·科技·算法·机器学习·数学建模
武帝为此2 小时前
【热卡填充法介绍】
人工智能·python·机器学习
microxiaoxiao2 小时前
Aeroshell:2026 年,支持AI的SSH 终端
运维·人工智能·ssh
feng14562 小时前
稳定性-风险文化建设和风险意识培养
运维·人工智能
小程故事多_803 小时前
AI编码效率革命,Agent Orchestrator如何让多智能体并行开发成为现实
人工智能·架构·智能体