数据采集

EVA将遥操作采集与推理运行写为LeRobot v2.1数据集

两种录制方式,一种格式

两条路径产出同一种数据集,均可通过dataset传输层回放。两者只在每帧记录的内容上不同。

下达动作的来源。遥操作时动作并非由EVA计算——它来自主端设备。采集配置指明哪条数据流携带该动作。
遥操作的 IK / FK。EVA 内核本身提供 IK 与 FK 求解。目前的遥操作样例只覆盖 gello 类同构主臂——ARX 与 UR——还没有 VR 的样例。这些求解暂未写入内核:不同遥操作方案较为混杂,为保持核心代码干净整洁,目前放在 hardware 层,内核只负责记录数据。若采集时需要实时 IK/FK,可在 hardware 层直接调用内核的 IK/FK 求解。待方案整理成熟后,后续版本会把采集的实时 IK/FK 逐步收入核心代码。

录制前的准备

填写采集配置

一旦配置列出要保存的数据列(collection.schema.columns),它就成为采集配置。EVA启动时校验schema,若缺少任何必填项就拒绝启动。

区块用途
storage输出文件夹(log_dir)、目标fps,以及后台保存队列深度(save_queue_max)。
schema每帧内容:机器人类型、最短episode长度、各手臂、各相机、输出列名。
transport要读取的在线数据流。每只手臂指明携带其位姿与下达动作的流。
tasks录制时可选的指令。每个任务独立成一份数据集文件夹。

schema内部:

eef编码。eef每只手臂八个数:位置(x y z)、旋转四元数(qw qx qy qz)、夹爪开合。

请从configs/02_collection/下对应示例开始,修改标注的值。除非训练流程要求不同列名,否则保留示例列名——它们是数据集的约定:

python
_base_ = ['../01_deploy/<你的机器人>/_base.py']   # ← 复用你机器人的部署配置

collection = dict(
    storage=dict(
        log_dir='<输出文件夹>',    # ← 数据集写到哪里;留空则为 work_dirs/<配置文件名>
        fps=30,                    # 目标帧率(合理默认;慢任务可调低)
        save_queue_max=15,          # 最多允许几个录完的 episode 排队保存
    ),
    schema=dict(
        robot_type='<你的机器人类型>',   # ← 例如 agilex_AGILEX
        min_episode_frames=10,            # 更短的录制会被打上 'episode_too_short' 标记
        arms=dict(left_arm='left', right_arm='right'),   # ← 你的手臂 → 名称前缀
        cameras=dict(
            cam_high='observation.images.cam_high',   # ← 你的相机 → 其数据集名
        ),
        columns=dict(           # 除非训练另有要求,保留这些列名
            qpos='observations.state.qpos',
            eef='observations.state.eef',
            action_qpos='action.qpos',
            action_eef='action.eef',
        ),
    ),
    transport=dict(           # ← 指明携带位姿与下达动作的在线数据流
        ros1=dict(groups=dict(
            left_arm=dict(
                qpos_topic='<机器人关节数据流>',           # ← 手臂上报关节的来源
                action_qpos_topic='<主臂关节数据流>',   # ← 你下达动作的来源
            ),
        )),
    ),
    tasks=['<你的任务指令>'],   # ← 例如 '拿起苹果'
)

log_dir留空,EVA写入work_dirs/<配置文件名>/

运行一次采集

用采集配置启动EVA;COLLECT在浏览器中打开:

bash
eva --config configs/02_collection/<你的配置>.py

逐按钮完整流程见COLLECT页。每次录制都在后台流水线上记录,实时采集不卡顿:

控制台显示实时状态:采集/保存/空闲、已采帧数、保存队列深度、预计完成保存时间。每次保留的录制都追加到该任务的数据集中;录制绝不会覆盖之前的episode。

每任务一份数据集文件夹。每个任务都在输出文件夹下单独建一份数据集,以任务命名(空格转_,斜杠转-)。数据落在<log_dir>/<任务名>/

确认采集成功

按STOP后等状态回到空闲。一次成功的录制会新增:

每行记录该episode的质量:所有帧通过为green,任一失败为red。红色episode仍会保存(坏值已修复,见下文),但应在COLLECT或REPLAY中回放后再决定是否重录。

数据集长什么样

每个任务一个文件夹。episode以六位数字编号(episode_000000……)归入chunk-000。一个chunk上限1000个;EVA只填满第一个。

text
<log_dir>/<任务名>/
├── data/
│   └── chunk-000/
│       └── episode_000000.parquet      # 主表,每帧一行
├── videos/
│   └── chunk-000/
│       └── <相机>/
│           └── episode_000000.mp4       # 每个相机一个 mp4
└── meta/
    ├── info.json            # 数据集元信息:格式版本、fps、各列
    ├── episodes.jsonl       # 每个 episode 一行:编号、任务、长度、质量
    ├── episodes_stats.jsonl # 每个 episode 的统计(仅采集路径)
    ├── tasks.jsonl          # 每个 episode 的任务文本
    └── stats.json           # 全数据集统计

仓库在examples/agilex_dataset/附带完整示例(双臂AGILEX,三个相机)。

逐帧质量检查

每帧在保存时都会被检查。任一失败将该episode标为red,原因记入episodes.jsonl;否则为green

标记触发条件
episode_too_short帧数少于min_episode_frames
non_monotonic_timestamp采集时间未超过前一帧。
missing_camera·invalid_image_shape已配置相机没有出帧,或形状不对。
missing_configured_column·invalid_vector_dim已配置字段缺失,或长度不符。
non_finite_value字段含无效数值(保存前置零)。
frame_count_mismatch某相机视频帧数与数据表行数不一致。

缺失或长度错误的字段会被替换为正确长度的零值,使表格保持规整;问题被标记。红色episode仍可使用,但值得检查。

时间戳如何记录

LeRobot要求各帧时间完全等间隔。EVA按配置的fps合成正式时间戳,真实采集时间另存入capture_time列以供诊断。

数据集元信息与统计

数据集定稿时,EVA写入info.jsonstats.json

把推理运行作为数据集

推理运行录制同样的格式,有两点不同:

覆盖与追加。遥操作新增episode;评测对同一提示词/试验的重跑则替换槽位。

关于评测的设置与评分,参见配置页与EVAL流程。