Skip to content

dataforge: robocap end-to-end slice (download/convert/register/view) - #112

Open
pablo-rerun wants to merge 3 commits into
grill-dataforge-handofffrom
dataforge-robocap
Open

dataforge: robocap end-to-end slice (download/convert/register/view)#112
pablo-rerun wants to merge 3 commits into
grill-dataforge-handofffrom
dataforge-robocap

Conversation

@pablo-rerun

Copy link
Copy Markdown
Collaborator

Stacked on #111 (contracts). The walking skeleton every dataset copies: robocap → one exoego:v2 base-layer rrd per (device, session, segment).

  • RobocapDataset (dataforge/datasets/robocap.py): verify-only download (corpus lives on the NAS), sequence discovery (23 sessions / 88 segments, -old dirs excluded), and convert:
    • 6 fisheye62 cameras — Kalibr calibration reused from simplecv's private helpers (donor deleted in a later migration), log_pinhole, video remuxed chunk-native (Mp4Readersend_chunks, retimed onto the absolute epoch from the MP4 comment tag).
    • dev0 IMU — first emitter of exoego:v2 §8's reserved /world/rig_NN/imu_MM/{gyro,accel}: raw native-rate samples from the SQLite db (stdlib sqlite3), basalt's measured scale constants and 14 902 432 ns camera↔IMU offset; video_time is the raw camera clock. dev1/dev2 + multi-IMU blueprint panes are TODO. Malformed dbs (session_1's dev2) degrade to a warning, never abort.
    • Blueprint (3D rig | six named camera panes | gyro+accel strip) embedded at convert and registered as the catalog dataset default at register.
  • Four tyro verbs (dataforge/apis/) + thin tools/apps/ shims + pixi tasks: pixi run -e dataforge dataforge-{download,convert,register,view}.
  • exoego_schema.md §8: IMU flips from reserved → emitted.

Validated end-to-end on real data: session_1 seg1 converted in ~2 s (pure remux; 6 cams, 336 frames, 36 MiB), registered into a robocap dataset on a local rerun server catalog (port 51235), and pixel-verified headless from the catalog URI — video decode, frustums, IMU plots, dataforge:v1 properties, and the default blueprint all render. Evidence: /tmp/rerun-viewer-validation/20260819-dataforge-robocap/.

Gates: pixi run -e dataforge-dev {tests,lint,typecheck,deadcode} all green (26 tests).

Next: HOCap + hf_fetch + the gt layer.

…gister / view

RobocapDataset converts one (device, session, segment) into one exoego:v2
base-layer rrd: 6 fisheye62 cameras (Kalibr calibration reused from simplecv,
video remuxed chunk-native via Mp4Reader and retimed onto the absolute
comment-tag epoch) plus the dev0 IMU parsed raw from its SQLite db (basalt's
scale constants and 14_902_432 ns camera->IMU offset; dev1/dev2 TODO).
Timeline is video_time on the raw camera clock. Blueprint (3D rig | named
camera panes | gyro+accel strip) is embedded at convert and registered as
the catalog dataset default at register. IMU db failures are recoverable
(session_1 ships a malformed dev2 db).

Four tyro verbs under dataforge/apis with thin tools/apps shims and pixi
tasks; exoego_schema.md §8 IMU section flips from reserved to emitted.

Validated on real data: session_1 seg1 converted (6 cams, 336 frames),
registered into 'robocap' on a local rerun server catalog, and
pixel-verified in a headless viewer from the catalog URI — video decoding,
frustums, IMU plots, dataforge:v1 properties, and the default blueprint
(evidence in /tmp/rerun-viewer-validation/20260819-dataforge-robocap/).
Three independent reviews (API-minimalist, correctness, altitude) all
upheld the chunk-retime design — the Mp4Reader docstring itself prescribes
the downstream map, and no offset option or lens path exists. Fixes from
the pass: preserve row/chunk ids in retime (no index=/entity_path=
overrides), close the IMU sqlite connection (sqlite3's context manager
only ends the transaction), reword the 'absolute epoch' docs to the
boot-relative device clock and pin the duration-timeline choice, comment
the send_chunks/sample_count eagerness coupling, and record start_time_ns
as a capture property so the clock origin is queryable without scanning
chunks.
…form, add cap mesh

A static Transform3D on /world/rig_00 permanently shadows any temporal
world_T_rig a derived pose layer stacks on the segment (verified against a
live catalog: poses query back as identity, and static translation +
temporal quaternion compose into silently wrong poses). Per exoego:v2 a
world-anchored rig carries no transform, so the base now logs none, and
also cedes the root ViewCoordinates to the pose layer (whose world is
gravity-aligned Z-up; the base's rig frame is LFD, not the RDF previously
declared).

The textured cap scan (robocap-mesh/3DModel.glb, optional, skipped when
unreadable) is logged as a static child at /world/rig_00/mesh with the
hand-tuned scan-to-IMU-frame alignment carried over from robocap-slam, so
the rig reads as a physical object and rides any pose layer for free.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants