| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| from dataclasses import dataclass |
|
|
| from lerobot.configs import FeatureType, PipelineFeatureType, PolicyFeature |
| from lerobot.types import PolicyAction, RobotAction |
|
|
| from .pipeline import ActionProcessorStep, ProcessorStepRegistry, RobotActionProcessorStep |
|
|
|
|
| @ProcessorStepRegistry.register("map_tensor_to_delta_action_dict") |
| @dataclass |
| class MapTensorToDeltaActionDictStep(ActionProcessorStep): |
| """ |
| Maps a flat action tensor from a policy to a structured delta action dictionary. |
| |
| This step is typically used after a policy outputs a continuous action vector. |
| It decomposes the vector into named components for delta movements of the |
| end-effector (x, y, z) and optionally the gripper. |
| |
| Attributes: |
| use_gripper: If True, assumes the 4th element of the tensor is the |
| gripper action. |
| """ |
|
|
| use_gripper: bool = True |
|
|
| def action(self, action: PolicyAction) -> RobotAction: |
| if not isinstance(action, PolicyAction): |
| raise ValueError("Only PolicyAction is supported for this processor") |
|
|
| if action.dim() > 1: |
| action = action.squeeze(0) |
|
|
| |
| delta_action = { |
| "delta_x": action[0].item(), |
| "delta_y": action[1].item(), |
| "delta_z": action[2].item(), |
| } |
| if self.use_gripper: |
| delta_action["gripper"] = action[3].item() |
| return delta_action |
|
|
| def transform_features( |
| self, features: dict[PipelineFeatureType, dict[str, PolicyFeature]] |
| ) -> dict[PipelineFeatureType, dict[str, PolicyFeature]]: |
| for axis in ["x", "y", "z"]: |
| features[PipelineFeatureType.ACTION][f"delta_{axis}"] = PolicyFeature( |
| type=FeatureType.ACTION, shape=(1,) |
| ) |
|
|
| if self.use_gripper: |
| features[PipelineFeatureType.ACTION]["gripper"] = PolicyFeature( |
| type=FeatureType.ACTION, shape=(1,) |
| ) |
| return features |
|
|
|
|
| @ProcessorStepRegistry.register("map_delta_action_to_robot_action") |
| @dataclass |
| class MapDeltaActionToRobotActionStep(RobotActionProcessorStep): |
| """ |
| Maps delta actions from teleoperators to robot target actions for inverse kinematics. |
| |
| This step converts a dictionary of delta movements (e.g., from a gamepad) |
| into a target action format that includes an "enabled" flag and target |
| end-effector positions. It also handles scaling and noise filtering. |
| |
| Attributes: |
| position_scale: A factor to scale the delta position inputs. |
| noise_threshold: The magnitude below which delta inputs are considered noise |
| and do not trigger an "enabled" state. |
| """ |
|
|
| |
| position_scale: float = 1.0 |
| noise_threshold: float = 1e-3 |
|
|
| def action(self, action: RobotAction) -> RobotAction: |
| |
| |
| delta_x = action.pop("delta_x") |
| delta_y = action.pop("delta_y") |
| delta_z = action.pop("delta_z") |
| gripper = action.pop("gripper") |
|
|
| |
| |
| position_magnitude = (delta_x**2 + delta_y**2 + delta_z**2) ** 0.5 |
| enabled = position_magnitude > self.noise_threshold |
|
|
| |
| scaled_delta_x = delta_x * self.position_scale |
| scaled_delta_y = delta_y * self.position_scale |
| scaled_delta_z = delta_z * self.position_scale |
|
|
| |
| |
| target_wx = 0.0 |
| target_wy = 0.0 |
| target_wz = 0.0 |
|
|
| |
| action = { |
| "enabled": enabled, |
| "target_x": scaled_delta_x, |
| "target_y": scaled_delta_y, |
| "target_z": scaled_delta_z, |
| "target_wx": target_wx, |
| "target_wy": target_wy, |
| "target_wz": target_wz, |
| "gripper_vel": float(gripper), |
| } |
|
|
| return action |
|
|
| def transform_features( |
| self, features: dict[PipelineFeatureType, dict[str, PolicyFeature]] |
| ) -> dict[PipelineFeatureType, dict[str, PolicyFeature]]: |
| for axis in ["x", "y", "z", "gripper"]: |
| features[PipelineFeatureType.ACTION].pop(f"delta_{axis}", None) |
|
|
| for feat in ["enabled", "target_x", "target_y", "target_z", "target_wx", "target_wy", "target_wz"]: |
| features[PipelineFeatureType.ACTION][f"{feat}"] = PolicyFeature( |
| type=FeatureType.ACTION, shape=(1,) |
| ) |
|
|
| return features |
|
|