主题
CLAUDE.md
技术背景
先读 技术文档:理解整个项目在做什么、8 层 pipeline 长什么样。 我只负责 Layer 2 - 数据生成层 和 Layer 3 - 数据处理层 这两层。
不要修改 docs/guide/pipeline.md 本身。 如果发现它有错误,在本仓库其他位置(本文件、对应章节的 docs/)指正即可。已知勘误:
- GR00T 要求的数据格式是 LeRobot v2,不是 v3。本仓库只研究 v2。
- IsaacLab 当前 develop 分支的所有 quat 已经统一为 scalar-last (x, y, z, w),跟 Warp
wp.transform一致。任何"IsaacLab 是 wxyz 而 Warp 是 xyzw"的旧说法对当前 commit 不再适用,不需要在 SM 边界 reorder。详见docs/schema/obs-action-alignment.md。 - LeRobot dataset stats 文件:**纯 lerobot v2.1 用 per-episode
episodes_stats.jsonl,但 GR00T N1.7 强依赖 v2.0 风格的全局meta/stats.json(带q01/q996 字段)。**本仓库以 GR00T 1.7 为消费方,所以写全局stats.json,不写episodes_stats.jsonl。详见docs/schema/gr00t-1-7-dataset-constraints.md,源码 verify 在Isaac-GR00T/gr00t/data/dataset/lerobot_episode_loader.py:182-185(assert) 与Isaac-GR00T/gr00t/data/stats.py:104-112(字段 check)。
下游消费方:GR00T 1.7
目标模型确认是 GR00T N1.7(NVIDIA Isaac-GR00T 仓库 main 分支 processing_gr00t_n1d7.py),不是 1.5 / 1.6。
NVIDIA Isaac-GR00T 源码已经 clone 在 ./Isaac-GR00T,checkout 到 n1.7-release tag(commit 23ace64)。所有"GR00T 1.7 怎么读 dataset"的问题都直接读这里的源码,不要再去 web 上调研、不要依赖针对 1.5 / 1.6 的旧结论。./Isaac-GR00T 已 gitignore,不进本仓库的 git tree。
- 所有 L3 输出格式决策都要按 GR00T 1.7 的 data loader 约束来定,不能再依赖针对 GR00T 旧版本调研出来的结论("v2.0 / v2.1 都行"那条话是 GR00T 早期版本的说法,1.7 必须重新 verify)。
- 具体 v2.0 vs v2.1 的二选一(决定要写
stats.json还是episodes_stats.jsonl)必须直接读./Isaac-GR00T源码 verify,结论落到docs/schema/lerobot-v2-schema.md和docs/research/lerobot-version-study.md,再据此调整l3/convert.py。
仓库定位
这是一个说明性 / 教学型仓库,不是产品代码。 目标:任何新人进来,看到文档和代码就能理解 L2/L3 在做什么、并上手跑通每一步。
由此推出几条硬性要求:
- 完整覆盖 L2 三种轨迹来源:scripted policy、RL policy、人类遥操作。三者作为平等的一等公民对待,不能只做 scripted 一支。
- 完整覆盖 L3 全流程:HDF5 中间产物 → LeRobot v2 → 质量过滤 → 统计。可选的视觉增强(Cosmos)即使本仓库不实现,也要在 doc 中说明接口和数据流向。
L2 / L3 实现状态
完整的 ✅ / 🚧 / 📋 / ⏭️ 状态清单见仓库根 README.md "实现状态" 一节,那是真相;本文件不再重复列表。
l2/rl 的关键约束(写在这里因为是 venv 层面的硬性依赖,不是状态描述):
- L2 venv
l2/pyproject.toml里加了isaaclab-rl(path editable)和rsl-rl-lib==5.0.1,因为isaaclab-rl强 pinh5py==3.15.1跟 L2 venv 的>=3.16.0冲突,所以加到tool.uv.override-dependencies里覆写 h5py。 - rollout 必须保
concatenate_terms=True(PPOMLPModel硬要求 1-D obs);自定义 RecorderTerm 自己按group_obs_term_dim切片成 dict 落盘,与 PPO 推理路径解耦。
文档站(可选)
仓库根带一个 VitePress 静态文档站,把 README.md + CLAUDE.md + docs/ + 各子目录 README 渲染成可搜索网页。
bash
pnpm install # 第一次装,只跑一次(用 corepack 启用的 pnpm)
pnpm dev # 起 http://127.0.0.1:5173,改 markdown 自动热刷新
pnpm build # 静态构建到 .vitepress/dist/ (gitignored)- 源文件就是仓库里的 .md,不复制不 symlink。VitePress 配
srcExclude屏蔽 IsaacLab/Isaac-GR00T/产物目录。 - 新增 markdown 后:在
.vitepress/config.mts的themeConfig.sidebar列上;不列也能通过 URL 直达,但侧边栏看不到。 - VitePress build 会校验所有 markdown 内的相对链接——
pnpm build跑通即所有交叉引用没断,是顺手的正确性 check。
项目环境
始终使用 uv run python 而不是系统的 python 来运行代码,确保使用正确的环境和依赖。
IsaacLab 源码已经 clone 在 ./IsaacLab 目录下, checkout 到了 develop 分支下的 f0234a82e432e2a0b0f0a26ca3c5b59e527ddaaa commit, 它比 v3.0.0-beta tag 要多一些 commit,修复了一些问题。
当前项目没有使用 IsaacLab 的官方安装方式,而是直接在项目自己的 pyproject.toml 中指定了 IsaacLab 的路径,这样可以更灵活地管理依赖和版本。 当前 IsaacSim 版本:6.0.0
已知依赖冲突
- LeRobot 与 IsaacSim 的依赖会冲突(已踩过坑)。HDF5 → LeRobot v2 的转换步骤大概率需要单独一个 venv,不能塞进当前 IsaacSim 的 venv。这就是为什么仓库拓扑上是
l2/(IsaacSim + IsaacLab)和l3/(lerobot)两个对称的独立 venv,用 HDF5 文件作为它们之间的边界。
L2 venv 的硬性版本约束(不许动)
torch==2.10.0 和 torchvision==0.25.0(都是 cu128)是 IsaacSim 6.0.0 的官方要求,写在 l2/pyproject.toml 里。
- 任何"建议升降 torch 版本以解决依赖冲突"的方案都要先排除 L2 venv,转去 L3 venv(或新建独立 venv)解决。
- L2 venv 的 GPU 是 cu128(Blackwell),意味着 torch wheel 必须从
pytorch-cu128index 拉。
关键区分:两个独立的"版本号"
讨论 LeRobot 时必须把两件事分开,不能混:
| 概念 | 例子 | 在哪里 |
|---|---|---|
lerobot PyPI 包版本 | 0.3.3, 0.5.1 | pip install lerobot==X.Y.Z,是库本身 |
| LeRobot Dataset 格式版本 | v2.0, v2.1, v3.0 | 写在 meta/info.json 的 codebase_version 字段,是磁盘 schema |
GR00T 要求的是 Dataset 格式 v2,不是 PyPI 包 v2。PyPI 现在已经到 0.5.x(写 dataset 格式 v3)。我们装哪个 PyPI 包版本来读写 v2 dataset 是单独要确认的事。任何文档里写到"v2"时必须明确说"dataset 格式 v2",避免误导。
代码风格
始终偏向「代码即文档」,将文档通过注释的方式直接嵌入到代码中去,方便一起维护。 正常的 .md 文档也是要有的,这是为了系统性地认识,可以加一些流程图什么的进去。
文档风格
文档风格
- 重视 citation,默认使用 Pandoc 风格脚注。
- 使用「正文引用 + 文末脚注」形式,把 claim 与来源直接绑定。
- 不单独维护 References / 参考文献 章节。
示例:
某个结论[1]
给 Claude 的工作约定
- CLAUDE.md 是契约:任何会持续影响后续工作的决策(命名约定、范围、勘误、要避免的做法),第一时间写进这里。重要的事情始终记得修改 CLAUDE.md。
- CLAUDE.md 是 living doc:发现旧条目过时立刻改,不要堆叠重复段落。
- README.md "实现状态"是真相:仓库根
README.md有一节"实现状态"列出 L2 / L3 / 跨层每一项的 ✅ / 🚧 / 📋 / ⏭️ 状态。任何一次新增、调整、砍掉某个能力,必须同时更新这一节。和代码不一致比没有 README 还误导新人;这条是硬约束。- 改了
l2_*或l3/的能力(不止文件挪动,是行为变化)→ 同步 README 状态表。 - 砍掉某个原计划的能力 → 改成 ⏭️ 并写"留给 X 仓库"或"硬件不足"。
- 完成一个原计划项 → 📋 → ✅,同时更新一句"要点"列。
- 同一个 PR 内,代码改动 + README 状态表更新要一起出。
- 改了
- 调研产物要落盘:用 web/agent 调研得到的结论不要只在对话里讲一遍,要整理成 markdown 写进
docs/,方便后续检索和复用。 - 写文档必须带来源链接:引用代码用绝对路径或
path:line格式,引用网络资源用 markdown 链接,方便读者 check。不确定的地方要明确写"未确认",不许编。 - 优先复用 IsaacLab 自带基础设施:HDF5 schema 用
HDF5DatasetFileHandler,episode 录制用RecorderManager+ActionStateRecorderManagerCfg,success 判定挂terminations.successDoneTerm。不要自己写 HDF5 写盘逻辑或自己 buffer obs/action——已经踩过坑,schema 会跟主线分叉。 - L2 采集脚本的 success 过滤靠
EXPORT_SUCCEEDED_ONLY+successtermination term:RecorderManager 在每个 reset 自动读termination_manager["success"]写到 episode attr,无需自己判定,无需在 step 之前手动检查 (那是没用 RecorderManager 时代的 workaround)。