COLLECT

COLLECT records teleoperation episodes to a standard robot-learning dataset, with PASS/FAIL review in the same tab.

COLLECT: pick a task, START/STOP, then replay for QC.

Overview

COLLECT is the third of the console's six tabs (DEBUG · MANUAL · COLLECT · REPLAY · EVAL · RESULT). It runs no policy: each episode records the arm's state alongside the operator's commanded action, so the dataset is replayable and trainable in one pass.

Tab is gated by config. COLLECT is enabled only when the launched config carries a collection section (see below). No separate process.

Prerequisites

Use MANUAL first to confirm motion and camera streams.

Why COLLECT may be greyed out

Relaunch with a collection config; see below.

Workflow

#StepAction
1TASKPick the task (list comes from collection.tasks). Saved with the episode; each task gets its own folder.
2STARTRecording begins. Status: COLLECTING; frame count climbs.
3STOPEpisode is handed to the background saver. Status: SAVING until written.
4QCReplay and mark PASS/FAIL, with optional note.
What gets recorded. Both halves of the teleop: observed state (joint angles + EEF) and commanded action (joint angles + EEF). Driven by the config, not the tab.

While recording

Status line: COLLECTING, SAVING, QUEUE_FULL, or IDLE, plus frame count, queue depth, and ETA.

Recordings append. Relaunching into the same folder appends new episodes after existing ones. See Data collection for the on-disk layout.

Success and common faults

SymptomCause / action
Frame count stuck at 0No data arriving. Verify drivers and that config topic names match the publishers.
Camera black / missingStream down or camera name mismatch. Confirm via MANUAL.
QUEUE_FULLSaver behind. Wait for IDLE; if persistent, lower fps or raise save_queue_max.
Episode red on reviewAn auto-check fired — see Quality control.

Quality control

On STOP, replay the episode and mark PASS/FAIL. In addition, every episode runs through automatic checks; any failure marks it red and persists the reasons alongside the data.

FlagRaised whenAction
episode_too_shortFewer frames than min_episode_frames.Re-record longer, or lower the threshold.
non_monotonic_timestampA frame's timestamp does not advance past the previous.Re-record. If recurring, check the publisher clock.
missing_camera · invalid_image_shapeConfigured camera absent, or image not H×W×3.Verify stream and config name match.
missing_configured_column · invalid_vector_dimConfigured field missing or wrong length.Verify topic publishing and arm count.
non_finite_valueNaN/Inf in a recorded value.Auto-zeroed; re-record if frequent.
frame_count_mismatchCamera video frame count differs from the data table.Re-record; indicates dropped/stalled camera.
Bad fields are zero-filled, not dropped. Schema stays consistent; the flag is persisted with the episode.

For deeper review and adding instruction text per episode, use REPLAY.

Writing a collection config

A config becomes a collection config the moment it declares columns to record — that is what enables the tab. A collection config inherits a per-robot deploy file via _base_ and adds a collection section (see Configuration).

Settings

SettingPurpose
storage.log_dirOutput root. Per-task subfolders. Empty → default folder named after the config.
storage.fpsTarget frame rate.
storage.save_queue_maxMax episodes queued for save. Full → QUEUE_FULL.
schema.robot_typeRobot id, e.g. agilex_AGILEX.
schema.min_episode_framesThreshold for episode_too_short.
schema.armsArms to record, one entry each.
schema.camerasCameras to record. At least one required.
schema.columnsThe four required dataset fields: qpos, eef, action_qpos, action_eef.
transport.ros1.groupsPer-arm source topics for observed and commanded state. Use ros2 for ROS 2.
tasksTask strings offered in the TASK picker.

Copy the shipped collection config for your robot (e.g. configs/02_collection/dual_agilex_AGILEX.py) and edit the marked values. Lines marked ← change… must match your robot.

configs/02_collection/my_robot.py
_base_ = ['<path to your robot's deploy _base.py>']  # ← point at your robot's deploy config

collection = dict(
    storage=dict(
        log_dir='',           # ← where to save (empty = a default folder named after this config).
        fps=30,               # sane default; change only if your robot runs at another rate.
        save_queue_max=15,     # sane default.
    ),
    schema=dict(
        robot_type='<your robot type>',  # ← e.g. 'agilex_AGILEX'.
        min_episode_frames=10,  # sane default.
        arms=dict(left_arm='left', right_arm='right'),  # ← one entry per arm.
        cameras=dict(
            cam_high='observation.images.cam_high',  # ← list your cameras (name → dataset field).
        ),
        columns=dict(           # keep these four keys; values are standard dataset field names.
            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='<arm joint topic>',          # ← change to your robot's real topics.
                eef_topic='<arm gripper-pose topic>',
                action_qpos_topic='<commanded joint topic>',
                action_eef_topic='<commanded gripper-pose topic>',
            ),
            # ...repeat for each arm.
        )),
    ),
    tasks=['<your task instruction>'],  # ← e.g. 'pick up the apple'.
)

Save under configs/02_collection/ and launch. The loader enforces:

Field lengths are checked. Joint fields must match the robot's joint count; EEF fields are 8-wide per arm (x, y, z, orientation, gripper). Mismatches are flagged on review.

Launching

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

Open the console at http://localhost:8080 (override via --web-port, see CLI reference). Episodes are replayable through the dataset transport and reviewable in REPLAY.