返回列表
2026年 2026-06 —— 2026-07 · 66 分钟

智能语音送餐机器人交互系统(侧轻量化版)

面向树莓派的端侧轻量化语音交互系统:KWS 唤醒与命令识别、Silero VAD、ERES2Net 声纹验证、Matcha-TTS 应答,多进程 + ZeroMQ 单机自闭环

语音送餐机器人交互系统 技术文档(树莓派端侧轻量化版)

版本定位:面向树莓派(Raspberry Pi)等轻量嵌入式设备的”端侧一体化、脱离服务器”版本。 唤醒、命令识别、声纹、语音合成等所有语音能力都在单台设备本地推理闭环完成, 不依赖任何云端/服务器语音算力,也不为语音处理联网;MQTT 仅用于送餐订单业务的对外上报。 本文档基于当前工作区代码编写,描述系统采用的实现方法与逻辑,不含具体代码。


1. 系统概述

本项目是一套面向送餐机器人的语音交互与说话人识别系统,实现了”唤醒 → 听令 → 声纹验证 → 执行送餐任务 → 语音应答”的完整闭环。

本版本为端侧轻量化版:整套系统以单台树莓派(或 Jetson 类设备)为唯一计算载体独立运行,所有语音链路(KWS 唤醒与命令识别、Silero VAD、ERES2Net 声纹、Matcha-TTS 合成)均为本地 ONNX 模型的 CPU 推理,系统整体脱离服务器/云端运行。与”依赖远程服务器做大词表 ASR、云端声纹、在线 TTS”的重型方案不同,本版本刻意采用 KWS 关键词检索 + 规则解析 + 端侧小模型 + 预合成语音 的低算力组合,把语音交互的时延与功耗收敛在设备本地。

主要能力包括:

  • 关键词唤醒:持续监听并识别唤醒词”小七小七”
  • 语音命令识别:通过流式关键词识别(KWS)检出”楼层 + 房间 + 动作”类短语命令(本方案不使用整句大词表 ASR,而是用关键词检索 + 规则解析实现命令意图)
  • 声纹(说话人)系统:声纹注册、声纹识别(识别是谁在说话)、声纹验证(命令执行前确认说话人身份)
  • 语音合成应答:预合成语音优先、实时 Matcha-TTS 兜底
  • 任务执行:送餐导航订单累积与提交、开门/关门、充电、取消订单等指令,并将订单通过 MQTT 上报局域网业务端(该上报为可选项,语音主流程不依赖)
  • 交互式状态机:空闲(IDLE)/ 唤醒(AWAKE)两种工作状态,超时自动退出唤醒

1.1 整体架构(多进程 + ZeroMQ 消息总线)

系统采用多进程解耦架构,但全部进程运行在同一台树莓派等设备上(单机部署,无服务器节点):由 launch.py 一键启动 4 个常驻进程,进程间走 ZeroMQ 本机回环tcp://localhost)。进程拆分的目的仅是”模块隔离、崩溃互不影响、便于单独重启”,并不是分布式部署,设备独立即可提供完整语音服务。

                    ┌─────────────────────────────────────────────┐
                    │             launch.py(进程管理器)           │
                    └───────┬──────────┬──────────┬────────┬──────┘
                            ▼          ▼          ▼        ▼
                     audio_capture controller recognition  agv.py
                     (音频采集/KWS)   (主控状态机)  (识别/声纹) (任务执行)
进程文件职责
音频采集audio_capture.py麦克风采集(16kHz/0.1s 帧)、自动增益(AGC)、流式 KWS 检测、音频分发;运行 TCP 切换服务(8889),可在”正常识别 / 声纹注册”两种模式间切换,声纹注册时以子进程方式拉起 register_speaker.py
主控controller.py全局状态机(IDLE/AWAKE);接收唤醒事件、调度识别开关、播放 TTS、管理唤醒超时、调节音量
识别recognition.py语音端点检测与分段、KWS 结果归属、声纹识别/验证、命令解析、向 AGV 分发命令
执行agv.py订单累积、导航/门控/充电/下单/取消等动作处理、请求 TTS 播报、写订单日志、上报执行完成
注册服务register_speaker.py声纹注册 TCP 服务(8888),由 audio_capture 按需启动为子进程
远端采集客户端client_mci_new.py(可选变体,树莓派单机形态默认不启用)运行在远端麦克风工控机上做采集与本地唤醒;本机版本由 audio_capture 用本地声卡直接采集

说明:系统所有常驻模块在树莓派单机上即可完整运行;client_mci_new.py / client/ 只是面向”麦克风不在机器人本体上”的特殊部署场景提供的可选项,不是本版本的必要组件。

1.2 进程间通信(ZeroMQ 端口拓扑)

进程间全部使用 ZeroMQ 通信(PUSH/PULL 单向流水、REQ/REP 控制应答、PUB/SUB 下行推送),端口定义集中在 config.py

端口模式发送方 → 接收方用途
5556 (REP_CTRL)REQ/REPcontroller → audio_capture控制音频采集(开关识别/KWS/清队列)
5557 (PORT_WAKE_PUSH)PUSH/PULLaudio_capture → controller唤醒事件上报
5558 (PUSH_REC)PUSH/PULLaudio_capture → recognition实时音频帧流(含帧序号、时间戳)
5562 (PORT_REC_CTRL)REQ/REPcontroller → recognition控制识别(start/stop/重载声纹库/查状态)
5572 (PORT_AGV_PUSH_CMD)PUSH/PULLrecognition → agv已通过声纹验证的命令下发
5573 (PORT_AGV_COMPLETE)PUSH/PULLagv → controller命令完成通知 / TTS 播报请求 / 音量调节请求
5574 (PORT_AGV_CTRL)REQ/REPcontroller → agvAGV 控制(stop/状态查询)
5575 (PORT_REC_ACTIVITY)PUSH/PULLrecognition → controller语音活动心跳(防 AWAKE 超时)
5576 (PORT_KWS_DETECTION)PUSH/PULLaudio_capture → recognition流式 KWS 检测结果(非唤醒关键词)
5553 (PORT_CLIENT_PUB)PUB/SUBcontroller → 客户端TTS 音频/清队列指令下行推送
8888TCP外部 → register_speaker声纹注册指令(enroll/list/delete)
8889TCP外部 → audio_capture识别/注册模式切换指令

上表中 5553~5576 均为本机进程间端口(仅监听/连接 localhost),它们只是模块间通道,并非对外网络服务;对外仅保留 8888/8889(注册与模式切换,供本机或局域网内调试工具调用)与 MQTT 1883(订单上报)。所有语音处理全程不出设备。

音频帧协议:时间戳 + 头部(帧序号 seq + 元数据)+ float32 PCM 字节。recognition 依 seq 做丢帧检测


2. 用到的模型与关键技术

2.1 模型清单

运行形态(端侧):所有模型均以 ONNX 文件随包存放在设备本地,推理引擎为 sherpa-onnx / onnxruntime,执行端一律 provider=cpu,运行期不产生任何云/服务器调用。每个模型选型都遵循端侧原则:能小则小(KWS 用轻量 Zipformer 流式解码并 int8 化)、能用小模型就不用大模型(声纹取 base 级 ERES2Net)、能离线预生成就不实时算(TTS 应答用预合成 wav)。

用途模型/文件运行引擎说明
关键词识别(唤醒/命令)sherpa-onnx KWS(sherpa-onnx-kws/):Zipformer transducer 流式关键词模型 encoder-...-chunk-16-left-64.int8.onnx + decoder-... + joiner-....int8.onnx + tokens.txt + keywords.txtsherpa-onnx KeywordSpotterint8 量化、chunk-16 流式编码、left-64 左上下文;通过 beam 解码在 38 个词条中检索
语音活动检测(VAD)Silero VAD model/silero_vad.onnxsherpa-onnx VoiceActivityDetector辅助/备用端点检测;min_silence_duration=0.7smin_speech_duration=0.4s
声纹特征提取3D-Speaker ERES2Net model/3dspeaker_speech_eres2net_base_sv_zh-cn_3dspeaker_16k.onnx(另有 large / int8 量化版)sherpa-onnx SpeakerEmbeddingExtractor输入 16kHz 语音,输出说话人 embedding 向量并做 L2 归一化;相似度用余弦(内积)度量
语音合成(TTS)Matcha-TTS 声学模型 tts_models/matcha-icefall-zh-baker/model-steps-3.onnx + Vocos 神经声码器 vocos-22khz-univ.onnx + lexicon.txt / tokens.txt;规则 FST phone.fst/date.fst/number.fstsherpa-onnx OfflineTts(Matcha 配置)中文烘焙语料模型;FST 规则负责数字/日期等的文本规范化

关键词库 sherpa-onnx-kws/keywords.txt 使用”拼音音素序列 + @词条”格式,覆盖:唤醒词”小七小七”、6 个房间短词(积厚厅/韶华厅/云程厅/行远厅/观潮厅等)、“第X层+房间”复合词、动作词(提高音量/降低音量/开门/关门/去送餐/取消送餐/取消订单)。设计上已删除短楼层词(如”第一层”)只保留房间短词与复合词,以避免短词先触发导致复合词漏检。

2.2 关键技术方案

  • 命令识别 = KWS 关键词检索 + 规则解析:不是通用 ASR。audio_capture 逐帧喂 KWS,命中唤醒词发唤醒事件;唤醒态命中其他关键词则转发 recognition;recognition 用 kws_command_detector.py 的文本规则(parse_keyword/parse_action)从关键词文本中解析出命令参数。
  • 说话人识别 = embedding 余弦相似度:语音段 → ERES2Net embedding → 与库中说话人特征做余弦相似度 → 取最高分与阈值(0.4)比较判定身份。
  • 多特征注册与融合:同一说话人可多次注册叠加特征,支持多种合并策略(见 §4.3)。
  • 异步声纹推理:声纹在独立工作线程中推理,通过”命令结果队列 + 声纹结果队列 + segment_id”配对,避免阻塞音频主循环。

3. 唤醒与主控状态机(controller.py)

3.1 交互流程

IDLE(空闲,仅跑 KWS)
  │  KWS 检测到"小七小七"

AWAKE(唤醒态,暂停 KWS 非唤醒词、开启识别)
  ├─ 播放 TTS"你好?" → 提前 0.12s 开识别(TTS 播完即听)
  ├─ 用户说命令 → KWS 检出关键词 → recognition 分段/声纹/解析 → agv 执行 → TTS 应答
  ├─ 有语音活动心跳 / 命令完成 → 重置 8s 超时定时器
  └─ 8s 无有效交互 → 随机播"等待超时。"等 → 回到 IDLE

3.2 状态管理细节

  • 唤醒去重:同一唤醒事件 1.8s 内去重,防止重复播报。
  • 唤醒响应:收到唤醒事件后先停识别/KWS、清空音频队列,播放”你好?“,然后按”音频时长 + 配置余量”规划恢复识别的时机,尽量贴近播报结束,避免漏听用户紧接的话。
  • 超时管理(AWAKE 超时回落):8 秒定时器 + generation 代际计数防止旧定时器误触发;AWAKE 期间 recognition 通过 5575 上报的语音活动心跳可重置超时;10s 内有有效命令也会重置;超时则播报超时文案并回到 IDLE(IDLE 下仅保留 KWS 检测唤醒词)。
  • 对识别进程的编排:所有识别开/关都由 controller 统一通过 5556/5562 下发,保证音频采集端与识别端状态一致;TTS 播放前停止识别、播放后恢复识别。
  • 音量控制:controller 持有 TTS 播放增益系数(默认 5.0,范围 0.5~5.0,步长 1)。识别到”提高/降低音量”命令后由 agv 上报 controller 调增益并播报反馈。

4. 声纹系统(speaker_identification.py 等)

核心类:StreamSpeakerRecognitionVoiceDatabaseAudioQualityAnalyzer

4.1 声纹注册(register_speaker.py + 注册数据流)

注册指令通过 TCP 8888 JSON 协议下发(enroll / list / delete)。执行流程(enroll):

  1. 录音sounddevice 采集 8 秒单声道 16kHz float32。
  2. 音频质量分析AudioQualityAnalyzer 基于频谱法估计信噪比(语音带 1004000Hz vs 噪声带),输出质量分数(0100)与等级(excellent/good/fair/poor/bad/silent);分数 < 30 直接拒绝注册。
  3. 特征提取:ERES2Net embedding 模型单次推理(_extract_directly),得到 L2 归一化声纹向量。
  4. 保存备份音频:录音写入 gallery/app/voice_data/audio_recordings/ 下 WAV。
  5. 写入特征库VoiceDatabase.add_speaker —— 新用户建条目;同名再次注册则追加为新特征(支持一人多音色/多次录音),并记录每次特征的 features_info(质量分、时间、时长);按 hybrid 合并策略更新融合特征后落盘。

注册过程会记录各阶段耗时日志,便于性能分析。注册完成后(audio_capture 收到子进程 [REGISTER_READY] 标记 → 通知 UI “arrange”),切换回正常识别模式时,audio_capture 会主动向 recognition 下发 reload_speakers,使识别进程热重载声纹库(无需重启)。

4.2 数据存储(VoiceDatabase)

文件格式内容
gallery/app/voice_data/voice_database.pklpickle,版本 3.0speakers(姓名 → embedding 特征列表)、merged_embeddings(融合特征缓存)、audio_filesspeakers_info
gallery/app/voice_data/speakers_info.jsonJSON每位说话人的注册时间、质量分、特征数等元信息
audio_recordings/*.wavWAV注册时的原始录音(删除用户时联动删除)

旧版本库(v2.0/旧字典格式)在 load() 时自动做版本兼容迁移

4.3 声纹匹配与验证逻辑

匹配流程(recognition.py 对每个待验证语音段):

  1. 语音段送入 ERES2Net 提取归一化 embedding;
  2. VoiceDatabase.find_similar_speaker 计算与库内各说话人的余弦相似度,取最高分;
  3. 最高分 ≥ 阈值(0.4)→ 判定为该说话人,否则判定”未知/不匹配”。

两种匹配模式(match_mode)

  • merged:与每个说话人的融合特征向量比较(默认,先合并再比,速度快、抗单次噪声干扰);
  • all_features:与该说话人注册的每一个特征逐一比较,取最高分(不丢细节)。

识别时特征合并策略(recognition_merge_strategy)——多特征说话人实时计算融合向量时可选:

策略方法特点
average算术平均后归一化最简单
quality_weighted按质量分加权(低分特征 40 分以下减半、20 分以下乘 0.2)抑制噪声录音
recency_weighted按时间指数衰减 exp(-天数/30) 加权强调近期音色
diversity_weighted与本说话人其它特征差异越大的特征权重越高覆盖音色多样性
hybrid0.4×质量 + 0.3×时间 + 0.3×多样性 加权(默认)综合最优

声纹验证的业务规则(recognition.py):

  • 只有真正要执行的业务命令才做声纹验证_action_requires_speaker):navigate/door/submit_order/cancel_order/charge 需要验证;volumemode_switch 这类低风险操作不需要验证;
  • 声纹库为空时不做验证,直接放行(避免空库时每条命令白跑一次推理);
  • 验证失败 → 生成 reject(reason=speaker_mismatch)消息发给 agv,由 agv 播报”声纹验证未通过”;验证通过 → 命令附上 user_id 与置信度发给 agv。

并发/时序设计:语音段完成后,如确认是业务命令才投递声纹任务(SPEAKER_VERIFY_ONLY_COMMANDS 默认开启)到有界任务队列(上限 20),由声纹工作线程异步推理,结果以 segment_id 与命令结果配对后统一出口,保证低延迟与不丢配对。

4.4 量化工具(quantize_sv.py)

使用 onnxruntime 对 ERES2Net fp32 模型做动态 int8 量化(权重 QUInt8,排除输出层 embedding 以保精度),生成 3dspeaker_eres2net_base_int8.onnx,用于低算力设备降载(model/ 目录内已有 int8/静态量化变体)。


5. 语音识别进程(recognition.py)

5.1 端点检测与语音分段

系统对每 0.1s 音频帧提取 RMS / 峰值 / 过零率(ZCR) 三指标,实现自适应双门限能量分段(主方案),另有 Silero VAD 模型作辅助/备用:

  • 开始判定:RMS 超过”绝对阈值 与 噪声底噪×倍数”、峰值达标、连续 N 帧满足(防止杂音误触发);对突发高能量脉冲有专门通道;
  • 噪声底噪自适应:指数平滑跟踪环境噪声(快降慢升,带上下限);
  • 结束/切段判定:静音持续 ≥ 1s,且当前 RMS/峰值需同时低于”本段峰值×相对比例”与绝对阈值(避免尾音衰减慢导致拖长);语音最长 5s 强制封段;不足 0.4s 的过短段丢弃;
  • 每段分配唯一 segment_id,可拼接入语音前的历史音频作为前缀(当前默认关闭前缀以避免污染声纹/KWS)。

5.2 KWS 检测结果归属(延迟归属)

由于 KWS 模型有约 500ms 内部解码延迟,检测结果发生时当前语音段可能已结束。方案:

  • 语音段结束后不立即处理,先存入 pending_segments(最多保留 10 段、10s);
  • 主循环 check_results() 定期轮询:对每条 KWS 检测,用 检测时间戳 − 0.5s 回推语音实际发生时刻,归属到时间窗匹配的暂存段;
  • 匹配成功后把该段的音频投递声纹任务、解析命令并进入配对出口;超过 10s 未匹配的段清理。

5.3 命令解析(kws_command_detector.py)

parse_keyword/parse_action 对 KWS 文本做规则解析(不是 NER/LLM):

  1. 文本归一化:去空白与标点、同音纠错(如”小气/小琪”→“小七”);
  2. 楼层提取:正则匹配”(第)X 层”,支持中文数字与阿拉伯数字,映射到 4 层索引;
  3. 房间匹配:命中配置的房间热词表(积厚厅、韶华厅、云程厅、行远厅、观潮厅、员工间);
  4. 解析出 navigate(含房间 + 楼层位向量 dish[4],标记每层各 1 份餐);
  5. 按顺序匹配其它动作关键词:取消优先于送餐(避免”取消送餐”误判为”去送餐”)→ 开门/关门 → 提交订单/送餐 → 充电;另有独立解析的模式切换(进送餐模式)与音量调节关键词。
  6. 唤醒词本身被过滤(不作为命令)。

5.4 命令出口

验证通过后消息带上 actionuser_idconfidence、时间戳、语音时长等字段推给 agv(5572)。


6. 任务执行进程(agv.py)

AGVHandler 采用响应模板 + 订单累积器模型:

  • 导航(navigate):校验楼层与房间齐全(缺楼层播”请告诉我几层。“,缺房间播”请告诉我房间名称。”),把 (room_id, dish[4]) 累积进订单池,并 TTS 播”好的,X层XX厅。”;
  • 提交订单(submit_order):将订单池封装为统一协议 JSON(含 protocol_versionrobot_idtask_info、时间戳),追加写入 orders_log.json 后清空订单池,播”送餐准备就绪。”;
  • 取消(cancel_order):清空订单池;
  • 充电(charge)门控(door)reject(声纹不通过)tts_prompt(模式切换提示) 均按模板播报;
  • 执行完成通知:每个动作处理后向 controller 发送 command_complete,controller 据此重置超时并确保识别已恢复(支持连续多轮对话下单)。

6.1 订单上报(MQTT,独立于语音主流程)

MQTT 只承担”把订单协议交给局域网内的送餐调度端”,与语音交互完全解耦:即使 broker 不可达,设备本地对话、下单累积不受任何影响(订单先落盘 orders_log.json,上报进程轮询补发)。

  • orders_log.jsonmqtt_publisher.py 轮询监控(1s),检测到新订单后通过 paho-mqtt 发布到主题 device/server/command(局域网 broker,QoS 与 keepalive 配置完备);
  • 发布前可自动切换 WiFi(nmcli 连接 ROS2_AGV),断线重连有重试策略;
  • mqtt_subcribe.py 为同协议的订阅测试工具,用于验证链路。

7. 语音合成应答(tts_utils.py)

TTSManager 采用两级合成策略

  1. 预合成文件优先:应答文本在 pre_synth/ 目录按 <文本>.wav 查找(由 pre_synthesize_all.py 离线批量生成固定应答与”好的,X层XX厅。“模板),命中即读取播放,避免运行时加载 TTS 模型(大幅降低内存与延迟);
  2. 实时合成兜底:未命中时延迟加载 Matcha-TTS + Vocos 模型实时合成,并带 32 条 LRU 结果缓存;模型加载失败不阻塞主流程。

其它细节:

  • 自动加标点:无句末标点时按语气词猜测 ?/! 或默认加”。“(提升语音自然度,预合成文件与实时合成使用同一文本规范,保证命中文案);
  • 音量后处理:峰值归一化 + 乘法增益系数(受语音调音量命令控制),可选择是否允许削波;
  • 播放通道:本地 sounddevice 播放为主,播放期间暂停识别,按 TTS 时长规划恢复识别,保证用户说完话后系统已就绪;(可选)经 PUB(5553) 同步推送给调试客户端。

8. 音频采集进程(audio_capture.py)

  • 本地麦克风:sounddevice.InputStream 采集 16kHz/单声道,按 0.1s 分块(可对接远端工控机网络推流);
  • 自动增益(AGC):以目标 RMS(默认 0.07)计算放大增益,限制最大增益(12)与峰值(0.95),弱信号不放大、强信号不削波;
  • 流式 KWS:每一块音频直接喂给 sherpa-onnx KeywordSpotter(单套模型同时负责唤醒词与命令词,避免两套 KWS 的重复算力——见修复记录 #15);命中唤醒词进入”唤醒态”并上报 controller;唤醒态内命中其它关键词转发 recognition;检测带 0.6s 冷却防抖;
  • 音频分发:识别态(AWAKE)才把音频帧推给 recognition,其余时间不转发以省 CPU;队列满时丢最旧帧并计数;
  • 模式切换:8889 TCP 服务接收 open(切注册模式:关麦克风 → 拉起 register_speaker 子进程 → 等待 [REGISTER_READY])与 close(杀子进程 → 开麦克风 → 通知识别进程重载声纹库)。

9. 目录结构与辅助文件说明

路径说明
launch.py单机进程启动器:清理残留进程、一次拉起树莓派上的全部模块进程、统一信号退出(重启即恢复整套语音服务)
config.py全局配置:采样率、所有 ZMQ 端口、模型路径、关键词/房间/音量参数、TTS 模型与参数
recognition.py / controller.py / audio_capture.py / agv.py / register_speaker.py / speaker_identification.py系统主体
kws_command_detector.py命令文本归一化与规则解析库(被 recognition 调用)
tts_utils.pyTTS 管理器(预合成优先 + 实时合成)
pre_synthesize_all.py批量预合成所有固定应答文案到 pre_synth/
quantize_sv.py声纹模型 int8 量化工具
mqtt_publisher.py / mqtt_subcribe.py订单 MQTT 上报发布器 / 测试订阅器
sherpa-onnx-kws/KWS 模型(encoder/decoder/joiner、tokens、keywords)
model/声纹 ERES2Net(fp32/int8/大模型)与 Silero VAD 模型
tts_models/Matcha-TTS 中文模型 + Vocos 声码器 + 规则 FST
gallery/app/voice_data/声纹库与注册录音实际存储位置
orders_log.json订单协议日志(MQTT 上报的数据源)
docs/issues_and_fixes.md开发中的问题定位与修复记录(KWS 流式化、双 KWS 合并、声纹归属、PulseAudio 冲突等)
1/备份2/历史版本代码

10. 典型业务时序

场景:注册声纹(8888/8889 为本机或局域网内的可选调试接口,不注册语音功能也能完整自运行)

调试工具 ──TCP 8889 open──▶ audio_capture:关麦克风 → 启动 register_speaker 子进程
register_speaker 加载模型后打印 [REGISTER_READY] → audio_capture 返回 arrange
调试工具 ──TCP 8888 enroll──▶ register_speaker:录音8s → SNR质量分析 → ERES2Net特征
        → 存WAV → add_speaker(追加特征+hybrid融合) → 返回成功
调试工具 ──TCP 8889 close──▶ audio_capture:杀子进程 → 开麦克风 → 通知 recognition reload_speakers

场景:唤醒 → 命令 → 声纹验证 → 执行

audio_capture 持续 KWS
  └─ "小七小七" → controller(IDLE→AWAKE) → TTS"你好?" → 开启识别
用户:"第一层积厚厅"
  ├─ audio_capture:KWS 检出复合词 → 音频帧推 recognition
  ├─ recognition:能量分段 → pending_segments;KWS归属到段 → 命令解析 navigate(积厚厅,第1层)
  │        → 声纹任务(异步 ERES2Net) → 余弦相似度≥0.4 → 命中 user → 推 agv
  ├─ agv:累积订单 → 请 controller 播"好的,一层积厚厅。" → command_complete
  └─ controller:重置超时、保持识别,等待下一句(如"提交订单")

11. 端侧轻量化与稳定性设计要点(面向树莓派)

11.1 “脱离服务器”的落地方式

  • 单机自闭环:唤醒、命令识别、声纹、TTS 全部由树莓派本机进程完成,不向任何服务器/云发送语音与推理请求;掉电或进程崩溃后由 launch.py 一键拉起全部进程,设备即恢复服务;
  • 断网可用:语音交互不依赖外网;网络仅用于可选的 MQTT 订单上报(断网只影响上报,不影响本地对话与执行)。

11.2 面向树莓派算力的轻量化手段

  • KWS 合并成单实例:唤醒词与命令词由同一套 int8 Zipformer KWS 承担(早期版本是双 KWS 实例,后合并),省掉一整份模型内存与推理开销;
  • 推理只在必要处花:KWS 用 chunk-16 流式解码省实时算力;声纹默认 base 级 ERES2Net(fp32 还可经 quantize_sv.py 动态量化为 int8);仅”业务命令且声纹库非空”才触发声纹推理,音量/模式切换等直接放行;
  • 空闲即省资源:IDLE 态只跑 KWS,AWAKE 态才推流给识别进程做分段与声纹;各队列 HWM 受限、队满丢旧帧并计数,杜绝内存膨胀;
  • 内存友好:固定应答全部预合成为 pre_synth/*.wavpre_synthesize_all.py 一次性生成),日常运行无需加载 TTS 模型;实时合成模型延迟加载 + LRU 缓存,合成带锁排队防止抢占 CPU;
  • 存储友好(保护 SD 卡):语音段默认不落盘,仅注册录音保留 wav;声纹库为小体积 pickle,注册后热更新无需重启;
  • 分层异步:音频接收 → 能量分段 → 命令解析与声纹推理分层解耦;声纹推理独享线程 + 有界队列(上限 20),CPU 峰值受控;
  • TTS 不阻塞关键路径:预合成优先、模型延迟加载、播放与识别时序精确衔接,避免”答话”堵住”听话”;
  • 可观测性:各进程输出带耗时/统计日志(丢帧数、识别数、语音段数、声纹耗时、TTS 时长等),便于在树莓派上现场调参(采样率、阈值、HWM 等集中在 config.py)。