基于树莓派 5 与 ESP32 的本地大模型语音智能家居系统项目总结报告
一、项目介绍和创意介绍
本项目是一款融合边缘计算、物联网(IoT)、本地语音识别以及轻量化大语言模型的智能家居语音交互系统。项目以树莓派 5作为本地智能中枢,结合ESP32设备控制节点,通过 MQTT 协议实现设备控制和环境数据查询,在低成本硬件平台上实现了较自然的本地化智能家居控制。
系统的核心亮点在于“端-边-设备”的协同设计:
- 在语音端:通过 USB 麦克风采集语音,采用 Silero VAD 进行语音活动检测,实现自动判断说话开始和结束;再结合 SenseVoiceSmall int8 模型完成本地语音识别,避免每次固定录音,提高了语音交互的自然性。
- 在边缘端:树莓派 5 本地运行 Qwen3-0.6B 轻量化大语言模型,并通过 llama.cpp 提供推理服务。系统优先使用规则匹配处理开灯、关灯、调亮、查询温湿度等高频指令;对于复杂表达,则调用本地大模型进行语义理解,提高了系统对自然语言的适应能力。
- 在设备端:ESP32 负责连接温湿度传感器、MQ135 空气质量传感器、灯光模块和窗帘控制模块,并将设备状态通过 MQTT 上报给树莓派。如温度、湿度、空气质量、灯光亮度和窗帘状态等数据都可以被系统实时缓存并用于语音播报。
- 在交互与结构上:系统采用 Python 常驻 ASR 服务、C++ 主控程序、MQTT 通信模块和启动脚本分层设计。ASR 服务通过 FIFO 与 C++ 程序通信,TTS 播放时会暂停语音监听,避免系统播报被再次识别。启动脚本会等待 ASR 和 LLM 服务就绪后再启动主程序,提高了整体运行稳定性。
二、使用到的硬件介绍
1. 主控设备:树莓派 5
处理器:Broadcom BCM2712,四核 Arm Cortex-A76,主频最高 2.4GHz
内存:4GB,可满足本地服务运行、语音识别和轻量化模型推理需求
存储:MicroSD 卡或 NVMe SSD,用于存放系统、程序、模型文件和日志数据
系统:Ubuntu 22.04,作为本项目的边缘计算平台
特点:算力较强、接口丰富、体积小,适合作为本地智能家居中枢

2. 设备控制节点:ESP32-S3-DEVKITC-1-N32R16V
处理器: Xtensa® LX7 双核处理器,主频最高可达 240MHz
内存:片上 SRAM,带有外部 PSRAM
无线:支持 2.4GHz Wi-Fi 和 Bluetooth / BLE
接口:GPIO、ADC、PWM、UART、I2C、SPI 等
特点:功耗低、成本低、无线通信能力强,适合作为传感器采集和设备控制节点

3. 语音输出设备:扬声器 / USB 声卡
接口:USB 或音频输出接口
功能:用于播放系统语音回复
输出形式:可连接小型扬声器、有源音箱或 USB 声卡
特点:结构简单,便于实现语音反馈

4. 温湿度传感器:DHT11
检测对象:室内温度和相对湿度
输出形式:数字信号输出
接口方式:通过 GPIO 单总线接入 ESP32
供电电压:3.3V
特点:体积小、功耗低、数据直观,适合室内环境监测

5. 空气质量传感器:MQ135
检测对象:空气质量、烟雾、异味及部分有害气体浓度变化
输出形式:模拟电压输出
接口方式:通过 ESP32 ADC 引脚读取
供电电压:常见模块多为 5V 供电,输出电压需注意是否适配 ESP32 ADC 输入范围
特点:成本较低、接线简单,可用于室内空气质量趋势检测

6. 灯光控制模块:ESP32板载RGB灯
控制对象:RGB 灯模拟家居灯光模块
控制方式:可通过 GPIO、PWM、MOS 管或继电器模块实现
供电方式:根据灯光模块类型选择 3.3V、5V 或外部电源
特点:便于演示开关和亮度变化效果,是智能家居控制中最直观的执行模块

7. 窗帘控制模块:舵机
执行器类型:舵机、电机或步进电机均可实现
控制方式:舵机可使用 PWM 控制,直流电机可配合电机驱动模块
供电要求:电机类负载建议使用独立电源,避免影响 ESP32 稳定运行
特点:能够模拟智能窗帘开合动作,适合展示家居自动化控制效果

三、方案框图和项目设计思路介绍
- 语音交互与智能决策在树莓派5上运行,采用本地语音识别(Silero VAD+ SenseVoiceSmall) 将用户语音转换为文本,通过唤醒词判断和规则匹配快速响应高频指令;对于复杂或不确定的指令,调用本地大语言模型(Qwen3-0.6B)进行语义理解,生成结构化控制命令或自然语言回复。C++主程序负责整体调度、命令解析、MQTT通信和TTS语音播报。
- 设备控制与数据采集由ESP32负责,连接各类传感器和执行器,周期性采集温湿度、空气质量等环境数据并上报至MQTT Broker,同时接收来自树莓派的控制指令驱动灯光、窗帘等设备动作,实现智能家居的双向通信与闭环控制。

四、原理图和 PCB 介绍
本项目根据智能家居控制节点的功能需求,设计了一块用于 ESP32 扩展连接的智能家居控制板。该电路板主要起到接口扩展、模块连接和线路整理的作用,方便将温湿度传感器、空气质量传感器、OLED 显示屏、舵机、触摸按键等外设统一连接到主控板上,提高系统整体的稳定性和可维护性。
1. 原理图介绍

从原理图可以看出,整体电路采用模块化接口设计,主要包括主控接口、OLED 接口、DHT11 接口、MQ135 接口、SR501 接口、舵机接口、指纹模块接口和触摸按键接口等部分。各个模块通过排针形式引出,便于后期接线、调试和更换传感器模块。
主控接口位于原理图左侧,用于连接 ESP32 主控板。接口将多个 GPIO 引脚、电源和 GND 引出,方便与各个外设模块相连。通过这种方式,ESP32 可以统一管理传感器采集、显示输出和执行器控制。
OLED 接口用于连接 0.96 英寸 OLED 显示屏。OLED 一般采用 I2C 通信方式,占用较少 IO 引脚,适合显示系统状态、温湿度、空气质量、联网状态等信息。通过显示屏,用户可以在不依赖串口终端的情况下查看设备运行状态。
DHT11 接口用于连接温湿度传感器。DHT11 可以采集室内温度和湿度数据,并通过单总线形式与 ESP32 通信。该模块对应本项目中的环境监测功能,采集到的数据可以通过 MQTT 上报到树莓派端,用于语音查询和状态显示。
MQ135 接口用于连接空气质量传感器。MQ135 传感器输出模拟电压信号,ESP32 通过 ADC 引脚读取其原始值,并根据设定阈值判断空气质量等级。该接口为系统提供空气质量检测能力,可用于判断室内是否存在异味、烟雾或空气污染变化。
舵机接口用于连接窗帘控制舵机。ESP32 可以通过 PWM 信号控制舵机角度,从而模拟窗帘开合动作。该接口对应项目中的智能窗帘控制功能,可实现打开、关闭或调节窗帘位置。
触摸按键接口连接多个触摸按键,图中分别使用 GPIO4、GPIO5、GPIO6、GPIO7 等引脚。触摸按键可以作为本地手动控制输入,例如手动开关灯、切换模式、控制窗帘或触发查询显示等。它与语音控制形成互补,在语音不便使用时仍可进行本地操作。
预留接口:
指纹模块接口预留给指纹识别模块使用。该接口一般包含电源、GND 以及串口通信引脚,可用于后续扩展门禁识别、身份认证或安全控制功能。
SR501 接口用于连接人体红外感应模块。SR501 可以检测人体活动,后续可扩展为自动开灯、人体存在检测、安防提醒等智能家居联动功能。虽然当前系统主要以语音控制为主,但该接口为后续自动化场景提供了扩展空间。
2. PCB介绍
PCB 设计与原理图保持一致,采用模块化布局方式。板上左侧主要布置主控排针和触摸按键区域,中间和右侧布置传感器、显示屏和执行器接口。整体走线较为清晰,接口分区明显,便于实际焊接和接线。
左侧区域预留了多个圆形触摸按键,对应 GPIO4、GPIO5、GPIO6、GPIO7。触摸按键面积较大,方便用户直接触摸操作,也便于在实际外壳中开孔或标识功能。主控排针位于板中央偏左,便于从 ESP32 引出信号并分配到各个外设接口。


五、软件流程图和关键代码介绍
系统软件由树莓派5(上位机)和ESP32(下位机)两部分组成,二者通过MQTT进行通信。
树莓派负责语音交互、语义理解、命令解析和语音播报。ESP32负责传感器数据采集和设备执行控制。


关键代码说明
Python 常驻语音识别服务
语音识别部分采用 Python 实现常驻 ASR 服务,主要完成“麦克风输入 → VAD 语音检测 → SenseVoice 识别 → FIFO 输出文本”的流程。程序启动后不会每次识别都重新加载模型,而是一次性加载 SenseVoiceSmall 模型,并通过多线程持续监听麦克风。
recognizer = self.create_recognizer()
log("SenseVoice loaded")
while not self.stop_event.is_set():
segment = self.audio_queue.get(timeout=0.2)
stream = recognizer.create_stream()
stream.accept_waveform(self.args.sample_rate, segment)
recognizer.decode_stream(stream)
text = stream.result.text.strip()
if text:
self.text_queue.put(text)
这段代码的作用是从音频队列中取出 VAD 截取好的语音片段,送入 SenseVoice 模型进行识别,并将识别出的文本放入文本队列。通过这种方式,系统可以连续处理用户语音,减少模型反复启动带来的延迟。
为了避免系统播放语音回复时被麦克风再次识别,程序还设计了控制 FIFO。C++ 主程序在 TTS 播放前发送 pause,播放完成后发送 resume,Python 端收到后暂停或恢复 VAD 监听。
if typ == "pause":
self.pause_event.set()
clear_queue(self.audio_queue)
elif typ == "resume":
clear_queue(self.audio_queue)
self.pause_event.clear()
2. C++ 主程序语音交互流程
C++ 主程序是系统的核心调度模块,负责接收 ASR 识别结果、判断唤醒词、解析用户意图、下发 MQTT 控制命令并进行语音播报。
主循环核心流程如下:
while (true) {
std::string raw_input = asr_.WaitText();
raw_input = Trim(raw_input);
if (raw_input.empty()) {
continue;
}
std::cout << "识别结果:" << raw_input << std::endl;
std::string user_command;
if (awakened) {
user_command = raw_input;
awakened = false;
} else {
if (!wake_detector_.ExtractCommand(raw_input, user_command)) {
std::cout << "未检测到唤醒词" << std::endl;
continue;
}
if (user_command.empty()) {
SpeakSafely("我在,请说指令。");
awakened = true;
continue;
}
}
HandleUserCommand(user_command);
}
3. MQTT 通信与状态缓存
树莓派和 ESP32 之间通过 MQTT 通信。C++ 程序一方面负责下发控制指令,另一方面后台订阅 home/#,实时缓存 ESP32 上报的设备状态和传感器数据。
if (topic == "home/temperature/state") {
values_["sensor.temperature"] = payload;
} else if (topic == "home/humidity/state") {
values_["sensor.humidity"] = payload;
} else if (topic == "home/air_quality/raw") {
values_["sensor.air_quality_raw"] = payload;
} else if (topic == "home/air_quality/level") {
values_["sensor.air_quality_level"] = payload;
}
这样当用户询问温度、湿度或空气质量时,系统不需要等待 ESP32 临时返回,而是直接读取最近一次缓存值并播报。例如用户说“贾维斯,家里温度怎么样”,系统会回复“当前温度是 27 摄氏度”。
4. TTS 安全播报
系统在语音播报时使用 SpeakSafely() 函数。它会先暂停 ASR 监听,再播放 TTS,最后延迟恢复监听。
void SmartHomeAssistant::SpeakSafely(const std::string& text) {
asr_.Pause();
speaker_.Speak(text);
std::this_thread::sleep_for(
std::chrono::milliseconds(config::ASR_RESUME_DELAY_MS)
);
asr_.Resume();
}
该设计可以避免系统播报声音被麦克风再次采集,从而减少误识别和重复触发。
5. ESP32 端关键代码说明
ESP32 作为下位机控制节点,主要负责三类任务:连接 Wi-Fi 和 MQTT Broker、采集传感器数据并上报、接收树莓派下发的控制指令并驱动外设。与树莓派端相比,ESP32 的代码更偏向底层硬件控制和实时状态上报。
ESP32 启动后会初始化 Wi-Fi,并连接到树莓派所在的局域网。连接成功后,ESP32 再连接树莓派上运行的 MQTT Broker。通过这种方式,ESP32 不需要和树莓派使用串口直连,而是通过无线网络完成数据交互。
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
mqttClient.setServer(MQTT_HOST, MQTT_PORT);
mqttClient.setCallback(mqttCallback);
ESP32 连接 MQTT 成功后,需要订阅树莓派下发的控制主题,例如灯光开关、灯光亮度和窗帘位置等。
mqttClient.subscribe("home/light/living_room/set");
mqttClient.subscribe("home/light/brightness/set");
mqttClient.subscribe("home/curtain/set");
传感器采集是 ESP32 的另一个核心功能。ESP32 会周期性读取温湿度传感器和 MQ135 空气质量传感器,并将结果通过 MQTT 上报。
void publishSensorData() {
float temperature = readTemperature();
float humidity = readHumidity();
int airRaw = analogRead(MQ135_PIN);
int airLevel = getAirQualityLevel(airRaw);
mqttClient.publish("home/temperature/state", String((int)temperature).c_str());
mqttClient.publish("home/humidity/state", String((int)humidity).c_str());
mqttClient.publish("home/air_quality/raw", String(airRaw).c_str());
mqttClient.publish("home/air_quality/level", String(airLevel).c_str());
}
6. 触摸按键本地交互功能说明
ESP32 端还设计了触摸按键作为本地交互方式。触摸按键的作用是让用户在不使用语音、不打开终端或手机页面的情况下,也可以直接查看环境数据或控制部分家居设备。这样可以提高系统的实用性和容错性,当语音识别不方便使用时,仍然可以通过按键完成基本操作。
本项目中触摸按键主要用于三类功能:一是切换 OLED 显示内容,查看温度、湿度和空气质量等环境数据;二是手动控制 LED 灯的开关或亮度状态;三是控制舵机转动,用于模拟窗帘开合动作。ESP32 在主循环中不断检测触摸按键状态,当检测到按键被触发时,根据不同按键编号执行对应功能。
触摸按键检测逻辑如下:
void handleTouchKeys() {
if (digitalRead(KEY_ENV_PIN) == LOW) {
showEnvPage();
delay(200);
}
if (digitalRead(KEY_LED_PIN) == LOW) {
toggleLed();
delay(200);
}
if (digitalRead(KEY_SERVO_PIN) == LOW) {
toggleCurtain();
delay(200);
}
}
六、智能家居手机APP说明
本手机 APP 是智能家居系统的移动端控制软件,主要用于远程查看家庭环境状态和下发设备控制命令。APP 基于 uni-app 框架开发,使用 HBuilderX 进行调试和 Android APK 打包。系统通过 OneNET 云平台实现手机端与树莓派网关之间的远程通信,用户无需处于同一局域网,也可以通过手机查看温湿度、空气质量、灯光状态、窗帘位置,并对灯光和窗帘进行远程控制。
手机APP整体架构

手机APP示意图

七、功能展示图及说明
图 1 可展示系统实物连接图,包括树莓派 5、ESP32、USB 麦克风、扬声器、温湿度传感器、MQ135 传感器、灯光模块和窗帘控制模块。

图 2 可展示终端启动日志。日志中可以看到 llama-server 启动、LLM ready、ASR service 启动、ASR ready、smart_home 主程序启动、模型预热完成等信息,说明系统具备完整的一键启动和就绪检测机制。

图 3 可展示手机APP获取数据的界面和控制设备。

图 4 可展示温湿度查询过程。ESP32 周期性发布 home/temperature/state 26 和 home/humidity/state 50,用户询问“小助手,家里温度怎么样”,系统播报“当前温度是 26 摄氏度”;用户询问湿度时,系统播报“当前湿度是百分之 50”。


图 5 可展示空气质量查询。ESP32 发布 MQ135 原始值和空气质量等级,用户询问“空气质量怎么样”,系统播报当前空气质量原始值和等级,例如“当前空气质量原始值是 250,等级是良好”。

图6可展示交互界面。可以通过触摸按键进行选择查询和操控RGB和舵机。


实物演示1:触摸按键控制

实物演示2:手机APP

八、设计中遇到的难题和解决方法
1. 语音识别模型选择困难
项目初期尝试使用 Whisper 模型进行语音识别,但在树莓派 5 上运行时存在识别速度偏慢、资源占用较高、中文短句识别不够稳定等问题,同时模型下载也容易受到网络环境影响。后续改用 sherpa-onnx + SenseVoiceSmall int8 模型,并结合 Silero VAD 进行语音活动检测,在保证本地运行的前提下提高了中文识别速度和准确率。
2. 固定录音方式交互体验较差
最初系统采用“按回车后录音 5 秒”的方式进行语音输入,用户必须等待录音结束,且说话时间过短或过长都会影响识别效果。为提升体验,后续改为常驻 ASR 服务,由 VAD 自动判断用户开始说话和结束说话,实现免按键、自动断句的语音交互方式,使系统更接近真实语音助手的使用体验。
3. 本地大模型资源占用与响应速度平衡
树莓派 5 的算力有限,如果模型过大,会导致响应速度慢、系统负载高。项目中选择使用轻量化的 Qwen3-0.6B 模型,并通过规则优先、大模型补充的方式处理指令。常见控制指令由规则快速响应,复杂表达再交给大模型理解,从而兼顾响应速度和智能程度。
4. 多进程启动顺序不稳定
本项目同时涉及 ASR 服务、LLM 服务、MQTT 通信和 C++ 主程序,如果启动顺序不正确,容易出现模型接口无法访问、语音识别服务未就绪、FIFO 通信失败等问题。为此设计了统一启动脚本 run.sh,在启动主程序前先检测 LLM 和 ASR 是否成功启动,确认服务就绪后再进入主控制流程,提高了系统启动可靠性。
九、对本次竞赛的心得体会
通过本次项目开发,我更加深刻地体会到,智能硬件项目并不是简单地完成某一个单独模块,而是硬件设计、嵌入式开发、网络通信、人工智能模型、系统脚本以及用户交互体验的综合集成。一个看似简单的“语音控制灯光”功能,背后实际涉及麦克风采集、音频设备管理、VAD 语音断句、ASR 语音识别、唤醒词判断、自然语言理解、MQTT 通信、ESP32 设备控制、状态上报以及 TTS 语音播报等多个环节。任何一个环节不稳定,都会影响最终的使用体验。
本项目让我对“边缘 AI”和“本地大模型部署”有了更直观的认识。相比直接调用云端 API,本地部署模型需要综合考虑模型大小、推理速度、线程数量、内存占用、启动顺序和接口兼容性等问题。虽然树莓派 5 的算力有限,但通过选择 Qwen3-0.6B 量化模型和 SenseVoiceSmall int8 语音识别模型,依然可以实现一个较完整的本地智能语音家居系统。这让我认识到,轻量化模型与边缘设备结合,在智能家居、环境监测和本地语音助手等场景中具有很大的应用潜力。
本次项目也让我将课堂中学习到的嵌入式开发、Linux 使用、网络通信、传感器采集、PCB 设计和 AI 模型部署等知识串联起来,形成了一个真实可运行的系统。后续如果继续完善,可以进一步加入 Web 控制界面、USB 摄像头监控、更多传感器模块以及更多智能联动场景,同时继续优化语音识别准确率和大模型控制提示词,使系统更加稳定、自然和实用。
非常感谢电子森林提供的项目展示与交流平台,让我有机会将自己的想法完整地实现并整理成项目作品;也感谢贸泽商城对赛事和硬件创新项目的支持,为参赛者提供了接触电子设计、嵌入式开发和智能硬件实践的机会。通过这次竞赛,我不仅提升了动手能力,也更加明确了后续在智能硬件和边缘 AI 方向继续学习和探索的目标。