“VLA 不死,只是进化”—— 2026 年具身智能领域的年度标语?

——谈一个具体问题

目录

01    Stage 1:跑通轻量化VLA模型的闭环仿真测试

硬件与软件环境规格

受试任务、机器人与模型细节

闭环仿真评测执行过程

实践过程中的技术死锁与“踩坑”记录

阶段性实验结论

02    Stage 1+:VLA 闭环数据流解密,从 RTX 渲染到关节 PD 驱动

闭环单步时序架构

观测路径:从 GPU RTX 像素到 VLA 多模态输入

动作路径:从 VLA 12维绝对输出到 PhysX PD 控制器

03    Stage 2:LLM 驱动的场景自适应生成与工作空间可达性验证

自动化自适应生成管线

协作局限性与技术踩坑

04    Stage 4:自适应数据飞轮(Data Flywheel)闭环探索

数据飞轮闭环的整体架构

数据飞轮闭环的本地实现过程

示教数据生成的探索与“放弃 cuRobo”的工程复盘

自蒸馏在 VLA 训练逻辑上的本质问题

协作环境局限性与 Stage 4 最终结论


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)设计:
    pinocchiocasadi 的导入拆分到独立的 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 强约束的特征输入键:

$\text{observation.images.left\_hand\_camera\_rgb} \longrightarrow \text{observation.images.left\_hand}$
$\text{observation.images.right\_hand\_camera\_rgb} \longrightarrow \text{observation.images.right\_hand}$
$\text{observation.images.first\_person\_camera\_rgb} \longrightarrow \text{observation.images.first\_person}$

最后,SmolVLA 的处理器(`processor_smolvla.py`)会将输入像素值从 $[0, 255]$ 范围归一化至 $[0, 1]$(或根据模型预训练分布进行均值‑标准差标准化);

并执行图像缩放(从渲染的 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(对应控制步长 $dt = 0.02\,\mathrm{s}$)。

物理底座并不只向前推进一次。

在 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 次更细颗粒度的物理推进(每子步$5\,\mathrm{ms}$ ,由 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

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐