File size: 30,862 Bytes
9da872f 6563dc6 9da872f 4467722 9da872f 4467722 9da872f 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 6563dc6 4467722 6563dc6 4467722 6563dc6 4467722 4e5c3ed 6563dc6 4e5c3ed 6563dc6 4467722 6563dc6 4467722 6563dc6 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 6563dc6 4e5c3ed 4467722 4e5c3ed 4467722 4e5c3ed 6563dc6 4e5c3ed 6563dc6 4467722 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 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 | # 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 # 运动控制 (高层 API)
│ ├── movement_manager.py # 统一运动管理器 (100Hz 控制循环)
│ ├── 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` - 回声消除收敛状态(只读)
---
## 🎉 Phase 1-12 实体已完成!
**已完成总计: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 个实体 (音频处理参数)
---
## 🚀 语音助手增强功能实现状态
### Phase 13 - 情感动作反馈系统 (部分实现) 🟡
**实现状态**: 基础架构已就绪,但仅支持手动触发,未与语音助手事件自动关联
**已实现功能**:
- ✅ Phase 8 Emotion Selector 实体 (`emotion`)
- ✅ 基础情感动作播放API (`_play_emotion`)
- ✅ 情感映射: Happy/Sad/Angry/Fear/Surprise/Disgust
- ✅ 与 HuggingFace 动作库集成 (`pollen-robotics/reachy-mini-emotions-library`)
**未实现功能**:
- ❌ 自动根据语音助手响应触发情感动作
- ❌ 意图识别与情感匹配
- ❌ 舞蹈动作库集成
- ❌ 上下文感知(如天气查询-晴天播放 happy,雨天播放 sad)
**代码位置**:
- `entity_registry.py:633-658` - Emotion Selector 实体
- `satellite.py:544-574` - `_play_emotion()` 方法
**原始规划** (未完全实现):
| 语音助手事件 | 触发动作 | SDK API | 实现状态 |
|-------------|---------|---------|---------|
| 唤醒词检测 | 播放 "greeting" 动作 | `play_move(moves.get("greeting"))` | ❌ 未实现 |
| 收到肯定回复 | 播放 "happy" / "nod" 动作 | `play_move(moves.get("happy"))` | ❌ 未实现 |
| 收到否定回复 | 播放 "sad" / "shake" 动作 | `play_move(moves.get("sad"))` | ❌ 未实现 |
| 播放音乐/娱乐 | 播放 "dance" 动作 | `play_move(moves.get("dance"))` | ❌ 未实现 |
| 定时器完成 | 播放 "alert" 动作 | `play_move(moves.get("surprised"))` | ❌ 未实现 |
| 错误/无法理解 | 播放 "confused" 动作 | `play_move(moves.get("confused"))` | ❌ 未实现 |
| 天气查询-晴天 | 播放 "happy" 动作 | 根据天气类型选择 | ❌ 未实现 |
| 天气查询-雨天 | 播放 "sad" 动作 | 根据天气类型选择 | ❌ 未实现 |
**代码示例**:
```python
from reachy_mini.motion.recorded_move import RecordedMoves
class EmotionMotionController:
def __init__(self, reachy_mini):
self.reachy = reachy_mini
# 预加载情感动作库
self.emotions = RecordedMoves("pollen-robotics/reachy-mini-emotions-library")
self.dances = RecordedMoves("pollen-robotics/reachy-mini-dances-library")
def on_intent_response(self, intent: str, sentiment: str):
"""根据意图和情感选择动作"""
if sentiment == "positive":
self.reachy.play_move(self.emotions.get("happy"), sound=True)
elif sentiment == "negative":
self.reachy.play_move(self.emotions.get("sad"), sound=True)
elif intent == "play_music":
self.reachy.play_move(self.dances.get("dance_1"), sound=True)
```
### Phase 14 - 智能声源追踪增强 (未实现) ❌
**目标**: 利用 DOA (Direction of Arrival) 实现更自然的声源追踪和多人对话支持。
**当前实现**: ✅ 唤醒时转向声源 (`motion.py:on_wakeup()`)
**未实现增强**:
| 功能 | 说明 | SDK API | 实现状态 |
|------|------|---------|---------|
| 持续声源追踪 | 对话过程中持续跟踪说话人位置 | `media.get_DoA()` | ❌ 未实现 |
| 多人对话切换 | 检测到新说话人时平滑转向 | `goto_target(head=..., method=MIN_JERK)` | ❌ 未实现 |
| 声源可视化 | LED 指示当前声源方向 | `LED_DOA_COLOR` 参数 | ❌ 未实现 |
| 语音活动检测 | 只在检测到语音时追踪 | `DoAInfo.speech_detected` | ✅ 已暴露为实体 |
### Phase 15 - 卡通风格运动模式 (部分实现) 🟡
**目标**: 使用 SDK 的插值技术让机器人动作更有个性和表现力。
**SDK 支持**: `InterpolationTechnique` 枚举
- `LINEAR` - 线性,机械感
- `MIN_JERK` - 最小加加速度,自然平滑(默认)
- `EASE_IN_OUT` - 缓入缓出,优雅
- `CARTOON` - 卡通风格,带回弹效果,活泼可爱
**已实现功能**:
- ✅ 100Hz 统一控制循环 (`movement_manager.py`)
- ✅ 平滑插值动作 (ease in-out 曲线)
- ✅ 呼吸动画 - 空闲时 Z 轴微动 + 天线摆动 (`BreathingAnimation`)
- ✅ 命令队列模式 - 线程安全的外部 API
- ✅ 错误节流 - 防止日志爆炸
**未实现功能**:
- ❌ 动态插值技术切换 (CARTOON/EASE_IN_OUT 等)
- ❌ 夸张的卡通回弹效果
**代码位置**:
- `movement_manager.py:192-243` - BreathingAnimation 类
- `movement_manager.py:246-697` - MovementManager 类
**场景实现状态**:
| 场景 | 推荐插值 | 效果 | 实现状态 |
|------|---------|------|---------|
| 唤醒点头 | `CARTOON` | 活泼的回弹效果 | ❌ 未实现 |
| 思考抬头 | `EASE_IN_OUT` | 优雅的过渡 | ✅ 已实现 (平滑插值) |
| 说话时微动 | `MIN_JERK` | 自然流畅 | ✅ 已实现 (SpeechSway) |
| 错误摇头 | `CARTOON` | 夸张的否定 | ❌ 未实现 |
| 返回中立 | `MIN_JERK` | 平滑归位 | ✅ 已实现 |
| 空闲呼吸 | - | 微妙的生命感 | ✅ 已实现 (BreathingAnimation) |
### Phase 16 - 说话时天线同步动画 (部分实现) 🟡
**目标**: TTS 播放时,天线随音频节奏摆动,模拟"说话"效果。
**已实现功能**:
- ✅ 语音驱动头部摆动 (`SpeechSwayGenerator`)
- ✅ 基于音频响度的 VAD 检测
- ✅ 多频率正弦波叠加 (Lissajous 运动)
- ✅ 平滑包络过渡
**代码位置**:
- `movement_manager.py:124-189` - SpeechSwayGenerator 类
- `motion.py:212-222` - update_audio_loudness() 方法
**技术细节**:
```python
# 语音摆动参数
SWAY_A_PITCH_DEG = 3.0 # 俯仰幅度 (度)
SWAY_A_YAW_DEG = 2.0 # 偏航幅度
SWAY_A_ROLL_DEG = 2.0 # 翻滚幅度
SWAY_F_PITCH = 0.8 # 俯仰频率 Hz
SWAY_F_YAW = 0.6 # 偏航频率
SWAY_F_ROLL = 0.5 # 翻滚频率
# VAD 阈值
VAD_DB_ON = -35 # 开始检测阈值
VAD_DB_OFF = -45 # 停止检测阈值
```
**未实现功能**:
- ❌ 天线随音频节奏摆动 (当前仅头部摆动)
- ❌ 音频频谱分析驱动动画
### Phase 17 - 视觉注视交互 (未实现) ❌
**目标**: 利用摄像头检测人脸,实现眼神交流。
**SDK 支持**:
- `look_at_image(u, v)` - 注视图像中的点
- `look_at_world(x, y, z)` - 注视世界坐标点
- `media.get_frame()` - 获取摄像头画面 (✅ 已在 `camera_server.py:146` 实现)
**未实现功能**:
| 功能 | 说明 | 实现状态 |
|------|------|---------|
| 人脸检测 | 使用 OpenCV/MediaPipe 检测人脸 | ❌ 未实现 |
| 眼神追踪 | 对话时注视说话人的脸 | ❌ 未实现 |
| 多人切换 | 检测到多人时,注视当前说话人 | ❌ 未实现 |
| 空闲扫视 | 空闲时随机环顾四周 | ❌ 未实现 |
### Phase 18 - 重力补偿互动模式 (部分实现) 🟡
**目标**: 允许用户物理触摸和引导机器人头部,实现"教学"式交互。
**SDK 支持**: `enable_gravity_compensation()` - 电机进入重力补偿模式,可手动移动
**已实现功能**:
- ✅ 重力补偿模式切换 (`motor_mode` Select 实体,选项 "gravity_compensation")
- ✅ `reachy_controller.py:236-237` - 重力补偿 API 调用
**未实现功能**:
- ❌ 教学模式 - 录制动作轨迹
- ❌ 保存/播放自定义动作
- ❌ 语音命令触发教学流程
**应用场景**:
- ❌ 用户说 "让我教你一个动作" → 进入重力补偿模式
- ❌ 用户手动移动头部 → 录制动作轨迹
- ❌ 用户说 "记住这个" → 保存动作
- ❌ 用户说 "做刚才的动作" → 播放录制的动作
### Phase 19 - 环境感知响应 (未实现) ❌
**目标**: 利用 IMU 传感器感知环境变化并做出响应。
**SDK 支持**:
- ✅ `mini.imu["accelerometer"]` - 加速度计 (Phase 7 已实现为实体)
- ✅ `mini.imu["gyroscope"]` - 陀螺仪 (Phase 7 已实现为实体)
**未实现功能**:
| 检测事件 | 响应动作 | 实现状态 |
|---------|---------|---------|
| 被拍打/敲击 | 播放惊讶动作 + 语音 "哎呀!" | ❌ 未实现 |
| 被摇晃 | 播放晕眩动作 + 语音 "别晃我~" | ❌ 未实现 |
| 倾斜/倒下 | 播放求助动作 + 语音 "我倒了,帮帮我" | ❌ 未实现 |
| 长时间静止 | 进入休眠动画 | ❌ 未实现 |
### Phase 20 - Home Assistant 场景联动 (未实现) ❌
**目标**: 根据 Home Assistant 的场景/自动化触发机器人动作。
**实现方案**: 通过 ESPHome 服务调用
**未实现场景**:
| HA 场景 | 机器人响应 | 实现状态 |
|--------|-----------|---------|
| 早安场景 | 播放唤醒动作 + "早上好!" | ❌ 未实现 |
| 晚安场景 | 播放睡眠动作 + "晚安~" | ❌ 未实现 |
| 有人回家 | 转向门口 + 挥手 + "欢迎回家!" | ❌ 未实现 |
| 门铃响起 | 转向门口 + 警觉动作 | ❌ 未实现 |
| 播放音乐 | 随音乐节奏摆动 | ❌ 未实现 |
---
## 📊 功能实现总结
### ✅ 已完成功能
#### 核心语音助手 (Phase 1-12)
- **45+ ESPHome 实体** - 全部实现
- **基础语音交互** - 唤醒词检测、STT/TTS 集成
- **运动反馈** - 点头、摇头、注视等基础动作
- **音频处理** - AGC、噪声抑制、回声消除
- **摄像头流** - MJPEG 实时预览
#### 部分实现功能 (Phase 13-20)
- **Phase 13** - 情感动作 API 基础设施 (手动触发可用)
- **Phase 18** - 重力补偿模式切换 (教学流程未实现)
### ❌ 未实现功能
#### 高优先级
- **Phase 13** - 自动情感动作反馈 (需与语音助手事件关联)
- **Phase 14** - 持续声源追踪 (仅唤醒时转向)
#### 中优先级
- **Phase 15** - 卡通风格运动模式 (需动态插值切换)
- **Phase 16** - 天线同步动画
- **Phase 17** - 人脸追踪与眼神交互
#### 低优先级
- **Phase 18** - 教学模式录制/播放功能
- **Phase 19** - IMU 环境感知响应
- **Phase 20** - Home Assistant 场景联动
---
## 功能优先级总结 (更新版)
### 高优先级 (已完成 ✅)
- ✅ **Phase 1-12**: 基础 ESPHome 实体 (45+ 个)
- ✅ 核心语音助手功能
- ✅ 基础运动反馈 (点头、摇头、注视)
### 高优先级 (部分实现 🟡)
- 🟡 **Phase 13**: 情感动作反馈系统
- ✅ Emotion Selector 实体与 API 基础设施
- ❌ 自动根据语音助手响应触发情感动作
- ❌ 意图识别与情感匹配
- ❌ 舞蹈动作库集成
### 高优先级 (未实现 ❌)
- ❌ **Phase 14**: 智能声源追踪增强
- ✅ 唤醒时转向声源
- ❌ 持续声源追踪
- ❌ 多人对话切换
- ❌ 声源可视化
### 中优先级 (部分实现 🟡)
- 🟡 **Phase 15**: 卡通风格运动模式
- ✅ 100Hz 统一控制循环架构
- ✅ 平滑插值动作 + 呼吸动画
- ❌ 动态插值技术切换 (CARTOON 等)
- 🟡 **Phase 16**: 说话时天线同步
- ✅ 语音驱动头部摆动 (SpeechSwayGenerator)
- ❌ 天线随音频节奏摆动
### 中优先级 (未实现 ❌)
- ❌ **Phase 17**: 视觉注视交互 - 眼神交流
### 低优先级 (部分实现 🟡)
- 🟡 **Phase 18**: 重力补偿互动模式
- ✅ 重力补偿模式切换
- ❌ 教学式交互 (录制/播放功能)
### 低优先级 (未实现 ❌)
- ❌ **Phase 19**: 环境感知响应 - IMU 触发动作
- ❌ **Phase 20**: Home Assistant 场景联动 - 智能家居整合
---
## 📈 完成度统计
| 阶段 | 状态 | 完成度 | 说明 |
|------|------|--------|------|
| Phase 1-12 | ✅ 完成 | 100% | 45+ ESPHome 实体全部实现 |
| Phase 13 | 🟡 部分完成 | 30% | API 基础设施就绪,缺自动触发 |
| Phase 14 | ❌ 未完成 | 20% | 仅实现唤醒时转向 |
| Phase 15 | 🟡 部分完成 | 60% | 100Hz控制循环+呼吸动画已实现 |
| Phase 16 | 🟡 部分完成 | 50% | 语音驱动头部摆动已实现 |
| Phase 17 | ❌ 未完成 | 10% | 摄像头已实现,缺人脸检测 |
| Phase 18 | 🟡 部分完成 | 40% | 模式切换已实现,缺教学流程 |
| Phase 19 | ❌ 未完成 | 10% | IMU 数据已暴露,缺触发逻辑 |
| Phase 20 | ❌ 未完成 | 0% | 完全未实现 |
**总体完成度**: **Phase 1-12: 100%** | **Phase 13-20: ~35%**
### 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)
|