基于 ESP32-S3 的四博 AI 台灯方案:摄像头拍照答题、语音大模型、双目屏与生活陪伴系统设计
1. 方案定位
四博 AI 台灯可以理解为"四博 AI 智能音箱方案"的多模态升级版。
传统 AI 音箱主要完成:
语音唤醒 → 语音识别 → 大模型对话 → TTS 播放
升级为 AI 台灯后,系统需要增加:
摄像头采集
拍照答题
双目屏表情
台灯 PWM 调光
触摸交互
震动反馈
舵机动作
生活陪伴
儿童学习辅助
因此,本方案的核心不再是单纯"语音音箱",而是:
ESP32-S3 + Camera + I2S Audio + LCD/Dual Eyes + Touch + Light PWM + Servo + Cloud AI
四博资料中,ESP32-S3 系列主要面向音视频/AI 市场,支持摄像头、LCD、外挂 PSRAM 等应用方向;四博 AI 开发宝典中也包含 AI-S3、双目、多模态开发板、小智 AI 对接等内容,适合作为 AI 台灯、拍照答题机、桌面陪伴机器人等产品的基础平台。
2. 系统整体架构
2.1 硬件架构
┌──────────────────────┐
│ 云端 AI 服务 │
│ ASR / LLM / VLM / TTS │
└──────────▲───────────┘
│ HTTPS/WebSocket
│
┌──────────────┐ ┌───────┴────────┐ ┌──────────────┐
│ 摄像头 │──────▶│ ESP32-S3 │──────▶│ 双目屏 / LCD │
│ OV2640/GC系列 │ DVP │ ESPS3-32 N16R8 │ SPI │ 表情/答案显示 │
└──────────────┘ └───────┬────────┘ └──────────────┘
│
┌──────────────┬───────┼────────┬──────────────┐
│ │ │ │ │
┌────▼────┐ ┌─────▼───┐ ┌─▼──┐ ┌──▼───┐ ┌────▼────┐
│ 麦克风 │ │ 喇叭功放 │ │触摸 │ │台灯PWM│ │舵机/震动 │
│ I2S/PDM │ │ I2S/DAC │ │GPIO │ │LEDC │ │PWM/GPIO │
└─────────┘ └─────────┘ └────┘ └──────┘ └─────────┘
2.2 软件模块
main
├── app_main.c
├── board
│ ├── board_config.h
│ └── pin_config.h
├── camera
│ ├── app_camera.c
│ └── app_camera.h
├── audio
│ ├── app_audio.c
│ ├── wakeup.c
│ ├── recorder.c
│ └── tts_player.c
├── ai
│ ├── ai_event.c
│ ├── ai_protocol.c
│ ├── ai_http_vision.c
│ └── ai_ws_client.c
├── ui
│ ├── eye_anim.c
│ ├── answer_page.c
│ └── lvgl_port.c
├── lamp
│ ├── lamp_pwm.c
│ └── lamp_scene.c
├── motor
│ ├── servo_ctrl.c
│ └── vibration.c
├── touch
│ └── touch_key.c
└── net
├── wifi_manager.c
└── blufi_config.c
3. 推荐硬件配置
3.1 标准版本
主控:ESP32-S3 / ESPS3-32
Flash:16MB
PSRAM:2MB / 8MB
摄像头:OV2640 / GC0308 / GC2145
音频:I2S 麦克风 + I2S DAC / Codec
功放:NS4150 / 8002 / 外置 Class-D
屏幕:0.71 寸双目屏 / 1.28 寸双目屏 / 2.0 寸 LCD
触摸:电容触摸 IC 或 GPIO 触摸按键
灯光:PWM 恒流驱动
动作:SG90 舵机 / 震动马达
联网:Wi-Fi,后续可扩展 4G
3.2 产品版本规划
基础版:AI 音箱 + 台灯
学习版:AI 音箱 + 台灯 + 摄像头拍题
陪伴版:AI 音箱 + 台灯 + 摄像头 + 双目屏 + 舵机
高配版:AI 音箱 + 台灯 + 摄像头 + 双目屏 + 4G 联网
4. 典型交互流程
4.1 拍照答题
用户:小博,帮我看一下这道题。
设备流程:
1. 唤醒词触发
2. 进入 listening 状态
3. ASR 识别到"拍照答题"意图
4. 摄像头采集 JPEG 图片
5. 图片通过 HTTP/WebSocket 上传云端
6. 云端视觉大模型识别题目
7. 云端大模型生成解题步骤
8. TTS 生成语音
9. 设备播放讲解
10. 双目屏显示思考/回答表情
11. 台灯切换学习模式
4.2 生活陪伴
用户:小博,我今天有点不开心。
设备流程:
1. 语音识别用户情绪
2. 大模型生成安慰类回复
3. 灯光切换暖光
4. 双眼显示微笑表情
5. 震动马达短震反馈
6. 舵机轻微点头
7. TTS 播放陪伴语音
5. ESP-IDF 工程初始化
idf.py set-target esp32s3
idf.py menuconfig
建议开启:
CONFIG_SPIRAM=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=16384
CONFIG_LWIP_TCP_WND_DEFAULT=32768
组件依赖示例:
idf_component_register(
SRCS
"app_main.c"
"camera/app_camera.c"
"ai/ai_http_vision.c"
"ai/ai_protocol.c"
"lamp/lamp_pwm.c"
"motor/servo_ctrl.c"
"motor/vibration.c"
"touch/touch_key.c"
"ui/eye_anim.c"
INCLUDE_DIRS
"."
"camera"
"ai"
"lamp"
"motor"
"touch"
"ui"
REQUIRES
esp_http_client
esp-tls
esp_wifi
nvs_flash
json
driver
esp_timer
)
6. 事件总线设计
AI 台灯建议使用事件驱动架构,所有动作通过统一事件调度。
typedef enum {
AI_EVT_NONE = 0,
AI_EVT_WAKEUP,
AI_EVT_LISTEN_START,
AI_EVT_LISTEN_STOP,
AI_EVT_PHOTO_QA,
AI_EVT_COMPANION_CHAT,
AI_EVT_TTS_START,
AI_EVT_TTS_STOP,
AI_EVT_TOUCH,
AI_EVT_ERROR,
} ai_event_id_t;
typedef struct {
ai_event_id_t id;
char text[256];
void *data;
size_t data_len;
} ai_event_t;
static QueueHandle_t s_ai_queue;
void ai_event_init(void)
{
s_ai_queue = xQueueCreate(8, sizeof(ai_event_t));
}
esp_err_t ai_event_post(ai_event_id_t id, const char *text)
{
ai_event_t evt = {
.id = id,
.data = NULL,
.data_len = 0,
};
if (text) {
snprintf(evt.text, sizeof(evt.text), "%s", text);
}
if (xQueueSend(s_ai_queue, &evt, pdMS_TO_TICKS(100)) != pdTRUE) {
return ESP_FAIL;
}
return ESP_OK;
}
7. 摄像头初始化
#pragma once
#include "esp_err.h"
#include "esp_camera.h"
esp_err_t app_camera_init(void);
camera_fb_t *app_camera_capture(void);
void app_camera_release(camera_fb_t *fb);
#include "app_camera.h"
#include "esp_log.h"
static const char *TAG = "app_camera";
#define CAM_PIN_PWDN -1
#define CAM_PIN_RESET -1
#define CAM_PIN_XCLK 15
#define CAM_PIN_SIOD 4
#define CAM_PIN_SIOC 5
#define CAM_PIN_D7 16
#define CAM_PIN_D6 17
#define CAM_PIN_D5 18
#define CAM_PIN_D4 12
#define CAM_PIN_D3 10
#define CAM_PIN_D2 8
#define CAM_PIN_D1 9
#define CAM_PIN_D0 11
#define CAM_PIN_VSYNC 6
#define CAM_PIN_HREF 7
#define CAM_PIN_PCLK 13
esp_err_t app_camera_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_0,
.ledc_channel = LEDC_CHANNEL_0,
.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 ret = esp_camera_init(&config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "camera init failed: %s", esp_err_to_name(ret));
return ret;
}
sensor_t *s = esp_camera_sensor_get();
if (s) {
s->set_brightness(s, 0);
s->set_contrast(s, 1);
s->set_saturation(s, 0);
s->set_framesize(s, FRAMESIZE_VGA);
}
ESP_LOGI(TAG, "camera init ok");
return ESP_OK;
}
camera_fb_t *app_camera_capture(void)
{
camera_fb_t *fb = esp_camera_fb_get();
if (!fb) {
ESP_LOGE(TAG, "capture failed");
return NULL;
}
ESP_LOGI(TAG, "capture ok, len=%d, size=%dx%d",
fb->len, fb->width, fb->height);
return fb;
}
void app_camera_release(camera_fb_t *fb)
{
if (fb) {
esp_camera_fb_return(fb);
}
}
8. 拍照答题协议设计
设备上报:
{
"type": "vision_qa",
"device_id": "sibo_ai_lamp_001",
"session_id": "20260513_001",
"format": "jpeg",
"prompt": "请识别图片中的题目,给出详细解题步骤,并用儿童可以理解的方式讲解。",
"image_base64": "..."
}
云端返回:
{
"code": 0,
"type": "vision_qa_result",
"answer": "这道题先看括号内的数字,再进行乘法计算......",
"display_text": "解题步骤:1. 先算括号;2. 再算乘法;3. 最后检查结果。",
"tts_url": "https://server.com/tts/001.mp3",
"action": {
"eye": "answering",
"lamp": "study",
"servo": "nod",
"vibration": "short"
}
}
9. 图片上传代码
对于 ESP32-S3,推荐优先使用二进制上传,减少 Base64 带来的 33% 数据膨胀。简单项目可以使用 Base64 JSON,量产项目更建议使用 multipart/form-data 或 WebSocket binary。
9.1 Base64 JSON 版本
#include "esp_http_client.h"
#include "mbedtls/base64.h"
#include "cJSON.h"
#include "esp_log.h"
#include <stdlib.h>
#include <string.h>
static const char *TAG = "vision_http";
#define VISION_API_URL "https://your-domain.com/api/v1/vision/qa"
#define DEVICE_ID "sibo_ai_lamp_001"
static char *base64_encode(const uint8_t *input, size_t input_len)
{
size_t out_len = 0;
mbedtls_base64_encode(NULL, 0, &out_len, input, input_len);
char *out = calloc(1, out_len + 1);
if (!out) {
return NULL;
}
int ret = mbedtls_base64_encode(
(unsigned char *)out,
out_len,
&out_len,
input,
input_len
);
if (ret != 0) {
free(out);
return NULL;
}
out[out_len] = '\0';
return out;
}
esp_err_t ai_send_vision_qa(camera_fb_t *fb, const char *prompt)
{
if (!fb || !prompt) {
return ESP_ERR_INVALID_ARG;
}
char *image_b64 = base64_encode(fb->buf, fb->len);
if (!image_b64) {
ESP_LOGE(TAG, "base64 encode failed");
return ESP_ERR_NO_MEM;
}
cJSON *root = cJSON_CreateObject();
cJSON_AddStringToObject(root, "type", "vision_qa");
cJSON_AddStringToObject(root, "device_id", DEVICE_ID);
cJSON_AddStringToObject(root, "format", "jpeg");
cJSON_AddStringToObject(root, "prompt", prompt);
cJSON_AddStringToObject(root, "image_base64", image_b64);
char *body = cJSON_PrintUnformatted(root);
cJSON_Delete(root);
free(image_b64);
if (!body) {
return ESP_ERR_NO_MEM;
}
esp_http_client_config_t config = {
.url = VISION_API_URL,
.timeout_ms = 30000,
.buffer_size = 4096,
.buffer_size_tx = 4096,
};
esp_http_client_handle_t client = esp_http_client_init(&config);
if (!client) {
free(body);
return ESP_FAIL;
}
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_header(client, "Content-Type", "application/json");
esp_http_client_set_post_field(client, body, strlen(body));
esp_err_t ret = esp_http_client_perform(client);
if (ret == ESP_OK) {
int status = esp_http_client_get_status_code(client);
ESP_LOGI(TAG, "vision qa status=%d", status);
} else {
ESP_LOGE(TAG, "http failed: %s", esp_err_to_name(ret));
}
esp_http_client_cleanup(client);
free(body);
return ret;
}
10. 云端 FastAPI 示例
from fastapi import FastAPI
from pydantic import BaseModel
import base64
import uuid
app = FastAPI()
class VisionQARequest(BaseModel):
type: str
device_id: str
format: str
prompt: str
image_base64: str
def call_vlm(image_bytes: bytes, prompt: str) -> str:
"""
这里可以接入:
1. 小智服务
2. 豆包视觉大模型
3. 通义千问 VL
4. ChatGPT 视觉模型
5. 私有化 OCR + LLM 服务
"""
return "识别到一道数学题。解题步骤:先分析题干,再列式计算,最后检查答案。"
def call_tts(text: str) -> str:
task_id = str(uuid.uuid4())
return f"https://your-domain.com/tts/{task_id}.mp3"
@app.post("/api/v1/vision/qa")
async def vision_qa(req: VisionQARequest):
image_bytes = base64.b64decode(req.image_base64)
answer = call_vlm(
image_bytes=image_bytes,
prompt=req.prompt
)
tts_url = call_tts(answer)
return {
"code": 0,
"type": "vision_qa_result",
"device_id": req.device_id,
"answer": answer,
"display_text": answer[:80],
"tts_url": tts_url,
"action": {
"eye": "answering",
"lamp": "study",
"servo": "nod",
"vibration": "short"
}
}
11. 台灯 PWM 控制
#include "driver/ledc.h"
#include "esp_log.h"
#define LAMP_PWM_GPIO 38
#define LAMP_LEDC_MODE LEDC_LOW_SPEED_MODE
#define LAMP_LEDC_TIMER LEDC_TIMER_1
#define LAMP_LEDC_CHANNEL LEDC_CHANNEL_1
#define LAMP_PWM_FREQ 5000
#define LAMP_DUTY_RES LEDC_TIMER_13_BIT
void lamp_pwm_init(void)
{
ledc_timer_config_t timer = {
.speed_mode = LAMP_LEDC_MODE,
.timer_num = LAMP_LEDC_TIMER,
.duty_resolution = LAMP_DUTY_RES,
.freq_hz = LAMP_PWM_FREQ,
.clk_cfg = LEDC_AUTO_CLK,
};
ledc_timer_config(&timer);
ledc_channel_config_t channel = {
.gpio_num = LAMP_PWM_GPIO,
.speed_mode = LAMP_LEDC_MODE,
.channel = LAMP_LEDC_CHANNEL,
.timer_sel = LAMP_LEDC_TIMER,
.duty = 0,
.hpoint = 0,
};
ledc_channel_config(&channel);
}
void lamp_set_brightness(uint8_t percent)
{
if (percent > 100) {
percent = 100;
}
uint32_t max_duty = (1 << 13) - 1;
uint32_t duty = max_duty * percent / 100;
ledc_set_duty(LAMP_LEDC_MODE, LAMP_LEDC_CHANNEL, duty);
ledc_update_duty(LAMP_LEDC_MODE, LAMP_LEDC_CHANNEL);
}
void lamp_scene_study(void)
{
lamp_set_brightness(85);
}
void lamp_scene_companion(void)
{
lamp_set_brightness(45);
}
void lamp_scene_sleep(void)
{
lamp_set_brightness(10);
}
12. 舵机点头动作
#include "driver/ledc.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define SERVO_GPIO 39
#define SERVO_MODE LEDC_LOW_SPEED_MODE
#define SERVO_TIMER LEDC_TIMER_2
#define SERVO_CHANNEL LEDC_CHANNEL_2
#define SERVO_FREQ_HZ 50
#define SERVO_DUTY_RES LEDC_TIMER_14_BIT
static uint32_t servo_angle_to_duty(int angle)
{
if (angle < 0) {
angle = 0;
}
if (angle > 180) {
angle = 180;
}
const uint32_t max_duty = (1 << 14) - 1;
float pulse_ms = 0.5f + ((float)angle / 180.0f) * 2.0f;
return (uint32_t)(max_duty * pulse_ms / 20.0f);
}
void servo_init(void)
{
ledc_timer_config_t timer = {
.speed_mode = SERVO_MODE,
.timer_num = SERVO_TIMER,
.duty_resolution = SERVO_DUTY_RES,
.freq_hz = SERVO_FREQ_HZ,
.clk_cfg = LEDC_AUTO_CLK,
};
ledc_timer_config(&timer);
ledc_channel_config_t channel = {
.gpio_num = SERVO_GPIO,
.speed_mode = SERVO_MODE,
.channel = SERVO_CHANNEL,
.timer_sel = SERVO_TIMER,
.duty = servo_angle_to_duty(90),
.hpoint = 0,
};
ledc_channel_config(&channel);
}
void servo_set_angle(int angle)
{
uint32_t duty = servo_angle_to_duty(angle);
ledc_set_duty(SERVO_MODE, SERVO_CHANNEL, duty);
ledc_update_duty(SERVO_MODE, SERVO_CHANNEL);
}
void servo_nod_once(void)
{
servo_set_angle(75);
vTaskDelay(pdMS_TO_TICKS(250));
servo_set_angle(105);
vTaskDelay(pdMS_TO_TICKS(250));
servo_set_angle(90);
}
13. 震动反馈
#include "driver/gpio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#define VIBRATION_GPIO 40
void vibration_init(void)
{
gpio_config_t cfg = {
.pin_bit_mask = 1ULL << VIBRATION_GPIO,
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = GPIO_PULLUP_DISABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_DISABLE,
};
gpio_config(&cfg);
gpio_set_level(VIBRATION_GPIO, 0);
}
void vibration_short(void)
{
gpio_set_level(VIBRATION_GPIO, 1);
vTaskDelay(pdMS_TO_TICKS(120));
gpio_set_level(VIBRATION_GPIO, 0);
}
14. 双目屏状态机
typedef enum {
EYE_IDLE = 0,
EYE_WAKEUP,
EYE_LISTENING,
EYE_THINKING,
EYE_ANSWERING,
EYE_SMILE,
EYE_SLEEP,
EYE_ERROR,
} eye_state_t;
void eye_set_state(eye_state_t state)
{
switch (state) {
case EYE_IDLE:
// show idle image
break;
case EYE_WAKEUP:
// show wakeup animation
break;
case EYE_LISTENING:
// show listening animation
break;
case EYE_THINKING:
// show thinking animation
break;
case EYE_ANSWERING:
// show speaking animation
break;
case EYE_SMILE:
// show smile image
break;
case EYE_SLEEP:
// show sleep image
break;
case EYE_ERROR:
// show error image
break;
default:
break;
}
}
动作映射建议:
void apply_ai_action(const char *eye, const char *lamp, const char *servo, const char *vibration)
{
if (strcmp(eye, "thinking") == 0) {
eye_set_state(EYE_THINKING);
} else if (strcmp(eye, "answering") == 0) {
eye_set_state(EYE_ANSWERING);
} else if (strcmp(eye, "smile") == 0) {
eye_set_state(EYE_SMILE);
}
if (strcmp(lamp, "study") == 0) {
lamp_scene_study();
} else if (strcmp(lamp, "companion") == 0) {
lamp_scene_companion();
} else if (strcmp(lamp, "sleep") == 0) {
lamp_scene_sleep();
}
if (strcmp(servo, "nod") == 0) {
servo_nod_once();
}
if (strcmp(vibration, "short") == 0) {
vibration_short();
}
}
15. 主任务调度
static void ai_main_task(void *arg)
{
ai_event_t evt;
while (1) {
if (xQueueReceive(s_ai_queue, &evt, portMAX_DELAY) == pdTRUE) {
switch (evt.id) {
case AI_EVT_WAKEUP:
eye_set_state(EYE_WAKEUP);
lamp_scene_companion();
break;
case AI_EVT_LISTEN_START:
eye_set_state(EYE_LISTENING);
break;
case AI_EVT_PHOTO_QA: {
eye_set_state(EYE_THINKING);
lamp_scene_study();
camera_fb_t *fb = app_camera_capture();
if (fb) {
ai_send_vision_qa(
fb,
"请识别图片中的题目,给出详细步骤,并用儿童能理解的方式讲解。"
);
app_camera_release(fb);
} else {
eye_set_state(EYE_ERROR);
}
break;
}
case AI_EVT_COMPANION_CHAT:
eye_set_state(EYE_SMILE);
lamp_scene_companion();
vibration_short();
break;
case AI_EVT_TTS_START:
eye_set_state(EYE_ANSWERING);
break;
case AI_EVT_TTS_STOP:
eye_set_state(EYE_IDLE);
break;
case AI_EVT_TOUCH:
eye_set_state(EYE_SMILE);
vibration_short();
servo_nod_once();
break;
default:
break;
}
}
}
}
void app_main(void)
{
nvs_flash_init();
ai_event_init();
wifi_manager_init();
lamp_pwm_init();
vibration_init();
servo_init();
touch_key_init();
app_camera_init();
audio_init();
display_init();
xTaskCreate(ai_main_task, "ai_main_task", 8192, NULL, 5, NULL);
ai_event_post(AI_EVT_WAKEUP, NULL);
}
16. Touch 触发拍照
#include "driver/gpio.h"
#define TOUCH_GPIO 3
static void IRAM_ATTR touch_isr_handler(void *arg)
{
ai_event_t evt = {
.id = AI_EVT_PHOTO_QA,
};
xQueueSendFromISR(s_ai_queue, &evt, NULL);
}
void touch_key_init(void)
{
gpio_config_t cfg = {
.pin_bit_mask = 1ULL << TOUCH_GPIO,
.mode = GPIO_MODE_INPUT,
.pull_up_en = GPIO_PULLUP_ENABLE,
.pull_down_en = GPIO_PULLDOWN_DISABLE,
.intr_type = GPIO_INTR_NEGEDGE,
};
gpio_config(&cfg);
gpio_install_isr_service(0);
gpio_isr_handler_add(TOUCH_GPIO, touch_isr_handler, NULL);
}
17. 产品化建议
17.1 拍照答题优化
1. 摄像头优先输出 JPEG,减少 ESP32-S3 编码压力
2. 图片分辨率建议 VGA / SVGA 起步
3. 拍题场景建议增加补光灯
4. 云端做 OCR + VLM 双通道识别
5. 回答不要只给答案,要给步骤
6. 儿童场景需要加入内容安全过滤
17.2 音频链路优化
1. 麦克风使用 I2S/PDM
2. 本地做 VAD,减少无效上传
3. 语音唤醒可以使用离线唤醒芯片或本地唤醒模型
4. TTS 音频建议使用 Opus 或 MP3
5. 播放端用 ringbuffer,避免网络抖动导致卡顿
17.3 量产建议
1. ESP32-S3 建议使用带 PSRAM 版本
2. 摄像头排线需要注意 EMI 和结构固定
3. 台灯 PWM 频率建议高于 2kHz,避免可视频闪
4. 舵机电源和主控电源需要隔离或单独稳压
5. 喇叭功放走线远离摄像头和 Wi-Fi 天线
6. 儿童产品需注意隐私、拍照提示和家长授权
18. 总结
四博 AI 台灯方案的核心价值,是把 AI 音箱从"语音交互终端"升级为"视觉、语音、表情、灯光、动作一体化的多模态陪伴终端"。
技术上,ESP32-S3 负责本地设备控制和多媒体采集,云端负责视觉识别、大模型推理和语音合成。产品上,它可以覆盖 AI 学习台灯、AI 拍学机、AI 儿童陪伴机器人、AI 桌面宠物、AI 智能音箱等多个方向