Skip to content

Latest commit

 

History

History
225 lines (155 loc) · 6.72 KB

File metadata and controls

225 lines (155 loc) · 6.72 KB
tags robotics, emotion, animation, best-practice, embodied-ai

机器人情绪与动作系统设计最佳实践

综合自:reachy-mini-conversation-app(Pollen Robotics)


问题描述

如何为社交机器人设计情绪和动作系统,使其:

  • 在交互时表现自然
  • 在空闲时保持鲜活感
  • 支持多种情绪/动作的无缝切换
  • 与语音同步产生有机的运动

核心设计原则

1. 永不静止(Always Alive)

原则:机器人永远不应该完全静止。

实现

  • 空闲 0.3 秒后自动进入呼吸动画
  • 呼吸参数:5mm Z 轴浮动 + 天线交替摆动
  • 频率接近人类呼吸(6 次/分钟)

理由:静止的机器人显得机械和"死亡",持续的微运动创造亲和感。


2. 双层融合架构

架构

┌─────────────────────────────────────┐
│         最终姿态输出(100Hz)         │
├─────────────────────────────────────┤
│  主要动作(互斥)  +  次要偏移(叠加)  │
│  ├─ 情绪          ├─ 语音摆动        │
│  ├─ 舞蹈          └─ 人脸追踪        │
│  ├─ Goto 定位                       │
│  └─ 呼吸                            │
└─────────────────────────────────────┘

理由

  • 主要动作互斥避免冲突
  • 次要偏移叠加增加自然感
  • 单一控制点确保一致性

3. 音频驱动自然运动

原则:说话时的运动应该由音频实时驱动。

关键参数

参数 作用
延迟补偿 200ms 对齐音频与机械延迟
VAD 开启阈值 -35 dB 检测语音开始
VAD 关闭阈值 -45 dB 滞后避免抖动
振荡轴数 6 轴 pitch/yaw/roll/x/y/z

理由

  • 多轴独立振荡避免机械感
  • 响度驱动幅度保持动态
  • 随机初始相位增加有机感

方案比较

动作触发方式

方式 优点 缺点 适用场景
LLM 工具调用 上下文相关、智能选择 延迟较高 交互式情绪表达
随机触发 简单、不可预测 缺乏意图 空闲时的自发行为
时间触发 可预测、可控 机械感 定期演示
音频驱动 自然同步 需要音频输入 说话时的辅助运动

推荐:组合使用 - LLM 决定"做什么",音频驱动"怎么做",随机增加"变化"。


呼吸状态设计

参数 保守值 活跃值 推荐
Z 轴浮动 3mm 10mm 5mm
呼吸频率 0.08 Hz 0.15 Hz 0.1 Hz
天线摆动 10° 20° 15°
天线频率 0.3 Hz 0.7 Hz 0.5 Hz

推荐:使用保守值作为基础,在特定人格或情绪状态下调整。


决策矩阵

场景 推荐方案 理由
用户说话时 语音摆动 + 天线冻结 避免干扰监听
机器人说话时 语音摆动 + 情绪动作 增强表达力
短暂空闲(<15s) 呼吸动画 保持鲜活感
长时间空闲(>15s) LLM 触发创意动作 主动吸引注意
情绪切换 插值过渡(1s) 避免突变

推荐最佳实践

设计层面

  1. 分层设计:将情绪、舞蹈、呼吸作为独立的 Move 对象,通过队列顺序执行

  2. 单一控制点:所有运动通过统一的 set_target 输出,避免并发冲突

  3. 线程安全:控制循环独占状态,外部通过消息队列通信

  4. 时间对齐:使用单调时钟,避免系统时间跳跃影响动画

参数层面

  1. 呼吸优先:任何空闲状态都应该回到呼吸,而不是完全静止

  2. 天线异步:两天线使用相反方向摆动,打破对称感

  3. 相位随机:每次会话使用不同的初始相位,避免重复感

  4. 响度映射:运动幅度应该与音量正相关,使用 gamma 曲线调整

时长与调用层面

  1. 时长协议:所有 Move 必须实现 duration 属性,控制循环依赖它判断完成

  2. 复合时长:多个子动作组成的复合动作,总时长 = Σ 子动作时长

  3. 即时响应:收到完整工具参数后立即执行,异步返回结果给 LLM

  4. 空闲区分:空闲触发的工具调用不生成语音回复,避免打扰


动作时长设计

时长类型

动作类型 时长来源 特点
情绪动作 预录制数据 固定,由录制决定
舞蹈动作 程序生成 固定,由动作定义
Goto 定位 参数指定 可配置(默认 1s)
呼吸动作 float("inf") 无限循环,被中断

时长判断

当前时间 - 开始时间 >= 动作时长  →  动作完成,开始下一个

流式工具调用流程

OpenAI Server → response.function_call_arguments.done
                     ↓
              dispatch_tool_call()
                     ↓
              Tool.__call__()
                     ↓
              movement_manager.queue_move()
                     ↓
              function_call_output → OpenAI Server

关键事件response.function_call_arguments.done 表示参数完全接收,触发执行。


应避免的反模式

反模式 问题 替代方案
直接操作姿态 绕过队列导致冲突 通过队列提交 Move
完全静止 机械感、"死亡"感 持续呼吸动画
对称运动 机械、不自然 天线/相位异步
固定相位 重复、可预测 随机化初始相位
控制循环 I/O 阻塞导致掉帧 异步/预取数据
突然切换 廉价感 插值过渡
时长不准 动作截断或拖沓 精确计算 duration
流式参数处理 参数不完整 等待 .done 事件

实现检查清单

  • 呼吸动画在空闲 0.3 秒后自动启动
  • 所有主要动作通过统一队列管理
  • 所有 Move 实现 duration 属性
  • 语音摆动与音频输出同步(200ms 延迟)
  • 天线在监听时冻结,恢复时平滑混合
  • 空闲 15 秒后触发 LLM 创意动作
  • 每次会话随机化振荡相位
  • 控制循环保持 100Hz 稳定
  • 工具调用等待完整参数再执行

参考


创建时间:2026-03-02 更新时间:2026-03-02