
🔍 机器人 lumina 运行时原理与 Q1/T1 动作红线图解(点击图片全屏放大)
🤔 为什么动手前必须先瞄一眼这页?
因为启元 Q1 / T1 的技能跑在专属的lumina温室里,根本不是常规的 ROS2 节点!如果你直接让蒙在鼓里的 AI(Claude Code / Cursor / Codex)自由发挥,它 100% 会条件反射写出import rclpy或import robot导致当场暴毙(ImportError),或者因为乱填动作 ID、说话不等人说完而让真机变成“哑巴木头人”。
💡 正确食用姿势:自己改代码前花 2 分钟扫一遍;让 AI 帮你写代码时,直接把文末现成的咒语糊它脸上!
一、五条代码高压红线(踩中任意一条,真机当场罢工)
- 🚫 严禁写
import robot/rclpy/ROS2(谁写谁报错): - 机器人肚子里的老管家
lumina_server在拉起剧本时,会自动用魔法往全局变量里塞好一个robot实例。 - 代码里直接拿来用
robot.xxx()就行,写import robot反而会因为找不到模块当场抛出ImportError! - 📦 只准用 Python 3.10 标准库(别惦记花里胡哨的第三方包):
- 只能导入 Python 自带的标准库(比如
time、json、math、random、urllib.request等;机上虽然躺着一个numpy 1.26,但像requests、pydantic之类的统统没有,导了必挂)。 - 🕺 Q1 室内模式只准动上半身(
upper_body白名单): - 普通用户室内模式(
motion_mode=0)下,为了防止机器人满屋子乱跑撞翻东西,Q1 的全身动作(whole_body)会被底层硬件全部无情驳回(日志记过:reason 24)。 - 🐾 T1 必须先问清它是“两条腿站着”还是“四条腿趴着”:
- T1 是个变形金刚,在四足修勾形态(
quadruped)下只允许做1 / 7 / 26 / 43四个动作(敢调双足比心握手直接报reason 19)。最稳的操作:先调robot.get_t1_robot_form()查户口,并优先用双形态通吃的王炸动作26(撒欢喜悦)和43(律动)! - 🗣️ 说话(
play_tts)必须等够 0.7 秒真安静,打印(print)必须带flush=True: robot.play_tts(text)是个不管售后的异步接口!不等上一句播完就发下一句,上一句直接被掐断吞字。- 更坑的是,
robot.get_audio_play_state()在念长句换气时,偶尔会出现短暂的1 ↔ 2状态假空闲抖动,必须盯着它连续0.7 秒稳定处于空闲(值为2)才算真说完。 - 所有的
print(..., flush=True)必须加上flush=True,否则日志全卡在内存缓冲池里,调试时屏幕比脸还干净。
二、robot 万能遥控器 API 说明书(真机实测签名)
# 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 秒大喘气假空闲抖动”和“死循环卡死”三大疑难杂症:
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 24 | Q1 在室内模式(motion_mode=0)下被封印了全身动作 | 乖乖换成 Q1 upper_body 上半身动作(如 3001 / 3007 / 3008) |
reason 19 | T1 当前姿势不对(四条腿趴着呢,你非让它做双足动作) | 换成四足通吃动作(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 帮你花式改技能时,直接复制下面这段话甩给它,保证它写出的代码一次成型不翻车:
请先阅读 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 确保全部测试通过。