2026年了,双臂VLA在IsaacLab上到底能跑成什么样?

“VLA 不死,只是进化”—— 2026 年具身智能领域的年度标语?
——谈一个具体问题
目录
02 Stage 1+:VLA 闭环数据流解密,从 RTX 渲染到关节 PD 驱动
动作路径:从 VLA 12维绝对输出到 PhysX PD 控制器
03 Stage 2:LLM 驱动的场景自适应生成与工作空间可达性验证
04 Stage 4:自适应数据飞轮(Data Flywheel)闭环探索
2026 年,VLA 的竞争焦点正在从"谁的模型更大"转向"谁的 pipeline 更顺"。
模型可以开源,权重可以下载,但数据流怎么组织、仿真场景怎么自动生成、数据飞轮怎么转起来?又该如何安全、高效、高保真地对这些动辄数亿甚至数十亿参数的泛化策略进行评估?
这些才是真正决定一个团队能不能持续产出成果的东西。
我们用 IsaacLab + LW-BenchHub 做仿真底座,以 PiPER 双臂仿真构型为载体,完整跑通了一个轻量化 VLA 模型从基线闭环、底层数据流解析,到 LLM 驱动场景生成与仿真数据飞轮原型探索的全流程。
每一层都是开源的、经过社区验证的、相互兼容的。
所以,本文记录的不是某个模型有多强,而是 pipeline 怎么搭、坑在哪、以及我们从中得到的真实判断。
本文全文近10000字,建议收藏分享~

01 Stage 1:跑通轻量化VLA模型的闭环仿真测试
硬件与软件环境规格
具身物理仿真对计算硬件以及图形渲染管线有着双重的严苛要求。
由于物理引擎和离屏相机渲染都在 GPU 上并行执行,我们的本地测试完全在一台无图形界面(Headless)的云服务器上展开。
具体的硬件与系统环境配置如下:
- 操作系统:Ubuntu 22.04 LTS (Kernel 6.2)
- 显卡与显存:NVIDIA A800-SXM4-40GB
- 显卡驱动:NVIDIA Server Driver 535.113.01(后升级至 580.159.03 以确保 GPU PhysX 稳定性)
- CUDA 版本:CUDA 11.8 (nvcc compilation tools release 11.8, V11.8.89)
- Conda 环境:专为项目建立的
lerobot-arena(Python 3.11.15) - 核心依赖约束:由于物理引擎的特殊绑定,整个 Python 环境中的
NumPy版本必须被严格、无条件地锁定在1.26.0。
受试任务、机器人与模型细节
在这一阶段的闭环评测中,我们选择了一套极具代表性的“厨房”操纵场景:
- 仿真场景与任务:
L90K1PutTheBlackBowlOnThePlate。
该任务源自 RoboCasa 厨房场景,要求机器人从凌乱的餐桌上,精准地抓取一只黑碗(akita_black_bowl)并将其平稳地放置到指定的盘子(plate)上。 - 机器人本体模型:
DoublePiper-Abs。
该仿真模型原型为松灵机器人 (Agilex)推出的双臂 Piper 机器人构型。在该环境下,我们采用绝对关节位置控制(Absolute Joint Position Control)。
其状态空间(Observation Space)为 16 维的关节位置,动作空间(Action Space)为 12 维(左臂5自由度 + 右臂5自由度 + 左右夹爪各1自由度,关节4被锁定跳过)。 - 受试 VLA 模型:
LightwheelAI/smolvla-double-piper-pnp。
这是一款参数量约为 300M 的轻量化 VLA 策略模型,其视觉主干基于 SmolVLM2 架构。它在 Lightwheel 专有的双臂 Piper 厨房操纵数据集上进行了微调。
在实际执行中,VLA 策略会根据当前左右手腕部相机及头部相机的实时渲染画面,闭环输出每一步的控制指令。

闭环仿真评测执行过程
要启动整个闭环评估,我们需要调用 lerobot-eval 命令行接口。
由于 LW-BenchHub 已经将底层的物理任务注册到了 Hugging Face 的统一环境接口(EnvHub)中,我们可以直接通过参数化配置来拉起这个复杂的双臂任务。
以下是我使用的黄金评测启动命令:
# 激活环境与系统变量
source /home/vipuser/miniconda3/etc/profile.d/conda.sh
conda activate lerobot-arena
source /mnt/robot/headless_env.sh
unset CUDA_VISIBLE_DEVICES # 关键:避免离屏渲染下显卡枚举导致的 Segfault
# 切换到 lw_benchhub 工作目录
cd /mnt/robot/lw_benchhub
# 执行闭环推理测试
lerobot-eval \
--policy.path=LightwheelAI/smolvla-double-piper-pnp \
--env.type=isaaclab_arena \
--env.hub_path=LightwheelAI/lw_benchhub_env \
--env.kwargs='{"config_path": "configs/envhub/example.yml"}' \
--rename_map='{"observation.images.left_hand_camera_rgb": "observation.images.left_hand", "observation.images.right_hand_camera_rgb": "observation.images.right_hand", "observation.images.first_person_camera_rgb": "observation.images.first_person"}' \
--trust_remote_code=true \
--env.state_keys=joint_pos \
--env.action_dim=12 \
--env.state_dim=16 \
--env.camera_keys=left_hand_camera_rgb,right_hand_camera_rgb,first_person_camera_rgb \
--env.enable_cameras=true \
--env.headless=true \
--env.video=true \
--env.video_length=200 \
--env.video_interval=1 \
--policy.device=cuda \
--eval.batch_size=1 \
--eval.n_episodes=10 \
--output_dir=/mnt/robot/eval_outputs_pathB_1
在这条命令中,--rename_map 承担了极其关键的桥梁作用。
它将底层环境渲染并输出的 left_hand_camera_rgb 等三路物理相机帧,自适应地重命名为策略模型期望输入的 observation.images.left_hand 规范键值,从而达成了数据流的闭合。
实践过程中的技术死锁与“踩坑”记录
在无 X11 图形界面的生产级服务器上部署具身大模型仿真,会遇到各种由于库版本漂移、C++ 扩展编译以及物理引擎严格限制导致的异常。
以下是我在 Stage 1 探索中梳理出的最典型的几个技术陷阱及对应的解决方案:
(1)“幽灵升级”的 NumPy 2.x 与 Isaac Sim 的 ABI 崩溃
在物理仿真中,NVIDIA Isaac Sim 5.1.0 内部的大量 C 扩展库在编译时强绑定了 numpy==1.26.0。
在安装其他 Python 依赖包(如用于机器人逆运动学解算的 pinocchio 库)时,pip 的依赖解析器会默认将 numpy 升级到 2.x 版本。
- 现象:升级后,一旦执行
import isaacsim进程就会立刻崩溃(Segmentation Fault),没有任何 Traceback 抛出。 - 解决方案:在任何
pip install操作之后,必须强制执行pip install --no-deps numpy==1.26.0进行版本回锁,并使用assert numpy.__version__ == "1.26.0"进行静态自检。
(2)cmeel `pin` 库中的 Casadi 绑定缺失与延迟故障(Lazy-Stub)设计
DoublePiper 机器人的配置文件在初始化时会默认构造 PiperPinocchioIK 实例。由于云服务器环境限制,直接使用 pip 安装的 pin==4.0.0 轮子并不包含 pinocchio.casadi 编译器绑定。
- 现象:由于底层缺少 Casadi,仿真在初始化导入机器人配置时就会直接报错中断。
- 解决方案:由于闭环模型评估时模型直接输出关节角度,我们其实并不需要真正的逆运动学(IK)实时解算。
因此我对lw_benchhub中的piper_ik.py进行了重构,采用了延迟故障(Lazy-Stub)设计:
将pinocchio与casadi的导入拆分到独立的try/except块中,如果缺失 Casadi,仅在实例上标记_is_stub = True,阻止其在初始化时崩溃;只有在实际调用solve_pose_to_joints()时才抛出异常。
同时,对reset()方法加入了 Stub 状态守卫。
(3)USD 场景图变换操作顺序不兼容问题
当 lightwheel-sdk 从云端加载高保真的 RoboCasa 厨房 USD 场景时,某些三维资产(如 table_front_group_1)在制作时使用了 [translate, rotateXYZ, scale] 的变换操作顺序。
然而,IsaacLab v2.3.2 对 XformPrimView 的初始化引入了强制性的 canonical 变换顺序校验(要求必须使用四元数 orient 形式)。
- 现象:仿真初始化抛出
ValueError: ... is not a xformable prim with standard transform operations。
因为这些 USD 资产是从只读的子图层中引用的,我们无法通过standardize_xform_ops()写入新的操作,直接导致加载死锁。 - 解决方案:我通过对
lw_benchhub中的monkey_patch.py写入了底层的 monkey-patch,重写了XformPrimView.__init__,强行设置validate_xform_ops = False跳过名字校验。
实践证明,下游的数据路径在通过GetLocalTransformation()获取局部空间变换时对操作顺序是自适应的,跳过校验完全不影响数据精度。
# 核心修复:重写 XformPrimView.__init__ 阻止 op 顺序校验死锁
_orig_init = XformPrimView.__init__
def _init(self, prim_path, device="cpu", validate_xform_ops=True, **kwargs):
return _orig_init(self, prim_path, device=device, validate_xform_ops=False, **kwargs)
XformPrimView.__init__ = _init
(4)CUDA_VISIBLE_DEVICES 与 EGL 渲染冲突
在云服务器环境下,离屏渲染必须通过 EGL 设备接口进行 GPU 硬件加速。
- 现象:如果系统或用户在环境变量中设置了
CUDA_VISIBLE_DEVICES,Isaac Sim 的内部物理显卡枚举机制就会与 Vulkan/EGL 的设备节点发生冲突,导致图像传感器初始化时直接发生 Segfault 闪退。 - 解决方案:在每次启动脚本前,必须在 shell 中显式执行
unset CUDA_VISIBLE_DEVICES。
阶段性实验结论
在排除上述所有软件栈冲突并成功部署 monkey-patch 之后,闭环仿真在 A800 服务器上实现了极其稳定的多回合串行评测。
在首批10 个 episodes的评测中,SmolVLA 策略成功完成了4 次完整的抓取与放置任务,录得40.0% 的闭环任务成功率(Task Success Rate)。
十回合评测的总耗时仅为10 分 39 秒,平均每个回合(包含物理仿真、三路相机 EGL 离屏像素渲染、VLA 神经网络前向推断以及动作下发)耗时约 64 秒。
这一基线数据的确立,充分验证了 LW-BenchHub 物理仿真底座在承载高维、多相机输入 VLA 模型闭环验证时的工程可行性与高效率。
02 Stage 1+:VLA 闭环数据流解密,从 RTX 渲染到关节 PD 驱动
在成功跑通 SmolVLA 的闭环仿真后,我认为,有必要深入探究其背后的底层交互机制。
对于具身智能策略而言,仿真环境与 VLA 模型之间的闭环交互绝对不是简单的“文本输入-文本输出”黑盒,而是一个涉及到高频图像渲染、本体状态估计、关节逆运动学(IK)或前向 PD 目标写入的严密控制系统。
在本节中,我将从仿真观测流(输入)与动作控制流(输出)两个维度,解密 VLA 模型如何与 LW-BenchHub 及 IsaacLab-Arena 的物理底座产生数据级交互。
闭环单步时序架构
在 lerobot 的评测主循环(rollout)中,每一个时间步(step)的执行都遵循着一套严格的同步阻塞流水线。
其数据流拓扑关系可以抽象为:
Policy Select Action (VLA 推理)
│
▼ action (torch.Tensor, shape=[1, 12])
+--------------------------------------------+
| lerobot Rollout (lerobot_eval.py) |
| Un-normalize -> convert to numpy |
+--------------------+-----------------------+
│ action_numpy (np.ndarray, shape=[1, 12])
▼
+--------------------------------------------+
| IsaacLabEnvWrapper.step() |
| CPU numpy -> GPU torch tensor |
+--------------------+-----------------------+
│ action_tensor (GPU, shape=[1, 12])
▼
+--------------------------------------------+
| ManagerBasedRLEnv.step() (IsaacLab 物理推进) |
| 1. ActionManager: Slice & Scale actions |
| 2. Decimation Loop (4x PhysX sub-steps): |
| - write joint targets (PD Controller) |
| - sim.step() & sim.render() (RTX) |
| 3. ObservationManager: Compute raw obs |
+--------------------+-----------------------+
│ raw obs dict (GPU, camera_obs & policy)
▼
+--------------------------------------------+
| preprocess_observation & RenameObs |
| Rename and normalize: [0, 255] -> [0, 1] |
+--------------------------------------------+
│
▼ observation dict (VLA inputs)
(循环回到 Policy Select Action 阶段)
下面我将针对输入(观测)与输出(控制)两个方向的具体实现进行深度剖析。
观测路径:从 GPU RTX 像素到 VLA 多模态输入
VLA 模型在前向推断时,需要同时接收当前的机器人状态(Proprioception)和多路视觉相机图像。
这些数据是如何从三维物理世界流入模型张量的?
(1)RTX 离屏像素渲染
在机器人本体定义文件(double_piper.py)中,预先为 DoublePiper-Abs 机器人注册了 3 路仿真相机。
这些相机的路径(prim_path)直接绑定在机器人的物理刚体(Links)上:
# 摘自 double_piper.py 的相机配置片段
self.observation_cameras: dict = {
"left_hand_camera": {
"camera_cfg": TiledCameraCfg(
prim_path="{ENV_REGEX_NS}/Robot/piper_L/hand_link_l/left_hand_camera", # 左手腕相机
data_types=["rgb"],
width=224, height=224, update_period=0.05,
),
},
"right_hand_camera": {
"camera_cfg": TiledCameraCfg(
prim_path="{ENV_REGEX_NS}/Robot/piper_R/hand_link_r/right_hand_camera", # 右手腕相机
data_types=["rgb"],
width=224, height=224, update_period=0.05,
),
},
"first_person_camera": {
"camera_cfg": TiledCameraCfg(
prim_path="{ENV_REGEX_NS}/Robot/piper_R/dummy_link/first_person_camera", # 头部视角
data_types=["rgb"],
width=224, height=224, update_period=0.05,
),
}
}
在每个物理子步(sub-step)推进时,NVIDIA Isaac Sim 的RTX 光线追踪渲染器在后台对这些 TiledCamera 传感器进行渲染。
由于这些数据在 GPU 显存中直接以张量(Tensor)形式产出,整个图像传输过程实现了零 CPU-GPU 拷贝。
(2)命名空间重组(Observation Re-alignment)
Hugging Face 的 lerobot 框架对输入数据的字典键有着严格的命名规范,它期望在 camera_obs 下看到图像输入,在 policy 下看到关节位置。
然而,IsaacLab 的原生输出并不匹配该结构。
为了对齐接口,在 envhub_utils.py 中通过 _reorg_observation_for_envhub 接口对 IsaacLab 导出的观测配置进行了静默重命名与重组:
# 摘自 envhub_utils.py 的观测配置对齐逻辑
embodiment_general_obs = env_cfg.observations.embodiment_general_obs # 关节状态等
policy_obs = env_cfg.observations.policy # 原始相机帧
setattr(env_cfg.observations, "policy", embodiment_general_obs) # 映射至 policy
setattr(env_cfg.observations, "camera_obs", policy_obs) # 映射至 camera_obs
(3)评估端对齐与图像预处理
当 wrapped_env.step() 返回底层的 GPU 张量时,lerobot 会在主循环中依次触发 preprocess_observation(位于 lerobot/envs/utils.py)以及重命名处理器 RenameObservationsProcessorStep。
根据我们在评估命令行中传入的 --rename_map,三路原始相机帧键名会被动态对齐至 SmolVLA 模型内部 config.json 强约束的特征输入键:
最后,SmolVLA 的处理器(`processor_smolvla.py`)会将输入像素值从 范围归一化至
(或根据模型预训练分布进行均值‑标准差标准化);
并执行图像缩放(从渲染的 224x224 像素插值到模型预期的 480x640 像素);
最后将 HWC 格式重排为模型期望的通道优先(CHW)格式,正式送入 VLA 多模态计算图。
动作路径:从 VLA 12维绝对输出到 PhysX PD 控制器
VLA 模型前向推理后,会为机器人输出一个动作张量。
那么,这 12 维的动作是如何映射到双臂 Piper 的机械关节,并改变仿真物理状态的?
(1)12维动作的物理切片(DoublePiper-Abs 构型)
双臂 Piper 机器人实际上包含 16 维的关节状态(每侧手臂有 6 个自由度,外加 2 个联动夹爪关节),但在动作空间上,模型只输出 12 维的控制向量。
这 12 维动作的物理分配机制如下:

关键技术细节:细心的朋友可能会发现,这其中跳过了双臂的 joint4。
这是因为 Piper 机械臂的第四关节属于非控制的被动联动关节(或通过内部物理约束进行了联动 mimic)。ActionManager 在查找关节时会自动将其过滤掉,动作分配极为紧凑。
当 12 维动作向量 action_numpy 传入环境接口时,IsaacLab 的 ActionManager 会依据各动作条目(Terms)的优先级,对这 12 维动作进行解包,并将其恢复为带有物理量纲的实际目标关节角:
# 动作恢复机制的数学实质
processed_actions = raw_actions * scale + offset
由于我们在 yml 场景中设置了 use_default_offset: True,这里的 offset 即为机器人的默认初始姿态(Home Pose)。
这意味着:VLA 模型输出的关节动作,其数值实质上是相对于默认初始关节角度的差分绝对量。
动作经过缩放恢复后,JointPositionAction.apply_actions 会直接调用物理引擎接口:
# 将动作写入底层仿真
self._asset.set_joint_position_target(self.processed_actions, joint_ids=self._joint_ids)
在向底层刚体写入关节 PD 目标位置后,物理底座开始推进。我们在配置文件中设置了评测时钟周期为 step_hz = 50(对应控制步长 )。
物理底座并不只向前推进一次。
在 ManagerBasedRLEnv.step() 内部,系统会执行一个消分循环(Decimation Loop):
# 物理消分循环
for _ in range(self.cfg.decimation): # decimation = 4
self.action_manager.apply_action() # 写关节 PD 目标
self.sim.step(render=False) # PhysX 刚体解算,单步 5ms
if render_interval_matched:
self.sim.render() # 触发离屏相机传感器渲染
self.scene.update()
在该消分循环中,每步控制被拆分为4 次更细颗粒度的物理推进(每子步 ,由 PhysX 刚体解算器独立推进并处理关节限位、力矩以及摩擦力)。
在此期间,相机按需在 GPU 中重新渲染像素,直至一回合物理时间结束,生成新的 obs_buf(观测),等待下一个控制循环。
通过这套基于 GPU 内存同步和自适应动作分发的物理设计,LW-BenchHub 成功将繁复的具身机器人物理特性抽象为极简且规范的 Python 接口,使 SmolVLA 这类端到端模型能够在一套统一的 API 框架下,源源不断地完成感知与控制的深度闭环。
03 Stage 2:LLM 驱动的场景自适应生成与工作空间可达性验证
在 Stage 1 阶段,我们在固定的预设厨房任务下完成了基线测试。然而,具身通用大模型的终极目标是泛化。
为了评估模型对场景多样性、物体随机摆放以及新型空间布局的鲁棒性,在 Stage 2 中,我引入了光轮科技的场景自适应生成管线。
这一阶段的开发工作,完全是在一台无头(Headless)云服务器上,通过Claude Code AI Agent协作完成的。
在这一过程中,LLM 被用作高级规划器来生成场景配置,而 cuRobo(NVIDIA GPU 加速运动规划器)则作为仿真底座内的运动学“守门员”,共同构建了一套“场景生成-可达性过滤-闭环评估”的自动化数据链。
自动化自适应生成管线
Stage 2 的核心逻辑是通过大语言模型(LLM)在合法的物理规则约束下,随机裂变出多个全新的场景配置(YML)。
为了防止 LLM 凭空幻觉出仿真器不支持的布局,我们采用以下双层闭环管线:
- LLM 布局生成:
我将基础场景 example.yml 的 Schema 结构以及从本地 layout_task_mapping.csv 中提取的合法任务对(如 DoublePiper-Abs 机器人所支持的 libero 厨房布局与任务配对)作为 Prompt 输入。
LLM(基于 DeepSeek-API)在规则限制的合法空间内,改写种子(Seed)、任务类型(Task)以及场景布局(Layout),批量生成 3 套候选 YML 场景文件。
- 工作空间可达性闸门(Reachability Gate):
生成的 YML 场景并不立即进入闭环评测。由于物体的随机放置可能超出了双臂 Piper 的物理极限,Claude Code 协助笔者编写了场景级可达性验证器 validate_scene_objects_reach_v5.py。
验证器在后台静默拉起 lw_benchhub环境,调用 env.reset(),读取黑碗、盘子等目标物体在当前种子下真实的 PhysX 世界坐标,并变换至机器人左右臂的基座(base_link)坐标系。
随后,通过 cuRobo 的 IKSolver 求解逆运动学。只有当双臂对场景中核心操纵物体的可达率(reach_ratio)大于 50% 时,该场景才被判定为“物理可达”,允许输出为正式的测试场景。
以下是触发这一一键式自适应场景生成与可达性验证的命令:
# 激活 cuRobo 专用环境并调用生成器
source /home/vipuser/miniconda3/etc/profile.d/conda.sh
conda activate lerobot-arena
source /mnt/robot/headless_env.sh
source /mnt/robot/lerobot_arena_curobo_env.sh
source /mnt/robot/llm_env.sh
unset CUDA_VISIBLE_DEVICES
# 执行生成与 live IK 验证
python /mnt/robot/generate_scenes_with_live_reach.py
在通过可达性闸门后,系统会自动调用 run_stage2_all.sh 串行驱动 SmolVLA 在这些全新场景下执行 22 秒(1100 帧)的完整闭环控制并录制视频。

协作局限性与技术踩坑
由于本阶段完全由 Claude Code AI Agent 在无 GUI 的云端服务器上独立编排并调试,这种“Headless + Agent”的开发模式极大地考验了自动化脚本与错误捕获机制的严密性,同时也暴露出了一些环境局限:
- 无图形界面(Headless)调试的天然屏障
在开发可达性验证器时,由于无法通过 Isaac Sim 的 GUI 窗口直观查看机械臂的关节限位或物体碰撞情况,Claude Code 只能完全依赖于高度结构化的日志信息(如 JSON 报告)、提取的仿真单帧图像以及评测指标文件。
为此,本项目编写了独立的 verify_stage2.py 脚本,用于从无头控制台日志中通过正则表达式强行反推并格式化 SmolVLA 的闭环表现,这种“数据盲检”机制使得每一步的物理量化精度都必须极其精准。
- 跨库环境下的 Warp 冲突与 ABI 崩溃(最大技术瓶颈)
为了在同一个 lerobot-arena 环境下同时拉起 IsaacLab 环境和 cuRobo 运动学求解器,我们遭遇了底层 warp 库的严重 ABI 冲突。
问题:
仿真器启动时会隐式加载 isaacsim 绑定的 omni.warp.core。而 cuRobo 又会从 PyPI 依赖中拉取最新版的 warp-lang(通常为 1.14.0)。
由于 1.14.0 删除了旧版本中关键的 warp.types.array 接口,这直接导致 Isaac Sim 在初始化相机渲染时因找不到符号而发生 Segmentation Fault 闪退。
修复:
Claude Code 协助分析了依赖版本树,通过强制将外侧 warp-lang 版本降级并锁死至兼容的 1.8.1,同时在安装后再次回锁 numpy==1.26.0,最终实现了 cuRobo 与物理仿真在同一 Python 进程中的和平共存。
- 资产加载时的云端网络挂起
在 Headless 环境下,lightwheel-sdk 首次加载特定 YML 场景的 USD 资产时需要高频访问 api.lightwheel.net。
问题:
云端网络偶发抖动会导致 USD 加载无限期挂起(曾出现单进程卡死 58 分钟无进展的记录),由于没有前台交互,这类挂起极易烧毁云端算力。
修复:
我在调度程序中引入了 Hang-Killer 守护进程:
通过实时检索输出日志中 scene retry 的行数以及进程 CPU 活跃时间,一旦检测到无响应超过 5 分钟,立即通过 pkill -9 强行击杀物理引擎进程并触发重试/禁用该场景机制,确保了自动化流转的自愈性。
04 Stage 4:自适应数据飞轮(Data Flywheel)闭环探索
在具身智能的工业落地流程中,数据是一切泛化能力的基石。然而,完全依赖人类手工采集示教数据(Demonstration)的成本极高,且难以覆盖无穷无尽的分布外(OOD)边缘场景。
因此,构建一套能够在仿真环境中自动发现失败、自适应退让生成渐进难度(Curriculum)场景、并自主收集成功示教轨迹的“数据自生长飞轮”,是实现具身大模型自我进化的必经之路。
在 Stage 4 中,我在 Headless A800 服务器上,针对双臂 Piper 的厨房抓取任务(L90K1PutTheBlackBowlOnThePlate),进行了一次完整的数据飞轮闭轮链路探索。
数据飞轮闭环的整体架构
我们设计的自适应数据飞轮主要包含以下四个核心循环节点:
1. OOD 困难场景部署 (Spawn Hard Scene)
(通过 Seed 搜索,将黑碗置于机械臂抓取范围的边缘界限)
│
▼ SmolVLA 闭环评估:录得 0% 成功率
2. 诊断器介入 (Failure Diagnosis)
(读取坐标、关节力和指标,判定为工作空间边缘引发的 reach-failure)
│
▼ 调用 DeepSeek-v4-pro 模型 (API 级防降级校验)
3. 渐进式难度场景生成 (Curriculum Generation)
(自适应生成 Y 轴向机器人基座方向退让 10cm/22cm 的 Easy/Medium 场景)
│
▼ 物理可达性校验通过
4. 成功轨迹自适应生成与过滤 (Trajectory Self-Filtering)
(策略网络闭环驱动自蒸馏 + 终态物理验证过滤 -> 导出 LeRobotDataset)

自生长飞轮打造的 HDF5/LeRobotDataset 数据集文件夹目录结构:
.
├── policy_demos_v3_lerobot
│ ├── data
│ │ └── chunk-000
│ │ ├── file-000.parquet
│ │ ├── file-001.parquet
......
│ │ └── file-009.parquet
│ ├── images
│ │ ├── observation.images.first_person
│ │ ├── observation.images.left_hand
│ │ └── observation.images.right_hand
│ └── meta
│ ├── episodes
│ │ └── chunk-000
│ │ └── file-000.parquet
│ ├── info.json
│ ├── stats.json
│ └── tasks.parquet
├── policy_demos_v3_manifest.json
└── raw
└── original
├── episode_0_summary.json
├── episode_10.h5
├── episode_10_summary.json
......
├── episode_8_summary.json
├── episode_9.h5
└── episode_9_summary.json
数据飞轮闭环的本地实现过程
- 步骤 1:OOD 困难场景构建(Seed-Sweep)
由于 lw_benchhub 中的黑碗是通过场景 seed 随机采样的,没有直接的 YML 位姿修改入口。
为了制造一个纯粹的 OOD 困难场景,我编写了 probe_bowl_seed.py。该脚本通过遍历 64 组随机种子并启动仿真,量化黑碗相对于机器人基座的距离,最终选出将黑碗推至工作空间最远边缘的种子(seed 48),将其写入 hard_scene.yml。
在这一 OOD 场景下,SmolVLA 模型进行闭环评测时毫无悬念地录得了0% 的任务成功率,成功触发了数据飞轮的诊断流。
- 步骤 2:API 级防降级检验下的 DeepSeek-v4-pro 诊断与场景分裂
当检测到成功率为 0% 且仿真非正常退出时,诊断器自动分析原因。
为了确保辅助生成场景布局的 LLM 始终保持最高物理推理水平,我们使用标准库 urllib 构造了严格契合Anthropic Messages协议的调用链,直连deepseek-v4-pro官方端点,并设置了响应模型回读校验。
DeepSeek-v4-pro 根据诊断报告(reach-failure 状态)和 Hard 场景物体的初始位姿,通过 Y 轴等长回归(Easy 梯度朝机器人方向拉回 10cm,Medium 梯度拉回 22cm),输出格式严密的 JSON 覆盖参数。
之后,脚本自动通过光轮底座的 fix_object_pose_cfg 补丁(我们在 context.py、env.py 和 base.py 中注入了 4 处无害的配置暴露,用于在 YML 中直接锁死特定物体的初始化位姿),生成了 easy_curriculum.yml 和 medium_curriculum.yml:
# 自动生成的 easy_curriculum.yml 片段
fix_object_pose_cfg:
akita_black_bowl:
pos: [2.45, -2.03, 0.81] # 由 Hard 场景的 -2.13m 精准向机器人方向退让 10cm
示教数据生成的探索与“放弃 cuRobo”的工程复盘
为了在这个渐进难度的课程场景中自动采集成功的示教轨迹,我们进行了极为艰难的工程探索。
(1)尝试 :基于 Scripted cuRobo 运动规划的数据生成(失败)
最初,我们尝试完全依赖 cuRobo 运动规划器和 Pinocchio 逆动力学来自动计算成功的抓取轨迹。为此,我们甚至克服了双臂 URDF 缺失的困难,手写脚本确定性合成了 double_piper_description.urdf。
但在真机仿真测试中,我们遭遇了严重的物理不一致性:
- 碰撞体免疫:
由于 cuRobo 默认的机器人配置文件将夹爪碰撞球(Collision Spheres)留空,物理引擎中真实的夹爪在向黑碗接近(reach)时,cuRobo 无法计算手指的几何避障。 - “推碗”惨剧:
这导致机械臂在执行准静态运动轨迹时,在 PhysX 中直接拦腰撞上黑碗,将黑碗横向推开了 11cm。
当随后的grasp技能闭合时,夹爪只能在空无一物的空气中捏合,导致 100% 的抓取失败(TASK_SUCCESS=False)。 - cuRobo 累积器崩塌:
为了解决碰撞,我们尝试引入分段直线下降(descend)规划。然而,在同一个进程内连续多次调用plan_batch会触发 cuRobo 内部累积器的shape mismatch内存崩塌 Bug,直接导致后续lift技能发生 Python 级别崩溃。
(2)方案转向:SmolVLA 闭环自滤波数据生成(自蒸馏)
面对 scripted 运动规划器不可逾越的动态执行障碍,我决定转变思维:
既然 SmolVLA 本身在 Baseline 场景下有 40% 的闭环成功率,我们为什么不让 SmolVLA 作为 Demonstrator,并在末端通过物理成功检测进行“自清洗”过滤?
我们在 generate_policy_demos.py 中完全解构了 lerobot-eval 的 step 循环,手动在每次 env.step 之前记录当前的 16 维关节状态(Proprioception)、12 维绝对动作以及三路 RGB 相机帧。
在 Episode 结束时,我们不再相信运动规划器“跑完技能就等于成功”,而是直接调用环境最底层的任务成功状态检测:
# 数据飞轮自过滤的核心判定
raw_env = wrapped_env._env
success_tensor = raw_env.cfg.isaaclab_arena_env.task.check_success_caller(raw_env)
task_success = last_terminated # 依赖 step 循环中捕获的、未被 auto-reset 污染的成功标志
只有当 task_success == True 时,这一整条高价值轨迹才会被打包序列化写入 policy_demos_v3/raw/ 目录下,并最终通过 build_policy_demos_dataset.py 导出为标准格式的 LeRobotDataset。
这一路线最终可以跑通闭环流程,在 A800 独占运行下,系统通过 29 次闭环评测,自动清洗并保留了 10 个 100% 成功的黄金 Episode,共计 6527 帧高画质图像数据。
自蒸馏在 VLA 训练逻辑上的本质问题
虽然方案三(SmolVLA 自滤波)让我们在工程上顺利拿到了 1.5 GB 的高品质、零黑帧数据集。
但从具身大模型的算法训练逻辑来看,这种“自蒸馏(Self-Distillation)”存在着致命的边界限制:
- 泛化边界无法自主扩张:
自滤波生成的成功轨迹,其数据分布(Data Distribution)本质上被严格限制在模型已有的、处于基线分布内的 40% 成功包络线内部。
在大模型完全不会做的 Medium(成功率 0%)和 Hard 课程场景下,由于策略网络永远无法输出任何一次成功的动作,自滤波机制只能产生 100% 丢弃的失败尝试,飞轮在 OOD 区域陷入了死锁。
要真正让飞轮“滚起来”并扩张模型的泛化边界,我们必须拥有一个能够解决 OOD 物理轨迹的外部规划器,如调优完备的 cuRobo 避障规划器,或者通过人类遥操作(Teleoperation)在仿真中强行写入高难度的成功轨迹。
否则,自蒸馏只会反复强化模型已有的行为,无法产生任何新的泛化特征。
协作环境局限性与 Stage 4 最终结论
在整个 Stage 4 任务的攻坚过程中,由于无图形界面服务器的天然屏障,我们完全无法引入任何有人工即时观察参与的示教轨迹生成调试,更无法在仿真环境中使用遥操作设备(如手柄、示教器)进行人工交互式轨迹补偿。
Claude Code 只能像一个“盲人”程序员一样,通过接触力传感器数值(net_contact_forces)、三维距离矩阵(bowl-plate dist)以及后期导出的 MP4 视频帧来推测碰撞发生的时间和空间偏置。
这种高度依赖遥测指标的开发模式,极大地拉长了运动学调试的迭代周期。

尽管由于物理世界限制与算法自蒸馏瓶颈,我们在数据飞轮的某些关键节点上(例如高难度 OOD 轨迹的生成、复杂的双臂物理碰撞规避),仍然强烈地依赖着人工代码级别的介入与调参,无法做到 100% 纯自主的无干预运转;
但是,这套在 LW-BenchHub 上跑通的“困难场景构建 - LLM 渐进课程裂变 - 策略闭环运行 - 终态自清洗 - 规范化数据集导出”完整闭环管线,依然在工程上验证了数据飞轮的理论可行性。
它表明,只要配合鲁棒的物理规划器或遥操作接口,大规模具身智能数据的自主低成本采集、评估与数据自生长将不再遥不可及。我们距离实现“数据驱动、自主进化”的终极具身智能,又向前迈出了扎实的一大步。
不过,这也带来一个思考:
2026 年的 VLA 竞争,模型还是主角吗?
本项目已开源:https://github.com/GimpelZhang/lw_benchhub_tour
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)