NERO 双臂03:《Dual NERO 仿真 Embodiment 与数据标准【仅仿真|16D State + 14D Action + 三相机 + LeRobotDataset v3】》

📅 2026/8/27 8:27:50
NERO 双臂03:《Dual NERO 仿真 Embodiment 与数据标准【仅仿真|16D State + 14D Action + 三相机 + LeRobotDataset v3】》
卷文章标题当前是否可做真机依赖核心性质第1卷《NERO 双臂仿真优先具身智能总体方案【无真机 + Isaac Lab + RLinf + π0.5 + DreamZero|总体架构与工程基线】》是无总体架构第2卷《Dual NERO Isaac Lab 纯仿真环境完整搭建【仅仿真|URDF/Xacro→USD + 双 Articulation + 三相机 + Handover Task】》是无纯 Isaac Lab第3卷《Dual NERO 仿真 Embodiment 与数据标准【仅仿真|16D State + 14D Action + 三相机 + LeRobotDataset v3】》是无纯仿真数据/Contract第4卷《开源 π0.5 / DreamZero 权重直接驱动 Dual NERO【仅仿真|Isaac Lab Frozen Inference + Policy Server + Baseline Evaluation】》是无开源权重直接仿真,不训练第5卷《RLinf + Isaac Lab + π0.5 双 NERO 仿真训练【纯仿真|SFT + PPO + Reward + Checkpoint + Evaluation】》是无π0.5 SFT + 仿真 RL第6卷《RLinf + DreamZero 5B 双 NERO 仿真训练【纯仿真|WAM Embodiment + Metadata + SFT + π0.5 Benchmark】》是无DreamZero 仿真训练第7卷《Dual NERO 真机后接入方案【真机|双 CAN + pyAgxArm + ROS2 + MoveIt2 + 标定 + Safety + Policy Deployment】》真机到位后需要真机基础设施与部署第8卷《Dual NERO Sim-to-Real 学习闭环【真机 + Isaac Lab + RLinf|Real Data + HG-DAgger + Domain Randomization + Co-Training】》真机到位后需要真机数据飞轮 / Sim-to-RealDual NERO 仿真 Embodiment 与数据标准【仅仿真|16D State + 14D Action + 三相机 + LeRobotDataset v3】文档版本:2026-08-25所属系列:NERO 双臂仿真优先具身智能闭环文档属性:第 3 卷 / 仿真 Embodiment 与数据标准当前硬件:RTX 6000 PRO 96GB当前机器人:Dual NERO Isaac Lab Digital Twin真机要求:无RLinf 要求:本卷不要求进行 RLinf 训练π0.5 / DreamZero:本卷不训练模型前置条件:第 2 卷全部核心 Gate 已通过最终目标:建立可被 π0.5、DreamZero、RLinf 和未来真机共同复用的本体契约(Embodiment Contract)与标准LeRobotDataset v3仿真数据链第1章 本卷目标与工程边界1.1 本卷解决什么问题步骤属性:非操作步骤(方案/知识点)。第 2 卷解决的是:(\boxed{\text{Dual NERO Simulation Works}})也就是:NERO USD 可以加载;两个 NERO关节系统(Articulation)稳定;左右夹爪正常;三相机正常;Differential IK 正常;Handover Scene 正常;Scripted Handover 可以稳定执行。但机器人“能动”还不能直接用于 π0.5 或 DreamZero 训练。模型还需要明确知道:什么是 State?什么是 Action?左臂和右臂按照什么顺序排列?Camera 按什么顺序进入模型?一个数据 Frame 到底对应哪个时间点?Action 是绝对 Joint Target,还是 Cartesian Delta?Gripper 的 0 和 1 分别是什么意思?图像是 RGB 还是 RGBA?一个 Episode 怎样开始和结束?怎样保存成 LeRobotDataset v3?怎样验证录下来的数据真的可以 Replay?本卷就是把这些问题全部固定下来。1.2 本卷最终建立的系统步骤属性:非操作步骤(最终架构)。本卷完成后,数据链应该变成:Isaac Lab │ ├── Base RGB ├── Left Wrist RGB ├── Right Wrist RGB ├── Left Joint State ├── Left Gripper ├── Right Joint State ├── Right Gripper ├── EEF Pose └── Scripted Action │ ▼ Embodiment Adapter │ ┌────┴────┐ ▼ ▼ State[16] Action[14] │ │ └────┬────┘ ▼ Canonical Recorder │ ▼ LeRobotDataset v3 │ ┌─────┴─────┐ ▼ ▼ Replay Statistics │ ▼ D_sim最终:(\boxed{D_{sim}\rightarrow\text{π0.5 / DreamZero / RLinf}})1.3 本卷不做什么步骤属性:非操作步骤(边界说明)。本卷不进行:π0.5 SFT;PPO;DreamZero SFT;RLinf Reward Training;真机数据采集;CAN;ROS2;MoveIt2;真机 Camera Calibration;Sim-to-Real;HG-DAgger。但是本卷生成的数据必须为这些后续工作做好准备。第2章 前置条件检查2.1 第2卷必须通过步骤属性:需要操作的步骤。进入本卷前确认:Isaac Sim 5.1.0 PASS Isaac Lab PASS Single NERO USD PASS Dual NERO PASS Left Gripper PASS Right Gripper PASS Global Camera PASS Left Wrist Camera PASS Right Wrist Camera PASS Left Differential IK PASS Right Differential IK PASS Scripted Handover PASS尤其建议达到:(10/10)固定条件 Scripted Handover Success。如果这一项没有达到,不要开始大规模采集训练数据。2.2 检查项目目录步骤属性:需要操作的步骤。操作位置:~/robot_stack/nero_dual_closed_loop执行:cd~/robot_stack/nero_dual_closed_loop tree-L3至少应存在:embodiment/ dataset/ isaac/ evaluation/以及第 2 卷建立的:isaac/ ├── assets/ ├── configs/ ├── scripts/ ├── tasks/ └── docs/第3章 建立本卷代码目录3.1 创建 Embodiment 文件步骤属性:需要操作的步骤。操作位置:~/robot_stack/nero_dual_closed_loop/embodiment执行:cd~/robot_stack/nero_dual_closed_loop/embodimenttouch__init__.pytouchschema.pytouchstate_codec.pytouchaction_codec.pytouchcamera_mapping.pytouchtiming.pytouchvalidation.py最终:embodiment/ ├── __init__.py ├── CONTRACT.md ├── schema.py ├── state_codec.py ├── action_codec.py ├── camera_mapping.py ├── timing.py └── validation.py3.2 创建 Dataset 文件步骤属性:需要操作的步骤。操作位置:~/robot_stack/nero_dual_closed_loop/dataset执行:cd~/robot_stack/nero_dual_closed_loop/datasettouch__init__.pytouchfeatures.pytouchrecorder_lerobot_v3.pytouchcollect_scripted_sim.pytouchinspect_dataset.pytouchvalidate_dataset.pytouchvalidate_sync.pytouchreplay_sim_episode.pytouchcompute_contract_stats.pytouchconvert_nero_dual_hdf5_to_lerobot_v3.py再建立:mkdir-prawmkdir-pcalibrationmkdir-psimmkdir-preportsmkdir-pdebug第4章 为什么必须建立 Embodiment Contract4.1 Embodiment 不是 URDF步骤属性:非操作步骤(重要知识点)。URDF 只告诉系统:Link;Joint;Geometry;Inertia;Collision。而本体契约(Embodiment Contract)告诉机器人学习模型:State 是什么;Action 是什么;Camera 是什么;左右顺序是什么;数值单位是什么;Coordinate Frame 是什么;Gripper 如何表示;时间频率是什么。因此:(\boxed{\text{URDF}\neq\text{Embodiment Contract}})4.2 Contract 一旦正式产生数据就不能随意修改步骤属性:非操作步骤(工程原则)。例如已经采集:nero_dual_handover_sim_v001之后突然把:action[0]从:left_delta_x改成:right_delta_x整个 Dataset 就失去统一语义。因此需要对 Contract 本身版本化。第5章 建立 Contract Version5.1 在schema.py固定版本步骤属性:需要操作的步骤。操作文件:~/robot_stack/nero_dual_closed_loop/embodiment/schema.py写入:CONTRACT_VERSION="nero_dual_cartesian_v1"STATE_DIM=16ACTION_DIM=14CAMERA_ORDER=("base","wrist_left","wrist_right",)PHYSICS_HZ=120POLICY_HZ=15DECIMATION=85.2 为什么需要 Contract Version步骤属性:非操作步骤(知识点)。以后如果真的要修改:Rotation Representation Action Frame Gripper Semantics Camera Order不要偷偷覆盖 V1。应该创建:nero_dual_cartesian_v2这样旧 Dataset 仍然可追踪。第6章 16D State 总体定义6.1 State Contract步骤属性:非操作步骤(核心 Contract)。统一:(s_t=[q_{L1},q_{L2},q_{L3},q_{L4},q_{L5},q_{L6},q_{L7},g_L,q_{R1},q_{R2},q_{R3},q_{R4},q_{R5},q_{R6},q_{R7},g_R])因此:(\boxed{\dim(s_t)=16})6.2 State 单位步骤属性:非操作步骤(核心 Contract)。关节:joint position → rad夹爪:dimensionless range [0,1]最终 State 不直接保存夹爪的原始米制 Width。原始 Width 另存 Auxiliary Field。第7章 State 永久索引7.1 固定 State Index步骤属性:需要操作的步骤。操作文件:embodiment/schema.py加入:STATE_NAMES=("left_joint_1","left_joint_2","left_joint_3","left_joint_4","left_joint_5","left_joint_6","left_joint_7","left_gripper","right_joint_1","right_joint_2","right_joint_3","right_joint_4","right_joint_5","right_joint_6","right_joint_7","right_gripper",)因此永久:0..6 Left Joints 7 Left Gripper 8..14 Right Joints 15 Right Gripper第8章 不能依赖 Isaac Joint Index8.1 为什么不能直接写joint_pos[:, :7]步骤属性:非操作步骤(重要知识点)。Isaac Articulation 内部的 Joint Index 由加载后的 Asset 决定。如果未来:URDF Import;Mimic;Fixed Joint;Gripper;发生变化,Joint Index 可能变化。因此:Model Contract 的顺序必须由 Joint Name 决定,不能由 Isaac 内部 Index 决定。8.2 按名称查找 Joint步骤属性:需要操作的步骤。从第 2 卷实际 Joint Names 找:joint1 joint2 ... joint7 gripper推荐建立:ARM_JOINT_NAMES=("joint1","joint2","joint3","joint4","joint5","joint6","joint7",)GRIPPER_JOINT_NAME="gripper"然后通过:robot.find_joints(...)建立 ID Mapping。第9章 建立 State Codec9.1 创建 State Encoder步骤属性:需要操作的步骤。操作文件:embodiment/state_codec.py核心职责:Isaac Joint State ↓ Name Mapping ↓ Gripper Conversion ↓ float32[16]9.2 推荐接口步骤属性:需要操作的步骤。定义类似:defpack_state(left_joint_pos,left_gripper_width,right_joint_pos,right_gripper_width,):...返回:np.ndarray dtype=float32 shape=(16,)第10章 Gripper State 规范10.1 模型 Gripper 定义步骤属性:非操作步骤(核心 Contract)。永久固定:g = 0 → open g = 1 → close10.2 Isaac NERO Gripper 原始范围步骤属性:非操作步骤(知识点)。第 2 卷已经确认 AgileX NERO 主 Gripper Joint 原始范围大致为:(w\in[0,0.1]\text{ m})其中:0.10 m → open 0.00 m → closed10.3 Width → Model State步骤属性:需要操作的步骤。统一转换:(g=1-\operatorname{clip}\left(\frac{w}{0.1},0,1\right))因此:width = 0.10 → g = 0 width = 0.00 → g = 1第11章 验证 State Codec11.1 创建单元测试步骤属性:需要操作的步骤。在:embodiment/validation.py检查:assertstate.shape==(16,)assertstate.dtype==np.float32assertnp.isfinite(state).all()并检查:assert0.0=state[7]=1.0assert0.0=state[15]=1.0第12章 14D Action 总体定义12.1 Action Contract步骤属性:非操作步骤(核心 Contract)。统一:(a_t=[a_tL,a_tR])其中左臂:(a_t^L=[\Delta x_L,\Delta y_L,\Delta z_L,\Delta r_{xL},\Delta r_{yL},\Delta r_{zL},g_L^{cmd}])右臂:(a_t^R=[\Delta x_R,\Delta y_R,\Delta z_R,\Delta r_{xR},\Delta r_{yR},\Delta r_{zR},g_R^{cmd}])因此:(\boxed{\dim(a_t)=14})第13章 Action 中哪些是 Delta、哪些不是13.1 Cartesian 6D 是 Delta步骤属性:非操作步骤(核心知识点)。每个 Arm 的:Δx Δy Δz Δrx Δry Δrz是相对于当前 EEF Pose 的小增量。13.2 Gripper 是 Target,不是 Delta步骤属性:非操作步骤(重要 Contract)。第七维:(g^{cmd})是 Gripper Target。不是:(\Delta g)因此每臂实际上是:6D relative Cartesian motion + 1D absolute normalized gripper command第14章 Action 永久索引14.1 写入schema.py步骤属性:需要操作的步骤。加入:ACTION_NAMES=("left_delta_x","left_delta_y","left_delta_z","left_delta_rx","left_delta_ry","left_delta_rz","left_gripper_cmd","right_delta_x","right_delta_y","right_delta_z","right_delta_rx","right_delta_ry","right_delta_rz","right_gripper_cmd",)以后:0..6 Left 7..13 Right永久不变。第15章 Cartesian Delta 使用哪个坐标系15.1 必须把这个问题现在确定下来步骤属性:非操作步骤(重要知识点)。只写:(\Delta x,\Delta y,\Delta z)是不够的。必须回答:是 World Frame?Left Base Frame?Right Base Frame?EEF Local Frame?如果 Dataset 中混用坐标系,模型无法学习。15.2 V1 固定使用 World Frame步骤属性:非操作步骤(核心 Contract)。本项目第一版固定:(\boxed{\text{Cartesian Delta expressed in World Frame}})也就是说:(\Delta p=p_{target}{world}-p_{current}{world})15.3 为什么第一版选 World Frame步骤属性:非操作步骤(方案说明)。Handover 是双臂共享工作区任务。使用统一 World Frame 有利于:左右 Action 语义一致;Handover Geometry 明确;Shared Workspace 明确;Cube / Tray / EEF 都可在同一坐标系分析;未来做双臂 Transfer 更直观。以后真机到位以后,只需要把 Real Robot Pose 先变换到同一 World Frame。第16章 Rotation Delta 必须明确16.1 不使用含义模糊的 Euler Increment步骤属性:非操作步骤(重要 Contract)。虽然字段仍命名:delta_rx delta_ry delta_rz但它们不定义为简单:roll difference pitch difference yaw difference因为 Euler Angle 在接近奇异位置时容易产生问题。16.2 V1 使用 Rotation Vector步骤属性:非操作步骤(核心 Contract)。采用旋转向量(Rotation Vector)。定义当前 Orientation:(R_t)目标 Orientation:(R_{t+1})世界坐标中的相对旋转:(\Delta R=R_{t+1}R_t^T)然后:(\Delta r=\operatorname{Log}(\Delta R))得到:(\Delta r=[\Delta r_x,\Delta r_y,\Delta r_z])其中:(|\Delta r|)等于旋转角度,单位:rad第17章 Action Step Limit17.1 第一版 Translation Limit步骤属性:需要操作的步骤。在:embodiment/schema.py增加第一版仿真工程值:MAX_TRANSLATION_DELTA_M=0.01即每一个 15Hz Control Tick:(|\Delta x_i|\le0.01\text{ m})17.2 第一版 Rotation Limit步骤属性:需要操作的步骤。加入:MAX_ROTATION_DELTA_RAD=0.05即:(|\Delta r_i|\le0.05\text{ rad})这些是仿真第一版控制限制,不代表已经验证过的 NERO 真机安全极限。第18章 Action Codec18.1 创建文件步骤属性:需要操作的步骤。操作:embodiment/action_codec.py职责:Desired EEF target ↓ World-frame delta ↓ Rotation vector ↓ Clip ↓ Gripper command ↓ float32[14]18.2 最终返回要求步骤属性:需要操作的步骤。检查:assertaction.shape==(14,)assertaction.dtype==np.float32assertnp.isfinite(action).all()以及:assert0.0=action[6]=1.0assert0.0=action[13]=1.0第19章 Scripted Controller 与 Dataset Action 必须完全相同19.1 禁止 Script 用一种 Action,Dataset 保存另一种步骤属性:非操作步骤(重要工程原则)。错误:Scripted Controller → Joint Position Dataset → 假装是 Cartesian Delta这种数据无法训练。19.2 正确链路步骤属性:非操作步骤(核心架构)。应该:Scripted Task Planner ↓ Desired EEF Delta ↓ Action Codec ↓ action[14] ├────────────→ Dataset │ ▼ Differential IK ↓ Joint Targets ↓ Isaac Physics即:(\boxed{\text{Dataset 保存的 Action 就是实际送给 Runtime Adapter 的高层 Action}})第20章 Observation 与 Action 的时间语义20.1 一帧 Dataset 的含义步骤属性:非操作步骤(核心 Contract)。第 (t) 个 Dataset Frame 定义为:(\boxed{(o_t,a_t)})其中:(o_t)是执行动作前的 Observation。(a_t)是根据 (o_