四博 AI 双目智能交互终端方案

四博 AI 双目智能交互终端方案

四路触控 + 震动马达 + 双目光屏 + 三轴姿态 + 小程序智能体平台

1. 方案定位

四博 AI 双目是一套面向 AI 桌宠、AI 音箱、儿童陪伴、智能学习终端、IP 潮玩、品牌定制 AI 硬件 的高集成度 AI 硬件方案。

方案以 ESP32-S3R8 + 16M Flash + VB6824 语音芯片 为核心,结合 0.71 / 1.28 寸双目光屏、四路触控感应、震动马达、三轴姿态传感器、麦克风、喇叭、Wi-Fi / BLE、小程序平台和云端大模型,实现一套"能听、能说、能看、能摸、能动、能感知"的多模态 AI 交互系统。

资料中 AI-S3 双目双屏方案已经明确采用 1.28 寸 LCD 显示屏 x2、ESP32S3R8 + 16M Flash + VB6824,并可对接小智、豆包、ChatGPT 等主流大模型,支持二次开发和品牌客户定制。


2. 核心卖点

2.1 双目情绪显示

四博 AI 双目支持 0.71 寸 / 1.28 寸双目屏,可根据产品定位选择低成本小尺寸版本或高显示效果版本。开发宝典中提到,双目主板屏幕支持 0.71 寸和 1.28 寸,V1 / V2 版本还区分不同屏幕和调光能力。

屏幕分辨率建议如下:

屏幕 分辨率 定位
0.71 寸双目屏 160 × 160 低成本、小体积、桌面摆件
1.28 寸双目屏 240 × 240 AI 音箱、AI 桌宠、陪伴机器人

资料中 QA 部分也给出了 1.28 寸屏幕为 240×240,0.71 寸屏幕为 160×160。

2.2 四路触控 + 震动马达

四路触控可以布置在顶部、左右侧、背部或底部,实现本地交互:

触控区域 功能建议
顶部触控 唤醒 / 暂停 / 继续
左侧触控 上一个角色 / 上一首
右侧触控 下一个角色 / 下一首
背部触控 进入配网 / 静音 / 长按恢复出厂

震动马达用于触觉反馈:

场景 反馈
触摸确认 短震
唤醒成功 双短震
网络异常 长震
低电量 间歇震动
摇晃互动 连续轻震
OTA 升级 节奏震动

开发宝典中的多模态 AI 开发板也明确提到,基于 ESP32-S3 主控,支持两块 1.28 寸双目屏、高清摄像头融合交互,并设有 4 个触摸节点。

2.3 三轴姿态感应

内置三轴传感器后,设备可以识别:

姿态动作 交互功能
拿起 自动唤醒
摇一摇 切换角色 / 切换表情
翻转 静音 / 睡眠
倾斜 眼球跟随
敲击 触发彩蛋
静置 自动待机

这类交互可以让设备从普通语音音箱升级成"有动作感知"的 AI 桌面伙伴。

2.4 VB6824 语音前端

ESP32-C2 / C3 / S3 + VB6824 语音方案的特点是开发生态好,可对接自有平台,并且 VB6824 承担音频编解码、AEC、语音唤醒、改唤醒词等功能,让主控专注于通信和 UI。资料中也提到该方案已成熟应用于电子吧唧、S3 双目、S3 拍学机、地球仪、拍拍灯等产品。

语音链路建议如下:

复制代码
麦克风
  ↓
VB6824:唤醒 / AEC / 降噪 / 打断 / 编解码
  ↓
ESP32-S3:网络通信 / AI协议 / UI状态机
  ↓
云端大模型:ASR / LLM / TTS / 知识库
  ↓
ESP32-S3:播放控制 / 双目联动
  ↓
功放 + 喇叭

VB6824 还支持自定义唤醒词,资料中以 AI-S3 双目为例说明了进入 VB6824 升级模式、设置"你好小智""小乐小乐"或定制唤醒词的流程,并提到升级后可支持 AI 说话过程中的随时打断。

2.5 四博小助手小程序

配合"四博小助手"小程序,可以实现:

  • AI 对话;

  • 声音克隆;

  • 知识库接入;

  • MCP 工具扩展;

  • 素材与固件在线更新;

  • 模型、参数、提示音统一管理。

资料中明确说明,选用 ESPS3R8 + VB6824 的 AI-S3 智能电子吧唧方案,可配合"四博小助手"小程序实现 AI 对话、声音克隆、知识库接入、MCP 扩展能力,以及素材与固件在线更新。


3. 整体系统架构

复制代码
┌────────────────────────────────────┐
│          四博小助手小程序             │
│  配网 / 声音克隆 / 知识库 / MCP / OTA │
└───────────────┬────────────────────┘
                │ BLE BluFi / HTTPS / WebSocket
┌───────────────▼────────────────────┐
│             ESP32-S3 主控            │
│ Wi-Fi / BLE / UI / 事件队列 / OTA     │
│ 双目动画 / 触控扫描 / 姿态融合 / MCP  │
└───────┬────────────┬────────────┬───┘
        │            │            │
        │            │            │
┌───────▼──────┐ ┌───▼──────┐ ┌──▼──────────┐
│   VB6824      │ │ 双目光屏   │ │ 触控/IMU/马达 │
│ 唤醒/AEC/打断 │ │ 0.71/1.28 │ │ 四触控/三轴/震动 │
└───────┬──────┘ └──────────┘ └─────────────┘
        │
┌───────▼──────────────┐
│ 麦克风 / 功放 / 喇叭   │
└──────────────────────┘

4. 推荐硬件配置

模块 推荐配置
主控 四博 ESPS3-32 / ESPS3-32E
芯片 ESP32-S3R8
存储 16MB Flash,建议带 PSRAM
语音前端 VB6824
显示 0.71 / 1.28 寸双目屏
触控 4 路触控感应
姿态 三轴加速度计 / 六轴 IMU 可选
反馈 震动马达
音频 麦克风 + 功放 + 喇叭
网络 Wi-Fi + BLE,可扩展 4G
电源 Type-C + 锂电池
平台 四博小助手小程序

四博模组选型资料中,ESP32-S3 系列定位于音视频 / AI 市场,ESPS3-32 和 ESPS3-32E 均兼容官方 ESP32-S3-WROOM 系列模组,并提供 S3R2 / S3R8 等配置选择。


5. 软件系统设计

建议采用 ESP-IDF + FreeRTOS + 事件驱动状态机 架构。AI 双目这种产品不建议把所有逻辑写在一个 while 循环中,而应拆成独立任务。

复制代码
app_main
 ├── wifi_task          // Wi-Fi 连接、重连、联网状态
 ├── blufi_task         // 四博小助手 BLE 配网
 ├── ai_ws_task         // WebSocket / MQTT AI通信
 ├── audio_task         // 录音、TTS、提示音、打断
 ├── vb6824_task        // 唤醒、打断、语音事件
 ├── eye_task           // 双目动画刷新
 ├── touch_task         // 四路触控扫描
 ├── imu_task           // 三轴姿态检测
 ├── haptic_task        // 震动马达控制
 ├── mcp_task           // MCP工具调用
 ├── ota_task           // 固件/素材升级
 └── factory_task       // 工厂测试

开发资料中 S3 双目工程推荐 ESP-IDF 版本大于等于 5.4.0;如果是 C5 则建议大于等于 5.5.0。


6. 核心代码示例

下面代码是方案级参考代码,实际 GPIO、I2C 地址、屏幕驱动、VB6824 协议,需要按四博硬件原理图调整。


6.1 全局事件队列

复制代码
// app_event.h
#pragma once

#include <stdint.h>
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"

typedef enum {
    APP_EVT_NONE = 0,

    APP_EVT_WIFI_CONNECTED,
    APP_EVT_WIFI_DISCONNECTED,

    APP_EVT_WAKE_WORD,
    APP_EVT_VOICE_INTERRUPT,

    APP_EVT_TOUCH_TOP,
    APP_EVT_TOUCH_LEFT,
    APP_EVT_TOUCH_RIGHT,
    APP_EVT_TOUCH_BACK,

    APP_EVT_IMU_PICKUP,
    APP_EVT_IMU_SHAKE,
    APP_EVT_IMU_FLIP,
    APP_EVT_IMU_TILT,

    APP_EVT_AI_LISTENING,
    APP_EVT_AI_THINKING,
    APP_EVT_AI_SPEAKING,
    APP_EVT_AI_ERROR,

    APP_EVT_MCP_TOOL,
    APP_EVT_OTA_START,
    APP_EVT_OTA_DONE,
} app_event_id_t;

typedef struct {
    app_event_id_t id;
    int param1;
    int param2;
    char payload[256];
} app_event_t;

extern QueueHandle_t g_app_event_queue;

void app_post_event(app_event_id_t id, int p1, int p2, const char *payload);

// app_event.c
#include "app_event.h"
#include <string.h>

QueueHandle_t g_app_event_queue = NULL;

void app_post_event(app_event_id_t id, int p1, int p2, const char *payload)
{
    if (!g_app_event_queue) return;

    app_event_t evt = {
        .id = id,
        .param1 = p1,
        .param2 = p2,
    };

    if (payload) {
        strncpy(evt.payload, payload, sizeof(evt.payload) - 1);
    }

    xQueueSend(g_app_event_queue, &evt, 0);
}

6.2 主程序初始化

复制代码
// app_main.c
#include "esp_log.h"
#include "nvs_flash.h"
#include "app_event.h"

static const char *TAG = "SIBO_AI_EYE";

void wifi_app_start(void);
void blufi_app_start(void);
void vb6824_app_start(void);
void eye_app_start(void);
void touch_app_start(void);
void imu_app_start(void);
void haptic_app_start(void);
void ai_client_start(void);
void mcp_app_start(void);
void ota_app_start(void);
void app_dispatch_start(void);

void app_main(void)
{
    ESP_ERROR_CHECK(nvs_flash_init());

    g_app_event_queue = xQueueCreate(32, sizeof(app_event_t));
    if (!g_app_event_queue) {
        ESP_LOGE(TAG, "事件队列创建失败");
        return;
    }

    haptic_app_start();
    eye_app_start();

    wifi_app_start();
    blufi_app_start();

    vb6824_app_start();
    touch_app_start();
    imu_app_start();

    ai_client_start();
    mcp_app_start();
    ota_app_start();

    app_dispatch_start();

    ESP_LOGI(TAG, "四博AI双目系统启动完成");
}

6.3 AI 状态机

复制代码
typedef enum {
    AI_STATE_BOOT = 0,
    AI_STATE_IDLE,
    AI_STATE_WAKEUP,
    AI_STATE_LISTENING,
    AI_STATE_THINKING,
    AI_STATE_SPEAKING,
    AI_STATE_TOUCH,
    AI_STATE_SHAKE,
    AI_STATE_SLEEP,
    AI_STATE_NET_ERROR,
    AI_STATE_OTA,
} ai_state_t;

static ai_state_t g_ai_state = AI_STATE_BOOT;

void eye_play_anim(const char *name);
void audio_play_prompt(const char *name);
void audio_start_record(void);
void audio_stop_tts(void);
void haptic_short(void);
void haptic_double(void);
void haptic_long(void);

void ai_set_state(ai_state_t state)
{
    g_ai_state = state;

    switch (state) {
    case AI_STATE_BOOT:
        eye_play_anim("boot");
        audio_play_prompt("boot.wav");
        break;

    case AI_STATE_IDLE:
        eye_play_anim("idle_blink");
        break;

    case AI_STATE_WAKEUP:
        eye_play_anim("wake");
        haptic_double();
        audio_play_prompt("ding.wav");
        break;

    case AI_STATE_LISTENING:
        eye_play_anim("listening");
        audio_start_record();
        break;

    case AI_STATE_THINKING:
        eye_play_anim("thinking");
        break;

    case AI_STATE_SPEAKING:
        eye_play_anim("speaking");
        break;

    case AI_STATE_TOUCH:
        eye_play_anim("happy");
        haptic_short();
        break;

    case AI_STATE_SHAKE:
        eye_play_anim("surprised");
        haptic_double();
        break;

    case AI_STATE_SLEEP:
        eye_play_anim("sleep");
        audio_stop_tts();
        break;

    case AI_STATE_NET_ERROR:
        eye_play_anim("net_error");
        haptic_long();
        audio_play_prompt("network_error.wav");
        break;

    case AI_STATE_OTA:
        eye_play_anim("ota");
        break;

    default:
        break;
    }
}

6.4 统一事件分发

复制代码
static void app_dispatch_task(void *arg)
{
    app_event_t evt;

    while (1) {
        if (xQueueReceive(g_app_event_queue, &evt, portMAX_DELAY)) {
            switch (evt.id) {
            case APP_EVT_WIFI_CONNECTED:
                ai_set_state(AI_STATE_IDLE);
                break;

            case APP_EVT_WIFI_DISCONNECTED:
                ai_set_state(AI_STATE_NET_ERROR);
                break;

            case APP_EVT_WAKE_WORD:
                ai_set_state(AI_STATE_WAKEUP);
                ai_set_state(AI_STATE_LISTENING);
                break;

            case APP_EVT_VOICE_INTERRUPT:
                audio_stop_tts();
                ai_set_state(AI_STATE_LISTENING);
                break;

            case APP_EVT_TOUCH_TOP:
                ai_set_state(AI_STATE_TOUCH);
                app_post_event(APP_EVT_WAKE_WORD, 0, 0, NULL);
                break;

            case APP_EVT_TOUCH_LEFT:
                eye_play_anim("prev_role");
                haptic_short();
                break;

            case APP_EVT_TOUCH_RIGHT:
                eye_play_anim("next_role");
                haptic_short();
                break;

            case APP_EVT_TOUCH_BACK:
                eye_play_anim("config");
                haptic_double();
                // 进入 BluFi 配网
                blufi_app_start();
                break;

            case APP_EVT_IMU_SHAKE:
                ai_set_state(AI_STATE_SHAKE);
                break;

            case APP_EVT_IMU_FLIP:
                ai_set_state(AI_STATE_SLEEP);
                break;

            case APP_EVT_AI_THINKING:
                ai_set_state(AI_STATE_THINKING);
                break;

            case APP_EVT_AI_SPEAKING:
                ai_set_state(AI_STATE_SPEAKING);
                break;

            case APP_EVT_AI_ERROR:
                ai_set_state(AI_STATE_NET_ERROR);
                break;

            case APP_EVT_OTA_START:
                ai_set_state(AI_STATE_OTA);
                break;

            default:
                break;
            }
        }
    }
}

void app_dispatch_start(void)
{
    xTaskCreate(app_dispatch_task, "app_dispatch", 4096, NULL, 6, NULL);
}

6.5 四路触控扫描示例

如果四路触控接 ESP32-S3 Touch Pad,可以参考下面逻辑;如果使用外置触控 IC,则把 touch_pad_read_raw_data() 改成 I2C 读取即可。

复制代码
#include "driver/touch_sensor.h"
#include "esp_log.h"
#include "app_event.h"

#define TOUCH_THRESHOLD_PERCENT 70

typedef struct {
    touch_pad_t pad;
    uint32_t baseline;
    app_event_id_t event_id;
    const char *name;
} touch_key_t;

static touch_key_t s_touch_keys[] = {
    {TOUCH_PAD_NUM1, 0, APP_EVT_TOUCH_TOP,   "TOP"},
    {TOUCH_PAD_NUM2, 0, APP_EVT_TOUCH_LEFT,  "LEFT"},
    {TOUCH_PAD_NUM3, 0, APP_EVT_TOUCH_RIGHT, "RIGHT"},
    {TOUCH_PAD_NUM4, 0, APP_EVT_TOUCH_BACK,  "BACK"},
};

static void touch_task(void *arg)
{
    while (1) {
        for (int i = 0; i < 4; i++) {
            uint32_t raw = 0;
            touch_pad_read_raw_data(s_touch_keys[i].pad, &raw);

            uint32_t threshold =
                s_touch_keys[i].baseline * TOUCH_THRESHOLD_PERCENT / 100;

            if (raw < threshold) {
                ESP_LOGI("TOUCH", "%s touched, raw=%lu",
                         s_touch_keys[i].name, raw);

                app_post_event(s_touch_keys[i].event_id, raw, 0, NULL);

                // 防止一次触摸重复触发
                vTaskDelay(pdMS_TO_TICKS(250));
            }
        }

        vTaskDelay(pdMS_TO_TICKS(30));
    }
}

void touch_app_start(void)
{
    touch_pad_init();

    for (int i = 0; i < 4; i++) {
        touch_pad_config(s_touch_keys[i].pad);
    }

    vTaskDelay(pdMS_TO_TICKS(300));

    for (int i = 0; i < 4; i++) {
        uint32_t sum = 0;

        for (int j = 0; j < 16; j++) {
            uint32_t raw = 0;
            touch_pad_read_raw_data(s_touch_keys[i].pad, &raw);
            sum += raw;
            vTaskDelay(pdMS_TO_TICKS(10));
        }

        s_touch_keys[i].baseline = sum / 16;

        ESP_LOGI("TOUCH", "%s baseline=%lu",
                 s_touch_keys[i].name,
                 s_touch_keys[i].baseline);
    }

    xTaskCreate(touch_task, "touch_task", 4096, NULL, 5, NULL);
}

6.6 震动马达 PWM 控制

复制代码
#include "driver/ledc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

#define MOTOR_GPIO          15
#define MOTOR_LEDC_MODE     LEDC_LOW_SPEED_MODE
#define MOTOR_LEDC_TIMER    LEDC_TIMER_0
#define MOTOR_LEDC_CHANNEL  LEDC_CHANNEL_0
#define MOTOR_FREQ_HZ       2000
#define MOTOR_DUTY_MAX      8191

static void motor_set(uint32_t duty)
{
    ledc_set_duty(MOTOR_LEDC_MODE, MOTOR_LEDC_CHANNEL, duty);
    ledc_update_duty(MOTOR_LEDC_MODE, MOTOR_LEDC_CHANNEL);
}

void haptic_short(void)
{
    motor_set(MOTOR_DUTY_MAX * 60 / 100);
    vTaskDelay(pdMS_TO_TICKS(60));
    motor_set(0);
}

void haptic_double(void)
{
    for (int i = 0; i < 2; i++) {
        motor_set(MOTOR_DUTY_MAX * 70 / 100);
        vTaskDelay(pdMS_TO_TICKS(50));
        motor_set(0);
        vTaskDelay(pdMS_TO_TICKS(80));
    }
}

void haptic_long(void)
{
    motor_set(MOTOR_DUTY_MAX * 80 / 100);
    vTaskDelay(pdMS_TO_TICKS(300));
    motor_set(0);
}

void haptic_app_start(void)
{
    ledc_timer_config_t timer = {
        .speed_mode      = MOTOR_LEDC_MODE,
        .timer_num       = MOTOR_LEDC_TIMER,
        .duty_resolution = LEDC_TIMER_13_BIT,
        .freq_hz         = MOTOR_FREQ_HZ,
        .clk_cfg         = LEDC_AUTO_CLK,
    };
    ESP_ERROR_CHECK(ledc_timer_config(&timer));

    ledc_channel_config_t channel = {
        .gpio_num   = MOTOR_GPIO,
        .speed_mode = MOTOR_LEDC_MODE,
        .channel    = MOTOR_LEDC_CHANNEL,
        .timer_sel  = MOTOR_LEDC_TIMER,
        .duty       = 0,
        .hpoint     = 0,
    };
    ESP_ERROR_CHECK(ledc_channel_config(&channel));
}

6.7 三轴传感器姿态检测

下面以通用 I2C 三轴传感器为例,实际项目可替换为 QMI8658、MPU6050、LIS3DH 等。

复制代码
#include "driver/i2c.h"
#include "esp_log.h"
#include "app_event.h"
#include <math.h>

#define I2C_PORT        I2C_NUM_0
#define I2C_SDA_GPIO    8
#define I2C_SCL_GPIO    9
#define I2C_FREQ_HZ     400000

#define IMU_ADDR        0x68
#define IMU_REG_ACCEL_X 0x3B

typedef struct {
    int16_t x;
    int16_t y;
    int16_t z;
} accel_data_t;

static esp_err_t imu_read_accel(accel_data_t *acc)
{
    uint8_t reg = IMU_REG_ACCEL_X;
    uint8_t data[6] = {0};

    esp_err_t ret = i2c_master_write_read_device(
        I2C_PORT,
        IMU_ADDR,
        &reg,
        1,
        data,
        sizeof(data),
        pdMS_TO_TICKS(50)
    );

    if (ret != ESP_OK) return ret;

    acc->x = (int16_t)((data[0] << 8) | data[1]);
    acc->y = (int16_t)((data[2] << 8) | data[3]);
    acc->z = (int16_t)((data[4] << 8) | data[5]);

    return ESP_OK;
}

static bool detect_shake(accel_data_t now, accel_data_t last)
{
    int dx = abs(now.x - last.x);
    int dy = abs(now.y - last.y);
    int dz = abs(now.z - last.z);

    return (dx + dy + dz) > 18000;
}

static bool detect_flip(accel_data_t now)
{
    return now.z < -12000;
}

static void imu_task(void *arg)
{
    accel_data_t last = {0};

    while (1) {
        accel_data_t now;

        if (imu_read_accel(&now) == ESP_OK) {
            if (detect_shake(now, last)) {
                ESP_LOGI("IMU", "检测到摇晃");
                app_post_event(APP_EVT_IMU_SHAKE, now.x, now.y, NULL);
            }

            if (detect_flip(now)) {
                ESP_LOGI("IMU", "检测到翻转");
                app_post_event(APP_EVT_IMU_FLIP, now.x, now.z, NULL);
            }

            last = now;
        }

        vTaskDelay(pdMS_TO_TICKS(80));
    }
}

void imu_app_start(void)
{
    i2c_config_t conf = {
        .mode = I2C_MODE_MASTER,
        .sda_io_num = I2C_SDA_GPIO,
        .scl_io_num = I2C_SCL_GPIO,
        .sda_pullup_en = GPIO_PULLUP_ENABLE,
        .scl_pullup_en = GPIO_PULLUP_ENABLE,
        .master.clk_speed = I2C_FREQ_HZ,
    };

    ESP_ERROR_CHECK(i2c_param_config(I2C_PORT, &conf));
    ESP_ERROR_CHECK(i2c_driver_install(I2C_PORT, conf.mode, 0, 0, 0));

    xTaskCreate(imu_task, "imu_task", 4096, NULL, 5, NULL);
}

6.8 VB6824 事件解析示例

VB6824 可通过 UART / GPIO 向 ESP32-S3 上报唤醒、打断、录音开始、录音结束等事件。

复制代码
#include "driver/uart.h"
#include "app_event.h"
#include "esp_log.h"

#define VB_UART_NUM      UART_NUM_1
#define VB_UART_TX       17
#define VB_UART_RX       18
#define VB_UART_BAUD     115200

#define VB_FRAME_HEAD    0xA5
#define VB_FRAME_TAIL    0x5A

typedef enum {
    VB_CMD_WAKEUP      = 0x01,
    VB_CMD_INTERRUPT   = 0x02,
    VB_CMD_REC_START   = 0x03,
    VB_CMD_REC_STOP    = 0x04,
} vb_cmd_t;

static void vb6824_parse_frame(uint8_t *buf, int len)
{
    if (len < 4) return;
    if (buf[0] != VB_FRAME_HEAD || buf[3] != VB_FRAME_TAIL) return;

    uint8_t cmd = buf[1];

    switch (cmd) {
    case VB_CMD_WAKEUP:
        ESP_LOGI("VB6824", "唤醒成功");
        app_post_event(APP_EVT_WAKE_WORD, 0, 0, NULL);
        break;

    case VB_CMD_INTERRUPT:
        ESP_LOGI("VB6824", "用户打断");
        app_post_event(APP_EVT_VOICE_INTERRUPT, 0, 0, NULL);
        break;

    case VB_CMD_REC_START:
        ESP_LOGI("VB6824", "录音开始");
        app_post_event(APP_EVT_AI_LISTENING, 0, 0, NULL);
        break;

    case VB_CMD_REC_STOP:
        ESP_LOGI("VB6824", "录音结束");
        app_post_event(APP_EVT_AI_THINKING, 0, 0, NULL);
        break;

    default:
        break;
    }
}

static void vb6824_uart_task(void *arg)
{
    uint8_t rx[64];

    while (1) {
        int len = uart_read_bytes(VB_UART_NUM, rx, sizeof(rx), pdMS_TO_TICKS(100));

        if (len > 0) {
            vb6824_parse_frame(rx, len);
        }
    }
}

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

    ESP_ERROR_CHECK(uart_driver_install(VB_UART_NUM, 2048, 0, 0, NULL, 0));
    ESP_ERROR_CHECK(uart_param_config(VB_UART_NUM, &uart_config));
    ESP_ERROR_CHECK(uart_set_pin(VB_UART_NUM, VB_UART_TX, VB_UART_RX,
                                 UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));

    xTaskCreate(vb6824_uart_task, "vb6824_uart", 4096, NULL, 6, NULL);
}

6.9 AI WebSocket 消息解析

AI 云端建议返回结构化 JSON,便于设备联动双目表情、TTS、震动和 UI。

云端消息示例:

复制代码
{
  "type": "tts",
  "state": "start",
  "emotion": "happy",
  "text": "你好,我在。"
}

设备侧解析:

复制代码
#include "cJSON.h"
#include "esp_log.h"
#include "app_event.h"

static void ai_handle_json(const char *json)
{
    cJSON *root = cJSON_Parse(json);
    if (!root) return;

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

    if (cJSON_IsString(type)) {
        if (strcmp(type->valuestring, "stt") == 0) {
            app_post_event(APP_EVT_AI_THINKING, 0, 0, NULL);
        }

        if (strcmp(type->valuestring, "llm") == 0) {
            app_post_event(APP_EVT_AI_THINKING, 0, 0, NULL);
        }

        if (strcmp(type->valuestring, "tts") == 0) {
            if (state && cJSON_IsString(state)) {
                if (strcmp(state->valuestring, "start") == 0) {
                    app_post_event(APP_EVT_AI_SPEAKING, 0, 0, NULL);
                } else if (strcmp(state->valuestring, "stop") == 0) {
                    app_post_event(APP_EVT_AI_LISTENING, 0, 0, NULL);
                }
            }
        }
    }

    if (cJSON_IsString(emotion)) {
        if (strcmp(emotion->valuestring, "happy") == 0) {
            eye_play_anim("happy");
        } else if (strcmp(emotion->valuestring, "thinking") == 0) {
            eye_play_anim("thinking");
        } else if (strcmp(emotion->valuestring, "sad") == 0) {
            eye_play_anim("sad");
        } else if (strcmp(emotion->valuestring, "surprised") == 0) {
            eye_play_anim("surprised");
        }
    }

    cJSON_Delete(root);
}

6.10 MCP 工具定义与设备侧处理

通过 MCP,可以让 AI 模型直接调用设备能力,例如切换表情、控制音量、启动配网、切换角色、播放提示音。

工具定义示例:

复制代码
{
  "name": "self.eye.set_expression",
  "description": "设置四博AI双目的表情状态",
  "parameters": {
    "type": "object",
    "properties": {
      "expression": {
        "type": "string",
        "enum": ["开心", "思考", "惊讶", "困惑", "睡觉", "待机"]
      }
    },
    "required": ["expression"]
  }
}

设备侧处理:

复制代码
void mcp_set_eye_expression(const char *expression)
{
    if (strcmp(expression, "开心") == 0) {
        eye_play_anim("happy");
        haptic_short();
    } else if (strcmp(expression, "思考") == 0) {
        eye_play_anim("thinking");
    } else if (strcmp(expression, "惊讶") == 0) {
        eye_play_anim("surprised");
        haptic_double();
    } else if (strcmp(expression, "困惑") == 0) {
        eye_play_anim("confused");
    } else if (strcmp(expression, "睡觉") == 0) {
        eye_play_anim("sleep");
    } else {
        eye_play_anim("idle_blink");
    }
}

再定义一个切换眼睛主题工具:

复制代码
{
  "name": "self.eye.set_theme",
  "description": "切换四博AI双目的眼睛主题",
  "parameters": {
    "type": "object",
    "properties": {
      "theme": {
        "type": "string",
        "enum": ["默认", "海洋", "爱心", "梦境", "彩虹", "机甲", "花仙子"]
      }
    },
    "required": ["theme"]
  }
}

void mcp_set_eye_theme(const char *theme)
{
    if (strcmp(theme, "海洋") == 0) {
        eye_load_theme("ocean");
    } else if (strcmp(theme, "爱心") == 0) {
        eye_load_theme("heart");
    } else if (strcmp(theme, "梦境") == 0) {
        eye_load_theme("dream");
    } else if (strcmp(theme, "彩虹") == 0) {
        eye_load_theme("rainbow");
    } else if (strcmp(theme, "机甲") == 0) {
        eye_load_theme("mecha");
    } else if (strcmp(theme, "花仙子") == 0) {
        eye_load_theme("flower");
    } else {
        eye_load_theme("default");
    }

    haptic_short();
}

7. 小程序功能设计

四博小助手小程序建议作为产品的"AI 配置中心"和"运营中心"。

复制代码
四博小助手
 ├── 设备绑定
 ├── Wi-Fi / BLE 配网
 ├── AI 智能体选择
 ├── 声音克隆
 ├── 知识库上传
 ├── MCP 工具配置
 ├── 眼睛主题管理
 ├── 提示音管理
 ├── OTA 升级
 ├── 音量 / 亮度 / 灵敏度配置
 └── 家长模式 / 儿童模式

设备配置结构可以这样设计:

复制代码
typedef struct {
    char device_id[32];
    char user_id[32];

    char wifi_ssid[32];

    char ai_agent_id[64];
    char voice_id[64];
    char kb_id[64];

    int volume;
    int brightness;
    int wake_sensitivity;
    int eye_theme;

    bool child_mode;
    bool quiet_mode;
    bool auto_sleep;
} device_config_t;

static device_config_t g_dev_cfg;

NVS 保存:

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

esp_err_t device_config_save(void)
{
    nvs_handle_t nvs;
    esp_err_t ret = nvs_open("dev_cfg", NVS_READWRITE, &nvs);
    if (ret != ESP_OK) return ret;

    ret = nvs_set_blob(nvs, "config", &g_dev_cfg, sizeof(g_dev_cfg));
    if (ret == ESP_OK) {
        ret = nvs_commit(nvs);
    }

    nvs_close(nvs);
    return ret;
}

esp_err_t device_config_load(void)
{
    nvs_handle_t nvs;
    size_t len = sizeof(g_dev_cfg);

    esp_err_t ret = nvs_open("dev_cfg", NVS_READONLY, &nvs);
    if (ret != ESP_OK) return ret;

    ret = nvs_get_blob(nvs, "config", &g_dev_cfg, &len);
    nvs_close(nvs);

    return ret;
}

小程序下发配置示例:

复制代码
{
  "cmd": "set_ai_profile",
  "ai_agent_id": "agent_sibo_001",
  "voice_id": "voice_clone_user_001",
  "kb_id": "kb_product_manual_001",
  "volume": 70,
  "brightness": 80,
  "eye_theme": 3,
  "child_mode": true
}

设备解析:

复制代码
void app_handle_config_json(const char *json)
{
    cJSON *root = cJSON_Parse(json);
    if (!root) return;

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

    if (cJSON_IsString(cmd) &&
        strcmp(cmd->valuestring, "set_ai_profile") == 0) {

        json_copy_string(root, "ai_agent_id",
                         g_dev_cfg.ai_agent_id,
                         sizeof(g_dev_cfg.ai_agent_id));

        json_copy_string(root, "voice_id",
                         g_dev_cfg.voice_id,
                         sizeof(g_dev_cfg.voice_id));

        json_copy_string(root, "kb_id",
                         g_dev_cfg.kb_id,
                         sizeof(g_dev_cfg.kb_id));

        g_dev_cfg.volume = json_get_int(root, "volume", 70);
        g_dev_cfg.brightness = json_get_int(root, "brightness", 80);
        g_dev_cfg.eye_theme = json_get_int(root, "eye_theme", 0);
        g_dev_cfg.child_mode = json_get_bool(root, "child_mode", false);

        audio_set_volume(g_dev_cfg.volume);
        lcd_set_brightness(g_dev_cfg.brightness);
        eye_theme_set(g_dev_cfg.eye_theme);

        device_config_save();

        eye_play_anim("happy");
        audio_tts_play("设备配置已经更新完成。");
    }

    cJSON_Delete(root);
}

8. OTA 与素材升级设计

AI 双目类产品建议支持两类升级:

升级类型 内容
系统 OTA 主程序、AI 协议、驱动、MCP、状态机
素材 OTA 眼睛动画、提示音、角色皮肤、表情包

推荐分区:

复制代码
# 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,  2M
ota_0,      app,  ota_0,   0x220000, 2M
ota_1,      app,  ota_1,   0x420000, 2M
assets,     data, spiffs,  0x620000, 4M
storage,    data, fat,     0xA20000, 4M

OTA manifest 示例:

复制代码
{
  "device": "sibo_ai_eye",
  "version": "1.0.8",
  "firmware": {
    "url": "https://server.com/firmware/sibo_ai_eye_v1.0.8.bin",
    "sha256": "xxxx"
  },
  "assets": {
    "url": "https://server.com/assets/eye_theme_v3.bin",
    "sha256": "yyyy"
  },
  "force": false
}

9. 产测方案

量产时建议提供专用 factory 固件,覆盖:

测试项 测试内容
双目屏 RGB、坏点、左右屏同步
四路触控 原始值、阈值、短按、长按
震动马达 PWM、短震、长震
三轴传感器 X/Y/Z 方向、摇晃、翻转
麦克风 录音电平、底噪
喇叭 提示音播放、音量
VB6824 唤醒、打断、升级模式
Wi-Fi RSSI、连接、重连
BLE 配网广播、连接
电池 ADC 电压、充电状态
Flash NVS、OTA、素材分区
小程序 绑定、配网、参数下发

产测命令示例:

复制代码
{
  "cmd": "factory_test",
  "item": "touch"
}

void factory_handle_cmd(const char *json)
{
    cJSON *root = cJSON_Parse(json);
    if (!root) return;

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

    if (strcmp(item->valuestring, "screen") == 0) {
        lcd_fill_color(0xF800);
        vTaskDelay(pdMS_TO_TICKS(300));
        lcd_fill_color(0x07E0);
        vTaskDelay(pdMS_TO_TICKS(300));
        lcd_fill_color(0x001F);
        factory_reply("screen", "ok");
    }

    if (strcmp(item->valuestring, "motor") == 0) {
        haptic_short();
        haptic_double();
        haptic_long();
        factory_reply("motor", "ok");
    }

    if (strcmp(item->valuestring, "touch") == 0) {
        int top = touch_get_raw(0);
        int left = touch_get_raw(1);
        int right = touch_get_raw(2);
        int back = touch_get_raw(3);

        if (top > 0 && left > 0 && right > 0 && back > 0) {
            factory_reply("touch", "ok");
        } else {
            factory_reply("touch", "fail");
        }
    }

    if (strcmp(item->valuestring, "imu") == 0) {
        accel_data_t acc;
        if (imu_read_accel(&acc) == ESP_OK) {
            factory_reply("imu", "ok");
        } else {
            factory_reply("imu", "fail");
        }
    }

    cJSON_Delete(root);
}

10. 推荐 SKU 规划

SKU 配置 定位
标准版 S3 + VB6824 + 0.71 双目 + 四触控 AI 玩具 / 小型桌宠
高配版 S3 + VB6824 + 1.28 双目 + 四触控 + 马达 AI 音箱 / AI 桌宠
Pro 版 S3 + VB6824 + 1.28 双目 + IMU + 电池 陪伴机器人 / 教育硬件
多模态版 S3 + 双目 + 摄像头 + 触控 AI 视觉交互终端
运营版 S3 + 小程序 + 声音克隆 + 知识库 + MCP 品牌定制 / IP 潮玩

11. 方案总结

四博 AI 双目方案的核心不是单个硬件模块,而是把 ESP32-S3 主控、VB6824 语音前端、双目光屏、四路触控、三轴姿态、震动反馈、小程序、声音克隆、知识库和 MCP 工具整合成一个完整的 AI 硬件平台。

它的优势可以概括为:

  1. 硬件配置完整:双目屏、触控、马达、姿态、语音、联网能力齐全。

  2. 交互体验强:语音、表情、触摸、动作、震动形成闭环。

  3. 开发生态成熟:基于 ESP32-S3 和 ESP-IDF,适合二次开发。

  4. AI 能力可扩展:可接入小智、豆包、ChatGPT 等主流大模型。

  5. 小程序平台完整:支持声音克隆、知识库、MCP、OTA 和素材管理。

  6. 量产友好:可做标准款、高配款、多模态款、IP 定制款。

一句话概括:

四博 AI 双目 = ESP32-S3 多模态主控 + VB6824 语音前端 + 0.71 / 1.28 双目屏 + 四路触控 + 三轴姿态 + 震动反馈 + 四博小助手 AI 平台。

它不仅是一个 AI 音箱,也可以是 AI 桌宠、AI 学习伙伴、AI 潮玩终端、品牌智能客服入口和智能家居语音入口。

相关推荐
小黄人软件12 分钟前
AI时代什么是高价值目标?
大数据·人工智能
gjhave14 分钟前
jetson agx xaviar刷机过程
人工智能
GIOTTO情14 分钟前
Infoseek 危机公关自动化闭环系统,实现 PR 运维工程化
人工智能·算法·机器学习
南屹川14 分钟前
【架构设计】微服务架构设计模式:从单体到分布式的演进之路
人工智能
财经资讯数据_灵砚智能14 分钟前
基于全球经济类多源新闻的NLP情感分析与数据可视化(夜间-次晨)2026年5月21日
大数据·人工智能·python·信息可视化·自然语言处理
Elastic 中国社区官方博客15 分钟前
用于调试 LLM 延迟、成本和 GPU 饱和度的 ES|QL 查询
大数据·人工智能·elasticsearch·搜索引擎·ai·云原生·serverless
2501_9458374315 分钟前
OpenClaw:让 AI 从 “说” 到 “做” 的开源智能体
人工智能
Q27068102015 分钟前
告别AI配乐短板:创作者音乐素材精准选型
人工智能
sali-tec16 分钟前
C# 基于OpenCv的视觉工作流-章76-轮廓-段距
图像处理·人工智能·opencv·算法·计算机视觉
踏着七彩祥云的小丑16 分钟前
AI——LangChain 三大核心概念
人工智能·ai·langchain