Delivery format

Custom HDF5 Robot Dataset

HDF5 stores each episode as one group of named, chunked arrays with per-stream nanosecond timestamps. We collect custom first-person video on demand against your written skill spec and deliver it as an HDF5 dataset: one group per episode with streams, annotations and calibration, a QA gate before anything ships, and a buyer-owned licence.
Container
One .h5 or .zarr group per episode
Groups
streams/ · annotations/ · calibration/
Also ships as
RLDS · LeRobot · WebDataset · Rerun .rrd
First batch
Median 48 h in deep-coverage settings
A contributor wearing a head-mounted capture rig performs a manual task, beside a graphic of synchronized hand-pose, depth, and action-segment annotation layers.
One captured and annotated episode, exported into an HDF5 group of streams, annotations and calibration.

What an HDF5 delivery includes

Captured to your spec, exported HDF5-ready.

01

The most complete format we ship

HDF5 is the format Firsthand’s own QA tooling reads, so it carries the full episode: every stream, the annotations and the calibration, rather than a projection of them.

02

Random access into long episodes

Episodes are chunked time-major in 30-frame chunks, so you can read a window of frames from the middle of a long recording without decoding everything before it.

03

Depth and IMU as separate arrays

streams/depth_mm, streams/depth_conf, streams/imu_head, streams/imu_wrist_l and streams/imu_wrist_r are their own arrays, each with its own timestamps, so a policy reads only what it consumes.

04

Sync you can check yourself

Every stream keeps its own nanosecond timestamps, so you can recompute the cross-stream residual on your own machine instead of trusting a published number.

Definition

What is a custom HDF5 robot dataset?

HDF5 is a hierarchical file format that organises data as groups and datasets, a little like folders and arrays, and it is read in Python with h5py. A custom HDF5 robot dataset is egocentric video that a buyer specifies, that is captured against that written spec, and that is delivered in this layout: one group per episode, with the streams, annotations and calibration for that episode inside it.

This page is about ordering a collection with HDF5 as the delivery format. It is the HDF5 counterpart of the custom RLDS dataset and custom LeRobot dataset pages, for teams whose training or evaluation code reads arrays from a file rather than a TFDS or LeRobot layout.

Why HDF5

Why do robot-learning teams ask for HDF5 delivery?

The first reason is completeness. HDF5 is the format the Firsthand QA tooling reads, so it is the most complete of the delivery formats: nothing is folded into a state vector or left in a separate export. If a team wants to see every stream and every annotation exactly as QA saw it, this is the delivery to ask for.

The second is access pattern. Episodes are stored as one group each, chunked time-major, which suits random access into long episodes. A training loop that samples windows, or an analysis script that inspects one stretch of an episode, reads just the chunks it needs.

The third is verification. HDF5 carries the per-stream nanosecond timestamps, so a team can verify synchronization itself.

Streams

Which streams does an HDF5 delivery contain?

The streams/ group carries the head RGB stream, the two wrist RGB streams, metric depth with a confidence channel, and the IMU streams, each with its own timestamps. Which streams a given delivery actually holds depends on which the written spec ordered: a perception model may need depth more than IMU, while a manipulation policy may lean on wrist motion.

Depth is recovered from the calibrated stereo rig rather than from a standalone depth sensor, and it is registered to the head-camera frame using the solved calibration extrinsics. The three IMUs are 6-DoF sensors, one on the head and one on each wrist, so each is its own array and can be analysed alone or together.

Layout

How is an episode laid out in HDF5?

Each episode is one .h5 file (or one .zarr group) named for the episode, such as EP_0117_KITCHEN_A.h5. Inside it are three groups that mirror the canonical episode schema: streams/, annotations/ and calibration/. The episode’s identity and licence live in meta.json under the same schema: episode_id, skill_id, site_id, participant_id, duration_ns, license and reject_flags.

Units are metric throughout. Depth is in millimetres and hand joints are in metres, in the head frame. T is the number of head-camera frames and N is the number of IMU samples, and they differ because the streams run at different rates. Streams are stored at native rate and resampled by your loader, never re-encoded in the delivery.

The calibration/ group carries intrinsics, extrinsics as SE3 transforms, and rms_reproj_px, along with both the opening and the closing solve, so you can check drift across a session. The head-camera frame is the identity for all extrinsics. For object storage, zarr is the better choice; for a single local file, HDF5.

Chunk shape and compression are stated on the format page as time-major, 30-frame chunks with blosc-zstd level 5, so read whole chunks rather than single frames to avoid decompression overhead. Per-stream chunk shapes beyond that, file sizes and shard sizes are not itemised on this site, and are set per program in the skill spec.

Labels

Which labels ship in the annotations group?

The annotations/ group holds the labels. The ones most orders ask for are hand_joints, a float32 array of shape [T, 2, 21, 3] in metres, so 21 joints per hand in 3D; hand_visible, the per-joint visibility flag; contact_events; and action_segments, a list of start_ns, end_ns, verb and noun entries that mark sub-steps of a skill.

The episode schema also lists instance_masks (uint16, [T, 480, 848]), body_joints, objects and gaze_target in the same group. Whether a given delivery includes them is a spec decision, so name the ones your policy needs in the skill spec and confirm them on the Spec Pilot batch rather than assuming them.

Comparison

How do HDF5, RLDS and LeRobot deliveries compare?

They are three exports of the same QA-passed episodes, so the choice is about your pipeline, not about data availability. HDF5 is the most complete and suits random access and sync verification. RLDS suits TensorFlow-based pipelines and RL-style step sequences, with depth carried per step. LeRobot suits imitation-learning pipelines on that ecosystem and is the smallest on disk.

The practical differences are depth, pose shape and footprint. HDF5 keeps depth, IMU and hand joints as separate arrays; RLDS keeps hand_joints as its own field per step; LeRobot flattens 2×21×3 hand joints, then 24×3 body joints, into one observation.state vector and leaves depth out of the mp4.

Sync

How are timestamps and sync handled across streams?

Every active stream is hardware-triggered onto one PTP clock domain, and each stream carries int64 nanosecond timestamps in that domain. The site states a cross-stream sync ceiling of 2.0 ms, hardware-triggered. The IMUs are aligned during calibration with a static hold plus a figure-eight excitation, and the stereo rig that produces depth is validated in the calibration pass.

Because the IMUs sample at 200 Hz and the cameras at 30 or 60 Hz, an episode holds more IMU samples than video frames for the same span of time. Consuming them together means resampling or windowing the IMU data to the frame you need, rather than assuming one sample per frame.

The HDF5 export carries the per-stream timestamps, so you can recompute the residual yourself. The head_rgb dataset exposes them as a timestamp_ns attribute, and the sync-error guide shows how the residual is measured. The Rerun recording plots the same residual against the ceiling if you would rather look first.

Skill spec

How does a skill spec define what is collected into HDF5?

Every custom collection starts with a written skill spec: the task your pipeline needs covered, the setting, the object set, the capture tier, the annotation depth and the accept criteria. That spec is quoted for reach, timeline and price before capture begins, and the accept criteria are signed into it.

For an HDF5 order the spec also names which streams and annotations go into each episode group and that the delivery format is HDF5, zarr or both. One attempt at the task is one episode and one group, tagged with skill_id and site_id in meta.json, so any episode traces back to the skill and setting it came from.

Collection and QA

How is a custom HDF5 dataset collected and validated?

Paid, consented contributors perform the real task against your spec while wearing the capture rig. The instrumented tier is a head-mounted stereo rig: first-person RGB, a metric depth stream recovered from the calibrated stereo rig, and 6-DoF IMU data at 200 Hz from head- and wrist-mounted sensors. The rig is calibrated before the session and again after it. We do not capture robot or teleoperation data, and we do not capture at a customer’s own facility.

QA happens once, against the canonical episode, before any format-specific export is produced, so the HDF5 files inherit the same calibrated, synced, QA-passed data as every other format. An episode is accepted only if RMS reprojection stays under 0.28 px and the drift is within tolerance. Otherwise it goes to the reject log, which ships with every batch. Only footage that clears the signed accept criteria is billed as a validated hour, and rejected items are recaptured at our cost.

Privacy sits in the same gate. Every episode is linked to a signed contributor release under a documented consent chain. Faces and screens in frame are detected and irreversibly blurred at ingest, with a reviewer confirming the result before anything ships, and clips that cannot be de-identified are discarded rather than delivered.

Licence and delivery

How is it licensed, and what do you receive?

You receive the dataset under a perpetual, irrevocable, worldwide commercial licence that is non-exclusive by default, with the buyer owning the resulting dataset and exclusivity available. The same terms apply whichever format the episodes are exported into.

The delivery is the HDF5 (or zarr) episodes and the reject log for the batch.

Speed

How fast can a custom HDF5 dataset be delivered?

Where coverage for the requested tasks and regions is already deep, the median time from signed spec to first validated batch is a median of 48 hours. Where it is thin, turnaround runs three to four weeks while recruiting expands in parallel across more regions. Choosing HDF5 adds no separate stage, because the export is built from episodes that already passed QA.

Getting started

How do you request a custom HDF5 dataset?

Write down the tasks, environments, objects and camera tier your model needs, name the streams and annotations you want in each episode group, and specify HDF5 or zarr as the delivery format. Most orders begin with a Spec Pilot: a small, fast first batch that proves the spec and the accept criteria hold up on real footage before you scale.

On that pilot, open an episode with h5py and check the stream paths and shapes you depend on. Anything not itemised on the format pages is agreed in the spec before volume is committed.

At a glance

What you get.

Container
One .h5 or .zarr group per episode
Chunking
Time-major, 30-frame chunks, blosc-zstd level 5
Groups
streams/, annotations/, calibration/ mirroring the episode schema
Depth
streams/depth_mm and streams/depth_conf, from the calibrated stereo rig
IMU
streams/imu_head, streams/imu_wrist_l, streams/imu_wrist_r
Timestamps
int64 nanoseconds per stream, PTP domain
File and shard sizes
Set per program in the skill spec
Also available as
RLDS, LeRobot, WebDataset, Rerun .rrd
Spec to first batch
a median of 48 hours (deep coverage)
License
Perpetual, irrevocable, buyer-owned, non-exclusive by default

Every collection runs through the same seven-stage end-to-end custom collection pipeline. End-to-end custom data collection is a managed service that takes an AI data need from problem to owned dataset in a single accountable pipeline.

Stream map

Streams in an HDF5 delivery, as the site states them

Each stream with its dtype, shape and rate from the episode schema, and its path in the streams/ group. "Not itemised" means the site does not state it.
StreamDtype, shape and rateSourceHDF5 path
Head RGBuint8 [T, 2160, 3840, 3], 60 HzHead-mounted stereo rigstreams/head_rgb
Wrist RGBuint8 [T, 1080, 1920, 3], 60 HzLeft and right wrist camerasstreams/wrist_l, streams/wrist_r
Metric depthuint16 [T, 480, 848], millimetres, 30 HzRecovered from the calibrated stereo rigstreams/depth_mm
Depth confidencePer-pixel confidence channel; shape not itemisedSame stereo rigstreams/depth_conf
Head IMUfloat32 [N, 6], 200 HzHead-mounted 6-DoF sensorstreams/imu_head
Wrist IMUsfloat32 [N, 6], 200 HzOne 6-DoF sensor per wriststreams/imu_wrist_l, streams/imu_wrist_r
Timestampsint64 nanoseconds per stream, PTP domainHardware-triggered shared clock*_timestamp_ns; timestamp_ns attribute on each dataset

Annotations

Labels in the annotations group and what each records

Label, what it records and its stated shape. "Not itemised" means the format pages do not state a shape; confirm on the Spec Pilot.
LabelWhat it recordsStated shape and units
annotations/hand_joints3D hand pose, 21 joints per handfloat32 [T, 2, 21, 3], metres, head frame
annotations/hand_visiblePer-joint visibility flagNot itemised
annotations/contact_eventsContact eventsNot itemised
annotations/action_segmentsSub-steps of a skillList of {start_ns, end_ns, verb, noun}
annotations/instance_masksInstance masksuint16 [T, 480, 848]
body_joints, objects, gaze_targetAlso listed in the episode schema annotations groupNot itemised; included only if the spec orders them

HDF5 vs RLDS vs LeRobot

HDF5, RLDS and LeRobot delivery, as the site states them

The same QA-passed episodes can be exported to any of the three layouts.
HDF5 / zarrRLDSLeRobot
ContainerOne .h5 or .zarr group per episodeTFDS-compatible tfrecord shardsParquet + mp4 per camera, Hugging Face datasets layout
Read withh5py (HDF5); zarrtensorflow_datasetslerobot.common.datasets.lerobot_dataset
Depthstreams/depth_mm and streams/depth_confobservation.depth_mm per stepNot embedded in the mp4; pull it from the HDF5 export
Hand poseannotations/hand_joints [T, 2, 21, 3]observation.hand_joints per step2×21×3 hand joints flattened into observation.state, then 24×3 body joints
Timestampsint64 nanoseconds per stream, PTP domainint64 nanoseconds, PTP domain, per streamPer-frame, aligned to the head-camera clock
Layout unit and sizeTime-major, 30-frame chunks, blosc-zstd level 5~1.9 GB shards, one skill line per directoryThe smaller on-disk option
Best forRandom access, sync verification, the most complete exportTensorFlow-based pipelines, RL-style step sequencesImitation-learning pipelines on the LeRobot ecosystem

Skill spec

What the skill spec fixes, and where it shows up in HDF5

Spec element and where a buyer can see it in the delivered HDF5 episodes. "Set per program" means the site states no fixed value.
Spec elementWhat it decidesWhere it shows up
Task and skillWhat one attempt is and how it is namedOne group per episode; skill_id in meta.json
SettingWhere the task is performedsite_id in meta.json
Capture tierWhich streams are recordedWhich paths exist under streams/
Annotation depthWhich labels are producedWhich paths exist under annotations/
Accept criteriaWhat passes QAReject log per batch; rms_reproj_px and reject_flags
File and shard sizesHow a batch is split across filesSet per program in the skill spec
Delivery formatHow the data is packagedHDF5, zarr or both

FAQ

Custom HDF5 robot dataset, answered.

What is a custom HDF5 robot dataset?
An egocentric video collection captured to a buyer’s skill spec and delivered as one .h5 group per episode, with streams, annotations and calibration groups and int64 nanosecond timestamps per stream.
Which streams does an HDF5 delivery include?
streams/head_rgb, streams/wrist_l and wrist_r, streams/depth_mm, streams/depth_conf, and streams/imu_head, streams/imu_wrist_l and streams/imu_wrist_r, each with its own timestamps. The spec decides which of them a given delivery holds.
Does the HDF5 delivery include depth and IMU?
Yes, as separate arrays. Depth is recovered from the calibrated stereo rig rather than a standalone depth sensor, and the three IMUs are 6-DoF sensors sampled at 200 Hz.
Which labels are in the annotations group?
hand_joints (21 joints per hand in 3D, in metres), hand_visible, contact_events, action_segments and instance_masks are listed there. Name the ones you need in the spec and confirm them on the Spec Pilot batch.
What are the chunk sizes, compression and file sizes?
The format page states time-major, 30-frame chunks with blosc-zstd level 5. Per-stream chunk shapes beyond that, file sizes and shard sizes are not stated, so they are set per program in the skill spec.
Can I verify synchronization myself?
Yes. The HDF5 export carries the per-stream nanosecond timestamps, so you can recompute the cross-stream residual yourself instead of relying on a published figure.
What licence does the dataset ship under, and how fast is it?
A perpetual, irrevocable, worldwide commercial licence that is non-exclusive by default, with the buyer owning the resulting dataset and exclusivity available. Where coverage is deep, the median time from signed spec to first validated batch is a median of 48 hours; thin coverage runs three to four weeks.

Sources

Where are the delivery formats documented?

Request a custom HDF5 dataset.

Tell us the tasks, environments and camera tier your model needs, and specify HDF5 or zarr as the delivery format. The same episodes can also ship as RLDS, LeRobot or WebDataset, with a first validated batch in a median of 48 hours where coverage is deep.