File size: 18,570 Bytes
9da872f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 | # Reachy Mini Home Assistant Voice Assistant - 项目计划
## 项目概述
将 Home Assistant 语音助手功能集成到 Reachy Mini 机器人,通过 ESPHome 协议与 Home Assistant 通信。
## 本地项目目录参考 (禁止修改参考目录内任何文件)
1. [linux-voice-assistant](linux-voice-assistant)
2. [Reachy Mini SDK](reachy_mini)
3. [reachy_mini_conversation_app](reachy_mini_conversation_app)
4. [reachy-mini-desktop-app](reachy-mini-desktop-app)
## 核心设计原则
1. **零配置安装** - 用户只需安装应用,无需手动配置
2. **使用 Reachy Mini 原生硬件** - 使用机器人自带的麦克风和扬声器
3. **Home Assistant 集中管理** - 所有配置在 Home Assistant 端完成
4. **运动反馈** - 语音交互时提供头部运动和天线动画反馈
## 技术架构
```
┌─────────────────────────────────────────────────────────────┐
│ Reachy Mini │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Microphone │→ │ Wake Word │→ │ ESPHome Protocol │ │
│ │ (ReSpeaker) │ │ Detection │ │ Server (Port 6053) │ │
│ └─────────────┘ └─────────────┘ └──────────┬──────────┘ │
│ │ │
│ ┌─────────────┐ ┌─────────────┐ │ │
│ │ Speaker │← │ Audio │←────────────┘ │
│ │ (ReSpeaker) │ │ Player │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Motion Controller (Head + Antennas) │ │
│ │ - on_wakeup: 点头确认 │ │
│ │ - on_listening: 注视用户 │ │
│ │ - on_thinking: 抬头思考 │ │
│ │ - on_speaking: 说话时微动 │ │
│ │ - on_idle: 返回中立位置 │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
│ ESPHome Protocol
▼
┌─────────────────────────────────────────────────────────────┐
│ Home Assistant │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ STT Engine │ │ Intent │ │ TTS Engine │ │
│ │ │ │ Processing │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
## 已完成功能
### 核心功能
- [x] ESPHome 协议服务器实现
- [x] mDNS 服务发现(自动被 Home Assistant 发现)
- [x] 本地唤醒词检测(microWakeWord)
- [x] 音频流传输到 Home Assistant
- [x] TTS 音频播放
- [x] 停止词检测
### Reachy Mini 集成
- [x] 使用 Reachy Mini SDK 的麦克风输入
- [x] 使用 Reachy Mini SDK 的扬声器输出
- [x] 头部运动控制(点头、摇头、注视)
- [x] 天线动画控制
- [x] 语音状态反馈动作
### 应用架构
- [x] 符合 Reachy Mini App 架构
- [x] 自动下载唤醒词模型
- [x] 自动下载音效文件
- [x] 无需 .env 配置文件
## 文件清单
```
reachy_mini_ha_voice/
├── reachy_mini_ha_voice/
│ ├── __init__.py # 包初始化
│ ├── __main__.py # 命令行入口
│ ├── main.py # ReachyMiniApp 入口
│ ├── voice_assistant.py # 语音助手服务
│ ├── satellite.py # ESPHome 协议处理
│ ├── audio_player.py # 音频播放器
│ ├── camera_server.py # MJPEG 摄像头流服务器
│ ├── motion.py # 运动控制
│ ├── models.py # 数据模型
│ ├── entity.py # ESPHome 基础实体
│ ├── entity_extensions.py # 扩展实体类型
│ ├── reachy_controller.py # Reachy Mini 控制器包装
│ ├── api_server.py # API 服务器
│ ├── zeroconf.py # mDNS 发现
│ └── util.py # 工具函数
├── wakewords/ # 唤醒词模型(自动下载)
│ ├── okay_nabu.json
│ ├── okay_nabu.tflite
│ ├── hey_jarvis.json
│ ├── hey_jarvis.tflite
│ ├── stop.json
│ └── stop.tflite
├── sounds/ # 音效文件(自动下载)
│ ├── wake_word_triggered.flac
│ └── timer_finished.flac
├── pyproject.toml # 项目配置
├── README.md # 说明文档
└── PROJECT_PLAN.md # 项目计划
```
## 依赖项
```toml
dependencies = [
"reachy-mini", # Reachy Mini SDK
"sounddevice>=0.4.6", # 音频处理(备用)
"soundfile>=0.12.0", # 音频文件读取
"numpy>=1.24.0", # 数值计算
"pymicro-wakeword>=2.0.0,<3.0.0", # 唤醒词检测
"pyopen-wakeword>=1.0.0,<2.0.0", # 备用唤醒词
"aioesphomeapi>=42.0.0", # ESPHome 协议
"zeroconf>=0.100.0", # mDNS 发现
"scipy>=1.10.0", # 运动控制
"pydantic>=2.0.0", # 数据验证
]
```
## 使用流程
1. **安装应用**
- 从 Reachy Mini App Store 安装
- 或 `pip install reachy-mini-ha-voice`
2. **启动应用**
- 应用自动启动 ESPHome 服务器(端口 6053)
- 自动下载所需模型和音效
3. **连接 Home Assistant**
- Home Assistant 自动发现设备(mDNS)
- 或手动添加:设置 → 设备与服务 → 添加集成 → ESPHome
4. **使用语音助手**
- 说 "Okay Nabu" 唤醒
- 说出命令
- Reachy Mini 会做出运动反馈
## ESPHome 实体规划
基于 Reachy Mini SDK 深入分析,以下实体已暴露给 Home Assistant:
### 已实现实体
| 实体类型 | 名称 | 说明 |
|---------|------|------|
| Media Player | `media_player` | 音频播放控制 |
| Voice Assistant | `voice_assistant` | 语音助手管道 |
### 已实现的控制实体 (Controls) - 可读写
#### Phase 1-3: 基础控制与姿态
| ESPHome 实体类型 | 名称 | SDK API | 范围/选项 | 说明 |
|-----------------|------|---------|----------|------|
| `Number` | `speaker_volume` | `AudioPlayer.set_volume()` | 0-100 | 扬声器音量 |
| `Select` | `motor_mode` | `set_motor_control_mode()` | enabled/disabled/gravity_compensation | 电机模式选择 |
| `Switch` | `motors_enabled` | `enable_motors()` / `disable_motors()` | on/off | 电机扭矩开关 |
| `Button` | `wake_up` | `mini.wake_up()` | - | 唤醒机器人动作 |
| `Button` | `go_to_sleep` | `mini.goto_sleep()` | - | 睡眠机器人动作 |
| `Number` | `head_x` | `goto_target(head=...)` | ±50mm | 头部 X 位置控制 |
| `Number` | `head_y` | `goto_target(head=...)` | ±50mm | 头部 Y 位置控制 |
| `Number` | `head_z` | `goto_target(head=...)` | ±50mm | 头部 Z 位置控制 |
| `Number` | `head_roll` | `goto_target(head=...)` | -40° ~ +40° | 头部翻滚角控制 |
| `Number` | `head_pitch` | `goto_target(head=...)` | -40° ~ +40° | 头部俯仰角控制 |
| `Number` | `head_yaw` | `goto_target(head=...)` | -180° ~ +180° | 头部偏航角控制 |
| `Number` | `body_yaw` | `goto_target(body_yaw=...)` | -160° ~ +160° | 身体偏航角控制 |
| `Number` | `antenna_left` | `goto_target(antennas=...)` | -90° ~ +90° | 左天线角度控制 |
| `Number` | `antenna_right` | `goto_target(antennas=...)` | -90° ~ +90° | 右天线角度控制 |
#### Phase 4: 注视控制
| ESPHome 实体类型 | 名称 | SDK API | 范围/选项 | 说明 |
|-----------------|------|---------|----------|------|
| `Number` | `look_at_x` | `look_at_world(x, y, z)` | 世界坐标 | 注视点 X 坐标 |
| `Number` | `look_at_y` | `look_at_world(x, y, z)` | 世界坐标 | 注视点 Y 坐标 |
| `Number` | `look_at_z` | `look_at_world(x, y, z)` | 世界坐标 | 注视点 Z 坐标 |
### 已实现的传感器实体 (Sensors) - 只读
#### Phase 1 & 5: 基础状态与音频传感器
| ESPHome 实体类型 | 名称 | SDK API | 说明 |
|-----------------|------|---------|------|
| `Text Sensor` | `daemon_state` | `DaemonStatus.state` | Daemon 状态 |
| `Binary Sensor` | `backend_ready` | `backend_status.ready` | 后端是否就绪 |
| `Text Sensor` | `error_message` | `DaemonStatus.error` | 当前错误信息 |
| `Sensor` | `doa_angle` | `DoAInfo.angle` | 声源方向角度 (°) |
| `Binary Sensor` | `speech_detected` | `DoAInfo.speech_detected` | 是否检测到语音 |
#### Phase 6: 诊断信息
| ESPHome 实体类型 | 名称 | SDK API | 说明 |
|-----------------|------|---------|------|
| `Sensor` | `control_loop_frequency` | `control_loop_stats` | 控制循环频率 (Hz) |
| `Text Sensor` | `sdk_version` | `DaemonStatus.version` | SDK 版本号 |
| `Text Sensor` | `robot_name` | `DaemonStatus.robot_name` | 机器人名称 |
| `Binary Sensor` | `wireless_version` | `DaemonStatus.wireless_version` | 是否为无线版本 |
| `Binary Sensor` | `simulation_mode` | `DaemonStatus.simulation_enabled` | 是否在仿真模式 |
| `Text Sensor` | `wlan_ip` | `DaemonStatus.wlan_ip` | 无线网络 IP |
#### Phase 7: IMU 传感器 (仅无线版本)
| ESPHome 实体类型 | 名称 | SDK API | 说明 |
|-----------------|------|---------|------|
| `Sensor` | `imu_accel_x` | `mini.imu["accelerometer"][0]` | X 轴加速度 (m/s²) |
| `Sensor` | `imu_accel_y` | `mini.imu["accelerometer"][1]` | Y 轴加速度 (m/s²) |
| `Sensor` | `imu_accel_z` | `mini.imu["accelerometer"][2]` | Z 轴加速度 (m/s²) |
| `Sensor` | `imu_gyro_x` | `mini.imu["gyroscope"][0]` | X 轴角速度 (rad/s) |
| `Sensor` | `imu_gyro_y` | `mini.imu["gyroscope"][1]` | Y 轴角速度 (rad/s) |
| `Sensor` | `imu_gyro_z` | `mini.imu["gyroscope"][2]` | Z 轴角速度 (rad/s) |
| `Sensor` | `imu_temperature` | `mini.imu["temperature"]` | IMU 温度 (°C) |
#### Phase 8-12: 扩展功能
| ESPHome 实体类型 | 名称 | 说明 |
|-----------------|------|------|
| `Select` | `emotion` | 表情选择器 (Happy/Sad/Angry/Fear/Surprise/Disgust) |
| `Number` | `microphone_volume` | 麦克风音量 (0-100%) |
| `Camera` | `camera` | ESPHome Camera 实体(实时预览) |
| `Number` | `led_brightness` | LED 亮度 (0-100%) |
| `Select` | `led_effect` | LED 效果 (off/solid/breathing/rainbow/doa) |
| `Number` | `led_color_r` | LED 红色分量 (0-255) |
| `Number` | `led_color_g` | LED 绿色分量 (0-255) |
| `Number` | `led_color_b` | LED 蓝色分量 (0-255) |
| `Switch` | `agc_enabled` | 自动增益控制开关 |
| `Number` | `agc_max_gain` | AGC 最大增益 (0-30 dB) |
| `Number` | `noise_suppression` | 噪声抑制级别 (0-100%) |
| `Binary Sensor` | `echo_cancellation_converged` | 回声消除收敛状态 |
> **注意**: 头部位置 (x/y/z) 和角度 (roll/pitch/yaw)、身体偏航角、天线角度都是**可控制**的实体,
> 使用 `Number` 类型实现双向控制。设置新值时调用 `goto_target()`,读取当前值时调用 `get_current_head_pose()` 等。
### 实现优先级
1. **Phase 1 - 基础状态与音量** (高优先级) ✅ **已完成**
- [x] `daemon_state` - Daemon 状态传感器
- [x] `backend_ready` - 后端就绪状态
- [x] `error_message` - 错误信息
- [x] `speaker_volume` - 扬声器音量控制
2. **Phase 2 - 电机控制** (高优先级) ✅ **已完成**
- [x] `motors_enabled` - 电机开关
- [x] `motor_mode` - 电机模式选择 (enabled/disabled/gravity_compensation)
- [x] `wake_up` / `go_to_sleep` - 唤醒/睡眠按钮
3. **Phase 3 - 姿态控制** (中优先级) ✅ **已完成**
- [x] `head_x/y/z` - 头部位置控制
- [x] `head_roll/pitch/yaw` - 头部角度控制
- [x] `body_yaw` - 身体偏航角控制
- [x] `antenna_left/right` - 天线角度控制
4. **Phase 4 - 注视控制** (中优先级) ✅ **已完成**
- [x] `look_at_x/y/z` - 注视点坐标控制
5. **Phase 5 - 音频传感器** (低优先级) ✅ **已完成**
- [x] `doa_angle` - 声源方向
- [x] `speech_detected` - 语音检测
6. **Phase 6 - 诊断信息** (低优先级) ✅ **已完成**
- [x] `control_loop_frequency` - 控制循环频率
- [x] `sdk_version` - SDK 版本
- [x] `robot_name` - 机器人名称
- [x] `wireless_version` - 无线版本标识
- [x] `simulation_mode` - 仿真模式标识
- [x] `wlan_ip` - 无线 IP 地址
7. **Phase 7 - IMU 传感器** (可选,仅无线版本) ✅ **已完成**
- [x] `imu_accel_x/y/z` - 加速度计
- [x] `imu_gyro_x/y/z` - 陀螺仪
- [x] `imu_temperature` - IMU 温度
8. **Phase 8 - 表情控制** ✅ **已完成**
- [x] `emotion` - 表情选择器 (Happy/Sad/Angry/Fear/Surprise/Disgust)
9. **Phase 9 - 音频控制** ✅ **已完成**
- [x] `microphone_volume` - 麦克风音量控制 (0-100%)
10. **Phase 10 - 摄像头集成** ✅ **已完成**
- [x] `camera` - ESPHome Camera 实体(实时预览)
11. **Phase 11 - LED 控制** ✅ **已完成**
- [x] `led_brightness` - LED 亮度 (0-100%)
- [x] `led_effect` - LED 效果 (off/solid/breathing/rainbow/doa)
- [x] `led_color_r/g/b` - LED RGB 颜色 (0-255)
12. **Phase 12 - 音频处理参数** ✅ **已完成**
- [x] `agc_enabled` - 自动增益控制开关
- [x] `agc_max_gain` - AGC 最大增益 (0-30 dB)
- [x] `noise_suppression` - 噪声抑制级别 (0-100%)
- [x] `echo_cancellation_converged` - 回声消除收敛状态(只读)
---
## 🎉 所有实体已完成!
**总计:45+ 个实体**
- Phase 1: 4 个实体 (基础状态与音量)
- Phase 2: 4 个实体 (电机控制)
- Phase 3: 9 个实体 (姿态控制)
- Phase 4: 3 个实体 (注视控制)
- Phase 5: 2 个实体 (音频传感器)
- Phase 6: 6 个实体 (诊断信息)
- Phase 7: 7 个实体 (IMU 传感器)
- Phase 8: 1 个实体 (表情控制)
- Phase 9: 1 个实体 (麦克风音量)
- Phase 10: 1 个实体 (摄像头)
- Phase 11: 5 个实体 (LED 控制)
- Phase 12: 4 个实体 (音频处理参数)
### SDK 数据结构参考
```python
# 电机控制模式
class MotorControlMode(str, Enum):
Enabled = "enabled" # 扭矩开启,位置控制
Disabled = "disabled" # 扭矩关闭
GravityCompensation = "gravity_compensation" # 重力补偿模式
# Daemon 状态
class DaemonState(Enum):
NOT_INITIALIZED = "not_initialized"
STARTING = "starting"
RUNNING = "running"
STOPPING = "stopping"
STOPPED = "stopped"
ERROR = "error"
# 完整状态
class FullState:
control_mode: MotorControlMode
head_pose: XYZRPYPose # x, y, z (m), roll, pitch, yaw (rad)
head_joints: list[float] # 7 个关节角度
body_yaw: float
antennas_position: list[float] # [right, left]
doa: DoAInfo # angle (rad), speech_detected (bool)
# IMU 数据 (仅无线版本)
imu_data = {
"accelerometer": [x, y, z], # m/s²
"gyroscope": [x, y, z], # rad/s
"quaternion": [w, x, y, z], # 姿态四元数
"temperature": float # °C
}
# 安全限制
HEAD_PITCH_ROLL_LIMIT = [-40°, +40°]
HEAD_YAW_LIMIT = [-180°, +180°]
BODY_YAW_LIMIT = [-160°, +160°]
YAW_DELTA_MAX = 65° # 头部与身体偏航角最大差值
```
### ESPHome 协议实现说明
ESPHome 协议通过 protobuf 消息与 Home Assistant 通信。需要实现以下消息类型:
```python
from aioesphomeapi.api_pb2 import (
# Number 实体 (音量/角度控制)
ListEntitiesNumberResponse,
NumberStateResponse,
NumberCommandRequest,
# Select 实体 (电机模式)
ListEntitiesSelectResponse,
SelectStateResponse,
SelectCommandRequest,
# Button 实体 (唤醒/睡眠)
ListEntitiesButtonResponse,
ButtonCommandRequest,
# Switch 实体 (电机开关)
ListEntitiesSwitchResponse,
SwitchStateResponse,
SwitchCommandRequest,
# Sensor 实体 (数值传感器)
ListEntitiesSensorResponse,
SensorStateResponse,
# Binary Sensor 实体 (布尔传感器)
ListEntitiesBinarySensorResponse,
BinarySensorStateResponse,
# Text Sensor 实体 (文本传感器)
ListEntitiesTextSensorResponse,
TextSensorStateResponse,
)
```
## 参考项目
- [OHF-Voice/linux-voice-assistant](https://github.com/OHF-Voice/linux-voice-assistant)
- [pollen-robotics/reachy_mini](https://github.com/pollen-robotics/reachy_mini)
|