COLLECT

COLLECT 把遥操作 episode 录制为标准机器人学习数据集,并在同一标签页内做 PASS/FAIL 审查。

COLLECT:选任务,START/STOP,回放质检。

概览

COLLECT 是控制台六个标签页(DEBUG·MANUAL·COLLECT·REPLAY·EVAL·RESULT)的第三个。它不跑策略:每段 episode 同时记录机械臂的观测状态和操作者下达的动作,得到的数据集可直接回放与训练。

标签页由配置门控。只有启动时的配置带有 collection 段,COLLECT 才会启用(见下文)。无独立进程。

前置条件

先用 MANUAL 确认机械臂运动与相机推流正常。

为什么 COLLECT 可能是灰的

改用一份采集配置重新启动;见下文

工作流

#步骤动作
1TASK选任务(列表来自 collection.tasks)。随 episode 一起保存,每个任务独立文件夹。
2START开始录制。状态 COLLECTING,帧数递增。
3STOPepisode 交给后台保存。状态 SAVING,写盘完成前保持。
4QC回放并标记 PASS/FAIL,可选备注。
录制内容。同时记录遥操作的两半:观测状态(关节角度 + EEF)与下达动作(关节角度 + EEF)。由配置决定,不在标签页里调。

录制期间

状态行:COLLECTING / SAVING / QUEUE_FULL / IDLE,附帧数、队列深度与 ETA。

录制为追加。重新启动后录入同一文件夹时,新 episode 追加在已有之后。磁盘布局见数据采集

成功与常见故障

现象原因 / 处理
帧数停在 0无数据到达。核对驱动与配置话题名是否与发布端一致。
相机黑屏或缺失未推流或相机名不匹配。先在 MANUAL 验证。
QUEUE_FULL保存跟不上。等回到 IDLE;若反复出现,降低 fps 或提高 save_queue_max
审查时被标红某项自动检查命中——见质量控制

质量控制

STOP 后回放并标记 PASS/FAIL。同时每段 episode 还会运行自动检查;任一项不通过即标,原因随数据一同持久化。

标记触发条件处理
episode_too_short帧数少于 min_episode_frames重录更长段,或降低阈值。
non_monotonic_timestamp某帧时间戳未越过前一帧。重录。反复出现则检查发布端时钟。
missing_camera · invalid_image_shape配置相机缺失,或图像不是 H×W×3。核对推流与配置中的相机名。
missing_configured_column · invalid_vector_dim配置字段缺失或长度不符。核对话题是否发布、手臂数是否一致。
non_finite_value录值出现 NaN/Inf。自动置零;频繁则重录。
frame_count_mismatch相机视频帧数与数据表行数不符。重录;通常是相机掉帧或卡住。
坏字段补零,不丢弃。schema 保持一致;标记随 episode 持久化。

需要更细审查并为每段补写指令文本,使用 REPLAY

编写采集配置

一份配置在声明要录哪些列的那一刻即成为采集配置——这一点正是 COLLECT 的启用条件。采集配置通过 _base_ 继承一份按机器人区分的部署文件,并叠加一个 collection 段(见配置)。

设置项

设置项作用
storage.log_dir输出根目录,按任务分子目录。留空 → 以本配置命名的默认目录。
storage.fps目标帧率。
storage.save_queue_max同时排队保存的最大 episode 数。排满 → QUEUE_FULL
schema.robot_type机器人 id,如 agilex_AGILEX
schema.min_episode_framesepisode_too_short 的阈值。
schema.arms要录的手臂,每只一条。
schema.cameras要录的相机,至少一个。
schema.columns四个必填数据集字段:qposeefaction_qposaction_eef
transport.ros1.groups每只手臂的观测与下达动作源话题。ROS 2 用 ros2
tasksTASK 选择器里的任务字符串。

复制机器人自带的采集配置(如 configs/02_collection/dual_agilex_AGILEX.py)并改其中标出的值。标 ← 改成… 的行必须与你的机器人对应。

configs/02_collection/my_robot.py
_base_ = ['<你机器人的部署 _base.py 路径>']  # ← 指向你机器人的部署配置。

collection = dict(
    storage=dict(
        log_dir='',           # ← 存到哪里(留空=用以本配置命名的默认文件夹)。
        fps=30,               # 合理默认值,机器人不是这个帧率时再改。
        save_queue_max=15,     # 合理默认值。
    ),
    schema=dict(
        robot_type='<你的机器人类型>',  # ← 如 'agilex_AGILEX'。
        min_episode_frames=10,  # 合理默认值。
        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='<手臂关节话题>',          # ← 改成你机器人的真实话题。
                eef_topic='<手臂夹爪位姿话题>',
                action_qpos_topic='<下达的关节话题>',
                action_eef_topic='<下达的夹爪位姿话题>',
            ),
            # ……每只手臂重复一组。
        )),
    ),
    tasks=['<你的任务指令>'],  # ← 如 'pick up the apple'。
)

存到 configs/02_collection/ 下并启动。加载器强制校验:

字段长度受校验。关节字段必须与机器人关节数一致;EEF 字段每只手臂 8 维(x、y、z、姿态、夹爪)。不符会在审查时标记。

启动

bash
eva --config configs/02_collection/my_robot.py

在浏览器打开 http://localhost:8080(可用 --web-port 覆盖,见命令行参考)。episode 可通过 dataset 传输回放,并在 REPLAY 中审查。