四博 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 潮玩终端、品牌智能客服入口和智能家居语音入口。

相关推荐
ai产品老杨1 小时前
解构企业级AI视频中台:基于X86/ARM与GPU/NPU异构架构的深度演进与源码交付实践
arm开发·人工智能·音视频
Godspeed Zhao1 小时前
具身智能中的传感器技术36——RGB-D相机2
人工智能·科技·机器学习·深度相机
G探险者1 小时前
ClawHub 下载量最高的 20 个 Skill 介绍
人工智能
TuCoder1 小时前
AI复刻5A景区智慧导览:从10万到千元的成本(六)真实商业化落地案例
人工智能·ai·智慧旅游·手绘地图·智慧导览·景区电子导览·景区地图
AI搅拌机1 小时前
百度也正式加入开源社区,发布了 ERNIE-Image 模型,直接对标 ZImage 和 Klein
人工智能
电科一班林耿超1 小时前
机器学习大师课 第 1 课:什么是机器学习?写出你的第一个 AI 程序
人工智能·机器学习
浪客川1 小时前
UniFFI 网络接口实战:从阿里云 AI 到移动端集成
人工智能·阿里云·云计算
一只数据集1 小时前
水稻叶片图像与SPAD值标注数据集-140张高质量图像-精准农业机器学习训练数据集
人工智能·深度学习·机器学习
AI技术增长1 小时前
Pytorch图像去噪实战(一):从0复现DnCNN并解决训练不收敛问题(附完整工程+踩坑总结)
人工智能·pytorch·python