chore: remove unused code (#2062)
This commit is contained in:
@@ -95,7 +95,6 @@ class HILSerlProcessorConfig:
|
|||||||
class ObservationConfig:
|
class ObservationConfig:
|
||||||
add_joint_velocity_to_observation: bool = False # Add joint velocities to state
|
add_joint_velocity_to_observation: bool = False # Add joint velocities to state
|
||||||
add_current_to_observation: bool = False # Add motor currents to state
|
add_current_to_observation: bool = False # Add motor currents to state
|
||||||
add_ee_pose_to_observation: bool = False # Add end-effector pose to state
|
|
||||||
display_cameras: bool = False # Display camera feeds during execution
|
display_cameras: bool = False # Display camera feeds during execution
|
||||||
|
|
||||||
class ImagePreprocessingConfig:
|
class ImagePreprocessingConfig:
|
||||||
@@ -105,7 +104,6 @@ class ImagePreprocessingConfig:
|
|||||||
class GripperConfig:
|
class GripperConfig:
|
||||||
use_gripper: bool = True # Enable gripper control
|
use_gripper: bool = True # Enable gripper control
|
||||||
gripper_penalty: float = 0.0 # Penalty for inappropriate gripper usage
|
gripper_penalty: float = 0.0 # Penalty for inappropriate gripper usage
|
||||||
gripper_penalty_in_reward: bool = False # Include gripper penalty in reward
|
|
||||||
|
|
||||||
class ResetConfig:
|
class ResetConfig:
|
||||||
fixed_reset_joint_positions: Any | None = None # Joint positions for reset
|
fixed_reset_joint_positions: Any | None = None # Joint positions for reset
|
||||||
@@ -288,7 +286,6 @@ You can enable multiple observation processing features simultaneously:
|
|||||||
"observation": {
|
"observation": {
|
||||||
"add_joint_velocity_to_observation": true,
|
"add_joint_velocity_to_observation": true,
|
||||||
"add_current_to_observation": true,
|
"add_current_to_observation": true,
|
||||||
"add_ee_pose_to_observation": false,
|
|
||||||
"display_cameras": false
|
"display_cameras": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,13 +136,12 @@ Additionally you can customize mapping or safety limits by editing the processor
|
|||||||
),
|
),
|
||||||
```
|
```
|
||||||
|
|
||||||
- The `EEBoundsAndSafety` step clamps EE motion to a workspace and checks for large ee step jumps to ensure safety. The `end_effector_bounds` are the bounds for the EE pose and can be modified to change the workspace. The `max_ee_step_m` and `max_ee_twist_step_rad` are the step limits for the EE pose and can be modified to change the safety limits.
|
- The `EEBoundsAndSafety` step clamps EE motion to a workspace and checks for large ee step jumps to ensure safety. The `end_effector_bounds` are the bounds for the EE pose and can be modified to change the workspace. The `max_ee_step_m` are the step limits for the EE pose and can be modified to change the safety limits.
|
||||||
|
|
||||||
```examples/phone_to_so100/teleoperate.py
|
```examples/phone_to_so100/teleoperate.py
|
||||||
EEBoundsAndSafety(
|
EEBoundsAndSafety(
|
||||||
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
||||||
max_ee_step_m=0.10,
|
max_ee_step_m=0.10,
|
||||||
max_ee_twist_step_rad=0.50,
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ phone_to_robot_ee_pose_processor = RobotProcessorPipeline[RobotAction, RobotActi
|
|||||||
kinematics=kinematics_solver, end_effector_step_sizes={"x": 0.5, "y": 0.5, "z": 0.5}, motor_names=list(robot.bus.motors.keys()),
|
kinematics=kinematics_solver, end_effector_step_sizes={"x": 0.5, "y": 0.5, "z": 0.5}, motor_names=list(robot.bus.motors.keys()),
|
||||||
),
|
),
|
||||||
EEBoundsAndSafety(
|
EEBoundsAndSafety(
|
||||||
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]}, max_ee_step_m=0.20, max_ee_twist_step_rad=0.50,
|
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]}, max_ee_step_m=0.20,
|
||||||
),
|
),
|
||||||
GripperVelocityToJoint(),
|
GripperVelocityToJoint(),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -84,7 +84,6 @@ phone_to_robot_ee_pose_processor = RobotProcessorPipeline[tuple[RobotAction, Rob
|
|||||||
EEBoundsAndSafety(
|
EEBoundsAndSafety(
|
||||||
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
||||||
max_ee_step_m=0.20,
|
max_ee_step_m=0.20,
|
||||||
max_ee_twist_step_rad=0.50,
|
|
||||||
),
|
),
|
||||||
GripperVelocityToJoint(speed_factor=20.0),
|
GripperVelocityToJoint(speed_factor=20.0),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ phone_to_robot_joints_processor = RobotProcessorPipeline[tuple[RobotAction, Robo
|
|||||||
EEBoundsAndSafety(
|
EEBoundsAndSafety(
|
||||||
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
||||||
max_ee_step_m=0.10,
|
max_ee_step_m=0.10,
|
||||||
max_ee_twist_step_rad=0.50,
|
|
||||||
),
|
),
|
||||||
GripperVelocityToJoint(
|
GripperVelocityToJoint(
|
||||||
speed_factor=20.0,
|
speed_factor=20.0,
|
||||||
|
|||||||
@@ -101,7 +101,6 @@ ee_to_follower_joints = RobotProcessorPipeline[tuple[RobotAction, RobotObservati
|
|||||||
EEBoundsAndSafety(
|
EEBoundsAndSafety(
|
||||||
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
||||||
max_ee_step_m=0.10,
|
max_ee_step_m=0.10,
|
||||||
max_ee_twist_step_rad=0.50,
|
|
||||||
),
|
),
|
||||||
InverseKinematicsEEToJoints(
|
InverseKinematicsEEToJoints(
|
||||||
kinematics=follower_kinematics_solver,
|
kinematics=follower_kinematics_solver,
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ ee_to_follower_joints = RobotProcessorPipeline[tuple[RobotAction, RobotObservati
|
|||||||
EEBoundsAndSafety(
|
EEBoundsAndSafety(
|
||||||
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
end_effector_bounds={"min": [-1.0, -1.0, -1.0], "max": [1.0, 1.0, 1.0]},
|
||||||
max_ee_step_m=0.10,
|
max_ee_step_m=0.10,
|
||||||
max_ee_twist_step_rad=0.50,
|
|
||||||
),
|
),
|
||||||
InverseKinematicsEEToJoints(
|
InverseKinematicsEEToJoints(
|
||||||
kinematics=follower_kinematics_solver,
|
kinematics=follower_kinematics_solver,
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ from lerobot.utils.constants import OBS_IMAGES, OBS_STATE, OBS_STR
|
|||||||
from lerobot.utils.utils import init_logging
|
from lerobot.utils.utils import init_logging
|
||||||
|
|
||||||
Action = torch.Tensor
|
Action = torch.Tensor
|
||||||
ActionChunk = torch.Tensor
|
|
||||||
|
|
||||||
# observation as received from the robot
|
# observation as received from the robot
|
||||||
RawObservation = dict[str, torch.Tensor]
|
RawObservation = dict[str, torch.Tensor]
|
||||||
@@ -46,7 +45,7 @@ Observation = dict[str, torch.Tensor]
|
|||||||
def visualize_action_queue_size(action_queue_size: list[int]) -> None:
|
def visualize_action_queue_size(action_queue_size: list[int]) -> None:
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
fig, ax = plt.subplots()
|
_, ax = plt.subplots()
|
||||||
ax.set_title("Action Queue Size Over Time")
|
ax.set_title("Action Queue Size Over Time")
|
||||||
ax.set_xlabel("Environment steps")
|
ax.set_xlabel("Environment steps")
|
||||||
ax.set_ylabel("Action Queue Size")
|
ax.set_ylabel("Action Queue Size")
|
||||||
|
|||||||
@@ -15,14 +15,10 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
import platform
|
import platform
|
||||||
from pathlib import Path
|
|
||||||
from typing import TypeAlias
|
|
||||||
|
|
||||||
from .camera import Camera
|
from .camera import Camera
|
||||||
from .configs import CameraConfig, Cv2Rotation
|
from .configs import CameraConfig, Cv2Rotation
|
||||||
|
|
||||||
IndexOrPath: TypeAlias = int | Path
|
|
||||||
|
|
||||||
|
|
||||||
def make_cameras_from_configs(camera_configs: dict[str, CameraConfig]) -> dict[str, Camera]:
|
def make_cameras_from_configs(camera_configs: dict[str, CameraConfig]) -> dict[str, Camera]:
|
||||||
cameras = {}
|
cameras = {}
|
||||||
|
|||||||
@@ -16,9 +16,6 @@
|
|||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
|
|
||||||
from lerobot import (
|
|
||||||
policies, # noqa: F401
|
|
||||||
)
|
|
||||||
from lerobot.datasets.transforms import ImageTransformsConfig
|
from lerobot.datasets.transforms import ImageTransformsConfig
|
||||||
from lerobot.datasets.video_utils import get_safe_default_codec
|
from lerobot.datasets.video_utils import get_safe_default_codec
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
# https://stackoverflow.com/questions/24481852/serialising-an-enum-member-to-json
|
# https://stackoverflow.com/questions/24481852/serialising-an-enum-member-to-json
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
from typing import Any, Protocol
|
|
||||||
|
|
||||||
|
|
||||||
class FeatureType(str, Enum):
|
class FeatureType(str, Enum):
|
||||||
@@ -38,10 +37,6 @@ class NormalizationMode(str, Enum):
|
|||||||
IDENTITY = "IDENTITY"
|
IDENTITY = "IDENTITY"
|
||||||
|
|
||||||
|
|
||||||
class DictLike(Protocol):
|
|
||||||
def __getitem__(self, key: Any) -> Any: ...
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class PolicyFeature:
|
class PolicyFeature:
|
||||||
type: FeatureType
|
type: FeatureType
|
||||||
|
|||||||
@@ -848,11 +848,6 @@ class LeRobotDataset(torch.utils.data.Dataset):
|
|||||||
|
|
||||||
return item
|
return item
|
||||||
|
|
||||||
def _add_padding_keys(self, item: dict, padding: dict[str, list[bool]]) -> dict:
|
|
||||||
for key, val in padding.items():
|
|
||||||
item[key] = torch.BoolTensor(val)
|
|
||||||
return item
|
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return self.num_frames
|
return self.num_frames
|
||||||
|
|
||||||
@@ -1396,11 +1391,6 @@ class MultiLeRobotDataset(torch.utils.data.Dataset):
|
|||||||
"""
|
"""
|
||||||
return {repo_id: i for i, repo_id in enumerate(self.repo_ids)}
|
return {repo_id: i for i, repo_id in enumerate(self.repo_ids)}
|
||||||
|
|
||||||
@property
|
|
||||||
def repo_index_to_id(self):
|
|
||||||
"""Return the inverse mapping if repo_id_to_index."""
|
|
||||||
return {v: k for k, v in self.repo_id_to_index}
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fps(self) -> int:
|
def fps(self) -> int:
|
||||||
"""Frames per second used during data collection.
|
"""Frames per second used during data collection.
|
||||||
|
|||||||
@@ -13,67 +13,10 @@
|
|||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
import inspect
|
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
import datasets
|
import datasets
|
||||||
import numpy
|
|
||||||
import PIL
|
|
||||||
import torch
|
import torch
|
||||||
|
|
||||||
from lerobot.datasets.video_utils import encode_video_frames
|
|
||||||
|
|
||||||
|
|
||||||
def concatenate_episodes(ep_dicts):
|
|
||||||
data_dict = {}
|
|
||||||
|
|
||||||
keys = ep_dicts[0].keys()
|
|
||||||
for key in keys:
|
|
||||||
if torch.is_tensor(ep_dicts[0][key][0]):
|
|
||||||
data_dict[key] = torch.cat([ep_dict[key] for ep_dict in ep_dicts])
|
|
||||||
else:
|
|
||||||
if key not in data_dict:
|
|
||||||
data_dict[key] = []
|
|
||||||
for ep_dict in ep_dicts:
|
|
||||||
for x in ep_dict[key]:
|
|
||||||
data_dict[key].append(x)
|
|
||||||
|
|
||||||
total_frames = data_dict["frame_index"].shape[0]
|
|
||||||
data_dict["index"] = torch.arange(0, total_frames, 1)
|
|
||||||
return data_dict
|
|
||||||
|
|
||||||
|
|
||||||
def save_images_concurrently(imgs_array: numpy.array, out_dir: Path, max_workers: int = 4):
|
|
||||||
out_dir = Path(out_dir)
|
|
||||||
out_dir.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
def save_image(img_array, i, out_dir):
|
|
||||||
img = PIL.Image.fromarray(img_array)
|
|
||||||
img.save(str(out_dir / f"frame_{i:06d}.png"), quality=100)
|
|
||||||
|
|
||||||
num_images = len(imgs_array)
|
|
||||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
|
||||||
[executor.submit(save_image, imgs_array[i], i, out_dir) for i in range(num_images)]
|
|
||||||
|
|
||||||
|
|
||||||
def get_default_encoding() -> dict:
|
|
||||||
"""Returns the default ffmpeg encoding parameters used by `encode_video_frames`."""
|
|
||||||
signature = inspect.signature(encode_video_frames)
|
|
||||||
return {
|
|
||||||
k: v.default
|
|
||||||
for k, v in signature.parameters.items()
|
|
||||||
if v.default is not inspect.Parameter.empty and k in ["vcodec", "pix_fmt", "g", "crf"]
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def check_repo_id(repo_id: str) -> None:
|
|
||||||
if len(repo_id.split("/")) != 2:
|
|
||||||
raise ValueError(
|
|
||||||
f"""`repo_id` is expected to contain a community or user id `/` the name of the dataset
|
|
||||||
(e.g. 'lerobot/pusht'), but contains '{repo_id}'."""
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO(aliberts): remove
|
# TODO(aliberts): remove
|
||||||
def calculate_episode_data_index(hf_dataset: datasets.Dataset) -> dict[str, torch.Tensor]:
|
def calculate_episode_data_index(hf_dataset: datasets.Dataset) -> dict[str, torch.Tensor]:
|
||||||
|
|||||||
@@ -298,9 +298,7 @@ class StreamingLeRobotDataset(torch.utils.data.IterableDataset):
|
|||||||
|
|
||||||
return padding_mask
|
return padding_mask
|
||||||
|
|
||||||
def make_frame(
|
def make_frame(self, dataset_iterator: Backtrackable) -> Generator:
|
||||||
self, dataset_iterator: Backtrackable, previous_dataset_iterator: Backtrackable | None = None
|
|
||||||
) -> Generator:
|
|
||||||
"""Makes a frame starting from a dataset iterator"""
|
"""Makes a frame starting from a dataset iterator"""
|
||||||
item = next(dataset_iterator)
|
item = next(dataset_iterator)
|
||||||
item = item_to_torch(item)
|
item = item_to_torch(item)
|
||||||
|
|||||||
@@ -67,18 +67,6 @@ DEFAULT_IMAGE_PATH = "images/{image_key}/episode-{episode_index:06d}/frame-{fram
|
|||||||
LEGACY_EPISODES_PATH = "meta/episodes.jsonl"
|
LEGACY_EPISODES_PATH = "meta/episodes.jsonl"
|
||||||
LEGACY_EPISODES_STATS_PATH = "meta/episodes_stats.jsonl"
|
LEGACY_EPISODES_STATS_PATH = "meta/episodes_stats.jsonl"
|
||||||
LEGACY_TASKS_PATH = "meta/tasks.jsonl"
|
LEGACY_TASKS_PATH = "meta/tasks.jsonl"
|
||||||
LEGACY_DEFAULT_VIDEO_PATH = "videos/chunk-{episode_chunk:03d}/{video_key}/episode_{episode_index:06d}.mp4"
|
|
||||||
LEGACY_DEFAULT_PARQUET_PATH = "data/chunk-{episode_chunk:03d}/episode_{episode_index:06d}.parquet"
|
|
||||||
|
|
||||||
DATASET_CARD_TEMPLATE = """
|
|
||||||
---
|
|
||||||
# Metadata will go there
|
|
||||||
---
|
|
||||||
This dataset was created using [LeRobot](https://github.com/huggingface/lerobot).
|
|
||||||
|
|
||||||
## {}
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
DEFAULT_FEATURES = {
|
DEFAULT_FEATURES = {
|
||||||
"timestamp": {"dtype": "float32", "shape": (1,), "names": None},
|
"timestamp": {"dtype": "float32", "shape": (1,), "names": None},
|
||||||
@@ -383,12 +371,6 @@ def load_episodes(local_dir: Path) -> datasets.Dataset:
|
|||||||
return episodes
|
return episodes
|
||||||
|
|
||||||
|
|
||||||
def backward_compatible_episodes_stats(
|
|
||||||
stats: dict[str, dict[str, np.ndarray]], episodes: list[int]
|
|
||||||
) -> dict[int, dict[str, dict[str, np.ndarray]]]:
|
|
||||||
return dict.fromkeys(episodes, stats)
|
|
||||||
|
|
||||||
|
|
||||||
def load_image_as_numpy(
|
def load_image_as_numpy(
|
||||||
fpath: str | Path, dtype: np.dtype = np.float32, channel_first: bool = True
|
fpath: str | Path, dtype: np.dtype = np.float32, channel_first: bool = True
|
||||||
) -> np.ndarray:
|
) -> np.ndarray:
|
||||||
@@ -1346,12 +1328,6 @@ class Backtrackable(Generic[T]):
|
|||||||
# When cursor<0, slice so the order remains chronological
|
# When cursor<0, slice so the order remains chronological
|
||||||
return list(self._back_buf)[: self._cursor or None]
|
return list(self._back_buf)[: self._cursor or None]
|
||||||
|
|
||||||
def lookahead_buffer(self) -> list[T]:
|
|
||||||
"""
|
|
||||||
Return a copy of the current lookahead buffer.
|
|
||||||
"""
|
|
||||||
return list(self._ahead_buf)
|
|
||||||
|
|
||||||
def can_peek_back(self, steps: int = 1) -> bool:
|
def can_peek_back(self, steps: int = 1) -> bool:
|
||||||
"""
|
"""
|
||||||
Check if we can go back `steps` items without raising an IndexError.
|
Check if we can go back `steps` items without raising an IndexError.
|
||||||
@@ -1377,31 +1353,6 @@ class Backtrackable(Generic[T]):
|
|||||||
except StopIteration:
|
except StopIteration:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def reset_cursor(self) -> None:
|
|
||||||
"""
|
|
||||||
Reset cursor to the most recent position (equivalent to calling next()
|
|
||||||
until you're back to the latest item).
|
|
||||||
"""
|
|
||||||
self._cursor = 0
|
|
||||||
|
|
||||||
def clear_ahead_buffer(self) -> None:
|
|
||||||
"""
|
|
||||||
Clear the ahead buffer, discarding any pre-fetched items.
|
|
||||||
"""
|
|
||||||
self._ahead_buf.clear()
|
|
||||||
|
|
||||||
def switch_source_iterable(self, new_source: Iterable[T]) -> None:
|
|
||||||
"""
|
|
||||||
Switch the source of the backtrackable to a new iterable, keeping the history.
|
|
||||||
|
|
||||||
This is useful when iterating over a sequence of datasets. The history from the
|
|
||||||
previous source is kept, but the lookahead buffer is cleared. The cursor is reset
|
|
||||||
to the present.
|
|
||||||
"""
|
|
||||||
self._source = iter(new_source)
|
|
||||||
self.clear_ahead_buffer()
|
|
||||||
self.reset_cursor()
|
|
||||||
|
|
||||||
|
|
||||||
def safe_shard(dataset: datasets.IterableDataset, index: int, num_shards: int) -> datasets.Dataset:
|
def safe_shard(dataset: datasets.IterableDataset, index: int, num_shards: int) -> datasets.Dataset:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -585,19 +585,6 @@ def get_video_pixel_channels(pix_fmt: str) -> int:
|
|||||||
raise ValueError("Unknown format")
|
raise ValueError("Unknown format")
|
||||||
|
|
||||||
|
|
||||||
def get_image_pixel_channels(image: Image):
|
|
||||||
if image.mode == "L":
|
|
||||||
return 1 # Grayscale
|
|
||||||
elif image.mode == "LA":
|
|
||||||
return 2 # Grayscale + Alpha
|
|
||||||
elif image.mode == "RGB":
|
|
||||||
return 3 # RGB
|
|
||||||
elif image.mode == "RGBA":
|
|
||||||
return 4 # RGBA
|
|
||||||
else:
|
|
||||||
raise ValueError("Unknown format")
|
|
||||||
|
|
||||||
|
|
||||||
def get_video_duration_in_s(video_path: Path | str) -> float:
|
def get_video_duration_in_s(video_path: Path | str) -> float:
|
||||||
"""
|
"""
|
||||||
Get the duration of a video file in seconds using PyAV.
|
Get the duration of a video file in seconds using PyAV.
|
||||||
|
|||||||
@@ -193,7 +193,6 @@ class ObservationConfig:
|
|||||||
|
|
||||||
add_joint_velocity_to_observation: bool = False
|
add_joint_velocity_to_observation: bool = False
|
||||||
add_current_to_observation: bool = False
|
add_current_to_observation: bool = False
|
||||||
add_ee_pose_to_observation: bool = False
|
|
||||||
display_cameras: bool = False
|
display_cameras: bool = False
|
||||||
|
|
||||||
|
|
||||||
@@ -203,7 +202,6 @@ class GripperConfig:
|
|||||||
|
|
||||||
use_gripper: bool = True
|
use_gripper: bool = True
|
||||||
gripper_penalty: float = 0.0
|
gripper_penalty: float = 0.0
|
||||||
gripper_penalty_in_reward: bool = False
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|||||||
@@ -99,12 +99,6 @@ class Motor:
|
|||||||
norm_mode: MotorNormMode
|
norm_mode: MotorNormMode
|
||||||
|
|
||||||
|
|
||||||
class JointOutOfRangeError(Exception):
|
|
||||||
def __init__(self, message="Joint is out of range"):
|
|
||||||
self.message = message
|
|
||||||
super().__init__(self.message)
|
|
||||||
|
|
||||||
|
|
||||||
class PortHandler(Protocol):
|
class PortHandler(Protocol):
|
||||||
def __init__(self, port_name):
|
def __init__(self, port_name):
|
||||||
self.is_open: bool
|
self.is_open: bool
|
||||||
|
|||||||
@@ -139,8 +139,6 @@ class SACConfig(PreTrainedConfig):
|
|||||||
# Training parameter
|
# Training parameter
|
||||||
# Number of steps for online training
|
# Number of steps for online training
|
||||||
online_steps: int = 1000000
|
online_steps: int = 1000000
|
||||||
# Seed for the online environment
|
|
||||||
online_env_seed: int = 10000
|
|
||||||
# Capacity of the online replay buffer
|
# Capacity of the online replay buffer
|
||||||
online_buffer_capacity: int = 100000
|
online_buffer_capacity: int = 100000
|
||||||
# Capacity of the offline replay buffer
|
# Capacity of the offline replay buffer
|
||||||
|
|||||||
@@ -1061,15 +1061,3 @@ class TanhMultivariateNormalDiag(TransformedDistribution):
|
|||||||
x = transform(x)
|
x = transform(x)
|
||||||
|
|
||||||
return x
|
return x
|
||||||
|
|
||||||
|
|
||||||
def _convert_normalization_params_to_tensor(normalization_params: dict) -> dict:
|
|
||||||
converted_params = {}
|
|
||||||
for outer_key, inner_dict in normalization_params.items():
|
|
||||||
converted_params[outer_key] = {}
|
|
||||||
for key, value in inner_dict.items():
|
|
||||||
converted_params[outer_key][key] = torch.tensor(value)
|
|
||||||
if "image" in outer_key:
|
|
||||||
converted_params[outer_key][key] = converted_params[outer_key][key].view(3, 1, 1)
|
|
||||||
|
|
||||||
return converted_params
|
|
||||||
|
|||||||
@@ -82,7 +82,6 @@ class VQBeTConfig(PreTrainedConfig):
|
|||||||
gpt_n_head: Number of headers of GPT
|
gpt_n_head: Number of headers of GPT
|
||||||
gpt_hidden_dim: Size of hidden dimensions of GPT
|
gpt_hidden_dim: Size of hidden dimensions of GPT
|
||||||
dropout: Dropout rate for GPT
|
dropout: Dropout rate for GPT
|
||||||
mlp_hidden_dim: Size of hidden dimensions of offset header / bin prediction headers parts of VQ-BeT
|
|
||||||
offset_loss_weight: A constant that is multiplied to the offset loss
|
offset_loss_weight: A constant that is multiplied to the offset loss
|
||||||
primary_code_loss_weight: A constant that is multiplied to the primary code prediction loss
|
primary_code_loss_weight: A constant that is multiplied to the primary code prediction loss
|
||||||
secondary_code_loss_weight: A constant that is multiplied to the secondary code prediction loss
|
secondary_code_loss_weight: A constant that is multiplied to the secondary code prediction loss
|
||||||
@@ -125,7 +124,6 @@ class VQBeTConfig(PreTrainedConfig):
|
|||||||
gpt_n_head: int = 8
|
gpt_n_head: int = 8
|
||||||
gpt_hidden_dim: int = 512
|
gpt_hidden_dim: int = 512
|
||||||
dropout: float = 0.1
|
dropout: float = 0.1
|
||||||
mlp_hidden_dim: int = 1024
|
|
||||||
offset_loss_weight: float = 10000.0
|
offset_loss_weight: float = 10000.0
|
||||||
primary_code_loss_weight: float = 5.0
|
primary_code_loss_weight: float = 5.0
|
||||||
secondary_code_loss_weight: float = 0.5
|
secondary_code_loss_weight: float = 0.5
|
||||||
|
|||||||
@@ -231,16 +231,6 @@ class GPT(nn.Module):
|
|||||||
torch.nn.init.zeros_(module.bias)
|
torch.nn.init.zeros_(module.bias)
|
||||||
torch.nn.init.ones_(module.weight)
|
torch.nn.init.ones_(module.weight)
|
||||||
|
|
||||||
def crop_block_size(self, gpt_block_size):
|
|
||||||
# model surgery to decrease the block size if necessary
|
|
||||||
# e.g. we may load the GPT2 pretrained model checkpoint (block size 1024)
|
|
||||||
# but want to use a smaller block size for some smaller, simpler model
|
|
||||||
assert gpt_block_size <= self.config.gpt_block_size
|
|
||||||
self.config.gpt_block_size = gpt_block_size
|
|
||||||
self.transformer.wpe.weight = nn.Parameter(self.transformer.wpe.weight[:gpt_block_size])
|
|
||||||
for block in self.transformer.h:
|
|
||||||
block.attn.bias = block.attn.bias[:, :, :gpt_block_size, :gpt_block_size]
|
|
||||||
|
|
||||||
def configure_parameters(self):
|
def configure_parameters(self):
|
||||||
"""
|
"""
|
||||||
This long function is unfortunately doing something very simple and is being very defensive:
|
This long function is unfortunately doing something very simple and is being very defensive:
|
||||||
|
|||||||
@@ -83,14 +83,12 @@ class MapDeltaActionToRobotActionStep(RobotActionProcessorStep):
|
|||||||
|
|
||||||
Attributes:
|
Attributes:
|
||||||
position_scale: A factor to scale the delta position inputs.
|
position_scale: A factor to scale the delta position inputs.
|
||||||
rotation_scale: A factor to scale the delta rotation inputs (currently unused).
|
|
||||||
noise_threshold: The magnitude below which delta inputs are considered noise
|
noise_threshold: The magnitude below which delta inputs are considered noise
|
||||||
and do not trigger an "enabled" state.
|
and do not trigger an "enabled" state.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Scale factors for delta movements
|
# Scale factors for delta movements
|
||||||
position_scale: float = 1.0
|
position_scale: float = 1.0
|
||||||
rotation_scale: float = 0.0 # No rotation deltas for gamepad/keyboard
|
|
||||||
noise_threshold: float = 1e-3 # 1 mm threshold to filter out noise
|
noise_threshold: float = 1e-3 # 1 mm threshold to filter out noise
|
||||||
|
|
||||||
def action(self, action: RobotAction) -> RobotAction:
|
def action(self, action: RobotAction) -> RobotAction:
|
||||||
|
|||||||
@@ -97,8 +97,6 @@ from .gym_manipulator import (
|
|||||||
step_env_and_process_transition,
|
step_env_and_process_transition,
|
||||||
)
|
)
|
||||||
|
|
||||||
ACTOR_SHUTDOWN_TIMEOUT = 30
|
|
||||||
|
|
||||||
# Main entry point
|
# Main entry point
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -102,8 +102,6 @@ from lerobot.utils.utils import (
|
|||||||
|
|
||||||
from .learner_service import MAX_WORKERS, SHUTDOWN_TIMEOUT, LearnerService
|
from .learner_service import MAX_WORKERS, SHUTDOWN_TIMEOUT, LearnerService
|
||||||
|
|
||||||
LOG_PREFIX = "[LEARNER]"
|
|
||||||
|
|
||||||
|
|
||||||
@parser.wrap()
|
@parser.wrap()
|
||||||
def train_cli(cfg: TrainRLServerPipelineConfig):
|
def train_cli(cfg: TrainRLServerPipelineConfig):
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ class HopeJrArm(Robot):
|
|||||||
def is_calibrated(self) -> bool:
|
def is_calibrated(self) -> bool:
|
||||||
return self.bus.is_calibrated
|
return self.bus.is_calibrated
|
||||||
|
|
||||||
def calibrate(self, limb_name: str = None) -> None:
|
def calibrate(self) -> None:
|
||||||
groups = {
|
groups = {
|
||||||
"all": list(self.bus.motors.keys()),
|
"all": list(self.bus.motors.keys()),
|
||||||
"shoulder": ["shoulder_pitch", "shoulder_yaw", "shoulder_roll"],
|
"shoulder": ["shoulder_pitch", "shoulder_yaw", "shoulder_roll"],
|
||||||
|
|||||||
@@ -193,16 +193,12 @@ class EEBoundsAndSafety(RobotActionProcessorStep):
|
|||||||
Attributes:
|
Attributes:
|
||||||
end_effector_bounds: A dictionary with "min" and "max" keys for position clipping.
|
end_effector_bounds: A dictionary with "min" and "max" keys for position clipping.
|
||||||
max_ee_step_m: The maximum allowed change in position (in meters) between steps.
|
max_ee_step_m: The maximum allowed change in position (in meters) between steps.
|
||||||
max_ee_twist_step_rad: The maximum allowed change in orientation (in radians) between steps.
|
|
||||||
_last_pos: Internal state storing the last commanded position.
|
_last_pos: Internal state storing the last commanded position.
|
||||||
_last_twist: Internal state storing the last commanded orientation.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
end_effector_bounds: dict
|
end_effector_bounds: dict
|
||||||
max_ee_step_m: float = 0.05
|
max_ee_step_m: float = 0.05
|
||||||
max_ee_twist_step_rad: float = 0.20
|
|
||||||
_last_pos: np.ndarray | None = field(default=None, init=False, repr=False)
|
_last_pos: np.ndarray | None = field(default=None, init=False, repr=False)
|
||||||
_last_twist: np.ndarray | None = field(default=None, init=False, repr=False)
|
|
||||||
|
|
||||||
def action(self, action: RobotAction) -> RobotAction:
|
def action(self, action: RobotAction) -> RobotAction:
|
||||||
x = action["ee.x"]
|
x = action["ee.x"]
|
||||||
@@ -233,7 +229,6 @@ class EEBoundsAndSafety(RobotActionProcessorStep):
|
|||||||
raise ValueError(f"EE jump {n:.3f}m > {self.max_ee_step_m}m")
|
raise ValueError(f"EE jump {n:.3f}m > {self.max_ee_step_m}m")
|
||||||
|
|
||||||
self._last_pos = pos
|
self._last_pos = pos
|
||||||
self._last_twist = twist
|
|
||||||
|
|
||||||
action["ee.x"] = float(pos[0])
|
action["ee.x"] = float(pos[0])
|
||||||
action["ee.y"] = float(pos[1])
|
action["ee.y"] = float(pos[1])
|
||||||
@@ -246,7 +241,6 @@ class EEBoundsAndSafety(RobotActionProcessorStep):
|
|||||||
def reset(self):
|
def reset(self):
|
||||||
"""Resets the last known position and orientation."""
|
"""Resets the last known position and orientation."""
|
||||||
self._last_pos = None
|
self._last_pos = None
|
||||||
self._last_twist = None
|
|
||||||
|
|
||||||
def transform_features(
|
def transform_features(
|
||||||
self, features: dict[PipelineFeatureType, dict[str, PolicyFeature]]
|
self, features: dict[PipelineFeatureType, dict[str, PolicyFeature]]
|
||||||
|
|||||||
@@ -49,5 +49,3 @@ class Stretch3RobotConfig(RobotConfig):
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
mock: bool = False
|
|
||||||
|
|||||||
@@ -164,10 +164,6 @@ class Stretch3Robot(Robot):
|
|||||||
# TODO(aliberts): return action_sent when motion is limited
|
# TODO(aliberts): return action_sent when motion is limited
|
||||||
return action
|
return action
|
||||||
|
|
||||||
def print_logs(self) -> None:
|
|
||||||
pass
|
|
||||||
# TODO(aliberts): move robot-specific logs logic here
|
|
||||||
|
|
||||||
def teleop_safety_stop(self) -> None:
|
def teleop_safety_stop(self) -> None:
|
||||||
if self.teleop is not None:
|
if self.teleop is not None:
|
||||||
self.teleop._safety_stop(robot=self)
|
self.teleop._safety_stop(robot=self)
|
||||||
|
|||||||
@@ -52,10 +52,6 @@ class InputController:
|
|||||||
"""Get the current movement deltas (dx, dy, dz) in meters."""
|
"""Get the current movement deltas (dx, dy, dz) in meters."""
|
||||||
return 0.0, 0.0, 0.0
|
return 0.0, 0.0, 0.0
|
||||||
|
|
||||||
def should_quit(self):
|
|
||||||
"""Return True if the user has requested to quit."""
|
|
||||||
return not self.running
|
|
||||||
|
|
||||||
def update(self):
|
def update(self):
|
||||||
"""Update controller state - call this once per frame."""
|
"""Update controller state - call this once per frame."""
|
||||||
pass
|
pass
|
||||||
@@ -198,14 +194,6 @@ class KeyboardController(InputController):
|
|||||||
|
|
||||||
return delta_x, delta_y, delta_z
|
return delta_x, delta_y, delta_z
|
||||||
|
|
||||||
def should_quit(self):
|
|
||||||
"""Return True if ESC was pressed."""
|
|
||||||
return self.key_states["quit"]
|
|
||||||
|
|
||||||
def should_save(self):
|
|
||||||
"""Return True if Enter was pressed (save episode)."""
|
|
||||||
return self.key_states["success"] or self.key_states["failure"]
|
|
||||||
|
|
||||||
|
|
||||||
class GamepadController(InputController):
|
class GamepadController(InputController):
|
||||||
"""Generate motion deltas from gamepad input."""
|
"""Generate motion deltas from gamepad input."""
|
||||||
@@ -351,8 +339,6 @@ class GamepadControllerHID(InputController):
|
|||||||
|
|
||||||
# Button states
|
# Button states
|
||||||
self.buttons = {}
|
self.buttons = {}
|
||||||
self.quit_requested = False
|
|
||||||
self.save_requested = False
|
|
||||||
|
|
||||||
def find_device(self):
|
def find_device(self):
|
||||||
"""Look for the gamepad device by vendor and product ID."""
|
"""Look for the gamepad device by vendor and product ID."""
|
||||||
@@ -472,11 +458,3 @@ class GamepadControllerHID(InputController):
|
|||||||
delta_z = -self.right_y * self.z_step_size # Up/down
|
delta_z = -self.right_y * self.z_step_size # Up/down
|
||||||
|
|
||||||
return delta_x, delta_y, delta_z
|
return delta_x, delta_y, delta_z
|
||||||
|
|
||||||
def should_quit(self):
|
|
||||||
"""Return True if quit button was pressed."""
|
|
||||||
return self.quit_requested
|
|
||||||
|
|
||||||
def should_save(self):
|
|
||||||
"""Return True if save button was pressed."""
|
|
||||||
return self.save_requested
|
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ from ..config import TeleoperatorConfig
|
|||||||
@TeleoperatorConfig.register_subclass("keyboard")
|
@TeleoperatorConfig.register_subclass("keyboard")
|
||||||
@dataclass
|
@dataclass
|
||||||
class KeyboardTeleopConfig(TeleoperatorConfig):
|
class KeyboardTeleopConfig(TeleoperatorConfig):
|
||||||
|
"""KeyboardTeleopConfig"""
|
||||||
|
|
||||||
# TODO(Steven): Consider setting in here the keys that we want to capture/listen
|
# TODO(Steven): Consider setting in here the keys that we want to capture/listen
|
||||||
mock: bool = False
|
|
||||||
|
|
||||||
|
|
||||||
@TeleoperatorConfig.register_subclass("keyboard_ee")
|
@TeleoperatorConfig.register_subclass("keyboard_ee")
|
||||||
|
|||||||
@@ -22,4 +22,4 @@ from ..config import TeleoperatorConfig
|
|||||||
@TeleoperatorConfig.register_subclass("stretch3")
|
@TeleoperatorConfig.register_subclass("stretch3")
|
||||||
@dataclass
|
@dataclass
|
||||||
class Stretch3GamePadConfig(TeleoperatorConfig):
|
class Stretch3GamePadConfig(TeleoperatorConfig):
|
||||||
mock: bool = False
|
"""Stretch3GamePadConfig"""
|
||||||
|
|||||||
@@ -112,10 +112,6 @@ class Stretch3GamePad(Teleoperator):
|
|||||||
def send_feedback(self, feedback: np.ndarray) -> None:
|
def send_feedback(self, feedback: np.ndarray) -> None:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def print_logs(self) -> None:
|
|
||||||
pass
|
|
||||||
# TODO(aliberts): move robot-specific logs logic here
|
|
||||||
|
|
||||||
def disconnect(self) -> None:
|
def disconnect(self) -> None:
|
||||||
self.api.stop()
|
self.api.stop()
|
||||||
self.is_connected = False
|
self.is_connected = False
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ TRUNCATED = "next.truncated"
|
|||||||
DONE = "next.done"
|
DONE = "next.done"
|
||||||
|
|
||||||
ROBOTS = "robots"
|
ROBOTS = "robots"
|
||||||
ROBOT_TYPE = "robot_type"
|
|
||||||
TELEOPERATORS = "teleoperators"
|
TELEOPERATORS = "teleoperators"
|
||||||
|
|
||||||
# files & directories
|
# files & directories
|
||||||
|
|||||||
@@ -30,14 +30,3 @@ class DeviceAlreadyConnectedError(ConnectionError):
|
|||||||
):
|
):
|
||||||
self.message = message
|
self.message = message
|
||||||
super().__init__(self.message)
|
super().__init__(self.message)
|
||||||
|
|
||||||
|
|
||||||
class InvalidActionError(ValueError):
|
|
||||||
"""Exception raised when an action is already invalid."""
|
|
||||||
|
|
||||||
def __init__(
|
|
||||||
self,
|
|
||||||
message="The action is invalid. Check the value follows what it is expected from the action space.",
|
|
||||||
):
|
|
||||||
self.message = message
|
|
||||||
super().__init__(self.message)
|
|
||||||
|
|||||||
@@ -330,10 +330,6 @@ class TimerManager:
|
|||||||
def history(self) -> list[float]:
|
def history(self) -> list[float]:
|
||||||
return deepcopy(self._history)
|
return deepcopy(self._history)
|
||||||
|
|
||||||
@property
|
|
||||||
def fps_history(self) -> list[float]:
|
|
||||||
return [1.0 / t for t in self._history]
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def fps_last(self) -> float:
|
def fps_last(self) -> float:
|
||||||
return 0.0 if self.last == 0 else 1.0 / self.last
|
return 0.0 if self.last == 0 else 1.0 / self.last
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ def test_sac_config_default_initialization():
|
|||||||
|
|
||||||
# Training parameters
|
# Training parameters
|
||||||
assert config.online_steps == 1000000
|
assert config.online_steps == 1000000
|
||||||
assert config.online_env_seed == 10000
|
|
||||||
assert config.online_buffer_capacity == 100000
|
assert config.online_buffer_capacity == 100000
|
||||||
assert config.offline_buffer_capacity == 100000
|
assert config.offline_buffer_capacity == 100000
|
||||||
assert config.async_prefetch is False
|
assert config.async_prefetch is False
|
||||||
|
|||||||
Reference in New Issue
Block a user