基于 ESP32-S3 的四博AI双目智能音箱方案:双目同显/异显、素材上传、触摸、G-sensor、舵机、TWS音频接入

基于 ESP32-S3 的四博AI双目智能音箱方案:双目同显/异显、素材上传、触摸、G-sensor、舵机、TWS音频接入

1. 项目概述

四博AI双目智能音箱方案是一套基于 ESP32-S3 / ESPS3-32E 的多模态AI硬件方案。它不是传统单纯"语音对话音箱",而是将 AI语音交互、双目屏动画显示、触摸交互、G-sensor姿态感知、震动反馈、舵机动作、Wi-Fi/4G/Bluetooth联网、TWS耳机/蓝牙音箱音频输出 集成到一个可二次开发的智能终端中。

在四博模组选型资料中,ESP32-S3系列被归类到音视频/AI市场,ESPS3-32、ESPS3-32E可作为AI音视频产品主控;AI开发宝典中也已经提供 RoPet_ESPS3_AI_EYE 双目工程,支持两块屏幕、主板、咪头、喇叭、0.71寸/1.28寸屏幕、小智功能、2.4G Wi-Fi以及4G模组联网等能力。

本文从工程角度设计一套完整方案,适合客户集成到自己的后端和自己的小程序中。


2. 方案核心能力

复制代码
复制代码
1. 主控基于 ESP32-S3,支持客户二次开发
2. 支持接入客户自有后端、私有AI服务、自有小程序
3. 支持双目同显、双目异显
4. 支持客户上传图片、GIF、短视频素材
5. 支持四路触摸传感器
6. 支持 G-sensor 姿态传感器
7. 支持震动马达反馈
8. 支持舵机驱动头部、尾部、耳朵等运动结构
9. 联网支持 Wi-Fi、4G、蓝牙
10. 支持连接 TWS 耳机和蓝牙音箱
11. 支持AI对话、TTS播放、语音唤醒、表情联动

需要注意:ESP32-S3 本身不支持传统 Bluetooth Classic A2DP/HFP 音频链路。如果要连接普通 TWS 蓝牙耳机或蓝牙音箱,建议增加外置蓝牙音频SoC,ESP32-S3负责AI、显示、网络和业务逻辑,外置蓝牙音频芯片负责 A2DP/HFP/TWS 音频链路。


3. 系统总体架构

复制代码
复制代码
+------------------------------------------------------+
|              四博AI双目智能音箱系统                  |
+------------------------------------------------------+
| 主控:ESPS3-32 / ESPS3-32E / ESP32-S3                 |
|                                                      |
|  AI通信层                                             |
|  ├── Wi-Fi 连接客户后端 / 小智 / Coze / 私有LLM        |
|  ├── 4G模组 PPP / UART / USB联网                      |
|  └── BLE 用于配网、绑定、小程序控制                   |
|                                                      |
|  显示层                                               |
|  ├── 左眼 LCD / SPI屏                                 |
|  ├── 右眼 LCD / SPI屏                                 |
|  ├── 双目同显                                         |
|  ├── 双目异显                                         |
|  └── 图片 / GIF / MJPEG / QOI / RAW帧播放              |
|                                                      |
|  交互层                                               |
|  ├── 4路触摸传感器                                    |
|  ├── G-sensor 姿态检测                                |
|  ├── 震动马达                                         |
|  └── 舵机控制头部 / 尾部 / 耳朵                        |
|                                                      |
|  音频层                                               |
|  ├── 麦克风采集                                       |
|  ├── 喇叭播放                                         |
|  ├── TTS语音播放                                      |
|  └── 外置BT Audio SoC连接TWS耳机/蓝牙音箱              |
+------------------------------------------------------+

4. 推荐工程目录

复制代码
复制代码
sibo_ai_dual_eye_speaker/
├── CMakeLists.txt
├── partitions.csv
├── sdkconfig.defaults
└── main/
    ├── app_main.c
    ├── app_config.h
    ├── board_pins.h
    ├── ai_client.c
    ├── ai_client.h
    ├── eye_display.c
    ├── eye_display.h
    ├── asset_manager.c
    ├── asset_manager.h
    ├── touch_manager.c
    ├── touch_manager.h
    ├── gsensor_manager.c
    ├── gsensor_manager.h
    ├── motor_manager.c
    ├── motor_manager.h
    ├── servo_manager.c
    ├── servo_manager.h
    ├── network_manager.c
    ├── network_manager.h
    ├── audio_route.c
    ├── audio_route.h
    ├── bt_audio_bridge.c
    ├── bt_audio_bridge.h
    ├── app_protocol.c
    └── app_protocol.h

5. 分区设计:支持客户上传图片和视频素材

双目方案需要存储表情素材、动画素材和短视频素材,因此建议使用 OTA + FATFS / LittleFS 分区。

复制代码
复制代码
# Name,     Type, SubType, Offset,   Size,      Flags
nvs,        data, nvs,     0x9000,   0x4000,
otadata,    data, ota,     0xd000,   0x2000,
phy_init,   data, phy,     0xf000,   0x1000,
ota_0,      app,  ota_0,   0x20000,  0x400000,
ota_1,      app,  ota_1,   ,         0x400000,
assets,     data, fat,     ,         0x600000,
config,     data, nvs,     ,         0x10000,

素材目录建议:

复制代码
复制代码
/assets/
├── eyes/
│   ├── idle_left.qoi
│   ├── idle_right.qoi
│   ├── happy_left.qoi
│   ├── happy_right.qoi
│   ├── sad_left.qoi
│   └── sad_right.qoi
├── video/
│   ├── boot.mjpeg
│   ├── thinking.mjpeg
│   └── speaking.mjpeg
└── audio/
    ├── wake.wav
    ├── hello.wav
    └── error.wav

6. 双目显示管理:同显与异显

AI双目的核心是两块屏的表情管理。可以抽象成两种模式:

复制代码
复制代码
typedef enum {
    EYE_DISPLAY_SYNC = 0,      // 双目同显
    EYE_DISPLAY_ASYNC,         // 双目异显
} eye_display_mode_t;

typedef enum {
    EYE_EXPR_IDLE = 0,
    EYE_EXPR_HAPPY,
    EYE_EXPR_SAD,
    EYE_EXPR_THINKING,
    EYE_EXPR_SPEAKING,
    EYE_EXPR_SLEEP,
    EYE_EXPR_CUSTOM
} eye_expression_t;

typedef struct {
    eye_display_mode_t mode;
    eye_expression_t left_expr;
    eye_expression_t right_expr;
    char left_asset[128];
    char right_asset[128];
    int fps;
    bool loop;
} eye_display_ctx_t;

显示接口:

复制代码
复制代码
void eye_display_init(void);
void eye_display_set_mode(eye_display_mode_t mode);
void eye_display_show_same(eye_expression_t expr);
void eye_display_show_diff(eye_expression_t left, eye_expression_t right);
void eye_display_play_custom(const char *left_asset, const char *right_asset, int fps);

实现示例:

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

static eye_display_ctx_t s_eye = {
    .mode = EYE_DISPLAY_SYNC,
    .left_expr = EYE_EXPR_IDLE,
    .right_expr = EYE_EXPR_IDLE,
    .fps = 15,
    .loop = true,
};

void eye_display_init(void)
{
    printf("[eye] init dual display\n");

    /*
     * 实际项目中初始化两块屏:
     * lcd_left_init();
     * lcd_right_init();
     * lvgl_port_init();
     */
}

void eye_display_set_mode(eye_display_mode_t mode)
{
    s_eye.mode = mode;
    printf("[eye] mode=%d\n", mode);
}

static const char *expr_to_asset(eye_expression_t expr, bool left)
{
    switch (expr) {
    case EYE_EXPR_HAPPY:
        return left ? "/assets/eyes/happy_left.qoi" : "/assets/eyes/happy_right.qoi";

    case EYE_EXPR_SAD:
        return left ? "/assets/eyes/sad_left.qoi" : "/assets/eyes/sad_right.qoi";

    case EYE_EXPR_THINKING:
        return left ? "/assets/eyes/thinking_left.qoi" : "/assets/eyes/thinking_right.qoi";

    case EYE_EXPR_SPEAKING:
        return left ? "/assets/eyes/speaking_left.qoi" : "/assets/eyes/speaking_right.qoi";

    case EYE_EXPR_SLEEP:
        return left ? "/assets/eyes/sleep_left.qoi" : "/assets/eyes/sleep_right.qoi";

    case EYE_EXPR_IDLE:
    default:
        return left ? "/assets/eyes/idle_left.qoi" : "/assets/eyes/idle_right.qoi";
    }
}

void eye_display_show_same(eye_expression_t expr)
{
    s_eye.mode = EYE_DISPLAY_SYNC;
    s_eye.left_expr = expr;
    s_eye.right_expr = expr;

    const char *left = expr_to_asset(expr, true);
    const char *right = expr_to_asset(expr, false);

    printf("[eye] sync display: left=%s right=%s\n", left, right);

    /*
     * display_image_left(left);
     * display_image_right(right);
     */
}

void eye_display_show_diff(eye_expression_t left, eye_expression_t right)
{
    s_eye.mode = EYE_DISPLAY_ASYNC;
    s_eye.left_expr = left;
    s_eye.right_expr = right;

    const char *left_asset = expr_to_asset(left, true);
    const char *right_asset = expr_to_asset(right, false);

    printf("[eye] async display: left=%s right=%s\n", left_asset, right_asset);

    /*
     * display_image_left(left_asset);
     * display_image_right(right_asset);
     */
}

void eye_display_play_custom(const char *left_asset, const char *right_asset, int fps)
{
    if (!left_asset || !right_asset) {
        return;
    }

    s_eye.mode = EYE_DISPLAY_ASYNC;
    s_eye.fps = fps;

    strncpy(s_eye.left_asset, left_asset, sizeof(s_eye.left_asset) - 1);
    strncpy(s_eye.right_asset, right_asset, sizeof(s_eye.right_asset) - 1);

    printf("[eye] custom play: L=%s R=%s fps=%d\n",
           s_eye.left_asset,
           s_eye.right_asset,
           s_eye.fps);

    /*
     * video_player_start_left(left_asset, fps);
     * video_player_start_right(right_asset, fps);
     */
}

7. 客户上传素材协议

客户可以通过自己的小程序或后端上传素材。设备端只需要支持素材下载、校验、保存、索引更新。

后端下发协议

复制代码
复制代码
{
  "cmd": "update_eye_asset",
  "data": {
    "asset_id": "happy_v2",
    "type": "image",
    "left_url": "https://cdn.example.com/eyes/happy_left.qoi",
    "right_url": "https://cdn.example.com/eyes/happy_right.qoi",
    "left_path": "/assets/eyes/happy_left.qoi",
    "right_path": "/assets/eyes/happy_right.qoi",
    "md5": "xxxxxxxxxxxxxxxx",
    "fps": 15
  }
}

设备端解析代码

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

void asset_handle_update_json(const char *json)
{
    cJSON *root = cJSON_Parse(json);
    if (!root) {
        printf("[asset] json parse failed\n");
        return;
    }

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

    if (!cmd || !data) {
        cJSON_Delete(root);
        return;
    }

    if (strcmp(cmd->valuestring, "update_eye_asset") == 0) {
        const char *left_url = cJSON_GetObjectItem(data, "left_url")->valuestring;
        const char *right_url = cJSON_GetObjectItem(data, "right_url")->valuestring;
        const char *left_path = cJSON_GetObjectItem(data, "left_path")->valuestring;
        const char *right_path = cJSON_GetObjectItem(data, "right_path")->valuestring;

        printf("[asset] download left: %s -> %s\n", left_url, left_path);
        printf("[asset] download right: %s -> %s\n", right_url, right_path);

        /*
         * http_download_file(left_url, left_path);
         * http_download_file(right_url, right_path);
         * asset_verify_md5();
         * asset_index_update();
         */
    }

    cJSON_Delete(root);
}

8. 四路触摸传感器设计

四路触摸可以定义为:

复制代码
复制代码
TOUCH0:摸头 / 唤醒
TOUCH1:左耳 / 上一个表情
TOUCH2:右耳 / 下一个表情
TOUCH3:下巴 / 进入AI对话

代码示例:

复制代码
复制代码
typedef enum {
    TOUCH_EVT_HEAD = 0,
    TOUCH_EVT_LEFT,
    TOUCH_EVT_RIGHT,
    TOUCH_EVT_CHIN
} touch_event_t;

void touch_manager_handle_event(touch_event_t evt)
{
    switch (evt) {
    case TOUCH_EVT_HEAD:
        printf("[touch] head touched\n");
        eye_display_show_same(EYE_EXPR_HAPPY);
        motor_vibrate_once(80);
        break;

    case TOUCH_EVT_LEFT:
        printf("[touch] left touched\n");
        eye_display_show_diff(EYE_EXPR_HAPPY, EYE_EXPR_IDLE);
        break;

    case TOUCH_EVT_RIGHT:
        printf("[touch] right touched\n");
        eye_display_show_diff(EYE_EXPR_IDLE, EYE_EXPR_HAPPY);
        break;

    case TOUCH_EVT_CHIN:
        printf("[touch] chin touched, start AI chat\n");
        eye_display_show_same(EYE_EXPR_THINKING);
        // ai_client_start_listen();
        break;

    default:
        break;
    }
}

9. G-sensor姿态联动

G-sensor可以用于检测摇晃、抬起、倾斜、拍打等动作。

复制代码
复制代码
typedef enum {
    GSENSOR_EVT_NONE = 0,
    GSENSOR_EVT_SHAKE,
    GSENSOR_EVT_TILT_LEFT,
    GSENSOR_EVT_TILT_RIGHT,
    GSENSOR_EVT_PICK_UP,
    GSENSOR_EVT_PUT_DOWN
} gsensor_event_t;

void gsensor_handle_event(gsensor_event_t evt)
{
    switch (evt) {
    case GSENSOR_EVT_SHAKE:
        printf("[gsensor] shake\n");
        eye_display_show_same(EYE_EXPR_HAPPY);
        servo_wag_tail();
        motor_vibrate_once(100);
        break;

    case GSENSOR_EVT_TILT_LEFT:
        printf("[gsensor] tilt left\n");
        eye_display_show_diff(EYE_EXPR_SAD, EYE_EXPR_IDLE);
        break;

    case GSENSOR_EVT_TILT_RIGHT:
        printf("[gsensor] tilt right\n");
        eye_display_show_diff(EYE_EXPR_IDLE, EYE_EXPR_SAD);
        break;

    case GSENSOR_EVT_PICK_UP:
        printf("[gsensor] pick up\n");
        eye_display_show_same(EYE_EXPR_HAPPY);
        break;

    default:
        break;
    }
}

10. 震动马达和舵机控制

震动马达用于触摸反馈、AI响应反馈、闹钟提醒。舵机可驱动头部、尾部或耳朵结构。

震动马达

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

#define PIN_MOTOR 11

void motor_init(void)
{
    gpio_config_t io = {
        .pin_bit_mask = 1ULL << PIN_MOTOR,
        .mode = GPIO_MODE_OUTPUT,
    };

    gpio_config(&io);
    gpio_set_level(PIN_MOTOR, 0);
}

void motor_vibrate_once(int ms)
{
    gpio_set_level(PIN_MOTOR, 1);
    vTaskDelay(pdMS_TO_TICKS(ms));
    gpio_set_level(PIN_MOTOR, 0);
}

舵机控制

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

#define SERVO_GPIO          12
#define SERVO_LEDC_TIMER    LEDC_TIMER_0
#define SERVO_LEDC_CHANNEL  LEDC_CHANNEL_0

void servo_init(void)
{
    ledc_timer_config_t timer = {
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .timer_num = SERVO_LEDC_TIMER,
        .duty_resolution = LEDC_TIMER_13_BIT,
        .freq_hz = 50,
        .clk_cfg = LEDC_AUTO_CLK,
    };

    ledc_timer_config(&timer);

    ledc_channel_config_t channel = {
        .gpio_num = SERVO_GPIO,
        .speed_mode = LEDC_LOW_SPEED_MODE,
        .channel = SERVO_LEDC_CHANNEL,
        .timer_sel = SERVO_LEDC_TIMER,
        .duty = 0,
        .hpoint = 0,
    };

    ledc_channel_config(&channel);
}

static uint32_t servo_angle_to_duty(int angle)
{
    if (angle < 0) angle = 0;
    if (angle > 180) angle = 180;

    int min_us = 500;
    int max_us = 2500;
    int us = min_us + (max_us - min_us) * angle / 180;

    return (uint32_t)(us * 8192 / 20000);
}

void servo_set_angle(int angle)
{
    uint32_t duty = servo_angle_to_duty(angle);

    ledc_set_duty(LEDC_LOW_SPEED_MODE, SERVO_LEDC_CHANNEL, duty);
    ledc_update_duty(LEDC_LOW_SPEED_MODE, SERVO_LEDC_CHANNEL);
}

void servo_wag_tail(void)
{
    servo_set_angle(60);
    vTaskDelay(pdMS_TO_TICKS(200));
    servo_set_angle(120);
    vTaskDelay(pdMS_TO_TICKS(200));
    servo_set_angle(90);
}

11. Wi-Fi / 4G / 蓝牙联网策略

AI开发宝典中已有 AI-C5 的 Wi-Fi 与4G模式切换说明,例如4G模式下重新开机,在等待网络时双击boot键可切换到Wi-Fi配网模式;设备配网也提供SoftAP和四博小助手BluFi方式。

联网管理建议抽象为:

复制代码
复制代码
typedef enum {
    NET_MODE_NONE = 0,
    NET_MODE_WIFI,
    NET_MODE_4G,
    NET_MODE_BLE_CONFIG
} net_mode_t;

typedef struct {
    net_mode_t current;
    bool wifi_connected;
    bool modem_4g_ready;
    bool ble_config_active;
} network_ctx_t;

static network_ctx_t s_net = {
    .current = NET_MODE_NONE,
};

void network_switch_to_wifi(void)
{
    printf("[net] switch to Wi-Fi\n");
    s_net.current = NET_MODE_WIFI;

    /*
     * wifi_init_sta();
     * wifi_connect();
     */
}

void network_switch_to_4g(void)
{
    printf("[net] switch to 4G\n");
    s_net.current = NET_MODE_4G;

    /*
     * modem_power_on();
     * pppos_start();
     */
}

void network_start_ble_config(void)
{
    printf("[net] start BLE config\n");
    s_net.current = NET_MODE_BLE_CONFIG;

    /*
     * blufi_start();
     */
}

12. TWS耳机和蓝牙音箱接入方案

因为 ESP32-S3 主要承担AI、显示、网络、控制逻辑,不建议让它直接承担传统A2DP/HFP蓝牙音频。更稳的方式是增加外置蓝牙音频模块:

复制代码
复制代码
ESP32-S3
├── I2S PCM音频输出 -> 外置BT Audio SoC
├── UART控制命令    -> 外置BT Audio SoC
└── GPIO状态检测    -> 连接状态 / 播放状态 / 配对状态

音频路由定义:

复制代码
复制代码
typedef enum {
    AUDIO_ROUTE_LOCAL_SPEAKER = 0,
    AUDIO_ROUTE_TWS_EARBUDS,
    AUDIO_ROUTE_BT_SPEAKER,
    AUDIO_ROUTE_35MM_JACK
} audio_route_t;

static audio_route_t s_audio_route = AUDIO_ROUTE_LOCAL_SPEAKER;

void audio_route_set(audio_route_t route)
{
    s_audio_route = route;

    switch (route) {
    case AUDIO_ROUTE_LOCAL_SPEAKER:
        printf("[audio] route: local speaker\n");
        // amp_enable(true);
        // bt_audio_mute(true);
        break;

    case AUDIO_ROUTE_TWS_EARBUDS:
        printf("[audio] route: TWS earbuds\n");
        // amp_enable(false);
        // bt_audio_connect_last_device();
        break;

    case AUDIO_ROUTE_BT_SPEAKER:
        printf("[audio] route: bluetooth speaker\n");
        // bt_audio_enter_pairing();
        break;

    case AUDIO_ROUTE_35MM_JACK:
        printf("[audio] route: 3.5mm jack\n");
        // amp_enable(false);
        break;

    default:
        break;
    }
}

外置BT音频模块控制示例:

复制代码
复制代码
void bt_audio_send_cmd(const char *cmd)
{
    printf("[bt-audio] send cmd: %s\n", cmd);

    /*
     * uart_write_bytes(BT_AUDIO_UART, cmd, strlen(cmd));
     * uart_write_bytes(BT_AUDIO_UART, "\r\n", 2);
     */
}

void bt_audio_pairing(void)
{
    bt_audio_send_cmd("AT+PAIR");
}

void bt_audio_connect_last(void)
{
    bt_audio_send_cmd("AT+CONNECT_LAST");
}

void bt_audio_disconnect(void)
{
    bt_audio_send_cmd("AT+DISCONNECT");
}

void bt_audio_set_volume(int volume)
{
    char cmd[32];
    snprintf(cmd, sizeof(cmd), "AT+VOLUME=%d", volume);
    bt_audio_send_cmd(cmd);
}

13. AI状态与双目表情联动

AI对话过程中,表情应该跟随状态变化:

复制代码
复制代码
待机:idle
唤醒:happy
思考:thinking
说话:speaking
网络异常:sad
睡眠:sleep

状态机代码:

复制代码
复制代码
typedef enum {
    AI_STATE_IDLE = 0,
    AI_STATE_WAKEUP,
    AI_STATE_LISTENING,
    AI_STATE_THINKING,
    AI_STATE_SPEAKING,
    AI_STATE_ERROR
} ai_state_t;

void ai_state_update(ai_state_t state)
{
    switch (state) {
    case AI_STATE_IDLE:
        eye_display_show_same(EYE_EXPR_IDLE);
        break;

    case AI_STATE_WAKEUP:
        eye_display_show_same(EYE_EXPR_HAPPY);
        motor_vibrate_once(60);
        break;

    case AI_STATE_LISTENING:
        eye_display_show_same(EYE_EXPR_THINKING);
        break;

    case AI_STATE_THINKING:
        eye_display_play_custom(
            "/assets/video/thinking_left.mjpeg",
            "/assets/video/thinking_right.mjpeg",
            15
        );
        break;

    case AI_STATE_SPEAKING:
        eye_display_show_same(EYE_EXPR_SPEAKING);
        servo_set_angle(100);
        break;

    case AI_STATE_ERROR:
        eye_display_show_same(EYE_EXPR_SAD);
        motor_vibrate_once(150);
        break;

    default:
        break;
    }
}

14. 小程序/后端控制协议

客户可以将设备接入自己的小程序和后端,只要后端按协议下发命令即可。

控制双目显示

复制代码
复制代码
{
  "cmd": "eye_display",
  "data": {
    "mode": "async",
    "left": "happy",
    "right": "idle"
  }
}

控制舵机动作

复制代码
复制代码
{
  "cmd": "servo_action",
  "data": {
    "target": "tail",
    "action": "wag",
    "duration_ms": 1200
  }
}

切换音频输出

复制代码
复制代码
{
  "cmd": "audio_route",
  "data": {
    "route": "tws"
  }
}

设备端统一解析

复制代码
复制代码
void app_protocol_handle_json(const char *json)
{
    cJSON *root = cJSON_Parse(json);
    if (!root) {
        printf("[proto] parse failed\n");
        return;
    }

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

    if (!cmd || !data) {
        cJSON_Delete(root);
        return;
    }

    if (strcmp(cmd->valuestring, "eye_display") == 0) {
        const char *mode = cJSON_GetObjectItem(data, "mode")->valuestring;
        const char *left = cJSON_GetObjectItem(data, "left")->valuestring;
        const char *right = cJSON_GetObjectItem(data, "right")->valuestring;

        if (strcmp(mode, "sync") == 0) {
            eye_display_show_same(EYE_EXPR_HAPPY);
        } else {
            eye_display_show_diff(EYE_EXPR_HAPPY, EYE_EXPR_IDLE);
        }

        printf("[proto] eye mode=%s left=%s right=%s\n", mode, left, right);
    }

    if (strcmp(cmd->valuestring, "audio_route") == 0) {
        const char *route = cJSON_GetObjectItem(data, "route")->valuestring;

        if (strcmp(route, "speaker") == 0) {
            audio_route_set(AUDIO_ROUTE_LOCAL_SPEAKER);
        } else if (strcmp(route, "tws") == 0) {
            audio_route_set(AUDIO_ROUTE_TWS_EARBUDS);
        } else if (strcmp(route, "bt_speaker") == 0) {
            audio_route_set(AUDIO_ROUTE_BT_SPEAKER);
        }
    }

    if (strcmp(cmd->valuestring, "servo_action") == 0) {
        const char *action = cJSON_GetObjectItem(data, "action")->valuestring;

        if (strcmp(action, "wag") == 0) {
            servo_wag_tail();
        }
    }

    cJSON_Delete(root);
}

15. app_main.c 示例

复制代码
复制代码
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"

void app_main(void)
{
    printf("SIBO AI Dual Eye Speaker Start\n");

    network_switch_to_wifi();

    eye_display_init();
    motor_init();
    servo_init();

    audio_route_set(AUDIO_ROUTE_LOCAL_SPEAKER);

    eye_display_show_same(EYE_EXPR_IDLE);

    while (1) {
        /*
         * 实际工程中:
         * 1. 处理触摸事件
         * 2. 处理G-sensor事件
         * 3. 处理AI状态
         * 4. 处理后端/小程序命令
         * 5. 刷新双目动画
         */

        vTaskDelay(pdMS_TO_TICKS(20));
    }
}

16. 总结

四博AI双目智能音箱方案适合做 AI桌面宠物、AI陪伴机器人、儿童AI音箱、情绪陪伴终端、IP互动摆件、智能玩具和AI语音机器人。

它的关键不是单个功能,而是把以下能力统一成一个可量产、可二次开发的系统:

复制代码
复制代码
ESP32-S3主控
双目屏显示
客户素材上传
四路触摸
G-sensor姿态感知
震动马达反馈
舵机动作控制
Wi-Fi / 4G / BLE联网
TWS耳机 / 蓝牙音箱音频输出
小程序 / 客户后端接入
AI大模型语音交互

对B端客户来说,最大的价值是:可以基于四博已有AI双目硬件和开源工程快速落地,同时保留接入客户自有后端、自有小程序、自有内容平台和自有AI服务的空间。

相关推荐
云上码厂1 小时前
卫星和航空影像的深度学习技术
人工智能·深度学习
吃好睡好便好1 小时前
在Matlab中绘制马鞍函数曲面图
开发语言·人工智能·学习·算法·matlab·信息可视化
tedcloud1231 小时前
OfficeCLI部署教程:让AI直接操作Word、Excel和PPT
服务器·人工智能·word·excel
测试员周周1 小时前
【Appium 系列】第01节-Appium 是什么 — 移动端自动化的行业标准
开发语言·人工智能·python·功能测试·appium·自动化·测试用例
工业机器人销售服务1 小时前
突破效率瓶颈:伯朗特大负载机器人实现连续模冲压多件同步取放
人工智能
前端小超人rui1 小时前
AI分类及AI大模型分类
人工智能·分类·数据挖掘·ai 大模型
薛定猫AI1 小时前
【深度解析】从 Gemini 3.2、Claude 限额变化到 AI Agent:大模型工程化选型与实战评估
人工智能·状态模式
weixin_377634841 小时前
【SkillRL】RL阶段
人工智能
RoboWizard1 小时前
DIY移动硬盘?2230能否堪大任!
数据库·人工智能·智能手机·性能优化·负载均衡