PrimeBot 启元 Q1 & T1 技能整活工作台
RUNTIME CONTRACT · 防炸机护身符

🛡️ 机器人运行时契约与避坑指南(防炸机护身符 & 喂 AI 专用咒语)

5 条高压红线 + robot 遥控器 API + Q1/T1 安全动作表 + AI 提示词咒语

😜 调皮课代表大白话划重点(30 秒读懂核心)
为什么别人写的代码一上真机就报 ImportError 或者哑巴装死?因为启元机器人跑在专属的 lumina 温室里,不是 ROS2!记住:老管家会自动往全局变量塞 robot 遥控器(千万别 import)、说话要盯够 0.7 秒真闭嘴防抖、Q1 室内只动上半身(防 reason 24)、T1 四足修勾只用 26/43(防 reason 19)!
机器人 lumina 运行时原理与 Q1/T1 动作红线图解
🔍 机器人 lumina 运行时原理与 Q1/T1 动作红线图解(点击图片全屏放大)
🤔 为什么动手前必须先瞄一眼这页?
因为启元 Q1 / T1 的技能跑在专属的 lumina 温室里,根本不是常规的 ROS2 节点!如果你直接让蒙在鼓里的 AI(Claude Code / Cursor / Codex)自由发挥,它 100% 会条件反射写出 import rclpy 或 import robot 导致当场暴毙(ImportError),或者因为乱填动作 ID、说话不等人说完而让真机变成“哑巴木头人”。
💡 正确食用姿势:自己改代码前花 2 分钟扫一遍;让 AI 帮你写代码时,直接把文末现成的咒语糊它脸上!

一、五条代码高压红线(踩中任意一条,真机当场罢工)

  1. 🚫 严禁写 import robot / rclpy / ROS2(谁写谁报错):
  2. 机器人肚子里的老管家 lumina_server 在拉起剧本时,会自动用魔法往全局变量里塞好一个 robot 实例。
  3. 代码里直接拿来用 robot.xxx() 就行,写 import robot 反而会因为找不到模块当场抛出 ImportError!
  4. 📦 只准用 Python 3.10 标准库(别惦记花里胡哨的第三方包):
  5. 只能导入 Python 自带的标准库(比如 time、json、math、random、urllib.request 等;机上虽然躺着一个 numpy 1.26,但像 requests、pydantic 之类的统统没有,导了必挂)。
  6. 🕺 Q1 室内模式只准动上半身(upper_body 白名单):
  7. 普通用户室内模式(motion_mode=0)下,为了防止机器人满屋子乱跑撞翻东西,Q1 的全身动作(whole_body)会被底层硬件全部无情驳回(日志记过:reason 24)。
  8. 🐾 T1 必须先问清它是“两条腿站着”还是“四条腿趴着”:
  9. T1 是个变形金刚,在四足修勾形态(quadruped)下只允许做 1 / 7 / 26 / 43 四个动作(敢调双足比心握手直接报 reason 19)。最稳的操作:先调 robot.get_t1_robot_form() 查户口,并优先用双形态通吃的王炸动作 26(撒欢喜悦)和 43(律动)!
  10. 🗣️ 说话(play_tts)必须等够 0.7 秒真安静,打印(print)必须带 flush=True:
  11. robot.play_tts(text) 是个不管售后的异步接口!不等上一句播完就发下一句,上一句直接被掐断吞字。
  12. 更坑的是,robot.get_audio_play_state() 在念长句换气时,偶尔会出现短暂的 1 ↔ 2 状态假空闲抖动,必须盯着它连续 0.7 秒 稳定处于空闲(值为 2)才算真说完。
  13. 所有的 print(..., flush=True) 必须加上 flush=True,否则日志全卡在内存缓冲池里,调试时屏幕比脸还干净。

二、robot 万能遥控器 API 说明书(真机实测签名)

💻 python
# 1. 开口说话(TTS):异步立即返回!必须套在下面的 speak() 防抖轮询函数里用
robot.play_tts(text: str)

# 2. 偷看嘴巴忙不忙:返回字典,如 {'pkg_name': 'tts', 'state': {'value': 1}}
#    state.value == 1 代表正在叭叭播放中;state.value == 2 代表嘴巴空闲
robot.get_audio_play_state() -> dict

# 3. 触发预设动作:返回 bool(注意:True 只代表“前台收到请求了”,电机真动没动得查 task_engine.log!)
#    敲黑板:interrupt=True 会一刀切掉当前正在播的声音!建议说完话再发动作,并老老实实传 interrupt=False
robot.play_animation(anim_id: int, interrupt: bool = False) -> bool

# 4. 询问 T1 当前是站着还是趴着(★仅 T1 专属,Q1 敢调这个接口会直接翻脸报错!)
#    返回 'biped'(双足酷盖形态)或 'quadruped'(四足修勾形态)
robot.get_t1_robot_form() -> str

# 5. 播放板载音频文件(挑食警告:只吃 .wav 格式,塞 .mp3 给它会直接装哑巴!)
robot.play_audio_file(path: str)

# 6. 点亮炫彩呼吸灯带(比如 mode=3 是蹦迪律动模式)
robot.play_light(color, mode)

# 7. 切换脸部屏幕表情包
robot.play_emotion(emotion_ids, ...)

# 8. 原地发呆等待(直接用标准库 time.sleep(seconds) 更顺手)
robot.wait("time", seconds)

三、Q1 与 T1 安全动作 ID 速查表(抄作业专用)

🔍 权威小秘密:完整动作表其实藏在机器人自己的肚子里(不在公开 SDK 文档里)。到了现场连上机器人后,使用 真机侦察与点火器 就会自动把机上真实动作表抓回存档。

3.1 🤖 Q1 社牛常用安全动作(upper_body 白名单,3000 系)

  • 放心大胆用的动作 ID:
  • 3001:👋 招手(开场迎宾首选)
  • 3002:🤝 握手
  • 3003:🤜🤛 碰拳
  • 3004:🙋 挥手
  • 3005:😄 开心
  • 3007:🫶 双手比心(谢幕求赞必杀技)
  • 3008:💪 加油(打气互动首选)
  • 3010:🙆 伸懒腰
  • 3012 / 3013 / 3014:🎙️ 演讲手势三连
  • 3046 / 3047 / 3048:💃 舞蹈 A / B / C(气氛组主力)
  • 3052 ~ 3057:✨ 其他上半身花式组合

3.2 🐾 T1 变形金刚常用安全动作(1 ~ 72 系)

  • 🌟 四足(quadruped)与双足(biped)通吃王炸白名单(闭眼首选,永不报 reason 19):
  • 26:🎉 喜悦(本项目主力选用,时长适中约 5s,表现力贼好)
  • 43:🎵 律动(本项目主力选用,时长约 9s,摇头晃脑节奏感拉满)
  • 1:👋 打招呼(注意:这招是个长达 15 秒的慢动作,且自带霸体不可打断!)
  • 7:🕺 跳舞(长达 33 秒的才艺大秀,注意留够超时时间)
  • 🔹 仅限双足站立(biped)可用动作(必须放在 get_t1_robot_form() == 'biped' 分支里用):
  • 2:握手 | 6:比心 | 10、11:跳舞 | 20 ~ 22:摆拍姿势 | 31:欢呼 | 52:太空步

四、工业级防吞字 speak() 模板(直接整段抄走)

下面这段黄金代码摘自 《启元百变互动官》 与 《社交能量补给站》,一口气治好了“4 秒哑巴不起声”、“0.7 秒大喘气假空闲抖动”和“死循环卡死”三大疑难杂症:

💻 python
import time

POLL_SECONDS = 0.1
IDLE_SECONDS = 0.7

def audio_state() -> int:
    snapshot = robot.get_audio_play_state()
    if isinstance(snapshot, dict):
        state = snapshot.get("state")
        if isinstance(state, dict) and state.get("value") in (1, 2):
            return state["value"]
    raise RuntimeError("AUDIO_STATE_INVALID")

def speak(text: str) -> None:
    """必须盯到开口出声(1)且连续 0.7 秒稳定闭嘴(2);超时果断报错,绝不吞字或死循环。"""
    print("SPEAK " + text, flush=True)
    robot.play_tts(text)
    start_deadline = time.monotonic() + 4.0
    while audio_state() != 1:
        if time.monotonic() >= start_deadline:
            raise RuntimeError("TTS_NOT_STARTED")
        time.sleep(POLL_SECONDS)

    finish_deadline = time.monotonic() + max(len(text) * 0.45, 4.0) + 8.0
    idle_since = None
    while time.monotonic() < finish_deadline:
        if audio_state() == 1:
            idle_since = None
        elif idle_since is None:
            idle_since = time.monotonic()
        elif time.monotonic() - idle_since >= IDLE_SECONDS:
            return
        time.sleep(POLL_SECONDS)
    raise RuntimeError("TTS_NOT_FINISHED")

五、真机动作日志验尸官:拒绝码(reason)10 秒急救字典

在真机上,robot.play_animation(...) 返回 True 只代表“门卫收下了你的传单”,不代表里面的电机真的动了! 运行真机脚本后会自动帮你把最新 12 条硬件日志贴到脸上:

  • ✅ 真动了的铁证:每个动作都有一行 创建Animation task成功, animation_id: XXXX
  • ❌ 罢工急救查表:要是没看到成功日志,按日志里的 reason 编号对表下药:
傲娇拒绝码 (reason)机器人在抱怨啥?10 秒钟怎么哄好它?
reason 24Q1 在室内模式(motion_mode=0)下被封印了全身动作乖乖换成 Q1 upper_body 上半身动作(如 3001 / 3007 / 3008)
reason 19T1 当前姿势不对(四条腿趴着呢,你非让它做双足动作)换成四足通吃动作(26 / 43 / 1 / 7),或用 get_t1_robot_form() 分支
reason 42上一个动作还在扭呢,动作队列堵车了把上一个动作后面的 time.sleep(hold) 等待秒数调大一点
reason 28上一个动作自带霸体不可打断(比如 T1 打招呼要扭 15s)老老实实等够它的完整时长,或者换个短平快的动作(如 26)
reason 17机器人翻遍了字典也没找到这个动作 ID核对从真机抓回来的真实动作表

六、直接复制喂给 AI Agent 的“防呆紧箍咒”提示词

当你想让 Claude Code、Cursor 或 Codex 帮你花式改技能时,直接复制下面这段话甩给它,保证它写出的代码一次成型不翻车:

💻 text
请先阅读 MustRead/02_机器人运行时契约与避坑必读.md,以及 Example/universal_skill/src/main.py 和 Tools/scripts/build.py。
请帮我基于 Example/universal_skill(或 Example/energy_station)修改技能为:【在这里填你的新脑洞,例如:赛博毒舌算命与三连拍合影导演】。
严格遵守以下 5 条保命约束:
1. 只用 Python 3.10 标准库和全局注入的 robot 对象,严禁 import robot / rclpy / ROS2。
2. 保留 ROBOT_MODEL = "q1" 声明(由 Tools/scripts/build.py 自动生成 Q1 和 T1 双包)。
3. Q1 只用 upper_body 动作(如 3001/3005/3007/3008),T1 检查 robot.get_t1_robot_form() 并用 26/43 等兼容动作。
4. 说话必须调用带 0.7 秒稳定空闲防抖的 speak(),动作使用 interrupt=False,所有 print 必须加 flush=True,结尾打印 *_DONE 标记。
5. 修改后请运行 Tools/scripts/build.py 和 Tools/tests/test_preparation.py 确保全部测试通过。