|
3 | 3 |
|
4 | 4 | import typer |
5 | 5 | from rcs.envs.storage_wrapper import StorageWrapper |
| 6 | +from rcs.lerobot_joint_converter import ( |
| 7 | + DEFAULT_CAMERAS, |
| 8 | + DEFAULT_DATASET_PATHS, |
| 9 | + DEFAULT_FPS, |
| 10 | + DEFAULT_GRIPPER_TYPE, |
| 11 | + DEFAULT_HF_DATA_DIR, |
| 12 | + DEFAULT_IMAGE_BATCH_SIZE, |
| 13 | + DEFAULT_JOINTS, |
| 14 | + DEFAULT_PER_ROBOT_ARM_DIM, |
| 15 | + DEFAULT_REPO_ID, |
| 16 | + DEFAULT_ROBOT_KEYS, |
| 17 | + DEFAULT_ROBOT_TYPE, |
| 18 | + camera_specs_to_configs, |
| 19 | + run_conversion, |
| 20 | +) |
6 | 21 | from rcs.sim.replayer import replay as replay_dataset |
7 | 22 |
|
8 | 23 | app = typer.Typer() |
@@ -67,5 +82,80 @@ def replay( |
67 | 82 | ) |
68 | 83 |
|
69 | 84 |
|
| 85 | +@app.command("lerobot-convert") |
| 86 | +def lerobot_convert( |
| 87 | + output: Annotated[ |
| 88 | + Path, |
| 89 | + typer.Argument( |
| 90 | + help="Output directory for the LeRobot dataset. Example: --output ./data_lerobot", |
| 91 | + ), |
| 92 | + ] = Path(DEFAULT_HF_DATA_DIR), |
| 93 | + dataset_paths: Annotated[ |
| 94 | + list[str] | None, |
| 95 | + typer.Option( |
| 96 | + "--dataset-path", |
| 97 | + help="Input parquet path or glob. Repeat for multiple datasets. Example: --dataset-path /data/session1 --dataset-path /data/session2", |
| 98 | + ), |
| 99 | + ] = None, |
| 100 | + repo_id: Annotated[ |
| 101 | + str, typer.Option(help="LeRobot repo id metadata. Example: --repo-id myorg/grasp_v2") |
| 102 | + ] = DEFAULT_REPO_ID, |
| 103 | + robot_type: Annotated[ |
| 104 | + str, typer.Option(help="Robot type for metadata and IK model lookup. Example: --robot-type fr3") |
| 105 | + ] = DEFAULT_ROBOT_TYPE, |
| 106 | + fps: Annotated[int, typer.Option(help="Dataset frames per second. Example: --fps 30")] = DEFAULT_FPS, |
| 107 | + robot_keys: Annotated[ |
| 108 | + list[str] | None, |
| 109 | + typer.Option( |
| 110 | + "--robot-key", |
| 111 | + help="Robot keys to concatenate. Repeat for multiple robots. Example: --robot-key left --robot-key right", |
| 112 | + ), |
| 113 | + ] = None, |
| 114 | + joints: Annotated[ |
| 115 | + bool, typer.Option(help="Whether absolute_action is already in joint space. Example: --joints") |
| 116 | + ] = DEFAULT_JOINTS, |
| 117 | + gripper_type: Annotated[ |
| 118 | + str, typer.Option(help="Gripper type used to derive TCP offset. Example: --gripper-type Robotiq2F85") |
| 119 | + ] = DEFAULT_GRIPPER_TYPE, |
| 120 | + camera_specs: Annotated[ |
| 121 | + list[str] | None, |
| 122 | + typer.Option( |
| 123 | + "--camera", |
| 124 | + help=( |
| 125 | + "Camera spec as name[:source_name][@HEIGHTxWIDTH]. Repeat for multiple cameras. " |
| 126 | + "The name becomes the LeRobot output key (observation.images.<name>). " |
| 127 | + "The optional source_name is the key in the source parquet (obs.frames.<source_name>.rgb.data); " |
| 128 | + "if omitted, the image_ prefix is stripped from name to derive it. " |
| 129 | + "Example: --camera head@256x256 --camera image_left_wrist:left_wrist@256x256" |
| 130 | + ), |
| 131 | + ), |
| 132 | + ] = None, |
| 133 | + image_batch_size: Annotated[ |
| 134 | + int, typer.Option(help="Batch size for image decoding. Example: --image-batch-size 32") |
| 135 | + ] = DEFAULT_IMAGE_BATCH_SIZE, |
| 136 | + per_robot_arm_dim: Annotated[ |
| 137 | + int, typer.Option(help="Per-robot arm joint/action dimension without gripper. Example: --per-robot-arm-dim 7") |
| 138 | + ] = DEFAULT_PER_ROBOT_ARM_DIM, |
| 139 | + success: Annotated[bool, typer.Option(help="Only include successful episodes. Example: --success")] = True, |
| 140 | + n: Annotated[int, typer.Option(help="Maximum number of episodes to convert. -1 means all. Example: --n 50")] = -1, |
| 141 | +): |
| 142 | + cameras = camera_specs_to_configs(camera_specs) if camera_specs is not None else list(DEFAULT_CAMERAS) |
| 143 | + run_conversion( |
| 144 | + root=output, |
| 145 | + dataset_paths=dataset_paths or list(DEFAULT_DATASET_PATHS), |
| 146 | + repo_id=repo_id, |
| 147 | + robot_type=robot_type, |
| 148 | + fps=fps, |
| 149 | + robot_keys=robot_keys or list(DEFAULT_ROBOT_KEYS), |
| 150 | + joints=joints, |
| 151 | + gripper_type=gripper_type, |
| 152 | + cameras=cameras, |
| 153 | + image_batch_size=image_batch_size, |
| 154 | + per_robot_arm_dim=per_robot_arm_dim, |
| 155 | + success=success, |
| 156 | + n=n, |
| 157 | + ) |
| 158 | + |
| 159 | + |
70 | 160 | if __name__ == "__main__": |
71 | 161 | app() |
0 commit comments