基于 ESP32 和 Rust 的简易语音助手开发
基于 ESP32-S3 和 Rust 语言开发简易语音助手的全过程。内容涵盖硬件选型(麦克风、喇叭)、开发环境搭建(WSL、esp-idf-svc)、I2S 音频接口连接、WiFi 配置及 HTTP 服务实现。重点讲解了模型调用流程(STT、LLM、TTS),并解决了 TLS 证书配置、线程阻塞及片外 RAM 扩展等常见问题。适合希望从软件转向嵌入式开发的开发者参考。

基于 ESP32-S3 和 Rust 语言开发简易语音助手的全过程。内容涵盖硬件选型(麦克风、喇叭)、开发环境搭建(WSL、esp-idf-svc)、I2S 音频接口连接、WiFi 配置及 HTTP 服务实现。重点讲解了模型调用流程(STT、LLM、TTS),并解决了 TLS 证书配置、线程阻塞及片外 RAM 扩展等常见问题。适合希望从软件转向嵌入式开发的开发者参考。

本文分享使用 ESP32 和 Rust 开发简易语音助手的经验与踩坑记录。虽然涉及嵌入式开发,但主要聚焦于应用层逻辑,适合从纯软件开发转向嵌入式的开发者参考。
项目地址:https://github.com/xgpxg/esp32-voice-assistant-demo
由于需要在几十块的板子上运行语音功能,ESP32 自带 WiFi、蓝牙并支持 I2S,是合适的选择。本次选择 ESP32-S3。
语音输入需要麦克风和喇叭,常用型号为 INM441 和 MAX98357A。

ESP32 官方提供了 Rust SDK esp-idf-svc,环境配置可参考:https://github.com/esp-rs/esp-idf-template。
环境示例:Windows + WSL2。
# 依赖包
sudo apt-get install git wget flex bison gperf python3 python3-pip python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0
# 工具包
cargo install cargo-generate
cargo install ldproxy
cargo install espup
cargo install espflash
# 安装 esp
espup install
# 安装 usbipd(用于将 Windows 的 USB 设备提供给 WSL)
winget install usbipd
烧录程序直接执行 cargo run -r 即可,无需 debug 模式以减小体积。
麦克风使用 INM441,引脚功能如下:

连接到 ESP32-S3 时,SD、WS 和 SCK 需与代码中分配的 IO 口保持一致。
喇叭包含解码器 MAX98357A 和小喇叭。

使用 cargo generate 快速生成模板:
cargo generate esp-rs/esp-idf-template
在 WSL 下烧录前,需在 Windows 上绑定 USB 设备:
# 查看设备
usbipd list
# 绑定并转移到 WSL
usbipd bind --busid=1-4
usbipd attach --wsl --busid=1-4
# 在 WSL 查看连接的设备
ls /dev/ttyACM*
ESP32 支持 STA 和 AP 模式。整体思路为启动 HTTP 服务提供配置页面,WiFi 同时启用 STA 和 AP,配置信息写入 NVS 以便下次自动连接。
// 创建 HTTP 服务
let mut server = EspHttpServer::new(&Configuration::default()).unwrap();
// 注册静态文件
server::register_static_files(&mut server).unwrap();
// 网络相关接口
server::network::register(&mut server, wifi.clone(), nvs.clone()).unwrap();
前端建议使用轻量版框架如 Petite-Vue 以减少体积。
WiFi 初始化代码示例:
fn init_wifi(wifi: &mut EspWifi<'static>, nvs: &EspDefaultNvs) -> anyhow::Result<()> {
let ssid = Config::get_wifi_ssid(nvs);
let password = Config::get_wifi_password(nvs);
// 混合模式,同时支持 AP 和 STA
let cfg = wifi::Configuration::Mixed(
ClientConfiguration {
ssid: ssid.as_str().try_into().unwrap(),
password: password.as_str().try_into().unwrap(),
..Default::default()
},
AccessPointConfiguration {
ssid: SSID.try_into().unwrap(),
ssid_hidden: false,
auth_method: AuthMethod::WPA2Personal,
password: PASSWORD.try_into().unwrap(),
channel: CHANNEL,
..Default::default()
},
);
wifi.set_configuration(&cfg)?;
wifi.start()?;
if !ssid.is_empty() {
log::info!("Wifi 连接中:{}", ssid);
wifi.connect()?;
}
Ok(())
}
使用标准 I2S 协议,芯片已封装好,调用 read 和 write 即可。
let std_config = StdConfig::new(Config::default(), StdClkConfig::from_sample_rate_hz(Self::SAMPLE_RATE), StdSlotConfig::philips_slot_default(DataBitWidth::Bits16, SlotMode::Mono), StdGpioConfig::new(false, false, false));
let mclk = AnyIOPin::none();
let mut i2s = I2sDriver::<I2sRx>::new_std_rx(i2s1, &std_config, bclk, sd, mclk, ws)?;
注意 SlotMode 应为 Mono,且采样率需与模型匹配。
语音对话流程:STT(语音识别)-> LLM(语言模型)-> TTS(文本转语音)。STT 和 TTS 使用 Websocket,LLM 使用 HTTP。
SDK 默认未启用 Websocket,需在 sdkconfig.defaults 中开启:
CONFIG_HTTPD_WS_SUPPORT=y
需启用 TLS,否则可能报错。建议配置全局 CA 存储:
let mut config = EspWebSocketClientConfig::default();
config.crt_bundle_attach = Some(esp_idf_svc::sys::esp_crt_bundle_attach);
config.use_global_ca_store = true;
需增加依赖:
[critical-section]
version = "1.1"
features = ["std"]
default-features = false
处理 WebSocket 事件时,避免多个地方调用 rx.recv() 导致阻塞,可使用 embassy-sync 或循环加 try_recv。
loop {
if let Ok(event) = rx.try_recv() {
match event {
WsEvent::ResultGenerated(text) => result.push_str(&text),
_ => break,
}
}
Timer::after_millis(100).await;
}
ESP32-S3 内存较小,可通过启用 PSRAM 扩展。需在 sdkconfig.defaults 中启用:
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
注意启用 PSRAM 后 33-37 号 GPIO 不可用,否则可能导致重启。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online
基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online