跳转至

Edge AI 本地推理:WhisperCPP 离线语音 + 毫米波雷达检测

云端 AI 好用但有个致命问题——你的语音数据被上传到服务器。家里装了 WhisperCPP 本地推理,所有语音识别在本地完成,数据不出门。配合毫米波雷达做人体检测, privacy-first 的智能家居终于有了完整方案。

为什么需要 Edge AI

方案 延迟 隐私 成本 稳定性
云端 API(OpenAI Whisper) 2-5 秒 ❌ 数据上传 月费 $0.006/分钟 依赖网络
Edge AI(WhisperCPP) 0.5-1 秒 ✅ 本地处理 一次性硬件成本 离线可用
传统语音识别(离线规则) < 0.1 秒 ✅ 低 准确率有限

我的判断:语音识别类场景(指令控制、跌倒语音呼救)必须本地化。云端 API 适合非敏感场景(天气查询、闲聊)。

WhisperCPP 本地部署

Docker 方案(推荐)

# ~/whisper/docker-compose.yml
services:
  whispercpp:
    image: ggerganov/whisper.cpp:latest
    restart: unless-stopped
    ports:
      - "8080:8080"           # REST API 端口
    volumes:
      - ./models:/models      # 模型文件
      - ./audio:/audio        # 输入音频
      - ./results:/results    # 转写结果
    environment:
      - WHISPER_MODEL=base    # tiny/base/small/large
      - WHISPER_LANG=zh       # 语言:zh/en/ja
      - WHISPER_DEVICE=cpu    # cpu/gpu(Pi 只能用 cpu)
      - WHISPER_BEAM_SIZE=3   # 束搜索宽度,越大越准越慢
    command: >
      ./server
      --model /models/base.bin
      --language zh
      --convert
# 下载模型(base 约 150MB,small 约 460MB)
mkdir -p ~/whisper/models
cd ~/whisper/models
wget https://huggingface.co/ggerganov/whisper.cpp/resolve/main/base.bin
wget https://huggingface.co/ggerganov/whisper.cpp/resolve/main/base.en.bin

# 启动
cd ~/whisper && docker compose up -d

# 测试
curl -X POST http://localhost:8080/v1/transcriptions \
  -F "[email protected]" \
  -F "language=zh" \
  -F "model=base"

模型选择

模型 大小 CPU 耗时(1 分钟音频) 中文准确率 推荐场景
tiny 39MB ~3 秒 65% 简单关键词检测
base 150MB ~10 秒 85% 日常语音指令(首选)
small 460MB ~30 秒 90% 复杂指令、长对话
medium 1.5GB ~80 秒 93% 会议转录(不推荐家用)
large 3GB ~150 秒 95% 专业转录

我的判断:家用语音指令控制选 base 模型,准确率和速度平衡最好。tiny 够用但错字多,small 以上对 Pi 4 压力太大。

毫米波雷达接入

硬件选型

型号 价格 检测距离 特点 推荐指数
LTCC-RD02PD ¥45 4-8 米 运动 + 存在检测,UART 输出 ⭐⭐⭐⭐⭐
LD2410 ¥60 6 米 有 RSSI 强度,可测速 ⭐⭐⭐⭐
RD02 ¥35 4 米 最便宜,基础款 ⭐⭐⭐
HM3301 ¥80 10 米 远距离,工业级 ⭐⭐⭐

推荐:老人跌倒检测选 LD2410(有 RSSI,能区分移动和静止);普通存在检测选 LTCC-RD02PD(便宜够用)。

ESPHome 固件

# rd02pd-sensor.yaml
esphome:
  name: living-room-radar
  platformio_options:
    lib_deps:
      - bblanchon/[email protected]

esp32:
  board: esp32-c6-devkitc-1
  framework:
    type: arduino

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

ota:
  password: !secret ota_password

# 毫米波雷达 UART(TX→GPIO6, RX→GPIO7)
uart:
  tx_pin: GPIO6
  rx_pin: GPIO7
  baud_rate: 115200
  parity: NONE
  stop_bits: 1

# 自定义解析 LTCC-RD02PD 协议
binary_sensor:
  - platform: gpio
    name: "Living Room Motion"
    pin:
      number: GPIO8
      mode:
        input: true
        pullup: true
    device_class: motion
    filters:
      - delayed_on: 100ms
      - delayed_off: 3s

# 通过 UART 解析雷达数据(存在/移动状态)
sensor:
  - platform: custom
    lambda: |-
      auto radar = new LtccRadarSensor();
      App.register_component(radar);
      return {radar->motion_detection, radar->presence_detection};
    sensors:
      - name: "Motion Level"
        unit_of_measurement: "%"
        accuracy_decimals: 0
      - name: "Presence Level"
        unit_of_measurement: "%"
        accuracy_decimals: 0

# 自定义组件(解析 LTCC-RD02PD 串口协议)
custom_component:
  - lambda: |
      class LtccRadarSensor : public Component, public Sensor {
       public:
        void setup() override {
          // 初始化 UART
          Serial2.begin(115200, SERIAL_8N1, GPIO6, GPIO7);
        }
        void loop() override {
          if (Serial2.available() >= 8) {
            uint8_t buf[8];
            Serial2.readBytes(buf, 8);
            // 协议解析:0xAA 0x55 + 状态字节 + 数据 + 校验
            if (buf[0] == 0xAA && buf[1] == 0x55) {
              motion_ = (buf[2] & 0x01) ? 100 : 0;
              presence_ = (buf[2] & 0x02) ? 100 : 0;
              // 发布传感器值
              motion_sensor_->publish_state(motion_);
              presence_sensor_->publish_state(presence_);
            }
          }
        }
       private:
        float motion_ = 0;
        float presence_ = 0;
        Sensor* motion_sensor_ = nullptr;
        Sensor* presence_sensor_ = nullptr;
      };
# 编译并上传
esphome run living-room-radar.yaml

HA 集成

雷达数据通过 ESPHome integration 自动出现在 HA 里: - binary_sensor.living_room_motion — 运动检测(on/off) - sensor.living_room_motion_level — 运动强度(0-100%) - sensor.living_room_presence_level — 存在强度(0-100%)

实际应用场景

场景一:离线语音指令控制

# 语音指令识别后触发自动化
alias: "语音控制灯光"
triggers:
  - trigger: event
    event_type: whisper_transcription
    event_data:
      text: "打开客厅灯"
conditions: []
actions:
  - action: light.turn_on
    target:
      entity_id: light.living_room
# WhisperCPP 监听麦克风,检测到语音后发布 event
# 用 pulseaudio 或 alsa 捕获音频
arecord -f S16_LE -r 16000 -d 3 /tmp/audio.wav
curl -X POST http://localhost:8080/v1/transcriptions \
  -F "file=@/tmp/audio.wav" \
  -F "language=zh" | jq .text

注意:HA 原生没有 Whisper 集成,需要用 Node-RED 或自定义 Python 脚本做桥接。

场景二:老人跌倒检测联动

# 毫米波雷达 + 语音双重确认
alias: "跌倒检测紧急响应"
triggers:
  - trigger: state
    entity_id: binary_sensor.living_room_motion
    to: "off"
    for: "00:00:05"    # 5 秒内无运动
conditions:
  - condition: template
    value_template: >
      {{ is_state('sensor.living_room_presence_level', '100')
         and is_state('binary_sensor.living_room_motion', 'off') }}
actions:
  # 1. 语音询问
  - action: tts.speak
    target:
      entity_id: media_player.living_room
    data:
      message: "检测到您可能跌倒,需要帮助吗?"
  # 2. 等待 10 秒
  - delay: "00:00:10"
  # 3. 无回应则通知
  - condition: state
    entity_id: binary_sensor.living_room_motion
    state: "off"
  actions:
    - action: notify.mobile_app
      data:
        message: "🚨 客厅疑似跌倒,请立即确认!"
        title: "紧急警报"
        data:
          priority: high

场景三:夜间智能夜灯

# 毫米波雷达检测静止存在,比 PIR 更适合夜间
alias: "夜间毫米波夜灯"
triggers:
  - trigger: state
    entity_id: sensor.living_room_presence_level
    above: 50
conditions:
  - condition: time
    after: "21:00:00"
    before: "06:00:00"
  - condition: state
    entity_id: light.living_room
    state: "off"
actions:
  - action: light.turn_on
    target:
      entity_id: light.hallway_night_light
    data:
      brightness_pct: 10    # 极低亮度,不打扰

为什么用雷达不用 PIR:PIR 检测不到静止人体(呼吸幅度太小),老人睡着后 PIR 会判定"无人"关灯。雷达检测的是微动(胸腔起伏),静止也能检测到。

3 个真实翻车案例

案例一:WhisperCPP 识别中文效果差

现象:base 模型英文识别准确率 90%,中文只有 60%。

根因:下载的模型是 base.en(英文专用),中文需要 base 模型(多语言)。

# 错误:下了英文模型
wget https://huggingface.co/ggerganov/whisper.cpp/resolve/main/base.en.bin

# 正确:下多语言模型
wget https://huggingface.co/ggerganov/whisper.cpp/resolve/main/base.bin

修复:

# 设置 WHISPER_MODEL=base(不是 base.en)
# 在请求时指定 language=zh
curl -X POST http://localhost:8080/v1/transcriptions \
  -F "[email protected]" \
  -F "language=zh" \
  -F "model=base"

案例二:毫米波雷达误触发

现象:雷达频繁报"有人",但其实屋里没人。

根因:雷达安装角度太低(< 15°),地面反射造成误检。

修复: 1. 调整安装高度:建议 2.0-2.5 米 2. 调整检测角度:向下 15-30°,不要水平或向上 3. 调低灵敏度:通过 UART 发送 AT 命令降低检测阈值

# ESPHome 里通过 UART 发 AT 命令
uart.write: "AT+SENS=5\r\n"  # 灵敏度 5(0-10,越低越不敏感)

案例三:WhisperCPP 内存溢出

现象:Pi 4 上跑 base 模型,转写时 OOM(Out of Memory)崩溃。

根因:默认模型加载到 RAM,Pi 4 4GB 内存被其他进程占用后剩余不足。

# 检查内存
free -h
# 剩余 < 500MB 时会 OOM

# 解决方案 1:用 tiny 模型(39MB,足够关键词检测)
WHISPER_MODEL=tiny

# 解决方案 2:加 swap
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

# 解决方案 3:换 x86 小主机(8GB+ RAM)

我的判断:Pi 4 4GB 跑 base 模型勉强够,但建议加 swap。如果跑 small 以上模型,换 x86 小主机更稳。

总结

Edge AI 本地推理的核心价值是隐私 + 离线可用。WhisperCPP 让语音识别不再依赖云端,毫米波雷达让存在检测不再侵犯隐私。两者结合,家庭 AI 才能真正"本地化"。

我的判断:现在入手 Edge AI 的时机已经成熟——WhisperCPP 在 Pi 4 上能跑 base 模型,LTCC-RD02PD 只要 ¥45。预算有限先装雷达(¥45),再逐步加语音识别(免费 Docker 镜像)。不要一开始就追求完整方案,分阶段上线风险更低。

延伸阅读