# 玩具厂 **Repository Path**: caco333/toy-factory ## Basic Information - **Project Name**: 玩具厂 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-17 - **Last Updated**: 2026-10-09 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 布比 ESP32-S3 固件 本工程为 AI 互动玩具顶板 v1.1 的独立 ESP-IDF 固件,业务代码使用 C。板级代码来源于 `https://gitee.com/caco333/toy-factory.git`,后端服务单独维护,本工程不包含服务器代码或部署凭据。 ## 硬件与配置 目标硬件:ESP32-S3R8、32 MB Flash、8 MB Octal PSRAM、GC2145 摄像头、ES8311 单麦克风音频、PCF8574 扩展 IO、SC7A20H 加速度计、PCA9685 四路舵机。默认双 NT090BE-C12-04(ST7735,128×128),可编译为单 ST7789(240×320)。 | 配置文件 | 职责 | | --- | --- | | [config.h](components/board/config/config.h) | 硬件引脚、后台地址、语音门限、音量、任务/缓冲、舵机范围、屏幕和电池参数;各项均附注释 | | [sdkconfig.defaults](sdkconfig.defaults) | IDF、ESP-SR、LVGL、PSRAM、DMA 与日志默认构建配置 | | [partitions.csv](partitions.csv) | 双 OTA 应用槽和语音模型分区 | | [version.txt](version.txt) | 三段数字固件版本;发布升级必须递增 | | [dependencies.lock](dependencies.lock) | 第三方组件的已解析版本;应随源码保留 | `TOY_DUAL_DISPLAY=1` 对应双屏镜像 `bubi_gc2145_r8_dual`,`=0` 对应单屏镜像 `bubi_gc2145_r8_single`。两种装配互斥。旧 Quad PSRAM 板不适用本工程。GPIO33~37 留给 Octal PSRAM;公共 I²C/SCCB 为 GPIO3/4,音频为 GPIO17~21。完整引脚与电平见 `config.h`。 现用服务入口集中在 `config.h`:配置发现 `TOY_OTA_URL`、OTA 下载白名单 `TOY_FIRMWARE_URL_PREFIX`、客户绑定网页 `TOY_BINDING_URL`。更换服务时同时核对这三项。WSS/视觉 URL 和 token 由后台下发,不在固件中预置。 ## 构建与首次烧录 使用 **ESP-IDF 5.4.4**,目标 `esp32s3`。首次构建需要联网下载锁定的组件。源码包已包含眼睛二进制素材、中文字库和离线语音,正常构建无需重新生成素材。 在已启用 ESP-IDF 5.4.4 环境的终端,切换到本工程目录: ```text idf.py -B build-v11-gc2145 -DIDF_TARGET=esp32s3 build ``` `sdkconfig` 是本地生成文件,已存在时其值优先于 defaults。从旧工程迁移时,应先备份并移走旧 `sdkconfig`,让此工程的 defaults 重新生成配置;不能仅修改 defaults 后假定原配置已经更新。 默认双屏主要产物: | 文件(均位于构建目录) | 用途 | | --- | --- | | `bubi_gc2145_r8_dual.bin` | 应用镜像;单屏名称为 `bubi_gc2145_r8_single.bin` | | `bootloader/bootloader.bin` | 支持 OTA 回滚的引导程序 | | `partition_table/partition-table.bin` | 分区表 | | `ota_data_initial.bin` | 首次安装的 OTA 状态数据 | | `srmodels/srmodels.bin` | MultiNet 中文语音模型 | | `flash_args` / `flasher_args.json` | 本次构建实际烧录地址与文件清单 | 首次安装须完整烧录以上引导、分区、OTA 状态、应用和模型,不能只写应用。用实际串口替换 ``: ```text idf.py -B build-v11-gc2145 -p flash monitor ``` 不执行整片擦除;NVS 保存 Wi-Fi、设备身份及音量。OTA 只升级应用,发布条件见 [维护与交接](docs/handoff.md)。 ## 使用流程 工厂安装舵盘前,将 `components/board/config/config.h` 中 `TOY_FACTORY_INSTALL_MODE` 改为 `1`,重新编译并烧录。设备开机即持续输出四路中立位 PWM,各路目标取 `TOY_SERVO_0_NEUTRAL`~`TOY_SERVO_3_NEUTRAL`,目前均为 90°(约 1500µs、50Hz)。通电期间不自动释放,不需要联网或唤醒;此模式不启动正常屏幕、语音和触摸动作。长按电源键达到 5 秒,停止 PWM 并关机。安装完成后将开关改回 `0`,重新编译烧录恢复正常业务;默认值为 `0`。中立角是控制目标,没有实际位置反馈,装配前确认舵机已到位。 - 空 NVS 开机进入配网,连接 `TOY_` 开头热点,访问 `http://192.168.4.1/` 保存 Wi-Fi;设备显示保存状态后重启。连接超时返回配网;长按 KEY_A 约 2 秒可重新配网。 - 后台未绑定时,屏幕显示实际六位激活码及客户绑定页二维码;绑定并建立 WSS 后进入眼睛界面。 - 本地命令词为“你好布比”(MultiNet7)。唤醒后进入实时对话;普通说话可通过本地 AEC/VAD 打断回答,无活动约 60 秒回到待机。 - 轻触 KEY_A/TP1 向左转头并回正,KEY_B/TP2 向右;按住不重复,同时触摸串行执行。长按 KEY_A 还会触发配网。 - 开机时按住电源键,首次释放只解除启动锁;之后长按约 5 秒并释放,播完关机语音再切断保持电源。切电写入失败会重试。 - 低电提醒使用离线语音;其他连接/配网状态主要通过屏幕显示。唤醒/未就绪使用合成音调。 ## 语音、相机与动作契约 上行 Opus 为 16 kHz、单声道、60 ms;下行为 24 kHz、单声道、60 ms。硬件 I²S 为 24 kHz,AEC/VAD/AGC 为 16 kHz。修改采样率或帧长必须同步后台与缓冲配置。 本地确认插话时取消旧播放,发送带编号的 abort;匹配停止回执到达后补送 300 ms 预卷及等待期间的人声。普通回答结束需等待解码、播放和尾音保护完成。后台须识别 `local_wake` / `local_barge_in` 能力,避免重复取消同一回复;闲置告别使用 `tts stop/reason=idle_timeout` 并保持长连接。 GC2145 使用 10 MHz XCLK、QVGA RGB565 单帧采集和软件 JPEG 编码,内部 DMA 块上限 8 KiB,整帧在 PSRAM。相机任务拥有帧与 HTTP 句柄,编码后先归还相机帧再上传,TLS 正文分块发送。成功须同时满足 HTTP 与业务 JSON 校验。没有本地人脸检测或自动跟随。 | MCP 工具 | 行为 | | --- | --- | | `self.get_device_status` | 音量、舵机映射/范围、电池有效性/估算电量/充电状态 | | `self.audio_speaker.set_volume` | 设置 0~100 业务音量并保存 NVS | | `self.camera.take_photo` | 拍摄 JPEG,携带问题请求后台视觉服务 | | `self.motion.perform` | 预设动作,默认最大幅度 30° | | `self.motion.set_servo_angle` | 指定角色、整数角度和运动时长 | 动作预设:`look_left`、`look_right`、`nod`、`shake_head`、`wave_left`、`wave_right`、`wave_both`、`raise_left`、`raise_right`、`reset`。动作与随话表情使用同一动作任务及会话检查。 | 角色 | 板上接口 | 逻辑编号 | PCA9685 通道 | 最小/中立/最大角度 | | --- | --- | --- | --- | --- | | head(扭头) | PWM5 | 3 | 11 | 50° / 90° / 130° | | left_arm(左手) | PWM3 | 2 | 13 | 60° / 90° / 120° | | right_arm(右手) | PWM1 | 0 | 15 | 60° / 90° / 120° | | nod(点头) | PWM2 | 1 | 14 | 65° / 90° / 110° | 点头和扭头范围由用户于 2026-10-01 实测确认,双臂保留默认范围。当前安装和标定开关均为 0,运行正常对话固件。正常启动时在联网/动作任务之前逐路回到配置中立角(当前全部 90°),每路沿用 300 ms 稳定等待;失败一路保留后续动作重新定位能力。角色编号不可重复。定位时长默认 1000 ms,允许 100~5000 ms,向上对齐到 20 ms。舵机没有反馈,成功仅表示 PWM 下发完成,机械方向和限位必须实装标定。 动作按 20 ms 绝对周期调度,以实际经过时间计算原三次缓动曲线,过期位置不密集补发;舵机更新优先级 12 高于绘图 11、低于实时音频 13/14/16,可在两核调度,避免固定 CPU1 等待音频处理。每段动作结束输出一次 `servo_timing`,记录目标/实际耗时、最大更新间隔、最大写入耗时及超过 30 ms 的间隔数,便于区别软件调度卡顿和实际机械问题。 正常模式长按电源键达到 5 秒即请求关机,不需要松手;停止交互、播完提示音后释放电源保持。PCF8574 输入刷新任务优先级为 15,保证 5 ms 采样不被绘图/唤醒推理长期推迟;保留 15 ms 快照有效期与故障后必须释放再重新按下的保护。`power_input` 记录输入电平,`input_timing` 记录最大刷新间隔、失效代次及读取错误,`Power long press reached` 记录长按判定。 ### 舵机行程标定控制台 `components/board/config/config.h` 的 `TOY_SERVO_CALIBRATION_MODE=1` 启用标定版,须同时保持 `TOY_FACTORY_INSTALL_MODE=0`;测试完成后将两个开关设为 0,重新编译烧录恢复正常业务。标定版开机释放全部舵机,复用原配网热点、DNS 和 HTTP 服务,保留原 Wi-Fi 凭据,不启动语音、联网业务和触摸动作。 手机连接 `BSP_WIFI_AP_SSID_PREFIX` 对应热点,浏览器打开 `http://192.168.4.1`。四张卡片对应 PWM1 右手、PWM2 点头、PWM3 左手、PWM5 扭头。支持回中、±1°/±5°、输入整数目标角度、单路释放和释放全部。标定接口允许 0~180°,直接沿用现有 500~2500μs / 50Hz 驱动,不受业务默认 60~120° 限位约束;这不是机械安全范围保证。逐步试探,出现干涉/堵转前停止并留余量,不自动扫到两端。 页面显示最后成功下发的目标角度,没有位置反馈;关闭页面或断网仍保持最后输出。长按电源键达到 5 秒可关闭。记录上下限只保存在该浏览器,导出的 `TOY_SERVO_n_MIN/NEUTRAL/MAX` 配置需核对后写回 `config.h` 再编译;无完整端点或不包含中立角的记录不会导出。网页源码为 `components/board/src/wifi/servo_console.html`,设备接口在 `bsp_wifi.c` 的 `/servo` GET/POST。 两块屏幕在标定模式显示“舵机标定”、实际热点名、`192.168.4.1` 和“网页控制”;安装模式显示“工厂安装 / 中立保持 / 长按电源 / 5秒关机”。复用原 LVGL 通知页和双屏传输,不启动眼睛动画及语音业务。 ## 显示与电池 LVGL 9.3.0 负责状态页、二维码与面板提交;Nuka C 绘制器提供 95 个预设和 15 项参数,目标调度周期 100 ms。没有自动自然眨眼,显式眨眼同步。表情控制入口见 [维护与交接](docs/handoff.md)。双屏各用 128×128 RGB565 PSRAM 画布,共享两块 16 行 DMA 缓冲,DMA 完成后才可复用。 电池每 10 秒采样 GPIO1,GPIO46 控制分压开关,使用 16 点平均和 ADC 校准。2500~4500 mV 之外、读取失败或超过两个采样周期的快照不能作为有效电量。连续 3 次不高于 3500 mV 确认低电,连续 3 次不低于 3650 mV 恢复。放电低电时每 5 分钟最多提醒一次,对话中延后,充电/充满时不提醒。百分比为电压插值估算,不是库仑计,也不自动关机。 ## 维护与验证 源码目录、保留模块的必要职责、删除清单及验证边界统一见 [维护与交接](docs/handoff.md)。仓库仅交付 ESP 固件及其构建/运行必需文件,开发期主机测试、网页原稿、素材生成脚本和录音不随此仓库交付。第三方本地按键组件的许可证保留在 `components/button/license.txt`;其他组件由 IDF Component Manager 按锁文件下载,并各自保留原许可证。