T800 / 后空翻动作重定向
把公开数据集里 G1 的后空翻迁移到 T800 人形机器人上:按 1.227 倍腿长比例重定向、逐帧 IK 修正关节角,再用 MuJoCo 运动学回放渲染 50 fps 成片。RL 自主翻墙那条线训练失败。
负责整条动作迁移流程:读参考动作数据、按腿长比例映射到 T800、逐帧 IK 修正、MuJoCo 离屏渲染与成片输出;另独立做了一条 mjlab 强化学习训练线,未成功。
2026-10-31 手机竖屏素材,原速 22 秒。开头场务说话的一段剪掉了,画面没有加速。
两段 640×480 仿真片段接在一起:先正面从躺姿起身,再接背面视角。无音轨。
左边是 T800 的走行画面,右边蓝色骨架是参考轨迹,切成一条对照。8 秒,无音轨。
需求方的 T800 人形机器人需要一段能对外展示的空翻动作。动作用的是公开数据:UniLab 数据集里 Unitree G1 的原地后空翻和翻墙后空翻,把这两段从 G1 迁到 T800 上,再渲染成片。交付物是 6 段 50 fps 视频和两份重定向后的关节轨迹。强化学习自主完成动作的那条线没有跑通,单独写在下面。
三步:对比例、解逆运动学、逐帧回放
- 01
按腿长比例做重定向
先量两台机器人差多少。T800 骨盆到踝俯仰关节的腿长 0.923 m,G1 是 0.752 m,比例 1.227。参考数据里每帧有 fps、joint_pos(29 维关节角)、body_pos_w(31 个刚体位置)、body_quat_w(四元数,wxyz)等字段;骨盆轨迹按 1.227 缩放,朝向不变,关节角按对应链映射到 T800 的 25 个铰链上。T800 一共 26 个自由度:1 个浮动基座加 25 个铰链。
scale 1.227 · 参考 50 fps · retargeting(重定向)= 把一段动作从一台机器人的关节结构映射到另一台
- 02
逐帧 IK 修正关节角
按链直接映射会在腿长和膝、踝结构不同的地方留下悬空和穿地。每一帧跑一次逆运动学(IK,inverse kinematics:给定末端目标位姿,反解关节角),用 scipy.optimize.least_squares 求解,每帧上限 200 次函数求值,diff_step 1e-4。
关节限位按 T800 的模型硬约束:留 0.02 rad 余量,踝俯仰 ±0.68 rad,膝 −0.26…2.35 rad。输出是 qpos(N,32) 的逐帧轨迹,两段动作分别 225 帧和 198 帧,文件里带 fps、joint_names、scale 三个字段。
least_squares · max_nfev 200 · diff_step 1e-4 · 余量 0.02 rad · 踝 ±0.68 rad · 膝 −0.26…2.35 rad
- 03
在 MuJoCo 里逐帧回放并渲染
渲染走 MuJoCo 离屏渲染,不做物理解算:每帧把 qpos 直接写进模型状态,渲染一帧,按 50 fps 串成视频。所以画面里没有接触力、没有平衡控制;脚不打滑是因为关节角本来就被锁在轨迹上,不是因为求解器算出了摩擦力。输出 1080p 横屏和 1080×1920 竖屏两种画幅,全程单张 RTX 5060 Ti 16GB。
MuJoCo offscreen · 50 fps · 1920×1080 / 1080×1920 · kinematic replay(运动学回放)= 不跑物理,直接按轨迹摆位
交付了什么
动作本身能用:两段参考动作都完整迁到了 T800 上,关节限位没有越界,渲染没有穿模,横竖两版都能直接发布。另外附了两段 10 秒的平地行走片段(T800、G1 各一段),作为画面对照。
边界也要写清楚:这些视频展示的是"T800 能做这个动作"的形态演示,不是"T800 会自己做这个动作"。全部关节角来自参考轨迹加 IK 修正,没有任何一步由策略网络给出。我们也没有对脚底滑移、落地冲击这类指标做量化评估——运动学回放里这些量根本不存在,测不了。
强化学习那条线,没有产出可用策略
目标:不止于回放,而是让 T800 在仿真里自己学会助跑、蹬墙、翻越,最后落稳。任务名 ZQ-T800-12DOF-Vault,12 自由度行走配置,2048 个并行环境,每次迭代约 0.73 秒。课程学习把墙高从 0.15 m 逐步抬到 0.55 m,墙厚 0.18 m,摆在出生点前方 1.6 m。
- 第一次训练在第 2488 次迭代崩溃。NaN,NanGuard 在第 95022 步、环境 1189 抓到。当时以为是随机种子或数值精度的偶发问题。
- 重启后发现不是偶发,是场景 bug。出生朝向在 −3.14…3.14 rad 整圈随机,墙有一半概率落在机器人身后。"走到墙前"这件事从第一步就不成立。修复方式是出生朝向固定 0 度(面朝 +x,也就是墙的方向),随机推搡的间隔从 5 秒放宽到 25–35 秒。
- 修复后重训到 2600 次迭代,策略仍然是失败的。它以 0.4 m/s 直线走到墙前摔倒,每回合在第 200–300 步终止,奖励一直停在 37–40,没有上升趋势;课程墙高从没离开最低档,卡在 0.16–0.25 m。
- 再训到 2284 次迭代,第二次崩溃。critic 的观测里出现 NaN,这次 NanGuard 没有抓到,训练是事后才发现已经坏掉的。
结论:"让 T800 自己学会翻墙"没有完成,也不是部分完成。视频里每一个动作都来自参考轨迹,没有一步是策略推理出来的。这条线留下的是两个可复现的失败点——场景配置错误在先,数值稳定性检查不足在后。
技术细节 / 数据、参数与配置 展开
参考动作数据
| 文件 | 帧数 / 时长 | 来源任务 |
|---|---|---|
| flip_360_001__A304.npz | 225 帧 · 4.50 s @ 50 fps | UniLab G1FlipTracking |
| flip_from_wall_104__A304.npz | 198 帧 · 3.96 s @ 50 fps | UniLab G1WallFlipTracking |
字段:fps、joint_pos(N,29)、joint_vel、body_pos_w(N,31,3)、body_quat_w(N,31,4)(wxyz)、body_lin_vel_w、body_ang_vel_w。数据来自 UniLab / Motphys 的公开动作集(HuggingFace unilabsim/unilab-motions)。
重定向输出
| 文件 | 内容 | 附加字段 |
|---|---|---|
| t800_flip360.npz | qpos(225,32) | fps · joint_names · scale 1.227 |
| t800_wallflip.npz | qpos(198,32) | fps · joint_names · scale 1.227 |
本体与 IK
| 腿长(骨盆→踝俯仰关节) | T800 0.923 m / G1 0.752 m |
| T800 自由度 | 26 = 1 浮动基座 + 25 铰链 |
| 求解器 | scipy.optimize.least_squares,max_nfev 200,diff_step 1e-4 |
| 限位余量 | 0.02 rad;踝俯仰 ±0.68 rad;膝 −0.26…2.35 rad |
| 渲染 | MuJoCo 离屏渲染,50 fps,1920×1080 与 1080×1920 |
| 硬件 | 单张 RTX 5060 Ti 16GB |
RL 训练配置(失败记录)
| 框架 | mjlab 1.2.0 + rsl_rl 5.0.1 + warp 1.13.0 |
| 任务 / 配置 | ZQ-T800-12DOF-Vault,12 自由度 |
| 并行环境 | 2048,单次迭代 ≈ 0.73 s |
| 课程学习 | 墙高 0.15 → 0.55 m,墙厚 0.18 m,距出生点 +x 1.6 m |
| 崩溃 1 | 第 2488 迭代,NaN,NanGuard 在 step 95022 / env 1189 捕获 |
| 修复 | 出生朝向随机 ±3.14 rad → 固定 0 rad;推搡间隔 5 s → 25–35 s |
| 重训结果 | 至 2600 迭代:0.4 m/s 直线行走后摔倒,200–300 步终止,奖励 37–40,课程墙高停在 0.16–0.25 m |
| 崩溃 2 | 第 2284 迭代,critic 观测 NaN,NanGuard 未捕获 |
这段工作真正跑通的是工程链条:读公开动作数据、按比例重定向、逐帧 IK 保证限位与接地、离屏渲染出两种画幅的成片,全部在一张消费级显卡上完成,结果可以直接发布。这条链条的价值在于可复用——换一套动作、换一台本体,代码结构不用重写。
但它证明的是流程,不是运动智能。重定向加运动学回放在这行里属于基础操作,真正的难点(接触力、平衡、落地冲击、足底滑移)被 IK 和回放整个绕过去了;视频好看,是因为参考动作本来就好看。RL 那条线暴露的问题更基础:场景配置错了 2488 次迭代才发现,数值崩了两次都没被守住,说明监控和单元检查没有建立起来。作为作品集材料,它诚实、可复现、边界写得清楚,这比吹一个"学会后空翻"要值钱;但要说技术含量,目前只到"能交付形态演示"这一层,离"研究"还差一条能自己爬上 0.55 m 墙的训练曲线。


