1. 系统结构
IMU 单元:5V 电池/充电宝 -> XIAO ESP32C3 -> 3.3V 给 MPU6050MPU6050 -> I2C -> XIAO -> BLE Notify 50Hz主控单元:USB-C PD 电源 -> HUSB238 -> 20V -> DCDC -> 5V 总线5V 总线 -> ESP32-S3 / WS2812B 灯带 / MAX98357A / 3.3V 稳压ESP32-S3 -> BLE 接收 IMU -> 灯效 + SD 卡 WAV 音效
核心思路:IMU 单元只负责稳定采集和广播 6 轴数据;主控单元负责连接、状态判断、方向识别、灯带渲染、SD 卡音频播放和故障降级。
2. 一些官方文档链接
ESP32-S3-DevKitC-1 可通过 USB、5V/GND 或 3V3/GND 供电,但这些是互斥供电方式;官方 v1.1 板载可编程 RGB LED 在 GPIO38,早期版本在 GPIO48。见 Espressif 文档:ESP32-S3-DevKitC-1 User Guide(https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-devkitc-1/user_guide_v1.1.html)。
Seeed XIAO ESP32C3 的 D4=SDA=GPIO6、D5=SCL=GPIO7,5V 可作为输入,3V3 是板载稳压输出。见 Seeed Wiki:XIAO ESP32C3 Getting Started(https://wiki.seeedstudio.com/XIAO_ESP32C3_Getting_Started/)。
Adafruit HUSB238 Breakout 的默认 I2C 地址是 0x08;I2C 没有板载上拉,需要接到外部逻辑电平;跳线/电阻设置会在上电启动时生效,I2C 命令只能在 MCU 启动后覆盖。见 Adafruit Guide:HUSB238 Pinouts(https://learn.adafruit.com/adafruit-husb238-usb-type-c-power-delivery-breakout/pinouts)。
NeoPixel/WS2812 类灯带建议先接地,数据线串联 300-500Ω 电阻,灯带电源首端并 500-1000uF 电解电容。见 Adafruit Guide:Powering NeoPixels(https://learn.adafruit.com/adafruit-neopixel-uberguide/powering-neopixels)。
MAX98357A 支持 I2S 数字音频输入,VDD 工作范围 2.5V 到 5.5V;SD_MODE 拉低进入 shutdown。见 Analog Devices:MAX98357A datasheet(https://www.analog.com/media/en/technical-documentation/data-sheets/MAX98357A-MAX98357B.pdf)。
常规 microSD 卡工作电压范围是 2.7V 到 3.6V;多数 SPI microSD 模块若未明确自带稳压/电平转换,就按 3.3V 供电。见 SD Association:SD Standard Overview(https://www.sdcard.org/developers/sd-standard-overview/)。
MicroPython ESP32 端内置 neopixel 模块,并提供 machine.I2S(id, sck, ws, sd, mode=I2S.TX, ...) 用于 I2S 输出。见 MicroPython 文档:neopixel(https://docs.micropython.org/en/latest/library/neopixel.html)、machine.I2S(https://docs.micropython.org/en/latest/library/machine.I2S.html)。
3. 材料清单
IMU 单元:
| 材料 | 数量 | 说明 |
|---|
| Seeed XIAO ESP32C3 | 1 | BLE 外设,运行 imu_module/main.py |
| MPU6050 模块 | 1 | I2C 六轴 IMU,地址默认 0x68 |
| 5V USB-C 电池/充电宝 | 1 | 直接给 XIAO USB-C 供电 |
| 杜邦线/短导线 | 若干 | MPU6050 的 3V3/GND/SDA/SCL |
主控单元:
| 材料 | 数量 | 说明 |
|---|
| ESP32-S3-DevKitC-1 | 1 | BLE 主机、灯带、音频、SD、HUSB238 控制 |
| HUSB238 PD Sink 模块 | 1 | 冷启动默认设为 20V 或适配器最高可用电压 |
| 6-35V 输入 DCDC 降压模块 | 1 | 输出 5V,建议可持续 6.5A 以上 |
| 5V WS2812B/NeoPixel 灯带 | 1 | 当前代码配置 108 颗,GPIO2 |
| MAX98357A I2S 功放 | 1 | 5V 供电,GPIO15/16/17 I2S,GPIO18 静音 |
| MicroSD SPI 模块 | 1 | 3.3V 供电,/sounds 下放 6 个 WAV |
| 3.3V 稳压模块 | 1 | 给 SD 模块和 I2C 上拉供电,不反灌 ESP 的 3V3 |
| 20-22AWG 线 | 若干 | HUSB238 到 DCDC、DCDC 到灯带等大电流路径 |
| 330Ω 电阻 | 1 | ESP GPIO2 到灯带 DIN 串联 |
| 4.7kΩ 电阻 | 2 | HUSB238 SDA/SCL 上拉到 3.3V |
| 10kΩ 电阻 | 1 | MAX98357A SD/MODE 上拉到 3.3V |
| 470uF 或 1000uF 电解电容 | 1 | 灯带首端 5V-GND,耐压 6.3V 以上,16V 更好 |
100nF 陶瓷电容 104 | 若干 | SD、功放、稳压模块附近去耦 |
4. 电源原则
主控实际使用时不接 ESP32-S3 的 Type-C。供电链路是:
USB-C PD 适配器 -> HUSB238 VOUT 20V -> DCDC IN -> DCDC OUT 5V -> ESP32-S3 5V/VIN、灯带 5V、MAX98357A VIN、3.3V 稳压输入
注意事项:
HUSB238 必须靠硬件跳线/电阻先输出高于 DCDC 最低输入的电压;当前方案已设为 20V。不能指望“默认 5V 启动后让 ESP 软件改 20V”,因为 ESP 需要 DCDC 先启动才有电。
DCDC 输出设为 5.0V ±0.1V 后再接 ESP 和灯带。
灯带满功率标称 18W,约 3.6A;加上 ESP、SD、功放、DCDC 余量,5V 输出建议按 6.5A 设计。当前软件把灯带亮度上限限制在 12%,日常电流远低于满白,但硬件仍按峰值留余量。
灯带和 DCDC 的大电流不要走面包板或普通杜邦线。DCDC 到灯带建议用 20-22AWG 线;面包板只适合小电流逻辑、上拉、SD 等。
所有模块必须共地:DCDC OUT-、ESP GND、灯带 GND、MAX98357A GND、SD GND、HUSB238 VOUT- 是同一个地。
使用 DCDC 5V 给 ESP 的 5V/VIN 后,不要再把外部 3.3V 稳压输出硬接到 ESP 的 3V3。
5. IMU 单元接线
| XIAO ESP32C3 | MPU6050 | 说明 |
|---|
| USB-C | 5V 电池 USB-C 输出 | 实际使用供电 |
3V3 | VCC 或 3V3 | 给 MPU6050 模块供电 |
GND | GND | 共地 |
D4 / GPIO6 | SDA | I2C 数据 |
D5 / GPIO7 | SCL | I2C 时钟 |
如果 MPU6050 模块同时有 VCC_IN 和 3v3,优先按模块丝印和原理图确认。当前项目按 3.3V 供电,避免把裸 MPU6050 芯片暴露在 5V 逻辑下。
6. 主控接线
6.1 HUSB238 和 DCDC
| HUSB238 | 连接到 | 说明 |
|---|
| USB-C | PD 适配器 | 支持 20V/足够功率的 USB-C PD 充电器 |
VOUT / V+ | DCDC IN+ | 20V,只能进 DCDC |
VOUT- / GND | DCDC IN- / 公共 GND | 高压侧地 |
SDA | ESP32-S3 GPIO8 | I2C,需 4.7kΩ 上拉到 3.3V |
SCL | ESP32-S3 GPIO10 | I2C,需 4.7kΩ 上拉到 3.3V |
HUSB238 的电压跳线建议设为 20V/最高可用档;电流档按模块规则选择 3A 或更高。若是 Adafruit 式跳线板,20V 通常是所有电压跳线断开,3A 通常是 1A/2A 电流跳线都断开;最终以你手上模块丝印为准。
6.2 DCDC 5V 分配
DCDC OUT+ -> 5V 分线点 -> ESP32-S3 5V/VIN -> 灯带 5V -> MAX98357A VIN -> 3.3V 稳压模块 INDCDC OUT- -> GND 分线点 -> ESP32-S3 GND -> 灯带 GND -> MAX98357A GND -> 3.3V 稳压模块 GND
建议把 DCDC 输出先做成焊接分线点或端子排,再分别拉线到灯带、ESP、功放和 3.3V 稳压。不要把 6.5A 级别的主电流穿过面包板电源轨。
6.3 灯带
| 灯带 | 连接到 | 说明 |
|---|
5V | DCDC 5V | 粗线,首端供电即可;当前亮度限制下通常不需要两端供电 |
GND | DCDC GND / 公共 GND | 粗线 |
DIN / Data | ESP32-S3 GPIO2 经 330Ω 电阻 | 数据线方向必须从 DIN 进入 |
灯带首端 5V 和 GND 之间并一个 470uF-1000uF 电解电容,正极接 5V,负极接 GND。手头的 16V 470uF 可以用;如果以后经常高亮,再换 1000uF。
6.4 MicroSD 模块
| MicroSD 模块 | ESP32-S3 / 电源 | 说明 |
|---|
VCC / 3V3 | 外部 3.3V 轨 | 不接 5V,除非模块明确自带稳压和电平转换 |
GND | 公共 GND | 必须与 ESP 共地 |
CS / SS | GPIO5 | SPI 片选 |
SCK / CLK | GPIO4 | SPI 时钟 |
MOSI / DI / CMD | GPIO6 | ESP 到 SD |
MISO / DO / DAT0 | GPIO7 | SD 到 ESP |
在 SD 模块电源附近并一颗 104 陶瓷电容。SD 卡建议 FAT32,根目录下建 sounds 文件夹,放 6 个 16-bit PCM WAV 文件。不要放 macOS 生成的 ._*.wav 隐藏资源文件。
6.5 MAX98357A 功放
| MAX98357A | ESP32-S3 / 电源 | 说明 |
|---|
VIN / VCC | DCDC 5V | 5V 供电 |
GND | 公共 GND | 与 ESP、DCDC 共地 |
BCLK / BCK | GPIO15 | I2S bit clock |
LRC / LRCLK / WS | GPIO16 | I2S word select |
DIN / SDIN | GPIO17 | I2S 音频数据 |
SD / MODE / SHDN | GPIO18 + 10kΩ 到 3.3V | 软件静音/关断 |
SPK+ / OUT+ | 扬声器 + | 桥接输出 |
SPK- / OUT- | 扬声器 - | 不要接 GND |
推荐 SD/MODE 接法:
3.3V -> 10kΩ -> SD/MODE 节点 -> MAX98357A SD/MODE | -> ESP32-S3 GPIO18
功放 VIN/GND 附近并一颗 104 陶瓷电容;若大音量爆音或电源抖动,再加 330uF/470uF 电解电容。
7. 代码上传
IMU 单元上传到 XIAO ESP32C3 根目录:
main.pyboot.pyble_peripheral.pympu6050.pyled.py
主控单元上传到 ESP32-S3 根目录:
main.pylib/ble_host.pylib/status_led.pylib/light_strip.pylib/light_fx.pylib/audio_mute.pylib/audio_player.pylib/sdcard.pylib/husb238.py
生产运行不需要上传 test_*.py。测试时可临时上传并运行:
test_husb238.pytest_light_strip.pytest_audio_sd.pytest_direction_sounds.py
8. 建议组装和测试流程
只接 HUSB238 和 DCDC。确认 HUSB238 冷启动输出 20V 左右,DCDC 输出稳定 5V。
DCDC 5V 接 ESP32-S3 的 5V/VIN 和 GND。暂不接灯带、SD、功放,确认主控可启动。
接 HUSB238 I2C:GPIO8/10、4.7kΩ 上拉到 3.3V,运行 test_husb238.py,确认能读到 0x08 并看到 20V/PD 能力。
接灯带:先只跑 test_light_strip.py,从前 10 颗、低亮度开始。
接 SD 和 MAX98357A,运行 test_audio_sd.py,确认能读 /sd/sounds 且 6 个 WAV 都是 RIFF/WAVE PCM。
启动 IMU 单元,确认它持续广播 IMU-Controller。
运行主控 main.py,观察主控从搜索、连接、工作、待机、故障等状态切换。
每一步上电前都先测短路:5V-GND 不应接近 0Ω;3.3V-GND 不应接近 0Ω;20V 只允许到 DCDC 输入。
9. 当前代码设计
9.1 IMU 单元
imu_module/main.py 启动后:
初始化 XIAO 的 I2C:SDA=GPIO6、SCL=GPIO7、100kHz。
扫描并初始化 MPU6050,使用 ±2g、±250dps;原始加速度保留重力,陀螺仪做零偏校准。
若没有 calib.json,首次启动会静止采样约 1 秒,只校准陀螺仪零偏,不会把单一姿态的重力错误扣掉。
6 面加速度校准只在手动 BLE 命令 0x02 时执行,属于开发/装配阶段功能。
进入 50Hz 主循环,发送 13 字节数据包:ax ay az gx gy gz flags,格式为 little-endian "<hhhhhhB"。
如果 MPU6050 缺失或读失败,BLE 仍继续广播/连接,但发送 FLAG_MPU_ERROR,让主控显示故障而不是误判为离线。
9.2 主控单元
main_controller/main.py 启动后:
板载 RGB 状态灯:默认 GPIO48;如果是官方 v1.1 且不亮,改 STATUS_LED_PIN = 38。
HUSB238:I2C0,SDA=GPIO8、SCL=GPIO10、地址 0x08;启动后优先请求 20V,其次 12V/15V/9V。软件请求只做验证和重新协商,不能替代硬件冷启动跳线。
灯带:GPIO2,108 颗,最大亮度 STRIP_MAX_BRIGHTNESS = 0.12。
音频:SD 卡 SPI 用 GPIO5/4/6/7;MAX98357A I2S 用 GPIO15/16/17;GPIO18 控制功放静音。
BLE 主机扫描目标名 IMU-Controller。找不到 IMU 时先快扫 60 秒,之后低占空比慢扫,但不会停止搜索。
收到 IMU 后以当前姿态建立方向基线;方向分为 up/down/left/right/front/back,灯效和音效都按这个相对方向触发。
静止未满 60 秒时,灯带会冻结上一帧动作效果;超过 60 秒进入软件待机后切到低亮彩虹,音频静音,BLE 不断开。当前 ESP_SLEEP_AFTER_STANDBY = False,所以 IMU 再晃动可以自动恢复。
SD 卡缺失或运行中拔出时,主控不会崩溃;音频会静音并每 8 秒尝试重新挂载。SPI SD 不是真正热插拔设备,仍建议不要在播放中拔卡。
9.3 状态灯和灯带逻辑
板载 RGB 只作为低亮状态提示;板上红色电源灯不是程序状态灯。
| 状态 | 板载 RGB | 灯带 |
|---|
| 启动 | 暖黄 | 低亮启动色 |
| 搜索 IMU | 蓝色脉冲 | 蓝色扫描 |
| 连接中 | 橙色脉冲 | 橙色脉冲 |
| 工作 | 低亮蓝色呼吸 | IMU 方向/强度驱动 |
| 待机 | 低亮慢呼吸 | 低亮彩虹 |
| 故障 | 红色闪烁 | 红色闪烁 |
灯带效果由 lib/light_fx.py 非阻塞渲染。动作越强,亮度、速度、尾迹长度越明显;不同方向使用不同色系和效果组。当前避免强闪烁,峰值可亮,但对比不过分刺激。
9.4 音频逻辑
主控启动时扫描 /sd/sounds,把前 6 个合法 WAV 按这个顺序映射:
up, down, left, right, front, back
方向音效触发比灯效更保守:需要超过阈值并稳定若干包,同方向有冷却时间,不同方向可较快打断。音量按动作强度动态映射,当前范围:
AUDIO_VOLUME_MIN = 0.15AUDIO_VOLUME_MAX = 0.9
如果小动作不出声,主要调:
AUDIO_DIRECTION_TRIGGER_THRESHOLDAUDIO_DIRECTION_RESET_THRESHOLDAUDIO_VOLUME_MINAUDIO_ACCEL_DELTA_THRESHOLD
10. 运行时边界情况
| 情况 | 当前行为 |
|---|
| 主控先启动,IMU 没启动 | 主控持续搜索;60 秒后慢扫待机,不会停止 |
| IMU 先启动,主控没启动 | IMU 持续广播,等待主控连接 |
| 两者连接后 IMU 断电 | 主控断开后重新扫描,音频静音 |
| MPU6050 断线但 XIAO 仍在线 | IMU 发送故障包,主控进入故障灯效并静音 |
| SD 卡未插 | 灯光/BLE 正常,音频禁用并定期重试 |
| SD 卡运行中拔出 | 播放/健康检查失败后静音,释放 I2S/SD 并重试 |
| SD 卡重新插入 | 尝试重新挂载并恢复方向音效 |
| HUSB238 只默认 5V | 如果 DCDC 最低输入 6V,整机不能冷启动 |
| ESP 进入 deep sleep | 当前未启用;如果启用,IMU 无线动作不能直接唤醒 ESP,需要复位/断电重启或另加唤醒硬件 |
11. 常用调参位置
| 目标 | 文件 | 参数 |
|---|
| 板载 RGB 引脚 | main_controller/main.py | STATUS_LED_PIN |
| 板载 RGB 亮度 | main_controller/main.py | STATUS_LED_BRIGHTNESS |
| 灯带引脚/数量 | main_controller/main.py | STRIP_PIN, STRIP_LED_COUNT |
| 灯带最大亮度 | main_controller/main.py | STRIP_MAX_BRIGHTNESS |
| 静止进入待机时间 | main_controller/main.py | STANDBY_AFTER_STILL_MS |
| 方向识别灵敏度 | main_controller/main.py | DIRECTION_ACCEL_THRESHOLD, DIRECTION_SWITCH_MARGIN |
| 音效触发灵敏度 | main_controller/main.py | AUDIO_DIRECTION_TRIGGER_THRESHOLD, AUDIO_DIRECTION_STABLE_PACKETS |
| 音量范围 | main_controller/main.py | AUDIO_VOLUME_MIN, AUDIO_VOLUME_MAX |
| IMU 采样频率 | imu_module/main.py | SEND_INTERVAL_MS |
| MPU I2C 引脚 | imu_module/main.py | PIN_SDA, PIN_SCL |
12. 最小复现思路
一个 BLE IMU 节点:任意 ESP32-C3/S3 + 任意 6 轴 IMU,50Hz 发送 6 轴数据。
一个主控节点:ESP32-S3 或类似 MCU,能跑 BLE Central、灯带驱动、I2S 音频。
一条 5V 可寻址灯带:电源单独供,数据由主控 GPIO 输出,必须共地。
一个音频输出:I2S 功放 + SD 卡或内置 Flash 音频。
软件分层:采集端只发数据;主控端做连接状态、动作分类、灯效、音效和故障处理。
参考源码:https://github.com/Zhiqi123/imu_toy。
这个项目关键的是电源和状态机:大电流单独走粗线,所有模块共地;主控即使没有 IMU、没有 SD、IMU 传感器故障,也要继续运行并给出可见状态。
13. 疯狂的线💩