Repository navigation
Conversation
Interface for storing SharpaDex episodes (a Dexmate robot with two Sharpa Wave hands): - EMBODIMENT.DEXMATE_BIMANUAL = 8 and "dexmate_bimanual" in episode_rules.EMBODIMENTS. 7 stays free: unmerged branches use it for YAM_BIMANUAL. Existing ids are unchanged. - MCAP keeps its own embodiment subset (human_*, eva_*), so an MCAP episode declaring dexmate_bimanual is rejected instead of being checked against the gripper ROBOT profile. - rldb/zarr/dexmate_rules.py (torch-free): key names, widths, URDF hand joint limits and margins, and check_dexmate(store, T, errors, warnings), which the validator runs for dexmate_bimanual only. - Intrinsics: ZarrWriter accepts intrinsics=MissingMetadata() only for dexmate_bimanual and stores an explicit null. The validator errors on an absent key for every embodiment; an explicit null is an error, or a warning with --allow-missing, for Dexmate, and stays an error elsewhere. camera_errors gains a keyword-only allow_null_intrinsics=False, so every existing caller is unchanged. - package-data for the converter's kinematics assets (egomimic/scripts/sharpa_process/kinematics/). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
Padding rows past total_frames are never read; hand-limit errors and warnings switch exactly at ERROR_MARGIN_RAD and WARN_MARGIN_RAD (commands only warn); optional cmd_hand_keypoints are shape- and NaN-checked when present; one-frame spikes and values beyond 2*pi warn with the joint name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
Dexmate reuses Human's keypoints keymap and transform list: it reads
{side}.obs_hand_keypoints and {side}.obs_ee_pose (palm) into the Human
batch names and re-expresses them in obs_head_link_pose, which works
because every track is in the robot base frame. actions_keypoints is 140
wide with quaternion palms (138 YPR). Wrist cameras are optional
(wrist_cameras=False); there is no Pi mode.
Tested on a padded synthetic episode with a moving head: the whole chunk
is in the current head link frame, and past the last frame it repeats
that frame instead of reading the zero padding.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
- data/dexmate_keypoints.yaml: Dexmate keypoints keymap (wrist cameras on) and keypoints_headframe_quat, stride 1, lab sharpa_dex. - model/hpt_bc_keypoints_dexmate.yaml: dims 140/140, domain and action key, state_keypoints and wrist stems, front/wrist encoders, FM head. - train_zarr_dexmate_keypoints.yaml: both, without the video evaluator; the episodes have no camera calibration to draw keypoints with. - test_model_dims EXPECTED row; the valid split follows train. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
The (dexmate, hpt) recipe trains 2 CPU steps on synthetic dexmate_bimanual episodes (null intrinsics, wrist cameras) through trainHydra.train(), and the batch carries actions_keypoints, the keypoint state and all three cameras. The shared overrides disable checkpointing, so a second test saves a checkpoint, rebuilds the model from it alone (norm stats keyed by id 8, identical weights) and resumes training from it. Dexmate stays out of the Pi parametrization. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
CONTRIBUTING_DATA.md: the intrinsics rule in §6.3 and §6.4 now names the one exception (dexmate_bimanual may store an explicit null, accepted only with --allow-missing; an absent key always fails); §9 lists dexmate_bimanual = 8 and that ids are never renumbered; §11.1 and the checklist cover the Dexmate checks. INTERNAL_DATA.md: ingest with --allow-missing, and the Dexmate keypoints recipe. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
- The moving-head keymap test now moves the hands too and checks the chunk's future endpoint (keypoints, palm position and palm rotation) against inverse(base_T_head[now]) @ base_T_palm[future], so a chunk that repeated the current hand configuration would fail. - SPIKE_MAX_ABS_RAD is 6.2832, the old SharpaDex schema's max_abs, not 2*pi: 2*pi itself no longer warns. Boundary cases added. - dexmate_keypoints.yaml: SharpaDex always has both wrist cameras; turning them off also needs the wrist stems and encoders removed, since DDP fails on parameters with no gradient. - CONTRIBUTING_DATA.md: the §6.4 "always a dict" note and the upload checklist (intrinsics, extrinsics, obs_head_pose, coordinate frame) now state the dexmate_bimanual exceptions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
sharpadex_records holds what the converter needs from a SharpaDex manifest: EpisodeRecord, read_manifest and ManifestError (the manifest generator stays in the ingest tooling). It also fixes the two ID namespaces: - the source id <task>/<season>/<episode_index> (the manifest's recording_id) selects and locates source episodes; - the canonical id vendor_recording_id(task, season, index) = <task>__<season>__<index:06d> is the episode's vendor_recording_id, one path component accepted by main's vendor_recording_id_error, and parses back. A task or season part containing "/" or "__" is rejected, so the mapping is injective. read_manifest runs id_problems over the whole manifest (each recording_id must match its fields, canonical ids must be valid and unique) and turns malformed records into ManifestError. The module needs only the stdlib. manifest_v1.jsonl (28,993 records) reads with no id problems. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
kinematics/ holds the converter's models, shipped as package data: - the NTH POC1.0 platform URDF and the left/right Sharpa Wave URDFs, byte for byte as delivered, with the hand package's LICENSE.txt and NOTICE.txt; - sharpa_dexmate.yaml: each URDF's sha256 (checked on load), the head link, the hand mount, the aux joint order and all 21 MANO slot -> link mappings, the palm link and the tactile layout per hand; - urdf.py: the mesh-free URDF -> pytorch-kinematics chain builder, trimmed to batched FK (the models have no mimic joints, so those are refused). sharpa_tracks maps Sharpa's 65-column state/action vectors to the dexmate_bimanual arrays and derives palm poses, MANO-21 keypoints and link poses in robot_base. Joint names, orders and hand limits come from main's dexmate_rules, and joint-limit excursions are labelled with the verdict main's validator gives them (error past ERROR_MARGIN_RAD for observed hand joints, warning past WARN_MARGIN_RAD). fk_residuals and tcp_side_check are the two torch-side checks the converter's verification adds. Tests check the URDF names and limits against dexmate_rules, sha256 refusal, the batched FK against pytorch-kinematics' own builder, block independence, excursion tiers, FK residuals and the swapped-arm TCP check. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
Ports the old branch's SharpaDex profile as the only profile. lerobot_reader reads a release's <task>/<season>/lerobot_v2.1 seasons (the v3.0 export is not read): parquet columns as arrays, frames through PyAV with a thread cap, and the frame-count, frame_index and global-index checks. sharpa_to_zarr takes names, clocks and the selection from the manifest (--tasks/--seasons/--episodes or --recording-ids) and writes through ZarrWriter with main's required metadata: operator "sharpa" (a documented vendor-level surrogate, one constant), lab "sharpa_dex", the task folder as task_name, the canonical vendor_recording_id, and MissingMetadata() for intrinsics, scene and objects. license and source_episode_id go through metadata_override, as do the provenance attrs, the conversion report and sharpa_array_names (joint, taxel and tile names; features stay the writer's). Annotations go through the writer, skills through write_annotations, before the store is renamed into place. Tactile strips are 3-channel JPEG. Kept from the old branch, with tests: per-hand subtask text joined with "; " (ab7dbaa), the tactile column and mosaic layout, FFmpeg threads capped at available_cpus() // streams (0e96505), --recording-ids and --skip-done with ownership checks, now comparing canonical ids and checking that source_episode_id corresponds (82c1f30), the vendor-layout and TCP gates, and the provenance verdict (complete only without data defects). Every episode gets <hash>.mp4 and <hash>.validation.json. The report merges main's validate_episode(allow_missing=True), which already runs the dexmate_bimanual rules, with the FK residuals of the stored observed and commanded keypoints and the TCP side check; it also fails a waiver other than scene/objects/intrinsics and ids that do not correspond. read_report treats a missing or malformed report as a failure and recomputes ok. Dropped with the RoCo/Origami profile: --calibration, clipping, --utc-timestamp-column, --keep-vendor-arrays, the strict status policy, --lerobot-version, and the string schema_version, morphology and camera_mounts attrs. --validate and --save-mp4 are no longer options. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
The wheel must contain the three URDFs, the spec, LICENSE.txt/NOTICE.txt and the kinematics modules. A second case unpacks the wheel, runs Python from there with only the unpacked tree on PYTHONPATH, checks that the kinematics package is imported from it rather than the checkout, verifies every URDF's sha256 and builds the models. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
How to run sharpa_to_zarr on a release and a manifest, what it writes, the two episode ids (source and canonical) and how resume and ownership use them, the required metadata (including the operator surrogate "sharpa" and lab "sharpa_dex"), the CC-BY-NC-4.0 licence, the array mapping, the verification report and data_status, and the shipped kinematic models. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
Runs main's stage_processed_folder.read_batch on a converted episode's zarr.json (served by a fake S3 client): the staged row has the embodiment, task, frame count, fps, annotations flag and start time, and raw_attrs is plain JSON (null intrinsics/scene/objects, no NaN) with the licence and lab. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
… exactly
vendor_recording_id("task_", "season", 1) gave "task___season__000001",
which split back as ("task", "_season", ...) and failed to parse; the same
held for a season ending in "_" (X3 finding 5). A task or season part may no
longer end in "_", which also makes the manifest-wide id_problems check
refuse such records, and the parser splits from the right.
manifest_v1.jsonl (28,993 records) still reads, and every id inverts.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
A NaN in observation.state.tcp_pose made position_error_m_p95 NaN, and NaN > tolerance is false, so the check passed (X3 finding 4). tcp_side_check now fails on non-finite TCP poses or Link_7 FK before comparing any threshold, and never returns a non-finite metric. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
…e report A truncated episode was marked structural_sample, but verification_report ignored the status, so the report passed (X3 finding 3). --max-frames is removed, as plan E drops partial-delivery options, and the reader always reads whole episodes. The report gains a conversion check: data_status must be complete, and the source, retained and stored frame counts must be equal; otherwise the report fails. A swapped-TCP episode now fails it on both counts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
…erdict read_report returned no problems for a report without checks or source_episode_id, and for one whose validator and TCP checks had failed, as long as the top level said ok=True with no errors (X3 finding 2). It now requires every field and every check (validator, fk_residual, tcp_check, conversion), rejects NaN and Infinity, and judges each check from its own results: no validator errors (consistent with its ok flag), all four FK residuals finite and within tolerance, a passed TCP check whose metrics pass the thresholds, a complete conversion with equal frame counts. ok=True beside a failed check is a problem, as are ids that do not correspond, a report for another episode (file name or given ids) and an unexpected waiver. The report is written as strict JSON; a non-finite FK residual is stored as null. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
…wnership --skip-done marked an episode done when its sidecar named it, without opening the store or reading the report, and without --skip-done a sidecar of another recording was never checked (X3 finding 1). check_outputs now runs for every job. Any existing store, sidecar or report must name the job's canonical and source ids; another recording's, or an unreadable store, is refused even with --overwrite. A job is done only if the store, MP4, report and sidecar all exist, the store and sidecar name it, and the report passes read_report. Any other output of the job needs --overwrite, and conversion removes the old sidecar and report before writing, so a crash part-way never looks finished. The final summary counts refused jobs (as failures, exit 1), and a converted episode's exit status follows read_report on its fresh report. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
--license replaced the release licence with arbitrary text (X3 finding 6). The converter now stores one constant, LICENSE = "cc-by-nc-4.0", the licence the leads approved, and fails an episode whose release README declares no licence or a different one (compared case-insensitively). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
The runbook and docstrings said the FK residual confirms joint order, units and frames. The converter derives the keypoints from the same joints under the same column interpretation, so a permuted source would pass (X3 finding 7). The check is now described as consistency between the stored joints, keypoints and palm poses; the TCP side check remains the only comparison with an independent vendor signal, for the arms. A test pins the limitation: a permuted hand block derives and checks clean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
--skip-done trusted the passing report written at conversion time, so a store that later lost arrays (or an empty MP4) still counted as done. check_outputs now also runs the episode validator on the store as it is and requires a non-empty MP4 before skipping. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
The real SharpaDex HPT keypoints recipe takes 5 bf16 steps on one GPU over converted episodes from EGOVERSE_TEST_DEXMATE_DIR (LocalEpisodeResolver, the first three hashes pinned), checks the loss is finite, and rebuilds the model from last.ckpt alone: norm stats keyed by embodiment id 8, identical weights. Encoders start from random weights, so the test needs no network. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
The manifest planner and the chunked ingest driver stay on the branch jmni/sharpa-ingest-tooling as a one-off job for the v1.0 run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013JEf2oCYFjeq2bxE77pt31
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Store, validate, and train on SharpaDex-1.0. Adds
dexmate_bimanualembodiment as ID 8 with arm, hand, keypoint, tactile, head-link validation (missing arrays, incorrect shapes, non-finite values, limit violations). Camera intrinsics not provided with dataset so added a permission rule to bypass requirement for Sharpa DexmateIMPORTANT!!! Existing human and EVA datasets need no reprocessing, but existing recipes will recompute normalization statistics once due to loader changes