15 KiB
超级小智-ESP32
(中文 | English(编写中) | 日本語(编写中))
基于 https://github.com/78/xiaozhi-esp32 改良的船新版本
💡介绍
这是一个由虾哥开源的 ESP32 项目,以 MIT 许可证发布,允许任何人免费使用,或用于商业用途。
我们希望通过这个项目,能够帮助大家了解 AI 硬件开发,将当下飞速发展的大语言模型应用到实际的硬件设备中。
如果你有任何想法或建议,请随时提出 Issues 或加入 QQ 群:暂无,Telegram群:暂无。
项目主要贡献者:小霜霜Meow(抖音、B站UP)、空白泡泡糖果(B站UP),硅灵造物科技(B站UP)
贡献者说明:引入部分其它贡献者在其它项目上的代码,并进行了部分修改。
音乐服务器、相关源码提供者(为爱发电):小霜霜Meow
音乐服务器源码请见 https://github.com/IntelligentlyEverything/MeowMusicServer
❕注意事项
- 如果小智说找不到歌曲怎么办? 进入小智后台,找到对应设备,修改角色配置
- 选择 DeepSeekV3 大语言模型
- 在人物介绍中填入
- 收到音乐相关的需求时,只使用 MPC tool self.music.play_song 工具,同时禁止使用 search_music 功能。
-
内置API调用失败怎么办? 请查看具体错误代码后,加入QQ群:865754861,或电报群 http://t.me/MeowMusicServer 给出错误代码和日志,等待我们修复。
-
歌曲播放时唤醒词不生效怎么办?
把main\application.cc文件的AddAudioData方法改成如下代码
void Application::AddAudioData(AudioStreamPacket&& packet) {
auto codec = Board::GetInstance().GetAudioCodec();
if (device_state_ == kDeviceStateIdle && codec->output_enabled()) {
// packet.payload包含的是原始PCM数据(int16_t)
if (packet.payload.size() >= 2) {
size_t num_samples = packet.payload.size() / sizeof(int16_t);
std::vector<int16_t> pcm_data(num_samples);
memcpy(pcm_data.data(), packet.payload.data(), packet.payload.size());
// 检查采样率是否匹配,如果不匹配则进行简单重采样
if (packet.sample_rate != codec->output_sample_rate()) {
// ESP_LOGI(TAG, "Resampling music audio from %d to %d Hz",
// packet.sample_rate, codec->output_sample_rate());
// 验证采样率参数
if (packet.sample_rate <= 0 || codec->output_sample_rate() <= 0) {
ESP_LOGE(TAG, "Invalid sample rates: %d -> %d",
packet.sample_rate, codec->output_sample_rate());
return;
}
std::vector<int16_t> resampled;
// 使用浮点数计算精确的重采样比率Add commentMore actions
float ratio = static_cast<float>(packet.sample_rate) / codec->output_sample_rate();
if (packet.sample_rate > codec->output_sample_rate()) {
// 降采样:按精确比率跳跃采样
size_t expected_size = static_cast<size_t>(pcm_data.size() / ratio + 0.5f);
resampled.reserve(expected_size);
for (float i = 0; i < pcm_data.size(); i += ratio) {
size_t index = static_cast<size_t>(i + 0.5f); // 四舍五入
if (index < pcm_data.size()) {
resampled.push_back(pcm_data[index]);
}
}
ESP_LOGD(TAG, "Downsampled %d -> %d samples (ratio: %.3f)",
pcm_data.size(), resampled.size(), ratio);
} else {
// 上采样:线性插值
float upsample_ratio = codec->output_sample_rate() / static_cast<float>(packet.sample_rate);
size_t expected_size = static_cast<size_t>(pcm_data.size() * upsample_ratio + 0.5f);
resampled.reserve(expected_size);
for (size_t i = 0; i < pcm_data.size(); ++i) {
// 添加原始样本
resampled.push_back(pcm_data[i]);
// 计算需要插值的样本数
int interpolation_count = static_cast<int>(upsample_ratio) - 1;
if (interpolation_count > 0 && i + 1 < pcm_data.size()) {
int16_t current = pcm_data[i];
int16_t next = pcm_data[i + 1];
for (int j = 1; j <= interpolation_count; ++j) {
float t = static_cast<float>(j) / (interpolation_count + 1);
int16_t interpolated = static_cast<int16_t>(current + (next - current) * t);
resampled.push_back(interpolated);
}
} else if (interpolation_count > 0) {
// 最后一个样本,直接重复
for (int j = 1; j <= interpolation_count; ++j) {
resampled.push_back(pcm_data[i]);
}
}
}
ESP_LOGI(TAG, "Upsampled %d -> %d samples (ratio: %.2f)",
pcm_data.size(), resampled.size(), upsample_ratio);
}
pcm_data = std::move(resampled);
}
// 确保音频输出已启用
if (!codec->output_enabled()) {
codec->EnableOutput(true);
}
// 发送PCM数据到音频编解码器
codec->OutputData(pcm_data);
// 更新最后输出时间,防止OnAudioOutput自动禁用音频
{
std::lock_guard<std::mutex> lock(mutex_);
last_output_time_ = std::chrono::steady_clock::now();
}
}
}
}
⚙️已支持硬件芯片系列
- ESP32
- ESP32-S2
- ESP32-S3
- ESP32-C2
- ESP32-C3
- ESP32-C5
- ESP32-C6
- ESP32-C61
- ESP32-H2
- ESP32-H4
- ESP32-H21
- ESP32-P4
❕大部分硬件由于没有进行完整测试,可能会存在一些问题,属于正常现象,具体可提交issues进行反馈。
项目改动范围
新增:
- main/boards/common/music.h
- main/boards/common/esp32_music.h
- main/boards/common/esp32_music.cc
修改:
- main/audio/audio_codec.h
- main/audio/audio_codec.cc
- main/audio/audio_service.h
- main/audio/audio_service.cc
- main/boards/common/board.h
- main/boards/common/board.cc
- main/display/display.h
- main/display/display.cc
- main/display/lcd_display.h
- main/display/lcd_display.cc
- main/application.h
- main/application.cc
- main/idf_component.yml
- main/mcp_server.cc
基于 MCP 控制万物
小智 AI 聊天机器人作为一个语音交互入口,利用 Qwen / DeepSeek 等大模型的 AI 能力,通过 MCP 协议实现多端控制。
已实现功能
- Wi-Fi / ML307 Cat.1 4G
- 离线语音唤醒 ESP-SR
- 支持两种通信协议(Websocket 或 MQTT+UDP)
- 采用 OPUS 音频编解码
- 基于流式 ASR + LLM + TTS 架构的语音交互
- 声纹识别,识别当前说话人的身份 3D Speaker
- OLED / LCD 显示屏,支持表情显示
- 电量显示与电源管理
- 支持多语言(中文、英文、日文)
- 支持 ESP32-C3、ESP32-S3、ESP32-P4 芯片平台
- 通过设备端 MCP 实现设备控制(音量、灯光、电机、GPIO 等)
- 通过云端 MCP 扩展大模型能力(智能家居控制、PC桌面操作、知识搜索、邮件收发等) 本项目新增功能:
- 新增音乐播放功能,支持播放本地音乐(开发中,敬请期待)、云端音乐(完善中)。
硬件
面包板手工制作实践
详见飞书文档教程:
面包板效果图如下:
支持 70 多个开源硬件(仅展示部分)
- 立创·实战派 ESP32-S3 开发板
- 乐鑫 ESP32-S3-BOX3
- M5Stack CoreS3
- M5Stack AtomS3R + Echo Base
- 神奇按钮 2.4
- 微雪电子 ESP32-S3-Touch-AMOLED-1.8
- LILYGO T-Circle-S3
- 虾哥 Mini C3
- 璀璨·AI 吊坠
- 无名科技 Nologo-星智-1.54TFT
- SenseCAP Watcher
- ESP-HI 超低成本机器狗
软件
固件烧录
新手第一次操作建议先不要搭建开发环境,直接使用免开发环境烧录的固件。
固件默认接入 xiaozhi.me 官方服务器,个人用户注册账号可以免费使用 Qwen 实时模型。
👉 新手烧录固件教程
开发环境
- Cursor 或 VSCode
- 安装 ESP-IDF 插件,选择 SDK 版本 5.4 或以上
- Linux 比 Windows 更好,编译速度快,也免去驱动问题的困扰
- 本项目使用 Google C++ 代码风格,提交代码时请确保符合规范
开发者文档
- 自定义开发板指南 - 学习如何为小智 AI 创建自定义开发板
- MCP 协议物联网控制用法说明 - 了解如何通过 MCP 协议控制物联网设备
- MCP 协议交互流程 - 设备端 MCP 协议的实现方式
- MQTT + UDP 混合通信协议文档
- 一份详细的 WebSocket 通信协议文档
大模型配置
如果你已经拥有一个小智 AI 聊天机器人设备,并且已接入官方服务器,可以登录 xiaozhi.me 控制台进行配置。
相关开源项目
在个人电脑上部署服务器,可以参考以下第三方开源的项目:
- xinnan-tech/xiaozhi-esp32-server Python 服务器
- joey-zhou/xiaozhi-esp32-server-java Java 服务器
- AnimeAIChat/xiaozhi-server-go Golang 服务器
使用小智通信协议的第三方客户端项目:
- huangjunsen0406/py-xiaozhi Python 客户端
- TOM88812/xiaozhi-android-client Android 客户端
- 100askTeam/xiaozhi-linux 百问科技提供的 Linux 客户端
- 78/xiaozhi-sf32 思澈科技的蓝牙芯片固件
- QuecPython/solution-xiaozhiAI 移远提供的 QuecPython 固件

