这次做的是一个 Isaac Lab 抓放任务:控制机械臂,把指定的工具从白箱搬到蓝箱。动作不复杂,但要让程序判断它有没有完成,就得把“放好了”说清楚。工具经过箱子上方,或是还被夹爪抓着,都不能算成功。录下成功的一次操作以后,还要检查同一串动作能不能再次完成任务。
场景里有一台 Franka Panda 机械臂、两个箱子、四种工具和三路相机。环境根据一句指令选择目标,接收键盘控制动作,再用明确的判据判断任务是否完成。这篇主要记录环境搭建和验证的过程。本次没有训练策略模型,也没有提供奖励函数。
实现、调试和自动化验证使用了 Codex 平台上的 GPT-6 Astra,推理强度为 low。下方四段正式录像由 AI 通过原生键盘控制接口操作,均保留 AI 标注。我后续完成了手动抓取,并检查了四种工具的动作回放;这些个人练习与正式录像分开记录。
这个项目做什么
这是一次机器人仿真工程技术题。需要交付的是一个能安装、操作、记录和回放的抓放环境:白箱里有螺丝刀、扳手、锤子和调色刀,程序指定其中一件,操作者控制 Franka Panda 把它搬到蓝箱,再由程序判断是否成功。
这里的 Franka Panda 是仿真里的机械臂模型。它和前几篇文章里实际连接相机、串口的 SO-101 真机是两个项目。这次也没有让 π0.5 自主决定动作:正式录像中的 AI 通过键盘接口操作,人工练习也使用这个接口。
一次完整运行可以这样理解:
重置场景并指定工具 → 操作者输入动作 → 仿真计算机械臂与工具的运动 → 相机和状态记录结果 → 程序检查是否放好。
交付内容除了四段录像,还包括环境代码、处理后的场景资产、结构化轨迹数据,以及安装、操作、回放和验证说明。录像用来直接看过程,轨迹和验证记录则用于检查过程能否恢复、判据是否可靠。
在什么平台上运行
| 平台或设备 | 在这次项目里负责什么 |
|---|---|
| Isaac Sim | NVIDIA 的机器人仿真平台,计算重力、碰撞、关节运动,并渲染相机画面;可以把它理解为机器人活动的虚拟实验室 |
| Isaac Lab | 建在 Isaac Sim 之上的机器人学习框架,组织动作、观测、重置和任务结束条件;本项目用它搭环境,没有训练策略 |
| 学校实验室的 Linux 工作站、RTX 3090 | 实际运行仿真、渲染、录制和回放;3090 是这台工作站里的 GPU |
| 家里的 Mac | 远程查看和操作 Linux 桌面,本次物理仿真不在 Mac 上运行 |
| Codex | 辅助编写、调试和验证代码的平台,与运行物理仿真的 Isaac Sim 分工不同 |
因此,Mac 上看到的是远程工作站传回来的画面。网络和触控板影响操作体验;机械臂会不会碰到箱壁、工具会不会滑落,则由工作站上的仿真计算决定。下面先放四段完整录像,再说明环境、控制和验证的实现。
四段完整录像
四段视频依次对应螺丝刀、扳手、锤子和调色刀。每段从重置开始,到环境实际触发成功结束;三路画面在同一帧内平铺,带有工具指令、操作者和判据状态。操作中的失误和调整都保留在原回合内。
视频采用 H.264 编码,播放帧率为 30 FPS。这里的时长是录像对应的仿真时间,不代表远程操作所花的真实时间。AI 操作使用分步键盘模式,输入之间暂停物理推进,再根据画面选择下一组按键。
螺丝刀 · 37.07 秒
螺丝刀这一段可用来查看完整流程:靠近目标、夹紧、搬运、松手,以及成功判据最后怎样变为成立。
扳手 · 46.10 秒
扳手第一次抓取后滑回了白箱,随后在同一回合中调整并完成任务。这段保留了修正过程。
锤子 · 45.83 秒
锤子同样经历了滑回白箱和重新抓取。它在仿真中设定为 0.7 kg,接触负载下的末端漂移更明显,需要操作时补偿。这个质量是工程假设,没有做实物标定。
调色刀 · 54.13 秒
调色刀这一段先误拿了螺丝刀,操作方将它放回白箱,再抓取指令指定的工具。任务判据始终检查调色刀,不会因为拿起了另一件工具就改变目标。
四段录像合计 5494 帧,已有完整解码及逐步记录核验。这证明这四个录制回合完成了任务,不能据此估计一般场景下的抓取成功率。
环境结构
运行基线为 Isaac Lab 0.47.2、Isaac Sim 5.1.0 和 RTX 3090。Isaac Sim 提供物理仿真与渲染,Isaac Lab 负责把机器人、动作、观测和任务逻辑组织成可运行的环境。
工程采用独立外部项目,没有修改 Isaac Lab 核心代码,也没有把任务塞进其内置任务目录。这里的 Manager-based 可以理解为按职责拆开配置:动作管理器解释输入,观测管理器组织输出,事件管理器负责重置,终止管理器判断这一回合何时结束。主要文件如下:
palatial/
├── README.md、REPORT.md
├── scripts/ # 启动、键盘操作、录制、回放、验证
├── assets/ # 工具与箱体原始文件、处理后的资产
├── datasets/
│ ├── videos/ # 四段 MP4 与逐步 JSON 记录
│ └── hdf5/ # 四份结构化轨迹数据
├── evidence/ # 检查结果和运行记录
└── source/palatial/
├── setup.py、pyproject.toml、config/extension.toml
└── palatial/tasks/bin_pick_place/
├── bin_pick_place_env_cfg.py
├── config/franka/env_cfg.py
└── mdp/
├── events.py
├── observations.py
└── terminations.py
安装后注册两个 Gym 环境 ID。Gym ID 就是启动时用于选择环境的名称:主环境在重置时选择目标;PLAY 版本固定一个环境、种子 42 和螺丝刀目标,便于重复检查同一个场景。
每回合的指令使用固定格式:
Pick the screwdriver from the white bin and place it in the blue bin.
指令中的工具名、观测中的目标编号和成功判据检查的物体,来自同一个目标配置。这样可以避免文字要求拿螺丝刀,程序却在检查锤子的错误。
箱体尺寸与碰撞
每次重置恢复机械臂、两个箱子和四件工具的位置,并清零线速度与角速度。蓝箱初始为空,四件工具分开放在白箱内;成功计数也从零开始。
资产接入时遇到了两个具体问题。
白箱原始水平尺寸约为 0.298 × 0.141 米,而锤子的占地宽度约为 0.145 米。为了给四件工具留下可抓取空间,白箱按 X、Y、Z 方向缩放为 2、3、1,工具保持原尺寸。这改变了白箱的真实比例,报告中保留了这个取舍。
蓝箱提供的是 OBJ/GLB 和凸碰撞网格,需要转换成 USD。USD 是这个工程里用于组织场景资产的文件格式。最初依照元数据坐标转换后,实际画面显示蓝箱部分陷入桌面;检查网格坐标后,对视觉网格和碰撞网格一起修正了变换。如果只修正外观,录像看着正常,工具仍可能碰到错误位置的“隐形箱壁”。
工具也需要统一刚体结构。刚体可以近似理解为仿真中不会自行变形的一个整体;一件工具不应因为源文件组织方式而散成多个独立运动的零件。处理后的工具各有一个根刚体,同时保留原来的视觉部件。
键盘控制
每个控制步输入七个数:
[dx, dy, dz, drx, dry, drz, gripper]
前三个表示末端平移,单位为米;接下来三个表示旋转增量,单位为弧度;最后一个控制夹爪开合。平移和旋转相对于机器人基座坐标系表达,不能直接把它们理解为屏幕上的上下左右。
逆运动学(IK) 解决的是“希望手移动到哪里,关节应该怎样动”。这里使用相对位姿命令和微分 IK,每一步根据当前位置计算小幅关节调整,控制 Panda 的七个手臂关节。环境只接收动作,没有内置自动抓取或搬运状态机。
TCP(工具中心点) 是用来控制和测量末端位置的参考点。本项目将它设在 panda_hand 局部 +Z 方向 0.107 米处,靠近夹爪实际操作区域;控制器和末端传感器使用相同偏移。
正夹爪动作表示张开,每根手指的目标位置为 0.04 米;负动作表示闭合,目标为 0。正式录像使用 0.012 米的键盘平移步长,默认旋转步长为 0.025 弧度。
物理仿真以 120 Hz 推进,每四个物理步接收一次控制动作,因此控制与录像采样为 30 Hz。单回合上限是 120 秒仿真时间。一次场景检查中实际测得约 9.53 个控制步/真实秒,可见设置 30 Hz 并不保证画面实时运行。连续键盘模式下,即使不按键,物理时间也会继续走。
怎样算放好了
成功判据只检查指令指定的工具。它必须同时满足入箱、稳定和释放三个条件,并连续保持 10 个控制步。
| 条件 | 本项目的具体检查 | 主要排除什么 |
|---|---|---|
| 入箱 | 工具包围盒八个角点全部位于蓝箱局部 X ±0.20、Y ±0.13、Z 0.003~0.25 米内 | 中心入箱但一端伸出、停在箱沿 |
| 稳定 | 线速度小于 0.025 米/秒,角速度小于 0.25 弧度/秒 | 仍在运动、弹跳或快速转动 |
| 释放 | 双指总开度大于 0.065 米,TCP 到工具有向包围盒的距离大于 0.04 米 | 夹爪仍闭合抓持,或末端尚未撤离 |
| 持续成立 | 上述条件连续满足 10 个控制步,中断就重新计数 | 一帧恰好满足条件就提前结束 |
包围盒是包住工具的几何外框。检查八个角点比只检查中心保守,但也可能拒绝一些实际可接受的斜放姿态。计算前先把工具角点变换到蓝箱坐标系,箱子发生旋转时仍以它自己的内部边界为准。
这些阈值是工程选择,没有经过大规模统计调优。10 步对应约三分之一秒;若持续接近速度阈值,物体在这段时间里仍可能移动约 8.3 毫米、转动约 4.8 度,所以“稳定”并不等于绝对静止。夹爪完全张开的目标总开度是 0.080 米,0.065 米要求它接近张开状态,再结合末端距离降低误判。这个组合仍是释放状态的近似判断,没有直接测量接触力。
失败与超时也分开处理。目标原点越出 X 为 −0.35~1.2 米、Y 为 −0.85~0.85 米的范围,或低于 Z = −0.15 米,记为工作空间失败;用完时间预算则单独记为超时。否则下游分析会把“来不及完成”和“工具已经掉落”混成同一种结果。
反例检查
验证覆盖四种工具的成功状态,以及放错工具、目标仍运动、夹爪闭合、箱沿、掉落、超时、成功计数中断和同一步重复读取等情况。
其中多数反例通过设置受控状态来隔离某一个条件。例如要检查“释放”是否生效,就需要避免速度或入箱条件同时不成立,让结果难以解释。另有真实键盘抓持工具进入蓝箱但没有触发成功的物理记录;该快照没有独立证明工具当时已经静止,因此不能拿它替代所有释放条件测试。
这些区分很重要:一段成功录像能证明某次操作完成了任务,却不能单独证明判据不会误报。反例检查补充的正是后一个问题。
相机与观测
两个外部相机从不同方向观察机械臂、双箱和搬运路径,手腕相机跟随机械臂观察抓取区域。每路 RGB 分辨率为 640 × 480;录像拼接后为 1920 × 544,多出的高度用于文字标注。
相机的内参描述三维点怎样投影到图像,本项目三路相机的测量值均为 fx = fy = 480、cx = 320、cy = 240。外参描述相机的位置与朝向;外部相机固定,手腕相机的世界位姿需要由手掌位姿和安装偏移组合得到。
环境将观测保留为字典,包含关节位置与速度、末端位姿、夹爪状态、四件工具和两个箱子的姿态、目标编号、目标相对末端与蓝箱的位置、上一动作及三路 RGB。目标编号用四维 one-hot 表示,例如一个位置为 1、其余为 0,明确告诉后续策略当前要操作哪件工具。
重置相机时也碰到过缓存问题。环境状态已经重置,首帧 RGB 却可能还是旧画面或黑帧。通过完整解码录像发现后,加入了只刷新渲染、不推进物理的步骤,并重新录制受影响回合。仅仅检查“生成了 MP4 文件”无法发现这种问题。
动作回放为什么只有 2/4 成功
HDF5 是一种能够在同一文件里保存多组数组和元数据的格式。本次用它记录动作、状态、观测、RGB、目标指令和判据结果,四份数据合计约 3.23 GB。
这些数据来自重新物理执行历史键盘动作日志,并非与原始四段 MP4 同时录制。工程接入了 Isaac Lab 的原生动作/状态 recorder,但使用自定义入口组织元数据、CPU 图像缓冲和终止观测,相关偏离在报告中说明。
这里有两种容易混淆的回放:
- 状态回放逐帧恢复已保存的位置、姿态等状态,用来查看记录内容是否能正确恢复。
- 动作回放只恢复初始状态,再把动作序列交给物理仿真重新执行。接触、摩擦和数值误差会影响后续轨迹。
| 工具 | 状态回放 | 严格执行原动作序列 | 另一次允许末尾等待的测试 |
|---|---|---|---|
| 螺丝刀 | 保存字段精确恢复 | 成功 | 无需额外等待 |
| 扳手 | 保存字段精确恢复 | 未成功,最后 hold = 9/10 | 多等待 1 步后成功 |
| 锤子 | 保存字段精确恢复 | 成功 | 无需额外等待 |
| 调色刀 | 保存字段精确恢复 | 未成功,最后 hold = 4/10 | 多等待 6 步后成功 |
hold 是当前连续满足成功条件的步数。扳手差一步,依然不能记为严格成功;调色刀同理。两次额外等待发生在单独测试里,没有通过降低阈值把失败改写成成功。四种工具的动作回放轨迹都出现数值偏差,包括最终完成任务的两种。
因此,本次结果是:四段原始录像成功,四份状态回放通过,严格动作回放成功 2/4。这三个结果分别回答不同的问题,应该一起保留。
安装与回放
下面的命令面向已配置兼容 Isaac Lab / Isaac Sim 的 Linux 工作站,在项目根目录执行。它们依赖完整工程与资产,单独复制脚本无法运行。
# 安装外部项目
python -m pip install -e source/palatial
# 启动固定目标的 PLAY 环境
python scripts/zero_agent.py --task Palatial-Franka-BinPickPlace-PLAY-v0 --num_envs 1 --enable_cameras
# 真人键盘操作,使用新的输出文件名
python scripts/teleop.py --enable_cameras --target 0 --operator human --video datasets/user_runs/practice_01.mp4
# 查看螺丝刀状态回放
python scripts/replay_hdf5.py --enable_cameras --dataset datasets/hdf5/demo_0.hdf5 --mode states --realtime
# 严格动作回放,不追加末尾等待
python scripts/replay_hdf5.py --enable_cameras --dataset datasets/hdf5/demo_0.hdf5 --mode actions --realtime
运行键盘控制时,需要图形桌面、仿真窗口焦点和英文键盘输入。W/S、A/D、Q/E 控制平移,Z/X、T/G、C/V 控制旋转,K 切换夹爪。已有正式录像受防覆盖保护,新练习要使用新文件名。
工程内打包了工具与箱体资产,Seattle 实验桌仍来自 NVIDIA 的默认资产源或本地缓存。首次加载可能等待数分钟,网络超时也会导致启动失败。安装和回放验证是在同一台 3090 上通过新目录、新环境完成的,不能推广为所有机器、所有版本均兼容。
在 Mac 上远程操作
3090 放在学校实验室,我在家用 Mac 远程连接。这次操作下来,触控板调整视角和缩放都不太顺手,一些平常很简单的操作要绕好几步,期间也遇到过窗口无响应。按我目前的设备和使用习惯,在 Mac 本地用 MuJoCo 可能会方便一些。这只是这次操作的感受,没有做两个仿真器的性能对比。
后面还能做什么
这个项目目前适合拿来学习环境组织、检查任务判据,以及观察多视角动作数据。四个回合对于训练仍然太少。若继续做模仿学习,需要扩充示范、规范化数据、划分训练与验证集,并在独立回合上评估;更换工具、箱子或机器人,还要重新检查几何边界、初始摆放、控制器和 TCP。
回头看这次任务,我更关心的是录像之外的检查:成功由哪个判据触发,反例能不能被排除,保存的状态能不能恢复,同一组动作重跑会有什么偏差。这些结果都留在记录里,后面继续做策略学习时,才知道该拿什么作比较。