Desmond-Dong commited on
Commit
a26fdbd
·
1 Parent(s): beb8e32

docs: Update PROJECT_PLAN.md - add face tracking, update Phase 14/17

Browse files
Files changed (1) hide show
  1. PROJECT_PLAN.md +68 -21
PROJECT_PLAN.md CHANGED
@@ -16,10 +16,11 @@
16
  2. **使用 Reachy Mini 原生硬件** - 使用机器人自带的麦克风和扬声器
17
  3. **Home Assistant 集中管理** - 所有配置在 Home Assistant 端完成
18
  4. **运动反馈** - 语音交互时提供头部运动和天线动画反馈
19
- 5. 整个项目需要严格遵循 [Reachy Mini SDK](reachy_mini) 的架构设计与约束
20
- 6. 严格遵循Python开发的标准,并做到代码风格一致,代码结构清晰,注释完整,文档完善,测试覆盖率高,代码质量高,代码可读性高,代码可维护性高,代码可扩展性高,代码可复用性高
21
- 7. 与home assistant的语音对话为最高优先级,任何其它的功能都是辅助功能,不能影响语音对的功能响应速度
22
- 8. LED都被隐藏在了机器人内部,所有的LED控制全部都忽略,不要使用LED控制
 
23
 
24
  ## 技术架构
25
 
@@ -37,12 +38,18 @@
37
  │ └─────────────┘ └─────────────┘ │
38
  │ │
39
  │ ┌─────────────────────────────────────────────────────┐ │
40
- │ │ Motion Controller (Head + Antennas) │ │
41
- │ │ - on_wakeup: 点头确认 │ │
42
- │ │ - on_listening: 注视用户 │ │
43
- │ │ - on_thinking: 抬头思考 │ │
44
- │ - on_speaking: 说话时微动 │
45
- - on_idle: 返回中立位置 │ │
 
 
 
 
 
 
46
  │ └─────────────────────────────────────────────────────┘ │
47
  └─────────────────────────────────────────────────────────────┘
48
 
@@ -73,6 +80,8 @@
73
  - [x] 头部运动控制(点头、摇头、注视)
74
  - [x] 天线动画控制
75
  - [x] 语音状态反馈动作
 
 
76
 
77
  ### 应用架构
78
  - [x] 符合 Reachy Mini App 架构
@@ -86,12 +95,13 @@
86
  reachy_mini_ha_voice/
87
  ├── reachy_mini_ha_voice/
88
  │ ├── __init__.py # 包初始化
89
- │ ├── __main__.py # 命令行入口
90
  │ ├── main.py # ReachyMiniApp 入口
91
  │ ├── voice_assistant.py # 语音助手服务
92
  │ ├── satellite.py # ESPHome 协议处理
93
  │ ├── audio_player.py # 音频播放器
94
- │ ├── camera_server.py # MJPEG 摄像头流服务��
 
95
  │ ├── motion.py # 运动控制 (高层 API)
96
  │ ├── movement_manager.py # 统一运动管理器 (20Hz 控制循环,优化以防止 daemon 崩溃)
97
  │ ├── models.py # 数据模型
@@ -407,19 +417,56 @@ automation:
407
  option: "Happy"
408
  ```
409
 
410
- ### Phase 14 - 智能声源追踪增强 (未实现) ❌
411
 
412
- **目标**: 利用 DOA (Direction of Arrival) 实现自然的声源追踪和多人对话支持
413
 
414
- **当前实现**: ✅ 唤醒时转向声源 (`motion.py:on_wakeup()`)
415
- **未实现增强**:
 
 
416
 
417
- | 功能 | 说明 | SDK API | 实现状态 |
 
 
418
  |------|------|---------|---------|
419
- | 持续声源追踪 | 对话过程中持续跟踪说话人位置 | `media.get_DoA()` | 实现 |
420
- | 对话切换 | 检测到新说话人时平滑转向 | `goto_target(head=..., method=MIN_JERK)` | 实现 |
421
- | 声源可视化 | ~~LED 指示当前声源方向~~ | ~~`LED_DOA_COLOR` 参数~~ | 取消(LED 不可见) |
422
- | 语音活动检测 | 只在检测到语音时追踪 | `DoAInfo.speech_detected` | ✅ 已暴露为 |
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
423
 
424
  ### Phase 15 - 卡通风格运动模式 (部分实现) 🟡
425
 
 
16
  2. **使用 Reachy Mini 原生硬件** - 使用机器人自带的麦克风和扬声器
17
  3. **Home Assistant 集中管理** - 所有配置在 Home Assistant 端完成
18
  4. **运动反馈** - 语音交互时提供头部运动和天线动画反馈
19
+ 5. **项目约束** - 整个项目需要严格遵循 [Reachy Mini SDK](reachy_mini) 的架构设计与约束
20
+ 6. **代码质量** - 严格遵循Python开发的标准,并做到代码风格一致,代码结构清晰,注释完整,文档完善,测试覆盖率高,代码质量高,代码可读性高,代码可维护性高,代码可扩展性高,代码可复用性高
21
+ 7. **功能优先级** - 与home assistant的语音对话为最高优先级,任何其它的功能都是辅助功能,不能影响语音对的功能响应速度
22
+ 8. **不调用任何LED功能** - LED都被隐藏在了机器人内部,所有的LED控制全部都忽略,不要使用LED控制
23
+ 9. **保留功能优先** - 任何代码修改都应该在保留已完成功能的前提下优化,不能以去除功能的方式来解决问题。当有问题发生时,应该充分参考案例之后以解决问题为优先级,而不是添加各种日志输出为优先级
24
 
25
  ## 技术架构
26
 
 
38
  │ └─────────────┘ └─────────────┘ │
39
  │ │
40
  │ ┌─────────────────────────────────────────────────────┐ │
41
+ │ │ Camera + Face Tracking (YOLO) │ │
42
+ │ │ - 15Hz 人脸检测与追踪 │ │
43
+ │ │ - look_at_image() 计算目标姿态 │ │
44
+ │ │ - 人脸丢失后平滑回中性位置 │ │
45
+ └─────────────────────────────────────────────────────┘
46
+
47
+ │ ┌─────────────────────────────────────────────────────┐ │
48
+ │ │ Motion Controller (Head + Antennas) - 5Hz │ │
49
+ │ │ - Face tracking offsets (secondary pose) │ │
50
+ │ │ - Speech sway (语音驱动微动) │ │
51
+ │ │ - Breathing animation (空闲呼吸) │ │
52
+ │ │ - on_wakeup → on_listening → on_speaking → on_idle │ │
53
  │ └─────────────────────────────────────────────────────┘ │
54
  └─────────────────────────────────────────────────────────────┘
55
 
 
80
  - [x] 头部运动控制(点头、摇头、注视)
81
  - [x] 天线动画控制
82
  - [x] 语音状态反馈动作
83
+ - [x] YOLO 人脸追踪(替代 DOA 声源定位)
84
+ - [x] 5Hz 统一运动控制循环
85
 
86
  ### 应用架构
87
  - [x] 符合 Reachy Mini App 架构
 
95
  reachy_mini_ha_voice/
96
  ├── reachy_mini_ha_voice/
97
  │ ├── __init__.py # 包初始化
98
+ │ ├── __main__.py py # 命令行入口
99
  │ ├── main.py # ReachyMiniApp 入口
100
  │ ├── voice_assistant.py # 语音助手服务
101
  │ ├── satellite.py # ESPHome 协议处理
102
  │ ├── audio_player.py # 音频播放器
103
+ │ ├── camera_server.py # MJPEG 摄像头流服务器 + 人脸追踪
104
+ │ ├── head_tracker.py # YOLO 人脸检测器
105
  │ ├── motion.py # 运动控制 (高层 API)
106
  │ ├── movement_manager.py # 统一运动管理器 (20Hz 控制循环,优化以防止 daemon 崩溃)
107
  │ ├── models.py # 数据模型
 
417
  option: "Happy"
418
  ```
419
 
420
+ ### Phase 14 - 人脸追踪(替代 DOA 声源追踪)✅ **已完成**
421
 
422
+ **目标**: 实现自然的人脸追踪,让机器对话时注视说话人
423
 
424
+ **设计决策**:
425
+ - ❌ 原计划使用 DOA (Direction of Arrival) 声源追踪
426
+ - ✅ 改用 YOLO 人脸检测,更稳定、更准确
427
+ - 原因:DOA 在唤醒时判断不够准确,且频繁查询会导致 daemon 崩溃
428
 
429
+ **已实现功能**:
430
+
431
+ | 功能 | 说明 | 实现位置 | 实现状态 |
432
  |------|------|---------|---------|
433
+ | YOLO 人脸检测 | 使用 `AdamCodd/YOLOv11n-face-detection` 模型 | `head_tracker.py` | 实现 |
434
+ | 15Hz 脸追踪 | 摄像头帧处理 + 人脸检测 | `camera_server.py` | 实现 |
435
+ | look_at_image() | 根据人脸位置计算目标姿态 | `camera_server.py` | 实现 |
436
+ | 平滑回中性位置 | 人脸丢失后 1 秒内平滑回归 | `camera_server.py` | ✅ 已实 |
437
+ | face_tracking_offsets | 作为 secondary pose 叠加到运动控制 | `movement_manager.py` | ✅ 已实现 |
438
+ | 语音活动检测 | DOA 实体仍可用于检测语音 | `DoAInfo.speech_detected` | ✅ 已暴露为实体 |
439
+
440
+ **代码位置**:
441
+ - `head_tracker.py` - YOLO 人脸检测器 (`HeadTracker` 类)
442
+ - `camera_server.py:_face_tracking_loop()` - 15Hz 人脸追踪循环
443
+ - `movement_manager.py:set_face_tracking_offsets()` - 人脸追踪偏移量 API
444
+
445
+ **技术细节**:
446
+ ```python
447
+ # head_tracker.py - YOLO 人脸检测
448
+ class HeadTracker:
449
+ def __init__(self):
450
+ self.model = YOLO("AdamCodd/YOLOv11n-face-detection")
451
+
452
+ def detect_faces(self, frame) -> list[FaceDetection]:
453
+ # 返回检测到的人脸列表,包含 bbox 和置信度
454
+
455
+ # camera_server.py - 人脸追踪循环
456
+ async def _face_tracking_loop(self):
457
+ while self._running:
458
+ frame = self._reachy_controller.get_camera_frame()
459
+ faces = self._head_tracker.detect_faces(frame)
460
+ if faces:
461
+ # 选择最大/最近的人脸
462
+ target_u, target_v = faces[0].center
463
+ pose = self._reachy_controller.look_at_image(target_u, target_v)
464
+ self._motion.set_face_tracking_offsets(pose)
465
+ else:
466
+ # 平滑回归中性位置
467
+ self._motion.clear_face_tracking_offsets()
468
+ await asyncio.sleep(1/15) # 15Hz
469
+ ```
470
 
471
  ### Phase 15 - 卡通风格运动模式 (部分实现) 🟡
472