From a68424c3c9d8807b255df975f987aa1d054ba091 Mon Sep 17 00:00:00 2001 From: "Jivin.L" <45867423+JivinDotL@users.noreply.github.com> Date: Tue, 23 Sep 2025 19:38:22 +0800 Subject: [PATCH 01/26] Fix: Resolve PermissionError and UnicodeDecodeError in Python scripts (#1980) * Fix: Resolve PermissionError and UnicodeDecodeError in Python scripts Problem: 1. PermissionError when running eval.py 2. UnicodeDecodeError: 'gbk' when running migrate_policy_normalization.py * To explicitly specify the file encoding and resolve linter warnings. Signed-off-by: Jivin.L <45867423+JivinDotL@users.noreply.github.com> --------- Signed-off-by: Jivin.L <45867423+JivinDotL@users.noreply.github.com> Co-authored-by: Steven Palma --- src/lerobot/configs/policies.py | 9 ++++----- src/lerobot/policies/pretrained.py | 4 +++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/lerobot/configs/policies.py b/src/lerobot/configs/policies.py index 7532f0612..9a2bb911a 100644 --- a/src/lerobot/configs/policies.py +++ b/src/lerobot/configs/policies.py @@ -196,11 +196,10 @@ class PreTrainedConfig(draccus.ChoiceRegistry, HubMixin, abc.ABC): config = json.load(f) config.pop("type") - with tempfile.NamedTemporaryFile("w+") as f: + with tempfile.NamedTemporaryFile("w+", delete=False, suffix=".json") as f: json.dump(config, f) config_file = f.name - f.flush() - cli_overrides = policy_kwargs.pop("cli_overrides", []) - with draccus.config_type("json"): - return draccus.parse(orig_config.__class__, config_file, args=cli_overrides) + cli_overrides = policy_kwargs.pop("cli_overrides", []) + with draccus.config_type("json"): + return draccus.parse(orig_config.__class__, config_file, args=cli_overrides) diff --git a/src/lerobot/policies/pretrained.py b/src/lerobot/policies/pretrained.py index 2f69309c1..b770c980b 100644 --- a/src/lerobot/policies/pretrained.py +++ b/src/lerobot/policies/pretrained.py @@ -246,7 +246,9 @@ class PreTrainedPolicy(nn.Module, HubMixin, abc.ABC): base_model=base_model, ) - template_card = files("lerobot.templates").joinpath("lerobot_modelcard_template.md").read_text() + template_card = ( + files("lerobot.templates").joinpath("lerobot_modelcard_template.md").read_text(encoding="utf-8") + ) card = ModelCard.from_template(card_data, template_str=template_card) card.validate() return card From 9d0cf64da611c816a229a1b8e6e301c7dda262f5 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Tue, 23 Sep 2025 15:51:19 +0200 Subject: [PATCH 02/26] fix(dataset): cast fps to int instead of float (#2001) --- src/lerobot/datasets/v30/convert_dataset_v21_to_v30.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lerobot/datasets/v30/convert_dataset_v21_to_v30.py b/src/lerobot/datasets/v30/convert_dataset_v21_to_v30.py index 96bdc1897..1327bd820 100644 --- a/src/lerobot/datasets/v30/convert_dataset_v21_to_v30.py +++ b/src/lerobot/datasets/v30/convert_dataset_v21_to_v30.py @@ -404,7 +404,7 @@ def convert_info(root, new_root, data_file_size_in_mb, video_file_size_in_mb): info["video_files_size_in_mb"] = video_file_size_in_mb info["data_path"] = DEFAULT_DATA_PATH info["video_path"] = DEFAULT_VIDEO_PATH - info["fps"] = float(info["fps"]) + info["fps"] = int(info["fps"]) for key in info["features"]: if info["features"][key]["dtype"] == "video": # already has fps in video_info From d6a32e9742571a2fc96a02e143cfdb1a1be8940d Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Tue, 23 Sep 2025 16:32:34 +0200 Subject: [PATCH 03/26] chore(rl): move rl related code to its directory at top level (#2002) * chore(rl): move rl related code to its directory at top level * chore(style): apply pre-commit to renamed headers * test(rl): fix rl imports * docs(rl): update rl headers doc --- docs/source/hilserl.mdx | 16 ++++++++-------- docs/source/hilserl_sim.mdx | 8 ++++---- docs/source/il_sim.mdx | 8 ++++---- src/lerobot/{scripts => }/rl/actor.py | 15 ++++++++------- src/lerobot/{scripts => }/rl/crop_dataset_roi.py | 0 src/lerobot/{scripts => }/rl/eval_policy.py | 3 ++- src/lerobot/{scripts => }/rl/gym_manipulator.py | 0 src/lerobot/{scripts => }/rl/learner.py | 11 ++++++----- src/lerobot/{scripts => }/rl/learner_service.py | 0 tests/rl/test_actor.py | 10 +++++----- tests/rl/test_actor_learner.py | 12 ++++++------ tests/rl/test_learner_service.py | 2 +- 12 files changed, 44 insertions(+), 41 deletions(-) rename src/lerobot/{scripts => }/rl/actor.py (99%) rename src/lerobot/{scripts => }/rl/crop_dataset_roi.py (100%) rename src/lerobot/{scripts => }/rl/eval_policy.py (97%) rename src/lerobot/{scripts => }/rl/gym_manipulator.py (100%) rename src/lerobot/{scripts => }/rl/learner.py (99%) rename src/lerobot/{scripts => }/rl/learner_service.py (100%) diff --git a/docs/source/hilserl.mdx b/docs/source/hilserl.mdx index f6bac1ffa..08301556f 100644 --- a/docs/source/hilserl.mdx +++ b/docs/source/hilserl.mdx @@ -518,7 +518,7 @@ During the online training, press `space` to take over the policy and `space` ag Start the recording process, an example of the config file can be found [here](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/env_config_so100.json): ```bash -python -m lerobot.scripts.rl.gym_manipulator --config_path src/lerobot/configs/env_config_so100.json +python -m lerobot.rl.gym_manipulator --config_path src/lerobot/configs/env_config_so100.json ``` During recording: @@ -549,7 +549,7 @@ Note: If you already know the crop parameters, you can skip this step and just s Use the `crop_dataset_roi.py` script to interactively select regions of interest in your camera images: ```bash -python -m lerobot.scripts.rl.crop_dataset_roi --repo-id username/pick_lift_cube +python -m lerobot.rl.crop_dataset_roi --repo-id username/pick_lift_cube ``` 1. For each camera view, the script will display the first frame @@ -618,7 +618,7 @@ Before training, you need to collect a dataset with labeled examples. The `recor To collect a dataset, you need to modify some parameters in the environment configuration based on HILSerlRobotEnvConfig. ```bash -python -m lerobot.scripts.rl.gym_manipulator --config_path src/lerobot/configs/reward_classifier_train_config.json +python -m lerobot.rl.gym_manipulator --config_path src/lerobot/configs/reward_classifier_train_config.json ``` **Key Parameters for Data Collection** @@ -764,7 +764,7 @@ or set the argument in the json config file. Run `gym_manipulator.py` to test the model. ```bash -python -m lerobot.scripts.rl.gym_manipulator --config_path path/to/env_config.json +python -m lerobot.rl.gym_manipulator --config_path path/to/env_config.json ``` The reward classifier will automatically provide rewards based on the visual input from the robot's cameras. @@ -777,7 +777,7 @@ The reward classifier will automatically provide rewards based on the visual inp 2. **Collect a dataset**: ```bash - python -m lerobot.scripts.rl.gym_manipulator --config_path src/lerobot/configs/env_config.json + python -m lerobot.rl.gym_manipulator --config_path src/lerobot/configs/env_config.json ``` 3. **Train the classifier**: @@ -788,7 +788,7 @@ The reward classifier will automatically provide rewards based on the visual inp 4. **Test the classifier**: ```bash - python -m lerobot.scripts.rl.gym_manipulator --config_path src/lerobot/configs/env_config.json + python -m lerobot.rl.gym_manipulator --config_path src/lerobot/configs/env_config.json ``` ### Training with Actor-Learner @@ -810,7 +810,7 @@ Create a training configuration file (example available [here](https://huggingfa First, start the learner server process: ```bash -python -m lerobot.scripts.rl.learner --config_path src/lerobot/configs/train_config_hilserl_so100.json +python -m lerobot.rl.learner --config_path src/lerobot/configs/train_config_hilserl_so100.json ``` The learner: @@ -825,7 +825,7 @@ The learner: In a separate terminal, start the actor process with the same configuration: ```bash -python -m lerobot.scripts.rl.actor --config_path src/lerobot/configs/train_config_hilserl_so100.json +python -m lerobot.rl.actor --config_path src/lerobot/configs/train_config_hilserl_so100.json ``` The actor: diff --git a/docs/source/hilserl_sim.mdx b/docs/source/hilserl_sim.mdx index 77191fde3..e2dddd9ed 100644 --- a/docs/source/hilserl_sim.mdx +++ b/docs/source/hilserl_sim.mdx @@ -91,7 +91,7 @@ Important parameters: To run the environment, set mode to null: ```bash -python -m lerobot.scripts.rl.gym_manipulator --config_path path/to/gym_hil_env.json +python -m lerobot.rl.gym_manipulator --config_path path/to/gym_hil_env.json ``` ### Recording a Dataset @@ -118,7 +118,7 @@ To collect a dataset, set the mode to `record` whilst defining the repo_id and n ``` ```bash -python -m lerobot.scripts.rl.gym_manipulator --config_path path/to/gym_hil_env.json +python -m lerobot.rl.gym_manipulator --config_path path/to/gym_hil_env.json ``` ### Training a Policy @@ -126,13 +126,13 @@ python -m lerobot.scripts.rl.gym_manipulator --config_path path/to/gym_hil_env.j To train a policy, checkout the configuration example available [here](https://huggingface.co/datasets/lerobot/config_examples/resolve/main/rl/gym_hil/train_config.json) and run the actor and learner servers: ```bash -python -m lerobot.scripts.rl.actor --config_path path/to/train_gym_hil_env.json +python -m lerobot.rl.actor --config_path path/to/train_gym_hil_env.json ``` In a different terminal, run the learner server: ```bash -python -m lerobot.scripts.rl.learner --config_path path/to/train_gym_hil_env.json +python -m lerobot.rl.learner --config_path path/to/train_gym_hil_env.json ``` The simulation environment provides a safe and repeatable way to develop and test your Human-In-the-Loop reinforcement learning components before deploying to real robots. diff --git a/docs/source/il_sim.mdx b/docs/source/il_sim.mdx index 6a615620b..9b7d7c111 100644 --- a/docs/source/il_sim.mdx +++ b/docs/source/il_sim.mdx @@ -61,14 +61,14 @@ Then we can run this command to start: ```bash -python -m lerobot.scripts.rl.gym_manipulator --config_path path/to/env_config_gym_hil_il.json +python -m lerobot.rl.gym_manipulator --config_path path/to/env_config_gym_hil_il.json ``` ```bash -mjpython -m lerobot.scripts.rl.gym_manipulator --config_path path/to/env_config_gym_hil_il.json +mjpython -m lerobot.rl.gym_manipulator --config_path path/to/env_config_gym_hil_il.json ``` @@ -198,14 +198,14 @@ Then you can run this command to visualize your trained policy ```bash -python -m lerobot.scripts.rl.eval_policy --config_path=path/to/eval_config_gym_hil.json +python -m lerobot.rl.eval_policy --config_path=path/to/eval_config_gym_hil.json ``` ```bash -mjpython -m lerobot.scripts.rl.eval_policy --config_path=path/to/eval_config_gym_hil.json +mjpython -m lerobot.rl.eval_policy --config_path=path/to/eval_config_gym_hil.json ``` diff --git a/src/lerobot/scripts/rl/actor.py b/src/lerobot/rl/actor.py similarity index 99% rename from src/lerobot/scripts/rl/actor.py rename to src/lerobot/rl/actor.py index baa284c4a..d1e709253 100644 --- a/src/lerobot/scripts/rl/actor.py +++ b/src/lerobot/rl/actor.py @@ -24,7 +24,7 @@ Examples of usage: - Start an actor server for real robot training with human-in-the-loop intervention: ```bash -python -m lerobot.scripts.rl.actor --config_path src/lerobot/configs/train_config_hilserl_so100.json +python -m lerobot.rl.actor --config_path src/lerobot/configs/train_config_hilserl_so100.json ``` **NOTE**: The actor server requires a running learner server to connect to. Ensure the learner @@ -64,12 +64,6 @@ from lerobot.policies.factory import make_policy from lerobot.policies.sac.modeling_sac import SACPolicy from lerobot.processor import TransitionKey from lerobot.robots import so100_follower # noqa: F401 -from lerobot.scripts.rl.gym_manipulator import ( - create_transition, - make_processors, - make_robot_env, - step_env_and_process_transition, -) from lerobot.teleoperators import gamepad, so101_leader # noqa: F401 from lerobot.teleoperators.utils import TeleopEvents from lerobot.transport import services_pb2, services_pb2_grpc @@ -96,6 +90,13 @@ from lerobot.utils.utils import ( init_logging, ) +from .gym_manipulator import ( + create_transition, + make_processors, + make_robot_env, + step_env_and_process_transition, +) + ACTOR_SHUTDOWN_TIMEOUT = 30 # Main entry point diff --git a/src/lerobot/scripts/rl/crop_dataset_roi.py b/src/lerobot/rl/crop_dataset_roi.py similarity index 100% rename from src/lerobot/scripts/rl/crop_dataset_roi.py rename to src/lerobot/rl/crop_dataset_roi.py diff --git a/src/lerobot/scripts/rl/eval_policy.py b/src/lerobot/rl/eval_policy.py similarity index 97% rename from src/lerobot/scripts/rl/eval_policy.py rename to src/lerobot/rl/eval_policy.py index aa97483b6..7cec66800 100644 --- a/src/lerobot/scripts/rl/eval_policy.py +++ b/src/lerobot/rl/eval_policy.py @@ -25,12 +25,13 @@ from lerobot.robots import ( # noqa: F401 make_robot_from_config, so100_follower, ) -from lerobot.scripts.rl.gym_manipulator import make_robot_env from lerobot.teleoperators import ( gamepad, # noqa: F401 so101_leader, # noqa: F401 ) +from .gym_manipulator import make_robot_env + logging.basicConfig(level=logging.INFO) diff --git a/src/lerobot/scripts/rl/gym_manipulator.py b/src/lerobot/rl/gym_manipulator.py similarity index 100% rename from src/lerobot/scripts/rl/gym_manipulator.py rename to src/lerobot/rl/gym_manipulator.py diff --git a/src/lerobot/scripts/rl/learner.py b/src/lerobot/rl/learner.py similarity index 99% rename from src/lerobot/scripts/rl/learner.py rename to src/lerobot/rl/learner.py index 5d9953827..6441ba55f 100644 --- a/src/lerobot/scripts/rl/learner.py +++ b/src/lerobot/rl/learner.py @@ -25,7 +25,7 @@ Examples of usage: - Start a learner server for training: ```bash -python -m lerobot.scripts.rl.learner --config_path src/lerobot/configs/train_config_hilserl_so100.json +python -m lerobot.rl.learner --config_path src/lerobot/configs/train_config_hilserl_so100.json ``` **NOTE**: Start the learner server before launching the actor server. The learner opens a gRPC server @@ -73,7 +73,6 @@ from lerobot.datasets.lerobot_dataset import LeRobotDataset from lerobot.policies.factory import make_policy from lerobot.policies.sac.modeling_sac import SACPolicy from lerobot.robots import so100_follower # noqa: F401 -from lerobot.scripts.rl import learner_service from lerobot.teleoperators import gamepad, so101_leader # noqa: F401 from lerobot.teleoperators.utils import TeleopEvents from lerobot.transport import services_pb2_grpc @@ -100,6 +99,8 @@ from lerobot.utils.utils import ( ) from lerobot.utils.wandb_utils import WandBLogger +from .learner_service import MAX_WORKERS, SHUTDOWN_TIMEOUT, LearnerService + LOG_PREFIX = "[LEARNER]" @@ -639,7 +640,7 @@ def start_learner( # TODO: Check if its useful _ = ProcessSignalHandler(False, display_pid=True) - service = learner_service.LearnerService( + service = LearnerService( shutdown_event=shutdown_event, parameters_queue=parameters_queue, seconds_between_pushes=cfg.policy.actor_learner_config.policy_parameters_push_frequency, @@ -649,7 +650,7 @@ def start_learner( ) server = grpc.server( - ThreadPoolExecutor(max_workers=learner_service.MAX_WORKERS), + ThreadPoolExecutor(max_workers=MAX_WORKERS), options=[ ("grpc.max_receive_message_length", MAX_MESSAGE_SIZE), ("grpc.max_send_message_length", MAX_MESSAGE_SIZE), @@ -670,7 +671,7 @@ def start_learner( shutdown_event.wait() logging.info("[LEARNER] Stopping gRPC server...") - server.stop(learner_service.SHUTDOWN_TIMEOUT) + server.stop(SHUTDOWN_TIMEOUT) logging.info("[LEARNER] gRPC server stopped") diff --git a/src/lerobot/scripts/rl/learner_service.py b/src/lerobot/rl/learner_service.py similarity index 100% rename from src/lerobot/scripts/rl/learner_service.py rename to src/lerobot/rl/learner_service.py diff --git a/tests/rl/test_actor.py b/tests/rl/test_actor.py index f078b4602..aa9913bb2 100644 --- a/tests/rl/test_actor.py +++ b/tests/rl/test_actor.py @@ -65,7 +65,7 @@ def close_service_stub(channel, server): @require_package("grpc") def test_establish_learner_connection_success(): - from lerobot.scripts.rl.actor import establish_learner_connection + from lerobot.rl.actor import establish_learner_connection """Test successful connection establishment.""" stub, _servicer, channel, server = create_learner_service_stub() @@ -82,7 +82,7 @@ def test_establish_learner_connection_success(): @require_package("grpc") def test_establish_learner_connection_failure(): - from lerobot.scripts.rl.actor import establish_learner_connection + from lerobot.rl.actor import establish_learner_connection """Test connection failure.""" stub, servicer, channel, server = create_learner_service_stub() @@ -101,7 +101,7 @@ def test_establish_learner_connection_failure(): @require_package("grpc") def test_push_transitions_to_transport_queue(): - from lerobot.scripts.rl.actor import push_transitions_to_transport_queue + from lerobot.rl.actor import push_transitions_to_transport_queue from lerobot.transport.utils import bytes_to_transitions from tests.transport.test_transport_utils import assert_transitions_equal @@ -137,7 +137,7 @@ def test_push_transitions_to_transport_queue(): @require_package("grpc") @pytest.mark.timeout(3) # force cross-platform watchdog def test_transitions_stream(): - from lerobot.scripts.rl.actor import transitions_stream + from lerobot.rl.actor import transitions_stream """Test transitions stream functionality.""" shutdown_event = Event() @@ -169,7 +169,7 @@ def test_transitions_stream(): @require_package("grpc") @pytest.mark.timeout(3) # force cross-platform watchdog def test_interactions_stream(): - from lerobot.scripts.rl.actor import interactions_stream + from lerobot.rl.actor import interactions_stream from lerobot.transport.utils import bytes_to_python_object, python_object_to_bytes """Test interactions stream functionality.""" diff --git a/tests/rl/test_actor_learner.py b/tests/rl/test_actor_learner.py index b2a7a5d5f..43a6b0957 100644 --- a/tests/rl/test_actor_learner.py +++ b/tests/rl/test_actor_learner.py @@ -90,13 +90,13 @@ def cfg(): @require_package("grpc") @pytest.mark.timeout(10) # force cross-platform watchdog def test_end_to_end_transitions_flow(cfg): - from lerobot.scripts.rl.actor import ( + from lerobot.rl.actor import ( establish_learner_connection, learner_service_client, push_transitions_to_transport_queue, send_transitions, ) - from lerobot.scripts.rl.learner import start_learner + from lerobot.rl.learner import start_learner from lerobot.transport.utils import bytes_to_transitions from tests.transport.test_transport_utils import assert_transitions_equal @@ -152,12 +152,12 @@ def test_end_to_end_transitions_flow(cfg): @require_package("grpc") @pytest.mark.timeout(10) def test_end_to_end_interactions_flow(cfg): - from lerobot.scripts.rl.actor import ( + from lerobot.rl.actor import ( establish_learner_connection, learner_service_client, send_interactions, ) - from lerobot.scripts.rl.learner import start_learner + from lerobot.rl.learner import start_learner from lerobot.transport.utils import bytes_to_python_object, python_object_to_bytes """Test complete interactions flow from actor to learner.""" @@ -226,8 +226,8 @@ def test_end_to_end_interactions_flow(cfg): @pytest.mark.parametrize("data_size", ["small", "large"]) @pytest.mark.timeout(10) def test_end_to_end_parameters_flow(cfg, data_size): - from lerobot.scripts.rl.actor import establish_learner_connection, learner_service_client, receive_policy - from lerobot.scripts.rl.learner import start_learner + from lerobot.rl.actor import establish_learner_connection, learner_service_client, receive_policy + from lerobot.rl.learner import start_learner from lerobot.transport.utils import bytes_to_state_dict, state_to_bytes """Test complete parameter flow from learner to actor, with small and large data.""" diff --git a/tests/rl/test_learner_service.py b/tests/rl/test_learner_service.py index f5e1e8d48..b0e61165a 100644 --- a/tests/rl/test_learner_service.py +++ b/tests/rl/test_learner_service.py @@ -50,7 +50,7 @@ def create_learner_service_stub( ): import grpc - from lerobot.scripts.rl.learner_service import LearnerService + from lerobot.rl.learner_service import LearnerService from lerobot.transport import services_pb2_grpc # generated from .proto """Fixture to start a LearnerService gRPC server and provide a connected stub.""" From 3068ce3569e122d910e66c0da0b1abc5282d65aa Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Tue, 23 Sep 2025 17:43:55 +0200 Subject: [PATCH 04/26] docs(rl): fix path (#2004) --- docs/source/hilserl.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/hilserl.mdx b/docs/source/hilserl.mdx index 08301556f..07f92b824 100644 --- a/docs/source/hilserl.mdx +++ b/docs/source/hilserl.mdx @@ -62,7 +62,7 @@ pip install -e ".[hilserl]" ### Understanding Configuration -The training process begins with proper configuration for the HILSerl environment. The main configuration class is `GymManipulatorConfig` in `lerobot/scripts/rl/gym_manipulator.py`, which contains nested `HILSerlRobotEnvConfig` and `DatasetConfig`. The configuration is organized into focused, nested sub-configs: +The training process begins with proper configuration for the HILSerl environment. The main configuration class is `GymManipulatorConfig` in `lerobot/rl/gym_manipulator.py`, which contains nested `HILSerlRobotEnvConfig` and `DatasetConfig`. The configuration is organized into focused, nested sub-configs: ```python From 1666097fd3588c7f9fa3f975af3a268a10085d0b Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Tue, 23 Sep 2025 17:55:53 +0200 Subject: [PATCH 05/26] refactor(scripts): update system info script (#2005) * refactor(scripts): update system info script * chore(scripts): rename info script * feat(scripts): add entrypoint for info * chore(ci): update issue report template --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- pyproject.toml | 1 + src/lerobot/scripts/display_sys_info.py | 90 ----------------------- src/lerobot/scripts/lerobot_info.py | 96 +++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 91 deletions(-) delete mode 100644 src/lerobot/scripts/display_sys_info.py create mode 100644 src/lerobot/scripts/lerobot_info.py diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index 2fb23051c..7423495de 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -25,7 +25,7 @@ body: id: system-info attributes: label: System Info - description: If needed, you can share your lerobot configuration with us by running `python -m lerobot.scripts.display_sys_info` and copy-pasting its outputs below + description: Please share your LeRobot configuration by running `lerobot-info` (if installed) or `python -m lerobot.scripts.display_sys_info` (if not installed) and pasting the output below. render: Shell placeholder: lerobot version, OS, python version, numpy version, torch version, and lerobot's configuration validations: diff --git a/pyproject.toml b/pyproject.toml index 6db5e1307..9ee3c962f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -171,6 +171,7 @@ lerobot-setup-motors="lerobot.setup_motors:main" lerobot-teleoperate="lerobot.teleoperate:main" lerobot-eval="lerobot.scripts.eval:main" lerobot-train="lerobot.scripts.train:main" +lerobot-info="lerobot.scripts.lerobot_info:main" # ---------------- Tool Configurations ---------------- [tool.setuptools.packages.find] diff --git a/src/lerobot/scripts/display_sys_info.py b/src/lerobot/scripts/display_sys_info.py deleted file mode 100644 index 4d3cc291f..000000000 --- a/src/lerobot/scripts/display_sys_info.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python - -# Copyright 2024 The HuggingFace Inc. team. All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -"""Use this script to get a quick summary of your system config. -It should be able to run without any of LeRobot's dependencies or LeRobot itself installed. -""" - -import platform - -HAS_HF_HUB = True -HAS_HF_DATASETS = True -HAS_NP = True -HAS_TORCH = True -HAS_LEROBOT = True - -try: - import huggingface_hub -except ImportError: - HAS_HF_HUB = False - -try: - import datasets -except ImportError: - HAS_HF_DATASETS = False - -try: - import numpy as np -except ImportError: - HAS_NP = False - -try: - import torch -except ImportError: - HAS_TORCH = False - -try: - import lerobot -except ImportError: - HAS_LEROBOT = False - - -lerobot_version = lerobot.__version__ if HAS_LEROBOT else "N/A" -hf_hub_version = huggingface_hub.__version__ if HAS_HF_HUB else "N/A" -hf_datasets_version = datasets.__version__ if HAS_HF_DATASETS else "N/A" -np_version = np.__version__ if HAS_NP else "N/A" - -torch_version = torch.__version__ if HAS_TORCH else "N/A" -torch_cuda_available = torch.cuda.is_available() if HAS_TORCH else "N/A" -cuda_version = torch._C._cuda_getCompiledVersion() if HAS_TORCH and torch.version.cuda is not None else "N/A" - - -# TODO(aliberts): refactor into an actual command `lerobot env` -def display_sys_info() -> dict: - """Run this to get basic system info to help for tracking issues & bugs.""" - info = { - "`lerobot` version": lerobot_version, - "Platform": platform.platform(), - "Python version": platform.python_version(), - "Huggingface_hub version": hf_hub_version, - "Dataset version": hf_datasets_version, - "Numpy version": np_version, - "PyTorch version (GPU?)": f"{torch_version} ({torch_cuda_available})", - "Cuda version": cuda_version, - "Using GPU in script?": "", - # "Using distributed or parallel set-up in script?": "", - } - print("\nCopy-and-paste the text below in your GitHub issue and FILL OUT the last point.\n") - print(format_dict(info)) - return info - - -def format_dict(d: dict) -> str: - return "\n".join([f"- {prop}: {val}" for prop, val in d.items()]) + "\n" - - -if __name__ == "__main__": - display_sys_info() diff --git a/src/lerobot/scripts/lerobot_info.py b/src/lerobot/scripts/lerobot_info.py new file mode 100644 index 000000000..9b49cad18 --- /dev/null +++ b/src/lerobot/scripts/lerobot_info.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python + +# Copyright 2024 The HuggingFace Inc. team. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +Use this script to get a quick summary of your system config. +It should be able to run without any of LeRobot's dependencies or LeRobot itself installed. + +Example: + +```shell +lerobot-info +``` +""" + +import importlib +import platform + + +def get_package_version(package_name: str) -> str: + """Get the version of a package if it exists, otherwise return 'N/A'.""" + try: + module = importlib.import_module(package_name) + return getattr(module, "__version__", "Installed (version not found)") + except ImportError: + return "N/A" + + +def get_sys_info() -> dict: + """Run this to get basic system info to help for tracking issues & bugs.""" + # General package versions + info = { + "lerobot version": get_package_version("lerobot"), + "Platform": platform.platform(), + "Python version": platform.python_version(), + "Huggingface Hub version": get_package_version("huggingface_hub"), + "Datasets version": get_package_version("datasets"), + "Numpy version": get_package_version("numpy"), + } + + # PyTorch and GPU specific information + torch_version = "N/A" + torch_cuda_available = "N/A" + cuda_version = "N/A" + gpu_model = "N/A" + try: + import torch + + torch_version = torch.__version__ + torch_cuda_available = torch.cuda.is_available() + if torch_cuda_available: + cuda_version = torch.version.cuda + # Gets the name of the first available GPU + gpu_model = torch.cuda.get_device_name(0) + except ImportError: + # If torch is not installed, the default "N/A" values will be used. + pass + + info.update( + { + "PyTorch version": torch_version, + "Is PyTorch built with CUDA support?": torch_cuda_available, + "Cuda version": cuda_version, + "GPU model": gpu_model, + "Using GPU in script?": "", + } + ) + + return info + + +def format_dict_for_markdown(d: dict) -> str: + """Formats a dictionary into a markdown-friendly bulleted list.""" + return "\n".join([f"- {prop}: {val}" for prop, val in d.items()]) + + +def main(): + system_info = get_sys_info() + print("\nCopy-and-paste the text below in your GitHub issue and FILL OUT the last point.\n") + print(format_dict_for_markdown(system_info)) + + +if __name__ == "__main__": + main() From c435d3cebc6395538158bee6d2919e6ee1f930ac Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Tue, 23 Sep 2025 18:46:27 +0200 Subject: [PATCH 06/26] feat(script): add entry point for dataset viz (#2006) * chore(scripts): rename script dataset viz * feat(scripts): add entry point for dataset-viz --------- Signed-off-by: Steven Palma --- README.md | 6 +++--- pyproject.toml | 1 + src/lerobot/robots/viperx/README.md | 2 +- .../{visualize_dataset.py => lerobot_dataset_viz.py} | 6 +++--- tests/datasets/test_visualize_dataset.py | 2 +- 5 files changed, 9 insertions(+), 8 deletions(-) rename src/lerobot/scripts/{visualize_dataset.py => lerobot_dataset_viz.py} (98%) diff --git a/README.md b/README.md index a3f28f552..a59f96deb 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,7 @@ Check out [example 1](https://github.com/huggingface/lerobot/blob/main/examples/ You can also locally visualize episodes from a dataset on the hub by executing our script from the command line: ```bash -python -m lerobot.scripts.visualize_dataset \ +lerobot-dataset-viz \ --repo-id lerobot/pusht \ --episode-index 0 ``` @@ -210,7 +210,7 @@ python -m lerobot.scripts.visualize_dataset \ or from a dataset in a local folder with the `root` option and the `--local-files-only` (in the following case the dataset will be searched for in `./my_local_data_dir/lerobot/pusht`) ```bash -python -m lerobot.scripts.visualize_dataset \ +lerobot-dataset-viz \ --repo-id lerobot/pusht \ --root ./my_local_data_dir \ --local-files-only 1 \ @@ -221,7 +221,7 @@ It will open `rerun.io` and display the camera streams, robot states and actions https://github-production-user-asset-6210df.s3.amazonaws.com/4681518/328035972-fd46b787-b532-47e2-bb6f-fd536a55a7ed.mov?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIAVCODYLSA53PQK4ZA%2F20240505%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20240505T172924Z&X-Amz-Expires=300&X-Amz-Signature=d680b26c532eeaf80740f08af3320d22ad0b8a4e4da1bcc4f33142c15b509eda&X-Amz-SignedHeaders=host&actor_id=24889239&key_id=0&repo_id=748713144 -Our script can also visualize datasets stored on a distant server. See `python -m lerobot.scripts.visualize_dataset --help` for more instructions. +Our script can also visualize datasets stored on a distant server. See `lerobot-dataset-viz --help` for more instructions. ### The `LeRobotDataset` format diff --git a/pyproject.toml b/pyproject.toml index 9ee3c962f..6fa054cde 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -171,6 +171,7 @@ lerobot-setup-motors="lerobot.setup_motors:main" lerobot-teleoperate="lerobot.teleoperate:main" lerobot-eval="lerobot.scripts.eval:main" lerobot-train="lerobot.scripts.train:main" +lerobot-dataset-viz="lerobot.scripts.lerobot_dataset_viz:main" lerobot-info="lerobot.scripts.lerobot_info:main" # ---------------- Tool Configurations ---------------- diff --git a/src/lerobot/robots/viperx/README.md b/src/lerobot/robots/viperx/README.md index f6386215a..2e8fc7289 100644 --- a/src/lerobot/robots/viperx/README.md +++ b/src/lerobot/robots/viperx/README.md @@ -118,7 +118,7 @@ echo ${HF_USER}/aloha_test If you didn't upload with `--control.push_to_hub=false`, you can also visualize it locally with [Rerun](https://github.com/rerun-io/rerun): ```bash -python -m lerobot.scripts.visualize_dataset \ +lerobot-dataset-viz \ --repo-id ${HF_USER}/aloha_test --episode 0 ``` diff --git a/src/lerobot/scripts/visualize_dataset.py b/src/lerobot/scripts/lerobot_dataset_viz.py similarity index 98% rename from src/lerobot/scripts/visualize_dataset.py rename to src/lerobot/scripts/lerobot_dataset_viz.py index dda12594a..2033b36ba 100644 --- a/src/lerobot/scripts/visualize_dataset.py +++ b/src/lerobot/scripts/lerobot_dataset_viz.py @@ -29,14 +29,14 @@ Examples: - Visualize data stored on a local machine: ``` -local$ python -m lerobot.scripts.visualize_dataset \ +local$ lerobot-dataset-viz \ --repo-id lerobot/pusht \ --episode-index 0 ``` - Visualize data stored on a distant machine with a local viewer: ``` -distant$ python -m lerobot.scripts.visualize_dataset \ +distant$ lerobot-dataset-viz \ --repo-id lerobot/pusht \ --episode-index 0 \ --save 1 \ @@ -50,7 +50,7 @@ local$ rerun lerobot_pusht_episode_0.rrd (You need to forward the websocket port to the distant machine, with `ssh -L 9087:localhost:9087 username@remote-host`) ``` -distant$ python -m lerobot.scripts.visualize_dataset \ +distant$ lerobot-dataset-viz \ --repo-id lerobot/pusht \ --episode-index 0 \ --mode distant \ diff --git a/tests/datasets/test_visualize_dataset.py b/tests/datasets/test_visualize_dataset.py index 303342e3c..8e92ec82e 100644 --- a/tests/datasets/test_visualize_dataset.py +++ b/tests/datasets/test_visualize_dataset.py @@ -15,7 +15,7 @@ # limitations under the License. import pytest -from lerobot.scripts.visualize_dataset import visualize_dataset +from lerobot.scripts.lerobot_dataset_viz import visualize_dataset @pytest.mark.skip("TODO: add dummy videos") From c9787bd98aecf9ff00387b085c4839a975d4f5a1 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Tue, 23 Sep 2025 18:47:36 +0200 Subject: [PATCH 07/26] feat(script): add entry point for image transform viz (#2007) * feat(Scripts): add entry point for img transform viz * chore(style): pre-commit style --- docs/source/lerobot-dataset-v3.mdx | 2 +- pyproject.toml | 1 + ...e_transforms.py => lerobot_imgtransform_viz.py} | 14 +++++++++----- tests/datasets/test_image_transforms.py | 2 +- 4 files changed, 12 insertions(+), 7 deletions(-) rename src/lerobot/scripts/{visualize_image_transforms.py => lerobot_imgtransform_viz.py} (97%) diff --git a/docs/source/lerobot-dataset-v3.mdx b/docs/source/lerobot-dataset-v3.mdx index 09fb17fad..cf1942fdc 100644 --- a/docs/source/lerobot-dataset-v3.mdx +++ b/docs/source/lerobot-dataset-v3.mdx @@ -246,7 +246,7 @@ You can also use any `torchvision.transforms.v2` transform by passing it directl Use the visualization script to preview how transforms affect your data: ```bash -python -m lerobot.scripts.visualize_image_transforms \ +lerobot-imgtransform-viz \ --repo-id=your-username/your-dataset \ --output-dir=./transform_examples \ --n-examples=5 diff --git a/pyproject.toml b/pyproject.toml index 6fa054cde..9ed3da006 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -173,6 +173,7 @@ lerobot-eval="lerobot.scripts.eval:main" lerobot-train="lerobot.scripts.train:main" lerobot-dataset-viz="lerobot.scripts.lerobot_dataset_viz:main" lerobot-info="lerobot.scripts.lerobot_info:main" +lerobot-imgtransform-viz="lerobot.scripts.lerobot_imgtransform_viz:main" # ---------------- Tool Configurations ---------------- [tool.setuptools.packages.find] diff --git a/src/lerobot/scripts/visualize_image_transforms.py b/src/lerobot/scripts/lerobot_imgtransform_viz.py similarity index 97% rename from src/lerobot/scripts/visualize_image_transforms.py rename to src/lerobot/scripts/lerobot_imgtransform_viz.py index 14caf89df..bc13f0508 100644 --- a/src/lerobot/scripts/visualize_image_transforms.py +++ b/src/lerobot/scripts/lerobot_imgtransform_viz.py @@ -20,10 +20,10 @@ Additionally, each individual transform can be visualized separately as well as Example: ```bash -python -m lerobot.scripts.visualize_image_transforms \ - --repo_id=lerobot/pusht \ - --episodes='[0]' \ - --image_transforms.enable=True +lerobot-imgtransform-viz \ + --repo_id=lerobot/pusht \ + --episodes='[0]' \ + --image_transforms.enable=True ``` """ @@ -126,5 +126,9 @@ def visualize_image_transforms(cfg: DatasetConfig, output_dir: Path = OUTPUT_DIR save_each_transform(cfg.image_transforms, original_frame, output_dir, n_examples) -if __name__ == "__main__": +def main(): visualize_image_transforms() + + +if __name__ == "__main__": + main() diff --git a/tests/datasets/test_image_transforms.py b/tests/datasets/test_image_transforms.py index 3ab93cb2c..98f957076 100644 --- a/tests/datasets/test_image_transforms.py +++ b/tests/datasets/test_image_transforms.py @@ -29,7 +29,7 @@ from lerobot.datasets.transforms import ( SharpnessJitter, make_transform_from_config, ) -from lerobot.scripts.visualize_image_transforms import ( +from lerobot.scripts.lerobot_imgtransform_viz import ( save_all_transforms, save_each_transform, ) From 7cf04a5ec38536a184a0a70c475c91b74a127083 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 11:11:53 +0200 Subject: [PATCH 08/26] chore: move constants to utils (#2016) --- examples/training/train_with_streaming.py | 2 +- src/lerobot/configs/policies.py | 2 +- src/lerobot/datasets/lerobot_dataset.py | 2 +- src/lerobot/datasets/pipeline_features.py | 2 +- src/lerobot/datasets/streaming_dataset.py | 2 +- .../datasets/v30/convert_dataset_v21_to_v30.py | 2 +- src/lerobot/envs/configs.py | 2 +- src/lerobot/optim/optimizers.py | 4 ++-- src/lerobot/optim/schedulers.py | 2 +- src/lerobot/policies/act/modeling_act.py | 2 +- src/lerobot/policies/act/processor_act.py | 2 +- src/lerobot/policies/diffusion/modeling_diffusion.py | 2 +- .../policies/diffusion/processor_diffusion.py | 2 +- src/lerobot/policies/factory.py | 2 +- src/lerobot/policies/pi0/modeling_pi0.py | 2 +- src/lerobot/policies/pi0/processor_pi0.py | 2 +- src/lerobot/policies/pi0fast/modeling_pi0fast.py | 2 +- src/lerobot/policies/pi0fast/processor_pi0fast.py | 2 +- src/lerobot/policies/sac/configuration_sac.py | 2 +- src/lerobot/policies/sac/processor_sac.py | 2 +- .../policies/sac/reward_model/modeling_classifier.py | 2 +- src/lerobot/policies/smolvla/modeling_smolvla.py | 2 +- src/lerobot/policies/smolvla/processor_smolvla.py | 2 +- src/lerobot/policies/tdmpc/modeling_tdmpc.py | 2 +- src/lerobot/policies/tdmpc/processor_tdmpc.py | 2 +- src/lerobot/policies/vqbet/modeling_vqbet.py | 2 +- src/lerobot/policies/vqbet/processor_vqbet.py | 2 +- src/lerobot/processor/batch_processor.py | 2 +- .../processor/joint_observations_processor.py | 2 +- src/lerobot/processor/observation_processor.py | 2 +- src/lerobot/processor/pipeline.py | 2 +- src/lerobot/processor/tokenizer_processor.py | 2 +- src/lerobot/rl/learner.py | 12 ++++++------ src/lerobot/robots/robot.py | 2 +- src/lerobot/robots/stretch3/robot_stretch3.py | 2 +- src/lerobot/robots/viperx/viperx.py | 2 +- src/lerobot/scripts/server/helpers.py | 2 +- src/lerobot/teleoperators/teleoperator.py | 2 +- src/lerobot/{ => utils}/constants.py | 0 src/lerobot/utils/random_utils.py | 2 +- src/lerobot/utils/train_utils.py | 12 ++++++------ src/lerobot/utils/wandb_utils.py | 2 +- tests/datasets/test_datasets.py | 2 +- tests/fixtures/constants.py | 2 +- tests/optim/test_optimizers.py | 8 ++++---- tests/optim/test_schedulers.py | 2 +- tests/policies/test_policies.py | 2 +- tests/processor/test_act_processor.py | 2 +- tests/processor/test_batch_processor.py | 2 +- tests/processor/test_classifier_processor.py | 2 +- tests/processor/test_device_processor.py | 4 ++-- tests/processor/test_diffusion_processor.py | 2 +- tests/processor/test_observation_processor.py | 2 +- tests/processor/test_pi0_processor.py | 2 +- tests/processor/test_sac_processor.py | 2 +- tests/processor/test_smolvla_processor.py | 2 +- tests/processor/test_tdmpc_processor.py | 2 +- tests/processor/test_tokenizer_processor.py | 2 +- tests/processor/test_vqbet_processor.py | 2 +- tests/utils/test_train_utils.py | 2 +- 60 files changed, 74 insertions(+), 74 deletions(-) rename src/lerobot/{ => utils}/constants.py (100%) diff --git a/examples/training/train_with_streaming.py b/examples/training/train_with_streaming.py index e7edc17f8..185be5b13 100644 --- a/examples/training/train_with_streaming.py +++ b/examples/training/train_with_streaming.py @@ -20,13 +20,13 @@ from pathlib import Path import torch from lerobot.configs.types import FeatureType -from lerobot.constants import ACTION from lerobot.datasets.lerobot_dataset import LeRobotDatasetMetadata from lerobot.datasets.streaming_dataset import StreamingLeRobotDataset from lerobot.datasets.utils import dataset_to_policy_features from lerobot.policies.act.configuration_act import ACTConfig from lerobot.policies.act.modeling_act import ACTPolicy from lerobot.policies.factory import make_pre_post_processors +from lerobot.utils.constants import ACTION def main(): diff --git a/src/lerobot/configs/policies.py b/src/lerobot/configs/policies.py index 9a2bb911a..06c220cb8 100644 --- a/src/lerobot/configs/policies.py +++ b/src/lerobot/configs/policies.py @@ -27,9 +27,9 @@ from huggingface_hub.constants import CONFIG_NAME from huggingface_hub.errors import HfHubHTTPError from lerobot.configs.types import FeatureType, PolicyFeature -from lerobot.constants import ACTION, OBS_STATE from lerobot.optim.optimizers import OptimizerConfig from lerobot.optim.schedulers import LRSchedulerConfig +from lerobot.utils.constants import ACTION, OBS_STATE from lerobot.utils.hub import HubMixin from lerobot.utils.utils import auto_select_torch_device, is_amp_available, is_torch_device_available diff --git a/src/lerobot/datasets/lerobot_dataset.py b/src/lerobot/datasets/lerobot_dataset.py index 4ac7a841c..9eebcea4b 100644 --- a/src/lerobot/datasets/lerobot_dataset.py +++ b/src/lerobot/datasets/lerobot_dataset.py @@ -31,7 +31,6 @@ import torch.utils from huggingface_hub import HfApi, snapshot_download from huggingface_hub.errors import RevisionNotFoundError -from lerobot.constants import HF_LEROBOT_HOME from lerobot.datasets.compute_stats import aggregate_stats, compute_episode_stats from lerobot.datasets.image_writer import AsyncImageWriter, write_image from lerobot.datasets.utils import ( @@ -79,6 +78,7 @@ from lerobot.datasets.video_utils import ( get_video_duration_in_s, get_video_info, ) +from lerobot.utils.constants import HF_LEROBOT_HOME CODEBASE_VERSION = "v3.0" diff --git a/src/lerobot/datasets/pipeline_features.py b/src/lerobot/datasets/pipeline_features.py index b55ccf8a9..cdf0b7448 100644 --- a/src/lerobot/datasets/pipeline_features.py +++ b/src/lerobot/datasets/pipeline_features.py @@ -17,9 +17,9 @@ from collections.abc import Sequence from typing import Any from lerobot.configs.types import PipelineFeatureType -from lerobot.constants import ACTION, OBS_IMAGES, OBS_STATE from lerobot.datasets.utils import hw_to_dataset_features from lerobot.processor import DataProcessorPipeline +from lerobot.utils.constants import ACTION, OBS_IMAGES, OBS_STATE def create_initial_features( diff --git a/src/lerobot/datasets/streaming_dataset.py b/src/lerobot/datasets/streaming_dataset.py index e354c4060..c3c48d90d 100644 --- a/src/lerobot/datasets/streaming_dataset.py +++ b/src/lerobot/datasets/streaming_dataset.py @@ -21,7 +21,6 @@ import numpy as np import torch from datasets import load_dataset -from lerobot.constants import HF_LEROBOT_HOME, LOOKAHEAD_BACKTRACKTABLE, LOOKBACK_BACKTRACKTABLE from lerobot.datasets.lerobot_dataset import CODEBASE_VERSION, LeRobotDatasetMetadata from lerobot.datasets.utils import ( Backtrackable, @@ -38,6 +37,7 @@ from lerobot.datasets.video_utils import ( VideoDecoderCache, decode_video_frames_torchcodec, ) +from lerobot.utils.constants import HF_LEROBOT_HOME, LOOKAHEAD_BACKTRACKTABLE, LOOKBACK_BACKTRACKTABLE class StreamingLeRobotDataset(torch.utils.data.IterableDataset): diff --git a/src/lerobot/datasets/v30/convert_dataset_v21_to_v30.py b/src/lerobot/datasets/v30/convert_dataset_v21_to_v30.py index 1327bd820..e5a6e3c9a 100644 --- a/src/lerobot/datasets/v30/convert_dataset_v21_to_v30.py +++ b/src/lerobot/datasets/v30/convert_dataset_v21_to_v30.py @@ -46,7 +46,6 @@ from datasets import Dataset, Features, Image from huggingface_hub import HfApi, snapshot_download from requests import HTTPError -from lerobot.constants import HF_LEROBOT_HOME from lerobot.datasets.compute_stats import aggregate_stats from lerobot.datasets.lerobot_dataset import CODEBASE_VERSION, LeRobotDataset from lerobot.datasets.utils import ( @@ -71,6 +70,7 @@ from lerobot.datasets.utils import ( write_tasks, ) from lerobot.datasets.video_utils import concatenate_video_files, get_video_duration_in_s +from lerobot.utils.constants import HF_LEROBOT_HOME V21 = "v2.1" diff --git a/src/lerobot/envs/configs.py b/src/lerobot/envs/configs.py index 8c66b278e..4456c51a5 100644 --- a/src/lerobot/envs/configs.py +++ b/src/lerobot/envs/configs.py @@ -19,9 +19,9 @@ from typing import Any import draccus from lerobot.configs.types import FeatureType, PolicyFeature -from lerobot.constants import ACTION, OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE from lerobot.robots import RobotConfig from lerobot.teleoperators.config import TeleoperatorConfig +from lerobot.utils.constants import ACTION, OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE @dataclass diff --git a/src/lerobot/optim/optimizers.py b/src/lerobot/optim/optimizers.py index ece4dc157..f2bd0df42 100644 --- a/src/lerobot/optim/optimizers.py +++ b/src/lerobot/optim/optimizers.py @@ -22,11 +22,11 @@ import draccus import torch from safetensors.torch import load_file, save_file -from lerobot.constants import ( +from lerobot.datasets.utils import flatten_dict, unflatten_dict, write_json +from lerobot.utils.constants import ( OPTIMIZER_PARAM_GROUPS, OPTIMIZER_STATE, ) -from lerobot.datasets.utils import flatten_dict, unflatten_dict, write_json from lerobot.utils.io_utils import deserialize_json_into_object diff --git a/src/lerobot/optim/schedulers.py b/src/lerobot/optim/schedulers.py index d08018175..55ee62e40 100644 --- a/src/lerobot/optim/schedulers.py +++ b/src/lerobot/optim/schedulers.py @@ -22,8 +22,8 @@ import draccus from torch.optim import Optimizer from torch.optim.lr_scheduler import LambdaLR, LRScheduler -from lerobot.constants import SCHEDULER_STATE from lerobot.datasets.utils import write_json +from lerobot.utils.constants import SCHEDULER_STATE from lerobot.utils.io_utils import deserialize_json_into_object diff --git a/src/lerobot/policies/act/modeling_act.py b/src/lerobot/policies/act/modeling_act.py index e0f3462cc..e4ebec199 100644 --- a/src/lerobot/policies/act/modeling_act.py +++ b/src/lerobot/policies/act/modeling_act.py @@ -33,9 +33,9 @@ from torch import Tensor, nn from torchvision.models._utils import IntermediateLayerGetter from torchvision.ops.misc import FrozenBatchNorm2d -from lerobot.constants import ACTION, OBS_IMAGES from lerobot.policies.act.configuration_act import ACTConfig from lerobot.policies.pretrained import PreTrainedPolicy +from lerobot.utils.constants import ACTION, OBS_IMAGES class ACTPolicy(PreTrainedPolicy): diff --git a/src/lerobot/policies/act/processor_act.py b/src/lerobot/policies/act/processor_act.py index b0d2067e9..727b18cef 100644 --- a/src/lerobot/policies/act/processor_act.py +++ b/src/lerobot/policies/act/processor_act.py @@ -17,7 +17,6 @@ from typing import Any import torch -from lerobot.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME from lerobot.policies.act.configuration_act import ACTConfig from lerobot.processor import ( AddBatchDimensionProcessorStep, @@ -29,6 +28,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import policy_action_to_transition, transition_to_policy_action +from lerobot.utils.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME def make_act_pre_post_processors( diff --git a/src/lerobot/policies/diffusion/modeling_diffusion.py b/src/lerobot/policies/diffusion/modeling_diffusion.py index 747ead334..0bd2e282b 100644 --- a/src/lerobot/policies/diffusion/modeling_diffusion.py +++ b/src/lerobot/policies/diffusion/modeling_diffusion.py @@ -33,7 +33,6 @@ from diffusers.schedulers.scheduling_ddim import DDIMScheduler from diffusers.schedulers.scheduling_ddpm import DDPMScheduler from torch import Tensor, nn -from lerobot.constants import ACTION, OBS_ENV_STATE, OBS_IMAGES, OBS_STATE from lerobot.policies.diffusion.configuration_diffusion import DiffusionConfig from lerobot.policies.pretrained import PreTrainedPolicy from lerobot.policies.utils import ( @@ -42,6 +41,7 @@ from lerobot.policies.utils import ( get_output_shape, populate_queues, ) +from lerobot.utils.constants import ACTION, OBS_ENV_STATE, OBS_IMAGES, OBS_STATE class DiffusionPolicy(PreTrainedPolicy): diff --git a/src/lerobot/policies/diffusion/processor_diffusion.py b/src/lerobot/policies/diffusion/processor_diffusion.py index 4383ec950..a7799be64 100644 --- a/src/lerobot/policies/diffusion/processor_diffusion.py +++ b/src/lerobot/policies/diffusion/processor_diffusion.py @@ -18,7 +18,6 @@ from typing import Any import torch -from lerobot.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME from lerobot.policies.diffusion.configuration_diffusion import DiffusionConfig from lerobot.processor import ( AddBatchDimensionProcessorStep, @@ -30,6 +29,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import policy_action_to_transition, transition_to_policy_action +from lerobot.utils.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME def make_diffusion_pre_post_processors( diff --git a/src/lerobot/policies/factory.py b/src/lerobot/policies/factory.py index 06c0c4ba5..60c05240e 100644 --- a/src/lerobot/policies/factory.py +++ b/src/lerobot/policies/factory.py @@ -24,7 +24,6 @@ from typing_extensions import Unpack from lerobot.configs.policies import PreTrainedConfig from lerobot.configs.types import FeatureType -from lerobot.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME from lerobot.datasets.lerobot_dataset import LeRobotDatasetMetadata from lerobot.datasets.utils import dataset_to_policy_features from lerobot.envs.configs import EnvConfig @@ -46,6 +45,7 @@ from lerobot.processor.converters import ( transition_to_batch, transition_to_policy_action, ) +from lerobot.utils.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME def get_policy_class(name: str) -> type[PreTrainedPolicy]: diff --git a/src/lerobot/policies/pi0/modeling_pi0.py b/src/lerobot/policies/pi0/modeling_pi0.py index 66bd81e61..4d3f4ffa1 100644 --- a/src/lerobot/policies/pi0/modeling_pi0.py +++ b/src/lerobot/policies/pi0/modeling_pi0.py @@ -57,13 +57,13 @@ import torch import torch.nn.functional as F # noqa: N812 from torch import Tensor, nn -from lerobot.constants import ACTION, OBS_LANGUAGE_ATTENTION_MASK, OBS_LANGUAGE_TOKENS, OBS_STATE from lerobot.policies.pi0.configuration_pi0 import PI0Config from lerobot.policies.pi0.paligemma_with_expert import ( PaliGemmaWithExpertConfig, PaliGemmaWithExpertModel, ) from lerobot.policies.pretrained import PreTrainedPolicy +from lerobot.utils.constants import ACTION, OBS_LANGUAGE_ATTENTION_MASK, OBS_LANGUAGE_TOKENS, OBS_STATE from lerobot.utils.utils import get_safe_dtype diff --git a/src/lerobot/policies/pi0/processor_pi0.py b/src/lerobot/policies/pi0/processor_pi0.py index cd9712201..50f5dec83 100644 --- a/src/lerobot/policies/pi0/processor_pi0.py +++ b/src/lerobot/policies/pi0/processor_pi0.py @@ -19,7 +19,6 @@ from typing import Any import torch from lerobot.configs.types import PipelineFeatureType, PolicyFeature -from lerobot.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME from lerobot.policies.pi0.configuration_pi0 import PI0Config from lerobot.processor import ( AddBatchDimensionProcessorStep, @@ -35,6 +34,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import policy_action_to_transition, transition_to_policy_action +from lerobot.utils.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME @ProcessorStepRegistry.register(name="pi0_new_line_processor") diff --git a/src/lerobot/policies/pi0fast/modeling_pi0fast.py b/src/lerobot/policies/pi0fast/modeling_pi0fast.py index 682a372f4..102cfb8fa 100644 --- a/src/lerobot/policies/pi0fast/modeling_pi0fast.py +++ b/src/lerobot/policies/pi0fast/modeling_pi0fast.py @@ -57,9 +57,9 @@ from transformers import AutoProcessor, AutoTokenizer, PaliGemmaForConditionalGe from transformers.cache_utils import HybridCache, StaticCache from transformers.models.auto import CONFIG_MAPPING -from lerobot.constants import ACTION, OBS_STATE from lerobot.policies.pi0fast.configuration_pi0fast import PI0FASTConfig from lerobot.policies.pretrained import PreTrainedPolicy +from lerobot.utils.constants import ACTION, OBS_STATE PRECISION = { "float16": torch.float16, diff --git a/src/lerobot/policies/pi0fast/processor_pi0fast.py b/src/lerobot/policies/pi0fast/processor_pi0fast.py index 81314aa37..95b5e541b 100644 --- a/src/lerobot/policies/pi0fast/processor_pi0fast.py +++ b/src/lerobot/policies/pi0fast/processor_pi0fast.py @@ -18,7 +18,6 @@ from typing import Any import torch -from lerobot.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME from lerobot.policies.pi0fast.configuration_pi0fast import PI0FASTConfig from lerobot.processor import ( AddBatchDimensionProcessorStep, @@ -30,6 +29,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import policy_action_to_transition, transition_to_policy_action +from lerobot.utils.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME def make_pi0fast_pre_post_processors( diff --git a/src/lerobot/policies/sac/configuration_sac.py b/src/lerobot/policies/sac/configuration_sac.py index c57eeeb72..a42758b85 100644 --- a/src/lerobot/policies/sac/configuration_sac.py +++ b/src/lerobot/policies/sac/configuration_sac.py @@ -19,8 +19,8 @@ from dataclasses import dataclass, field from lerobot.configs.policies import PreTrainedConfig from lerobot.configs.types import NormalizationMode -from lerobot.constants import ACTION, OBS_IMAGE, OBS_STATE from lerobot.optim.optimizers import MultiAdamConfig +from lerobot.utils.constants import ACTION, OBS_IMAGE, OBS_STATE def is_image_feature(key: str) -> bool: diff --git a/src/lerobot/policies/sac/processor_sac.py b/src/lerobot/policies/sac/processor_sac.py index 9e8013d31..cf90e3cb4 100644 --- a/src/lerobot/policies/sac/processor_sac.py +++ b/src/lerobot/policies/sac/processor_sac.py @@ -19,7 +19,6 @@ from typing import Any import torch -from lerobot.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME from lerobot.policies.sac.configuration_sac import SACConfig from lerobot.processor import ( AddBatchDimensionProcessorStep, @@ -31,6 +30,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import policy_action_to_transition, transition_to_policy_action +from lerobot.utils.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME def make_sac_pre_post_processors( diff --git a/src/lerobot/policies/sac/reward_model/modeling_classifier.py b/src/lerobot/policies/sac/reward_model/modeling_classifier.py index ca501c3a7..dba6a174b 100644 --- a/src/lerobot/policies/sac/reward_model/modeling_classifier.py +++ b/src/lerobot/policies/sac/reward_model/modeling_classifier.py @@ -19,9 +19,9 @@ import logging import torch from torch import Tensor, nn -from lerobot.constants import OBS_IMAGE, REWARD from lerobot.policies.pretrained import PreTrainedPolicy from lerobot.policies.sac.reward_model.configuration_classifier import RewardClassifierConfig +from lerobot.utils.constants import OBS_IMAGE, REWARD class ClassifierOutput: diff --git a/src/lerobot/policies/smolvla/modeling_smolvla.py b/src/lerobot/policies/smolvla/modeling_smolvla.py index 48d4b2315..23fc3ca4f 100644 --- a/src/lerobot/policies/smolvla/modeling_smolvla.py +++ b/src/lerobot/policies/smolvla/modeling_smolvla.py @@ -59,13 +59,13 @@ import torch import torch.nn.functional as F # noqa: N812 from torch import Tensor, nn -from lerobot.constants import ACTION, OBS_LANGUAGE_ATTENTION_MASK, OBS_LANGUAGE_TOKENS, OBS_STATE from lerobot.policies.pretrained import PreTrainedPolicy from lerobot.policies.smolvla.configuration_smolvla import SmolVLAConfig from lerobot.policies.smolvla.smolvlm_with_expert import SmolVLMWithExpertModel from lerobot.policies.utils import ( populate_queues, ) +from lerobot.utils.constants import ACTION, OBS_LANGUAGE_ATTENTION_MASK, OBS_LANGUAGE_TOKENS, OBS_STATE from lerobot.utils.utils import get_safe_dtype diff --git a/src/lerobot/policies/smolvla/processor_smolvla.py b/src/lerobot/policies/smolvla/processor_smolvla.py index ac3cd4626..3fc130aa1 100644 --- a/src/lerobot/policies/smolvla/processor_smolvla.py +++ b/src/lerobot/policies/smolvla/processor_smolvla.py @@ -19,7 +19,6 @@ from typing import Any import torch from lerobot.configs.types import PipelineFeatureType, PolicyFeature -from lerobot.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME from lerobot.policies.smolvla.configuration_smolvla import SmolVLAConfig from lerobot.processor import ( AddBatchDimensionProcessorStep, @@ -34,6 +33,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import policy_action_to_transition, transition_to_policy_action +from lerobot.utils.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME def make_smolvla_pre_post_processors( diff --git a/src/lerobot/policies/tdmpc/modeling_tdmpc.py b/src/lerobot/policies/tdmpc/modeling_tdmpc.py index e160310b3..f83048862 100644 --- a/src/lerobot/policies/tdmpc/modeling_tdmpc.py +++ b/src/lerobot/policies/tdmpc/modeling_tdmpc.py @@ -35,10 +35,10 @@ import torch.nn as nn import torch.nn.functional as F # noqa: N812 from torch import Tensor -from lerobot.constants import ACTION, OBS_ENV_STATE, OBS_IMAGE, OBS_STATE, REWARD from lerobot.policies.pretrained import PreTrainedPolicy from lerobot.policies.tdmpc.configuration_tdmpc import TDMPCConfig from lerobot.policies.utils import get_device_from_parameters, get_output_shape, populate_queues +from lerobot.utils.constants import ACTION, OBS_ENV_STATE, OBS_IMAGE, OBS_STATE, REWARD class TDMPCPolicy(PreTrainedPolicy): diff --git a/src/lerobot/policies/tdmpc/processor_tdmpc.py b/src/lerobot/policies/tdmpc/processor_tdmpc.py index 75a7d4f7e..9b6f97e50 100644 --- a/src/lerobot/policies/tdmpc/processor_tdmpc.py +++ b/src/lerobot/policies/tdmpc/processor_tdmpc.py @@ -18,7 +18,6 @@ from typing import Any import torch -from lerobot.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME from lerobot.policies.tdmpc.configuration_tdmpc import TDMPCConfig from lerobot.processor import ( AddBatchDimensionProcessorStep, @@ -30,6 +29,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import policy_action_to_transition, transition_to_policy_action +from lerobot.utils.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME def make_tdmpc_pre_post_processors( diff --git a/src/lerobot/policies/vqbet/modeling_vqbet.py b/src/lerobot/policies/vqbet/modeling_vqbet.py index bb6040e90..34e5b1c0d 100644 --- a/src/lerobot/policies/vqbet/modeling_vqbet.py +++ b/src/lerobot/policies/vqbet/modeling_vqbet.py @@ -27,11 +27,11 @@ import torch.nn.functional as F # noqa: N812 import torchvision from torch import Tensor, nn -from lerobot.constants import ACTION, OBS_IMAGES, OBS_STATE from lerobot.policies.pretrained import PreTrainedPolicy from lerobot.policies.utils import get_device_from_parameters, get_output_shape, populate_queues from lerobot.policies.vqbet.configuration_vqbet import VQBeTConfig from lerobot.policies.vqbet.vqbet_utils import GPT, ResidualVQ +from lerobot.utils.constants import ACTION, OBS_IMAGES, OBS_STATE # ruff: noqa: N806 diff --git a/src/lerobot/policies/vqbet/processor_vqbet.py b/src/lerobot/policies/vqbet/processor_vqbet.py index 1c741cd33..1e19ff779 100644 --- a/src/lerobot/policies/vqbet/processor_vqbet.py +++ b/src/lerobot/policies/vqbet/processor_vqbet.py @@ -19,7 +19,6 @@ from typing import Any import torch -from lerobot.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME from lerobot.policies.vqbet.configuration_vqbet import VQBeTConfig from lerobot.processor import ( AddBatchDimensionProcessorStep, @@ -31,6 +30,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import policy_action_to_transition, transition_to_policy_action +from lerobot.utils.constants import POLICY_POSTPROCESSOR_DEFAULT_NAME, POLICY_PREPROCESSOR_DEFAULT_NAME def make_vqbet_pre_post_processors( diff --git a/src/lerobot/processor/batch_processor.py b/src/lerobot/processor/batch_processor.py index a563599cd..e1a90421f 100644 --- a/src/lerobot/processor/batch_processor.py +++ b/src/lerobot/processor/batch_processor.py @@ -25,7 +25,7 @@ from dataclasses import dataclass, field from torch import Tensor from lerobot.configs.types import PipelineFeatureType, PolicyFeature -from lerobot.constants import OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE +from lerobot.utils.constants import OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE from .core import EnvTransition, PolicyAction from .pipeline import ( diff --git a/src/lerobot/processor/joint_observations_processor.py b/src/lerobot/processor/joint_observations_processor.py index ab3c6ecc1..2fbcc7c46 100644 --- a/src/lerobot/processor/joint_observations_processor.py +++ b/src/lerobot/processor/joint_observations_processor.py @@ -20,12 +20,12 @@ from typing import Any import torch from lerobot.configs.types import PipelineFeatureType, PolicyFeature -from lerobot.constants import OBS_STATE from lerobot.processor.pipeline import ( ObservationProcessorStep, ProcessorStepRegistry, ) from lerobot.robots import Robot +from lerobot.utils.constants import OBS_STATE @dataclass diff --git a/src/lerobot/processor/observation_processor.py b/src/lerobot/processor/observation_processor.py index 71fdbbf0d..2b9402bee 100644 --- a/src/lerobot/processor/observation_processor.py +++ b/src/lerobot/processor/observation_processor.py @@ -21,7 +21,7 @@ import torch from torch import Tensor from lerobot.configs.types import PipelineFeatureType, PolicyFeature -from lerobot.constants import OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE +from lerobot.utils.constants import OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE from .pipeline import ObservationProcessorStep, ProcessorStepRegistry diff --git a/src/lerobot/processor/pipeline.py b/src/lerobot/processor/pipeline.py index 1c88cd741..e14d8b0b9 100644 --- a/src/lerobot/processor/pipeline.py +++ b/src/lerobot/processor/pipeline.py @@ -422,7 +422,7 @@ class DataProcessorPipeline(HubMixin, Generic[TInput, TOutput]): """ if save_directory is None: # Use default directory in HF_LEROBOT_HOME - from lerobot.constants import HF_LEROBOT_HOME + from lerobot.utils.constants import HF_LEROBOT_HOME sanitized_name = re.sub(r"[^a-zA-Z0-9_]", "_", self.name.lower()) save_directory = HF_LEROBOT_HOME / "processors" / sanitized_name diff --git a/src/lerobot/processor/tokenizer_processor.py b/src/lerobot/processor/tokenizer_processor.py index 23db7b5e3..2ef89c107 100644 --- a/src/lerobot/processor/tokenizer_processor.py +++ b/src/lerobot/processor/tokenizer_processor.py @@ -29,7 +29,7 @@ from typing import TYPE_CHECKING, Any import torch from lerobot.configs.types import FeatureType, PipelineFeatureType, PolicyFeature -from lerobot.constants import OBS_LANGUAGE_ATTENTION_MASK, OBS_LANGUAGE_TOKENS +from lerobot.utils.constants import OBS_LANGUAGE_ATTENTION_MASK, OBS_LANGUAGE_TOKENS from lerobot.utils.import_utils import _transformers_available from .core import EnvTransition, TransitionKey diff --git a/src/lerobot/rl/learner.py b/src/lerobot/rl/learner.py index 6441ba55f..8d6831286 100644 --- a/src/lerobot/rl/learner.py +++ b/src/lerobot/rl/learner.py @@ -62,12 +62,6 @@ from torch.optim.optimizer import Optimizer from lerobot.cameras import opencv # noqa: F401 from lerobot.configs import parser from lerobot.configs.train import TrainRLServerPipelineConfig -from lerobot.constants import ( - CHECKPOINTS_DIR, - LAST_CHECKPOINT_LINK, - PRETRAINED_MODEL_DIR, - TRAINING_STATE_DIR, -) from lerobot.datasets.factory import make_dataset from lerobot.datasets.lerobot_dataset import LeRobotDataset from lerobot.policies.factory import make_policy @@ -83,6 +77,12 @@ from lerobot.transport.utils import ( state_to_bytes, ) from lerobot.utils.buffer import ReplayBuffer, concatenate_batch_transitions +from lerobot.utils.constants import ( + CHECKPOINTS_DIR, + LAST_CHECKPOINT_LINK, + PRETRAINED_MODEL_DIR, + TRAINING_STATE_DIR, +) from lerobot.utils.process import ProcessSignalHandler from lerobot.utils.random_utils import set_seed from lerobot.utils.train_utils import ( diff --git a/src/lerobot/robots/robot.py b/src/lerobot/robots/robot.py index 2a9004380..5e88b915b 100644 --- a/src/lerobot/robots/robot.py +++ b/src/lerobot/robots/robot.py @@ -19,8 +19,8 @@ from typing import Any import draccus -from lerobot.constants import HF_LEROBOT_CALIBRATION, ROBOTS from lerobot.motors import MotorCalibration +from lerobot.utils.constants import HF_LEROBOT_CALIBRATION, ROBOTS from .config import RobotConfig diff --git a/src/lerobot/robots/stretch3/robot_stretch3.py b/src/lerobot/robots/stretch3/robot_stretch3.py index b907d6a3f..8a0ff5c6a 100644 --- a/src/lerobot/robots/stretch3/robot_stretch3.py +++ b/src/lerobot/robots/stretch3/robot_stretch3.py @@ -22,8 +22,8 @@ from stretch_body.robot import Robot as StretchAPI from stretch_body.robot_params import RobotParams from lerobot.cameras.utils import make_cameras_from_configs -from lerobot.constants import OBS_IMAGES, OBS_STATE from lerobot.datasets.utils import get_nested_item +from lerobot.utils.constants import OBS_IMAGES, OBS_STATE from ..robot import Robot from .configuration_stretch3 import Stretch3RobotConfig diff --git a/src/lerobot/robots/viperx/viperx.py b/src/lerobot/robots/viperx/viperx.py index 881640cd5..006c780e3 100644 --- a/src/lerobot/robots/viperx/viperx.py +++ b/src/lerobot/robots/viperx/viperx.py @@ -18,13 +18,13 @@ from functools import cached_property from typing import Any from lerobot.cameras.utils import make_cameras_from_configs -from lerobot.constants import OBS_STATE from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.dynamixel import ( DynamixelMotorsBus, OperatingMode, ) +from lerobot.utils.constants import OBS_STATE from ..robot import Robot from ..utils import ensure_safe_goal_position diff --git a/src/lerobot/scripts/server/helpers.py b/src/lerobot/scripts/server/helpers.py index d8051b76e..175cecf6d 100644 --- a/src/lerobot/scripts/server/helpers.py +++ b/src/lerobot/scripts/server/helpers.py @@ -22,12 +22,12 @@ from pathlib import Path import torch from lerobot.configs.types import PolicyFeature -from lerobot.constants import OBS_IMAGES, OBS_STATE from lerobot.datasets.utils import build_dataset_frame, hw_to_dataset_features # NOTE: Configs need to be loaded for the client to be able to instantiate the policy config from lerobot.policies import ACTConfig, DiffusionConfig, PI0Config, SmolVLAConfig, VQBeTConfig # noqa: F401 from lerobot.robots.robot import Robot +from lerobot.utils.constants import OBS_IMAGES, OBS_STATE from lerobot.utils.utils import init_logging Action = torch.Tensor diff --git a/src/lerobot/teleoperators/teleoperator.py b/src/lerobot/teleoperators/teleoperator.py index c360ee7bb..95020a962 100644 --- a/src/lerobot/teleoperators/teleoperator.py +++ b/src/lerobot/teleoperators/teleoperator.py @@ -19,8 +19,8 @@ from typing import Any import draccus -from lerobot.constants import HF_LEROBOT_CALIBRATION, TELEOPERATORS from lerobot.motors.motors_bus import MotorCalibration +from lerobot.utils.constants import HF_LEROBOT_CALIBRATION, TELEOPERATORS from .config import TeleoperatorConfig diff --git a/src/lerobot/constants.py b/src/lerobot/utils/constants.py similarity index 100% rename from src/lerobot/constants.py rename to src/lerobot/utils/constants.py diff --git a/src/lerobot/utils/random_utils.py b/src/lerobot/utils/random_utils.py index da3ecf37f..1bb1f0631 100644 --- a/src/lerobot/utils/random_utils.py +++ b/src/lerobot/utils/random_utils.py @@ -23,8 +23,8 @@ import numpy as np import torch from safetensors.torch import load_file, save_file -from lerobot.constants import RNG_STATE from lerobot.datasets.utils import flatten_dict, unflatten_dict +from lerobot.utils.constants import RNG_STATE def serialize_python_rng_state() -> dict[str, torch.Tensor]: diff --git a/src/lerobot/utils/train_utils.py b/src/lerobot/utils/train_utils.py index be2eb8146..08d1bcc9d 100644 --- a/src/lerobot/utils/train_utils.py +++ b/src/lerobot/utils/train_utils.py @@ -21,18 +21,18 @@ from torch.optim import Optimizer from torch.optim.lr_scheduler import LRScheduler from lerobot.configs.train import TrainPipelineConfig -from lerobot.constants import ( +from lerobot.datasets.utils import load_json, write_json +from lerobot.optim.optimizers import load_optimizer_state, save_optimizer_state +from lerobot.optim.schedulers import load_scheduler_state, save_scheduler_state +from lerobot.policies.pretrained import PreTrainedPolicy +from lerobot.processor import PolicyProcessorPipeline +from lerobot.utils.constants import ( CHECKPOINTS_DIR, LAST_CHECKPOINT_LINK, PRETRAINED_MODEL_DIR, TRAINING_STATE_DIR, TRAINING_STEP, ) -from lerobot.datasets.utils import load_json, write_json -from lerobot.optim.optimizers import load_optimizer_state, save_optimizer_state -from lerobot.optim.schedulers import load_scheduler_state, save_scheduler_state -from lerobot.policies.pretrained import PreTrainedPolicy -from lerobot.processor import PolicyProcessorPipeline from lerobot.utils.random_utils import load_rng_state, save_rng_state diff --git a/src/lerobot/utils/wandb_utils.py b/src/lerobot/utils/wandb_utils.py index 91b4ec95c..b13254421 100644 --- a/src/lerobot/utils/wandb_utils.py +++ b/src/lerobot/utils/wandb_utils.py @@ -23,7 +23,7 @@ from huggingface_hub.constants import SAFETENSORS_SINGLE_FILE from termcolor import colored from lerobot.configs.train import TrainPipelineConfig -from lerobot.constants import PRETRAINED_MODEL_DIR +from lerobot.utils.constants import PRETRAINED_MODEL_DIR def cfg_to_group(cfg: TrainPipelineConfig, return_list: bool = False) -> list[str] | str: diff --git a/tests/datasets/test_datasets.py b/tests/datasets/test_datasets.py index 2eca82346..d1d6dbdb2 100644 --- a/tests/datasets/test_datasets.py +++ b/tests/datasets/test_datasets.py @@ -112,7 +112,7 @@ def test_dataset_initialization(tmp_path, lerobot_dataset_factory): # and test the small resulting function that validates the features def test_dataset_feature_with_forward_slash_raises_error(): # make sure dir does not exist - from lerobot.constants import HF_LEROBOT_HOME + from lerobot.utils.constants import HF_LEROBOT_HOME dataset_dir = HF_LEROBOT_HOME / "lerobot/test/with/slash" # make sure does not exist diff --git a/tests/fixtures/constants.py b/tests/fixtures/constants.py index 0af499364..973c5b050 100644 --- a/tests/fixtures/constants.py +++ b/tests/fixtures/constants.py @@ -11,7 +11,7 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -from lerobot.constants import HF_LEROBOT_HOME +from lerobot.utils.constants import HF_LEROBOT_HOME LEROBOT_TEST_DIR = HF_LEROBOT_HOME / "_testing" DUMMY_REPO_ID = "dummy/repo" diff --git a/tests/optim/test_optimizers.py b/tests/optim/test_optimizers.py index 4152c7f8d..d18565562 100644 --- a/tests/optim/test_optimizers.py +++ b/tests/optim/test_optimizers.py @@ -14,10 +14,6 @@ import pytest import torch -from lerobot.constants import ( - OPTIMIZER_PARAM_GROUPS, - OPTIMIZER_STATE, -) from lerobot.optim.optimizers import ( AdamConfig, AdamWConfig, @@ -26,6 +22,10 @@ from lerobot.optim.optimizers import ( load_optimizer_state, save_optimizer_state, ) +from lerobot.utils.constants import ( + OPTIMIZER_PARAM_GROUPS, + OPTIMIZER_STATE, +) @pytest.mark.parametrize( diff --git a/tests/optim/test_schedulers.py b/tests/optim/test_schedulers.py index 43851c458..1e566a6ba 100644 --- a/tests/optim/test_schedulers.py +++ b/tests/optim/test_schedulers.py @@ -13,7 +13,6 @@ # limitations under the License. from torch.optim.lr_scheduler import LambdaLR -from lerobot.constants import SCHEDULER_STATE from lerobot.optim.schedulers import ( CosineDecayWithWarmupSchedulerConfig, DiffuserSchedulerConfig, @@ -21,6 +20,7 @@ from lerobot.optim.schedulers import ( load_scheduler_state, save_scheduler_state, ) +from lerobot.utils.constants import SCHEDULER_STATE def test_diffuser_scheduler(optimizer): diff --git a/tests/policies/test_policies.py b/tests/policies/test_policies.py index 28c395bfc..b577e5763 100644 --- a/tests/policies/test_policies.py +++ b/tests/policies/test_policies.py @@ -27,7 +27,6 @@ from lerobot import available_policies from lerobot.configs.default import DatasetConfig from lerobot.configs.train import TrainPipelineConfig from lerobot.configs.types import FeatureType, PolicyFeature -from lerobot.constants import ACTION, OBS_STATE from lerobot.datasets.factory import make_dataset from lerobot.datasets.utils import cycle, dataset_to_policy_features from lerobot.envs.factory import make_env, make_env_config @@ -42,6 +41,7 @@ from lerobot.policies.factory import ( make_pre_post_processors, ) from lerobot.policies.pretrained import PreTrainedPolicy +from lerobot.utils.constants import ACTION, OBS_STATE from lerobot.utils.random_utils import seeded_context from tests.artifacts.policies.save_policy_to_safetensors import get_policy_stats from tests.utils import DEVICE, require_cpu, require_env, require_x86_64_kernel diff --git a/tests/processor/test_act_processor.py b/tests/processor/test_act_processor.py index f96f871aa..00a4dbb96 100644 --- a/tests/processor/test_act_processor.py +++ b/tests/processor/test_act_processor.py @@ -21,7 +21,6 @@ import pytest import torch from lerobot.configs.types import FeatureType, NormalizationMode, PolicyFeature -from lerobot.constants import ACTION, OBS_STATE from lerobot.policies.act.configuration_act import ACTConfig from lerobot.policies.act.processor_act import make_act_pre_post_processors from lerobot.processor import ( @@ -34,6 +33,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import create_transition, transition_to_batch +from lerobot.utils.constants import ACTION, OBS_STATE def create_default_config(): diff --git a/tests/processor/test_batch_processor.py b/tests/processor/test_batch_processor.py index f7cbafd27..5c94b0657 100644 --- a/tests/processor/test_batch_processor.py +++ b/tests/processor/test_batch_processor.py @@ -21,7 +21,6 @@ import numpy as np import pytest import torch -from lerobot.constants import OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE from lerobot.processor import ( AddBatchDimensionProcessorStep, DataProcessorPipeline, @@ -29,6 +28,7 @@ from lerobot.processor import ( TransitionKey, ) from lerobot.processor.converters import create_transition, identity_transition +from lerobot.utils.constants import OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE def test_state_1d_to_2d(): diff --git a/tests/processor/test_classifier_processor.py b/tests/processor/test_classifier_processor.py index 139e99bd7..e1567bf29 100644 --- a/tests/processor/test_classifier_processor.py +++ b/tests/processor/test_classifier_processor.py @@ -21,7 +21,6 @@ import pytest import torch from lerobot.configs.types import FeatureType, NormalizationMode, PolicyFeature -from lerobot.constants import OBS_IMAGE, OBS_STATE from lerobot.policies.sac.reward_model.configuration_classifier import RewardClassifierConfig from lerobot.policies.sac.reward_model.processor_classifier import make_classifier_processor from lerobot.processor import ( @@ -32,6 +31,7 @@ from lerobot.processor import ( TransitionKey, ) from lerobot.processor.converters import create_transition, transition_to_batch +from lerobot.utils.constants import OBS_IMAGE, OBS_STATE def create_default_config(): diff --git a/tests/processor/test_device_processor.py b/tests/processor/test_device_processor.py index ba00bde4d..10ee313d7 100644 --- a/tests/processor/test_device_processor.py +++ b/tests/processor/test_device_processor.py @@ -284,8 +284,8 @@ def test_features(): def test_integration_with_robot_processor(): """Test integration with RobotProcessor.""" - from lerobot.constants import OBS_STATE from lerobot.processor import AddBatchDimensionProcessorStep + from lerobot.utils.constants import OBS_STATE # Create a pipeline with DeviceProcessorStep device_processor = DeviceProcessorStep(device="cpu") @@ -948,12 +948,12 @@ def test_simulated_accelerate_scenario(): def test_policy_processor_integration(): """Test integration with policy processors - input on GPU, output on CPU.""" from lerobot.configs.types import FeatureType, NormalizationMode, PolicyFeature - from lerobot.constants import ACTION, OBS_STATE from lerobot.processor import ( AddBatchDimensionProcessorStep, NormalizerProcessorStep, UnnormalizerProcessorStep, ) + from lerobot.utils.constants import ACTION, OBS_STATE # Create features and stats features = { diff --git a/tests/processor/test_diffusion_processor.py b/tests/processor/test_diffusion_processor.py index 5d280f9cc..67981c70d 100644 --- a/tests/processor/test_diffusion_processor.py +++ b/tests/processor/test_diffusion_processor.py @@ -21,7 +21,6 @@ import pytest import torch from lerobot.configs.types import FeatureType, NormalizationMode, PolicyFeature -from lerobot.constants import ACTION, OBS_IMAGE, OBS_STATE from lerobot.policies.diffusion.configuration_diffusion import DiffusionConfig from lerobot.policies.diffusion.processor_diffusion import make_diffusion_pre_post_processors from lerobot.processor import ( @@ -34,6 +33,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import create_transition, transition_to_batch +from lerobot.utils.constants import ACTION, OBS_IMAGE, OBS_STATE def create_default_config(): diff --git a/tests/processor/test_observation_processor.py b/tests/processor/test_observation_processor.py index 57f32482d..6abc9edef 100644 --- a/tests/processor/test_observation_processor.py +++ b/tests/processor/test_observation_processor.py @@ -19,9 +19,9 @@ import pytest import torch from lerobot.configs.types import FeatureType, PipelineFeatureType -from lerobot.constants import OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE from lerobot.processor import TransitionKey, VanillaObservationProcessorStep from lerobot.processor.converters import create_transition +from lerobot.utils.constants import OBS_ENV_STATE, OBS_IMAGE, OBS_IMAGES, OBS_STATE from tests.conftest import assert_contract_is_typed diff --git a/tests/processor/test_pi0_processor.py b/tests/processor/test_pi0_processor.py index c481cb18f..24afc648f 100644 --- a/tests/processor/test_pi0_processor.py +++ b/tests/processor/test_pi0_processor.py @@ -21,7 +21,6 @@ import pytest import torch from lerobot.configs.types import FeatureType, NormalizationMode, PolicyFeature -from lerobot.constants import ACTION, OBS_IMAGE, OBS_STATE from lerobot.policies.pi0.configuration_pi0 import PI0Config from lerobot.policies.pi0.processor_pi0 import Pi0NewLineProcessor, make_pi0_pre_post_processors from lerobot.processor import ( @@ -35,6 +34,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import create_transition, transition_to_batch +from lerobot.utils.constants import ACTION, OBS_IMAGE, OBS_STATE class MockTokenizerProcessorStep(ProcessorStep): diff --git a/tests/processor/test_sac_processor.py b/tests/processor/test_sac_processor.py index 7cbcb1882..a1a4b285d 100644 --- a/tests/processor/test_sac_processor.py +++ b/tests/processor/test_sac_processor.py @@ -21,7 +21,6 @@ import pytest import torch from lerobot.configs.types import FeatureType, NormalizationMode, PolicyFeature -from lerobot.constants import ACTION, OBS_STATE from lerobot.policies.sac.configuration_sac import SACConfig from lerobot.policies.sac.processor_sac import make_sac_pre_post_processors from lerobot.processor import ( @@ -34,6 +33,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import create_transition, transition_to_batch +from lerobot.utils.constants import ACTION, OBS_STATE def create_default_config(): diff --git a/tests/processor/test_smolvla_processor.py b/tests/processor/test_smolvla_processor.py index ce162c10d..227b1dc35 100644 --- a/tests/processor/test_smolvla_processor.py +++ b/tests/processor/test_smolvla_processor.py @@ -21,7 +21,6 @@ import pytest import torch from lerobot.configs.types import FeatureType, NormalizationMode, PipelineFeatureType, PolicyFeature -from lerobot.constants import ACTION, OBS_IMAGE, OBS_STATE from lerobot.policies.smolvla.configuration_smolvla import SmolVLAConfig from lerobot.policies.smolvla.processor_smolvla import ( SmolVLANewLineProcessor, @@ -38,6 +37,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import create_transition, transition_to_batch +from lerobot.utils.constants import ACTION, OBS_IMAGE, OBS_STATE class MockTokenizerProcessorStep(ProcessorStep): diff --git a/tests/processor/test_tdmpc_processor.py b/tests/processor/test_tdmpc_processor.py index 20979fd6d..edbc25ae3 100644 --- a/tests/processor/test_tdmpc_processor.py +++ b/tests/processor/test_tdmpc_processor.py @@ -21,7 +21,6 @@ import pytest import torch from lerobot.configs.types import FeatureType, NormalizationMode, PolicyFeature -from lerobot.constants import ACTION, OBS_IMAGE, OBS_STATE from lerobot.policies.tdmpc.configuration_tdmpc import TDMPCConfig from lerobot.policies.tdmpc.processor_tdmpc import make_tdmpc_pre_post_processors from lerobot.processor import ( @@ -34,6 +33,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import create_transition, transition_to_batch +from lerobot.utils.constants import ACTION, OBS_IMAGE, OBS_STATE def create_default_config(): diff --git a/tests/processor/test_tokenizer_processor.py b/tests/processor/test_tokenizer_processor.py index b3b0c9bfc..9e6c8de2f 100644 --- a/tests/processor/test_tokenizer_processor.py +++ b/tests/processor/test_tokenizer_processor.py @@ -9,9 +9,9 @@ import pytest import torch from lerobot.configs.types import FeatureType, PipelineFeatureType, PolicyFeature -from lerobot.constants import OBS_LANGUAGE from lerobot.processor import DataProcessorPipeline, TokenizerProcessorStep, TransitionKey from lerobot.processor.converters import create_transition, identity_transition +from lerobot.utils.constants import OBS_LANGUAGE from tests.utils import require_package diff --git a/tests/processor/test_vqbet_processor.py b/tests/processor/test_vqbet_processor.py index 98e05eae8..47e41dff4 100644 --- a/tests/processor/test_vqbet_processor.py +++ b/tests/processor/test_vqbet_processor.py @@ -21,7 +21,6 @@ import pytest import torch from lerobot.configs.types import FeatureType, NormalizationMode, PolicyFeature -from lerobot.constants import ACTION, OBS_IMAGE, OBS_STATE from lerobot.policies.vqbet.configuration_vqbet import VQBeTConfig from lerobot.policies.vqbet.processor_vqbet import make_vqbet_pre_post_processors from lerobot.processor import ( @@ -34,6 +33,7 @@ from lerobot.processor import ( UnnormalizerProcessorStep, ) from lerobot.processor.converters import create_transition, transition_to_batch +from lerobot.utils.constants import ACTION, OBS_IMAGE, OBS_STATE def create_default_config(): diff --git a/tests/utils/test_train_utils.py b/tests/utils/test_train_utils.py index 2d963d7ae..0eeaf907c 100644 --- a/tests/utils/test_train_utils.py +++ b/tests/utils/test_train_utils.py @@ -14,7 +14,7 @@ from pathlib import Path from unittest.mock import Mock, patch -from lerobot.constants import ( +from lerobot.utils.constants import ( CHECKPOINTS_DIR, LAST_CHECKPOINT_LINK, OPTIMIZER_PARAM_GROUPS, From 1033680a57e1b1a9a6045606b6de8d892b09a666 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 11:14:23 +0200 Subject: [PATCH 09/26] chore: move errors to utils (#2017) Signed-off-by: Steven Palma --- src/lerobot/cameras/opencv/camera_opencv.py | 2 +- src/lerobot/cameras/reachy2_camera/reachy2_camera.py | 2 +- src/lerobot/cameras/realsense/camera_realsense.py | 2 +- src/lerobot/motors/motors_bus.py | 2 +- src/lerobot/robots/hope_jr/hope_jr_arm.py | 2 +- src/lerobot/robots/hope_jr/hope_jr_hand.py | 2 +- src/lerobot/robots/koch_follower/koch_follower.py | 2 +- src/lerobot/robots/lekiwi/lekiwi.py | 2 +- src/lerobot/robots/lekiwi/lekiwi_client.py | 2 +- src/lerobot/robots/so100_follower/so100_follower.py | 2 +- src/lerobot/robots/so101_follower/so101_follower.py | 2 +- src/lerobot/robots/viperx/viperx.py | 2 +- src/lerobot/teleoperators/homunculus/homunculus_arm.py | 2 +- src/lerobot/teleoperators/homunculus/homunculus_glove.py | 2 +- src/lerobot/teleoperators/keyboard/teleop_keyboard.py | 2 +- src/lerobot/teleoperators/koch_leader/koch_leader.py | 2 +- src/lerobot/teleoperators/phone/teleop_phone.py | 2 +- src/lerobot/teleoperators/so100_leader/so100_leader.py | 2 +- src/lerobot/teleoperators/so101_leader/so101_leader.py | 2 +- src/lerobot/teleoperators/stretch3_gamepad/stretch3_gamepad.py | 2 +- src/lerobot/teleoperators/widowx/widowx.py | 2 +- src/lerobot/{ => utils}/errors.py | 0 tests/cameras/test_opencv.py | 2 +- tests/cameras/test_reachy2_camera.py | 2 +- tests/cameras/test_realsense.py | 2 +- tests/mocks/mock_robot.py | 2 +- tests/mocks/mock_teleop.py | 2 +- 27 files changed, 26 insertions(+), 26 deletions(-) rename src/lerobot/{ => utils}/errors.py (100%) diff --git a/src/lerobot/cameras/opencv/camera_opencv.py b/src/lerobot/cameras/opencv/camera_opencv.py index 3665a909f..50e55f0c2 100644 --- a/src/lerobot/cameras/opencv/camera_opencv.py +++ b/src/lerobot/cameras/opencv/camera_opencv.py @@ -31,7 +31,7 @@ if platform.system() == "Windows" and "OPENCV_VIDEOIO_MSMF_ENABLE_HW_TRANSFORMS" import cv2 import numpy as np -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..camera import Camera from ..utils import get_cv2_backend, get_cv2_rotation diff --git a/src/lerobot/cameras/reachy2_camera/reachy2_camera.py b/src/lerobot/cameras/reachy2_camera/reachy2_camera.py index 0daeb6bbb..c96789f96 100644 --- a/src/lerobot/cameras/reachy2_camera/reachy2_camera.py +++ b/src/lerobot/cameras/reachy2_camera/reachy2_camera.py @@ -31,7 +31,7 @@ import numpy as np from reachy2_sdk.media.camera import CameraView from reachy2_sdk.media.camera_manager import CameraManager -from lerobot.errors import DeviceNotConnectedError +from lerobot.utils.errors import DeviceNotConnectedError from ..camera import Camera from .configuration_reachy2_camera import ColorMode, Reachy2CameraConfig diff --git a/src/lerobot/cameras/realsense/camera_realsense.py b/src/lerobot/cameras/realsense/camera_realsense.py index 12ce89c91..cc816e552 100644 --- a/src/lerobot/cameras/realsense/camera_realsense.py +++ b/src/lerobot/cameras/realsense/camera_realsense.py @@ -29,7 +29,7 @@ try: except Exception as e: logging.info(f"Could not import realsense: {e}") -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..camera import Camera from ..configs import ColorMode diff --git a/src/lerobot/motors/motors_bus.py b/src/lerobot/motors/motors_bus.py index 97830fc35..dca7650e0 100644 --- a/src/lerobot/motors/motors_bus.py +++ b/src/lerobot/motors/motors_bus.py @@ -32,7 +32,7 @@ import serial from deepdiff import DeepDiff from tqdm import tqdm -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.utils.utils import enter_pressed, move_cursor_up NameOrID: TypeAlias = str | int diff --git a/src/lerobot/robots/hope_jr/hope_jr_arm.py b/src/lerobot/robots/hope_jr/hope_jr_arm.py index 0e3a615a9..baa36b560 100644 --- a/src/lerobot/robots/hope_jr/hope_jr_arm.py +++ b/src/lerobot/robots/hope_jr/hope_jr_arm.py @@ -20,12 +20,12 @@ from functools import cached_property from typing import Any from lerobot.cameras.utils import make_cameras_from_configs -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorNormMode from lerobot.motors.calibration_gui import RangeFinderGUI from lerobot.motors.feetech import ( FeetechMotorsBus, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..robot import Robot from ..utils import ensure_safe_goal_position diff --git a/src/lerobot/robots/hope_jr/hope_jr_hand.py b/src/lerobot/robots/hope_jr/hope_jr_hand.py index 8dc100e06..9e960642b 100644 --- a/src/lerobot/robots/hope_jr/hope_jr_hand.py +++ b/src/lerobot/robots/hope_jr/hope_jr_hand.py @@ -20,12 +20,12 @@ from functools import cached_property from typing import Any from lerobot.cameras.utils import make_cameras_from_configs -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorNormMode from lerobot.motors.calibration_gui import RangeFinderGUI from lerobot.motors.feetech import ( FeetechMotorsBus, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..robot import Robot from .config_hope_jr import HopeJrHandConfig diff --git a/src/lerobot/robots/koch_follower/koch_follower.py b/src/lerobot/robots/koch_follower/koch_follower.py index 563325b88..41a57828b 100644 --- a/src/lerobot/robots/koch_follower/koch_follower.py +++ b/src/lerobot/robots/koch_follower/koch_follower.py @@ -20,12 +20,12 @@ from functools import cached_property from typing import Any from lerobot.cameras.utils import make_cameras_from_configs -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.dynamixel import ( DynamixelMotorsBus, OperatingMode, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..robot import Robot from ..utils import ensure_safe_goal_position diff --git a/src/lerobot/robots/lekiwi/lekiwi.py b/src/lerobot/robots/lekiwi/lekiwi.py index 7004cc0fe..357109cb0 100644 --- a/src/lerobot/robots/lekiwi/lekiwi.py +++ b/src/lerobot/robots/lekiwi/lekiwi.py @@ -23,12 +23,12 @@ from typing import Any import numpy as np from lerobot.cameras.utils import make_cameras_from_configs -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.feetech import ( FeetechMotorsBus, OperatingMode, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..robot import Robot from ..utils import ensure_safe_goal_position diff --git a/src/lerobot/robots/lekiwi/lekiwi_client.py b/src/lerobot/robots/lekiwi/lekiwi_client.py index 9a8001401..9f6367152 100644 --- a/src/lerobot/robots/lekiwi/lekiwi_client.py +++ b/src/lerobot/robots/lekiwi/lekiwi_client.py @@ -23,7 +23,7 @@ from typing import Any import cv2 import numpy as np -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..robot import Robot from .config_lekiwi import LeKiwiClientConfig diff --git a/src/lerobot/robots/so100_follower/so100_follower.py b/src/lerobot/robots/so100_follower/so100_follower.py index 1e117e80b..d660ebed4 100644 --- a/src/lerobot/robots/so100_follower/so100_follower.py +++ b/src/lerobot/robots/so100_follower/so100_follower.py @@ -20,12 +20,12 @@ from functools import cached_property from typing import Any from lerobot.cameras.utils import make_cameras_from_configs -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.feetech import ( FeetechMotorsBus, OperatingMode, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..robot import Robot from ..utils import ensure_safe_goal_position diff --git a/src/lerobot/robots/so101_follower/so101_follower.py b/src/lerobot/robots/so101_follower/so101_follower.py index 31b06c2fd..acfd4bd11 100644 --- a/src/lerobot/robots/so101_follower/so101_follower.py +++ b/src/lerobot/robots/so101_follower/so101_follower.py @@ -20,12 +20,12 @@ from functools import cached_property from typing import Any from lerobot.cameras.utils import make_cameras_from_configs -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.feetech import ( FeetechMotorsBus, OperatingMode, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..robot import Robot from ..utils import ensure_safe_goal_position diff --git a/src/lerobot/robots/viperx/viperx.py b/src/lerobot/robots/viperx/viperx.py index 006c780e3..31e99ffdb 100644 --- a/src/lerobot/robots/viperx/viperx.py +++ b/src/lerobot/robots/viperx/viperx.py @@ -18,13 +18,13 @@ from functools import cached_property from typing import Any from lerobot.cameras.utils import make_cameras_from_configs -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.dynamixel import ( DynamixelMotorsBus, OperatingMode, ) from lerobot.utils.constants import OBS_STATE +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..robot import Robot from ..utils import ensure_safe_goal_position diff --git a/src/lerobot/teleoperators/homunculus/homunculus_arm.py b/src/lerobot/teleoperators/homunculus/homunculus_arm.py index 6f5137af9..4eca4b9e2 100644 --- a/src/lerobot/teleoperators/homunculus/homunculus_arm.py +++ b/src/lerobot/teleoperators/homunculus/homunculus_arm.py @@ -22,8 +22,8 @@ from typing import Deque import serial -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors.motors_bus import MotorCalibration, MotorNormMode +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.utils.utils import enter_pressed, move_cursor_up from ..teleoperator import Teleoperator diff --git a/src/lerobot/teleoperators/homunculus/homunculus_glove.py b/src/lerobot/teleoperators/homunculus/homunculus_glove.py index 7b0ced9f6..52fd19def 100644 --- a/src/lerobot/teleoperators/homunculus/homunculus_glove.py +++ b/src/lerobot/teleoperators/homunculus/homunculus_glove.py @@ -22,10 +22,10 @@ from typing import Deque import serial -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import MotorCalibration from lerobot.motors.motors_bus import MotorNormMode from lerobot.teleoperators.homunculus.joints_translation import homunculus_glove_to_hope_jr_hand +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.utils.utils import enter_pressed, move_cursor_up from ..teleoperator import Teleoperator diff --git a/src/lerobot/teleoperators/keyboard/teleop_keyboard.py b/src/lerobot/teleoperators/keyboard/teleop_keyboard.py index 7f489b25a..6f53a17c7 100644 --- a/src/lerobot/teleoperators/keyboard/teleop_keyboard.py +++ b/src/lerobot/teleoperators/keyboard/teleop_keyboard.py @@ -21,7 +21,7 @@ import time from queue import Queue from typing import Any -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..teleoperator import Teleoperator from ..utils import TeleopEvents diff --git a/src/lerobot/teleoperators/koch_leader/koch_leader.py b/src/lerobot/teleoperators/koch_leader/koch_leader.py index f703d5b6e..0409f2e57 100644 --- a/src/lerobot/teleoperators/koch_leader/koch_leader.py +++ b/src/lerobot/teleoperators/koch_leader/koch_leader.py @@ -17,13 +17,13 @@ import logging import time -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.dynamixel import ( DriveMode, DynamixelMotorsBus, OperatingMode, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..teleoperator import Teleoperator from .config_koch_leader import KochLeaderConfig diff --git a/src/lerobot/teleoperators/phone/teleop_phone.py b/src/lerobot/teleoperators/phone/teleop_phone.py index c90729efa..91e613190 100644 --- a/src/lerobot/teleoperators/phone/teleop_phone.py +++ b/src/lerobot/teleoperators/phone/teleop_phone.py @@ -26,9 +26,9 @@ import hebi import numpy as np from teleop import Teleop -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.teleoperators.phone.config_phone import PhoneConfig, PhoneOS from lerobot.teleoperators.teleoperator import Teleoperator +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.utils.rotation import Rotation logger = logging.getLogger(__name__) diff --git a/src/lerobot/teleoperators/so100_leader/so100_leader.py b/src/lerobot/teleoperators/so100_leader/so100_leader.py index a8f6d29b5..edcfe53e6 100644 --- a/src/lerobot/teleoperators/so100_leader/so100_leader.py +++ b/src/lerobot/teleoperators/so100_leader/so100_leader.py @@ -17,12 +17,12 @@ import logging import time -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.feetech import ( FeetechMotorsBus, OperatingMode, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..teleoperator import Teleoperator from .config_so100_leader import SO100LeaderConfig diff --git a/src/lerobot/teleoperators/so101_leader/so101_leader.py b/src/lerobot/teleoperators/so101_leader/so101_leader.py index 15a363e37..be804bf70 100644 --- a/src/lerobot/teleoperators/so101_leader/so101_leader.py +++ b/src/lerobot/teleoperators/so101_leader/so101_leader.py @@ -17,12 +17,12 @@ import logging import time -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.feetech import ( FeetechMotorsBus, OperatingMode, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..teleoperator import Teleoperator from .config_so101_leader import SO101LeaderConfig diff --git a/src/lerobot/teleoperators/stretch3_gamepad/stretch3_gamepad.py b/src/lerobot/teleoperators/stretch3_gamepad/stretch3_gamepad.py index bdcb57d40..94e1ca7cc 100644 --- a/src/lerobot/teleoperators/stretch3_gamepad/stretch3_gamepad.py +++ b/src/lerobot/teleoperators/stretch3_gamepad/stretch3_gamepad.py @@ -20,7 +20,7 @@ import numpy as np from stretch_body.gamepad_teleop import GamePadTeleop from stretch_body.robot_params import RobotParams -from lerobot.errors import DeviceAlreadyConnectedError +from lerobot.utils.errors import DeviceAlreadyConnectedError from ..teleoperator import Teleoperator from .configuration_stretch3 import Stretch3GamePadConfig diff --git a/src/lerobot/teleoperators/widowx/widowx.py b/src/lerobot/teleoperators/widowx/widowx.py index 6becd767f..1a00bd4d2 100644 --- a/src/lerobot/teleoperators/widowx/widowx.py +++ b/src/lerobot/teleoperators/widowx/widowx.py @@ -17,13 +17,13 @@ import logging import time -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.dynamixel import ( DriveMode, DynamixelMotorsBus, OperatingMode, ) +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from ..teleoperator import Teleoperator from .config_widowx import WidowXConfig diff --git a/src/lerobot/errors.py b/src/lerobot/utils/errors.py similarity index 100% rename from src/lerobot/errors.py rename to src/lerobot/utils/errors.py diff --git a/tests/cameras/test_opencv.py b/tests/cameras/test_opencv.py index a9c060c4f..a3d98a679 100644 --- a/tests/cameras/test_opencv.py +++ b/tests/cameras/test_opencv.py @@ -26,7 +26,7 @@ import pytest from lerobot.cameras.configs import Cv2Rotation from lerobot.cameras.opencv import OpenCVCamera, OpenCVCameraConfig -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError # NOTE(Steven): more tests + assertions? TEST_ARTIFACTS_DIR = Path(__file__).parent.parent / "artifacts" / "cameras" diff --git a/tests/cameras/test_reachy2_camera.py b/tests/cameras/test_reachy2_camera.py index 66c7675a6..0b38e8b0b 100644 --- a/tests/cameras/test_reachy2_camera.py +++ b/tests/cameras/test_reachy2_camera.py @@ -21,7 +21,7 @@ import numpy as np import pytest from lerobot.cameras.reachy2_camera import Reachy2Camera, Reachy2CameraConfig -from lerobot.errors import DeviceNotConnectedError +from lerobot.utils.errors import DeviceNotConnectedError PARAMS = [ ("teleop", "left"), diff --git a/tests/cameras/test_realsense.py b/tests/cameras/test_realsense.py index 4b3fbae82..fb9912257 100644 --- a/tests/cameras/test_realsense.py +++ b/tests/cameras/test_realsense.py @@ -26,7 +26,7 @@ import numpy as np import pytest from lerobot.cameras.configs import Cv2Rotation -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError pytest.importorskip("pyrealsense2") diff --git a/tests/mocks/mock_robot.py b/tests/mocks/mock_robot.py index 8108c7c25..027ee45ed 100644 --- a/tests/mocks/mock_robot.py +++ b/tests/mocks/mock_robot.py @@ -20,8 +20,8 @@ from functools import cached_property from typing import Any from lerobot.cameras import CameraConfig, make_cameras_from_configs -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.robots import Robot, RobotConfig +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError @RobotConfig.register_subclass("mock_robot") diff --git a/tests/mocks/mock_teleop.py b/tests/mocks/mock_teleop.py index e37d4a2c5..71b49947c 100644 --- a/tests/mocks/mock_teleop.py +++ b/tests/mocks/mock_teleop.py @@ -19,8 +19,8 @@ from dataclasses import dataclass from functools import cached_property from typing import Any -from lerobot.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError from lerobot.teleoperators import Teleoperator, TeleoperatorConfig +from lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError @TeleoperatorConfig.register_subclass("mock_teleop") From bd09b2153f0bcd2cce8d97142f6361a964d06690 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 11:14:48 +0200 Subject: [PATCH 10/26] chore(scripts): move find_cameras to scripts (#2018) --- pyproject.toml | 2 +- .../{find_cameras.py => scripts/lerobot_find_cameras.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/lerobot/{find_cameras.py => scripts/lerobot_find_cameras.py} (100%) diff --git a/pyproject.toml b/pyproject.toml index 9ed3da006..3f5ef3f87 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -163,7 +163,7 @@ all = [ [project.scripts] lerobot-calibrate="lerobot.calibrate:main" -lerobot-find-cameras="lerobot.find_cameras:main" +lerobot-find-cameras="lerobot.scripts.lerobot_find_cameras:main" lerobot-find-port="lerobot.find_port:main" lerobot-record="lerobot.record:main" lerobot-replay="lerobot.replay:main" diff --git a/src/lerobot/find_cameras.py b/src/lerobot/scripts/lerobot_find_cameras.py similarity index 100% rename from src/lerobot/find_cameras.py rename to src/lerobot/scripts/lerobot_find_cameras.py From a4178f385b05434b7c60c5190316678d4e2e31a4 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 11:28:56 +0200 Subject: [PATCH 11/26] feat(script): add entry point for find joints limits (#2010) Signed-off-by: Steven Palma --- docs/source/hilserl.mdx | 16 +++++++-------- pyproject.toml | 1 + src/lerobot/rl/actor.py | 2 +- ...limits.py => lerobot_find_joint_limits.py} | 20 +++++++++++-------- 4 files changed, 22 insertions(+), 17 deletions(-) rename src/lerobot/scripts/{find_joint_limits.py => lerobot_find_joint_limits.py} (93%) diff --git a/docs/source/hilserl.mdx b/docs/source/hilserl.mdx index 07f92b824..bc38408e6 100644 --- a/docs/source/hilserl.mdx +++ b/docs/source/hilserl.mdx @@ -304,19 +304,19 @@ Before collecting demonstrations, you need to determine the appropriate operatio This helps simplify the problem of learning on the real robot in two ways: 1) by limiting the robot's operational space to a specific region that solves the task and avoids unnecessary or unsafe exploration, and 2) by allowing training in end-effector space rather than joint space. Empirically, learning in joint space for reinforcement learning in manipulation is often a harder problem - some tasks are nearly impossible to learn in joint space but become learnable when the action space is transformed to end-effector coordinates. -**Using find_joint_limits.py** +**Using lerobot-find-joint-limits** This script helps you find the safe operational bounds for your robot's end-effector. Given that you have a follower and leader arm, you can use the script to find the bounds for the follower arm that will be applied during training. Bounding the action space will reduce the redundant exploration of the agent and guarantees safety. ```bash -python -m lerobot.scripts.find_joint_limits \ - --robot.type=so100_follower \ - --robot.port=/dev/tty.usbmodem58760431541 \ - --robot.id=black \ - --teleop.type=so100_leader \ - --teleop.port=/dev/tty.usbmodem58760431551 \ - --teleop.id=blue +lerobot-find-joint-limits \ + --robot.type=so100_follower \ + --robot.port=/dev/tty.usbmodem58760431541 \ + --robot.id=black \ + --teleop.type=so100_leader \ + --teleop.port=/dev/tty.usbmodem58760431551 \ + --teleop.id=blue ``` **Workflow** diff --git a/pyproject.toml b/pyproject.toml index 3f5ef3f87..acd1e8a0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -173,6 +173,7 @@ lerobot-eval="lerobot.scripts.eval:main" lerobot-train="lerobot.scripts.train:main" lerobot-dataset-viz="lerobot.scripts.lerobot_dataset_viz:main" lerobot-info="lerobot.scripts.lerobot_info:main" +lerobot-find-joint-limits="lerobot.scripts.lerobot_find_joint_limits:main" lerobot-imgtransform-viz="lerobot.scripts.lerobot_imgtransform_viz:main" # ---------------- Tool Configurations ---------------- diff --git a/src/lerobot/rl/actor.py b/src/lerobot/rl/actor.py index d1e709253..b38858ca6 100644 --- a/src/lerobot/rl/actor.py +++ b/src/lerobot/rl/actor.py @@ -35,7 +35,7 @@ gamepad to take control of the robot during training. Initially intervene freque reduce interventions as the policy improves. **WORKFLOW**: -1. Determine robot workspace bounds using `find_joint_limits.py` +1. Determine robot workspace bounds using `lerobot-find-joint-limits` 2. Record demonstrations with `gym_manipulator.py` in record mode 3. Process the dataset and determine camera crops with `crop_dataset_roi.py` 4. Start the learner server with the training configuration diff --git a/src/lerobot/scripts/find_joint_limits.py b/src/lerobot/scripts/lerobot_find_joint_limits.py similarity index 93% rename from src/lerobot/scripts/find_joint_limits.py rename to src/lerobot/scripts/lerobot_find_joint_limits.py index f7e07514f..07d57a760 100644 --- a/src/lerobot/scripts/find_joint_limits.py +++ b/src/lerobot/scripts/lerobot_find_joint_limits.py @@ -20,13 +20,13 @@ Simple script to control a robot from teleoperation. Example: ```shell -python -m lerobot.scripts.server.find_joint_limits \ - --robot.type=so100_follower \ - --robot.port=/dev/tty.usbmodem58760431541 \ - --robot.id=black \ - --teleop.type=so100_leader \ - --teleop.port=/dev/tty.usbmodem58760431551 \ - --teleop.id=blue +lerobot-find-joint-limits \ + --robot.type=so100_follower \ + --robot.port=/dev/tty.usbmodem58760431541 \ + --robot.id=black \ + --teleop.type=so100_leader \ + --teleop.port=/dev/tty.usbmodem58760431551 \ + --teleop.id=blue ``` """ @@ -117,5 +117,9 @@ def find_joint_and_ee_bounds(cfg: FindJointLimitsConfig): busy_wait(0.01) -if __name__ == "__main__": +def main(): find_joint_and_ee_bounds() + + +if __name__ == "__main__": + main() From 98bcda2d8bb2ecc272a71c8a89948549898f5a84 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 11:38:04 +0200 Subject: [PATCH 12/26] chore(scripts): move find_port to scripts (#2019) --- pyproject.toml | 2 +- src/lerobot/scripts/lerobot_find_cameras.py | 2 +- src/lerobot/{find_port.py => scripts/lerobot_find_port.py} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/lerobot/{find_port.py => scripts/lerobot_find_port.py} (100%) diff --git a/pyproject.toml b/pyproject.toml index acd1e8a0c..9785481ee 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -164,7 +164,7 @@ all = [ [project.scripts] lerobot-calibrate="lerobot.calibrate:main" lerobot-find-cameras="lerobot.scripts.lerobot_find_cameras:main" -lerobot-find-port="lerobot.find_port:main" +lerobot-find-port="lerobot.scripts.lerobot_find_port:main" lerobot-record="lerobot.record:main" lerobot-replay="lerobot.replay:main" lerobot-setup-motors="lerobot.setup_motors:main" diff --git a/src/lerobot/scripts/lerobot_find_cameras.py b/src/lerobot/scripts/lerobot_find_cameras.py index ec8f5ff30..e17dca805 100644 --- a/src/lerobot/scripts/lerobot_find_cameras.py +++ b/src/lerobot/scripts/lerobot_find_cameras.py @@ -24,7 +24,7 @@ lerobot-find-cameras ``` """ -# NOTE(Steven): RealSense can also be identified/opened as OpenCV cameras. If you know the camera is a RealSense, use the `lerobot.find_cameras realsense` flag to avoid confusion. +# NOTE(Steven): RealSense can also be identified/opened as OpenCV cameras. If you know the camera is a RealSense, use the `lerobot-find-cameras realsense` flag to avoid confusion. # NOTE(Steven): macOS cameras sometimes report different FPS at init time, not an issue here as we don't specify FPS when opening the cameras, but the information displayed might not be truthful. import argparse diff --git a/src/lerobot/find_port.py b/src/lerobot/scripts/lerobot_find_port.py similarity index 100% rename from src/lerobot/find_port.py rename to src/lerobot/scripts/lerobot_find_port.py From 42e4b3d09e10b84806c470a47bf38ac5eb834e9a Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 12:01:21 +0200 Subject: [PATCH 13/26] chore(scripts): move teleop to scripts (#2023) --- pyproject.toml | 2 +- src/lerobot/{teleoperate.py => scripts/lerobot_teleoperate.py} | 0 tests/test_control_robot.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/lerobot/{teleoperate.py => scripts/lerobot_teleoperate.py} (100%) diff --git a/pyproject.toml b/pyproject.toml index 9785481ee..0a4096a40 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -168,7 +168,7 @@ lerobot-find-port="lerobot.scripts.lerobot_find_port:main" lerobot-record="lerobot.record:main" lerobot-replay="lerobot.replay:main" lerobot-setup-motors="lerobot.setup_motors:main" -lerobot-teleoperate="lerobot.teleoperate:main" +lerobot-teleoperate="lerobot.scripts.lerobot_teleoperate:main" lerobot-eval="lerobot.scripts.eval:main" lerobot-train="lerobot.scripts.train:main" lerobot-dataset-viz="lerobot.scripts.lerobot_dataset_viz:main" diff --git a/src/lerobot/teleoperate.py b/src/lerobot/scripts/lerobot_teleoperate.py similarity index 100% rename from src/lerobot/teleoperate.py rename to src/lerobot/scripts/lerobot_teleoperate.py diff --git a/tests/test_control_robot.py b/tests/test_control_robot.py index 374f98129..8df71e040 100644 --- a/tests/test_control_robot.py +++ b/tests/test_control_robot.py @@ -19,7 +19,7 @@ from unittest.mock import patch from lerobot.calibrate import CalibrateConfig, calibrate from lerobot.record import DatasetRecordConfig, RecordConfig, record from lerobot.replay import DatasetReplayConfig, ReplayConfig, replay -from lerobot.teleoperate import TeleoperateConfig, teleoperate +from lerobot.scripts.lerobot_teleoperate import TeleoperateConfig, teleoperate from tests.fixtures.constants import DUMMY_REPO_ID from tests.mocks.mock_robot import MockRobotConfig from tests.mocks.mock_teleop import MockTeleopConfig From 2b59850f15fea55b24b4a6ce3eab932d3100cf4b Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 13:38:12 +0200 Subject: [PATCH 14/26] chore(scripts): move record to scripts (#2022) Signed-off-by: Steven Palma --- examples/lekiwi/evaluate.py | 2 +- examples/lekiwi/record.py | 2 +- examples/phone_to_so100/evaluate.py | 2 +- examples/phone_to_so100/record.py | 2 +- examples/so100_to_so100_EE/evaluate.py | 2 +- examples/so100_to_so100_EE/record.py | 2 +- pyproject.toml | 2 +- src/lerobot/{record.py => scripts/lerobot_record.py} | 0 tests/test_control_robot.py | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename src/lerobot/{record.py => scripts/lerobot_record.py} (100%) diff --git a/examples/lekiwi/evaluate.py b/examples/lekiwi/evaluate.py index 3dbb10f56..8993a5e14 100644 --- a/examples/lekiwi/evaluate.py +++ b/examples/lekiwi/evaluate.py @@ -19,8 +19,8 @@ from lerobot.datasets.utils import hw_to_dataset_features from lerobot.policies.act.modeling_act import ACTPolicy from lerobot.policies.factory import make_pre_post_processors from lerobot.processor import make_default_processors -from lerobot.record import record_loop from lerobot.robots.lekiwi import LeKiwiClient, LeKiwiClientConfig +from lerobot.scripts.lerobot_record import record_loop from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say from lerobot.utils.visualization_utils import _init_rerun diff --git a/examples/lekiwi/record.py b/examples/lekiwi/record.py index f5d109d5d..f59093b26 100644 --- a/examples/lekiwi/record.py +++ b/examples/lekiwi/record.py @@ -17,9 +17,9 @@ from lerobot.datasets.lerobot_dataset import LeRobotDataset from lerobot.datasets.utils import hw_to_dataset_features from lerobot.processor import make_default_processors -from lerobot.record import record_loop from lerobot.robots.lekiwi.config_lekiwi import LeKiwiClientConfig from lerobot.robots.lekiwi.lekiwi_client import LeKiwiClient +from lerobot.scripts.lerobot_record import record_loop from lerobot.teleoperators.keyboard import KeyboardTeleop, KeyboardTeleopConfig from lerobot.teleoperators.so100_leader import SO100Leader, SO100LeaderConfig from lerobot.utils.control_utils import init_keyboard_listener diff --git a/examples/phone_to_so100/evaluate.py b/examples/phone_to_so100/evaluate.py index e76b11350..c7d6eb240 100644 --- a/examples/phone_to_so100/evaluate.py +++ b/examples/phone_to_so100/evaluate.py @@ -34,13 +34,13 @@ from lerobot.processor.converters import ( transition_to_observation, transition_to_robot_action, ) -from lerobot.record import record_loop from lerobot.robots.so100_follower.config_so100_follower import SO100FollowerConfig from lerobot.robots.so100_follower.robot_kinematic_processor import ( ForwardKinematicsJointsToEE, InverseKinematicsEEToJoints, ) from lerobot.robots.so100_follower.so100_follower import SO100Follower +from lerobot.scripts.lerobot_record import record_loop from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say from lerobot.utils.visualization_utils import _init_rerun diff --git a/examples/phone_to_so100/record.py b/examples/phone_to_so100/record.py index 768041d63..6681017a0 100644 --- a/examples/phone_to_so100/record.py +++ b/examples/phone_to_so100/record.py @@ -26,7 +26,6 @@ from lerobot.processor.converters import ( transition_to_observation, transition_to_robot_action, ) -from lerobot.record import record_loop from lerobot.robots.so100_follower.config_so100_follower import SO100FollowerConfig from lerobot.robots.so100_follower.robot_kinematic_processor import ( EEBoundsAndSafety, @@ -36,6 +35,7 @@ from lerobot.robots.so100_follower.robot_kinematic_processor import ( InverseKinematicsEEToJoints, ) from lerobot.robots.so100_follower.so100_follower import SO100Follower +from lerobot.scripts.lerobot_record import record_loop from lerobot.teleoperators.phone.config_phone import PhoneConfig, PhoneOS from lerobot.teleoperators.phone.phone_processor import MapPhoneActionToRobotAction from lerobot.teleoperators.phone.teleop_phone import Phone diff --git a/examples/so100_to_so100_EE/evaluate.py b/examples/so100_to_so100_EE/evaluate.py index fd10bf865..f47a216d6 100644 --- a/examples/so100_to_so100_EE/evaluate.py +++ b/examples/so100_to_so100_EE/evaluate.py @@ -34,13 +34,13 @@ from lerobot.processor.converters import ( transition_to_observation, transition_to_robot_action, ) -from lerobot.record import record_loop from lerobot.robots.so100_follower.config_so100_follower import SO100FollowerConfig from lerobot.robots.so100_follower.robot_kinematic_processor import ( ForwardKinematicsJointsToEE, InverseKinematicsEEToJoints, ) from lerobot.robots.so100_follower.so100_follower import SO100Follower +from lerobot.scripts.lerobot_record import record_loop from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say from lerobot.utils.visualization_utils import _init_rerun diff --git a/examples/so100_to_so100_EE/record.py b/examples/so100_to_so100_EE/record.py index abb8fb99d..60c96835f 100644 --- a/examples/so100_to_so100_EE/record.py +++ b/examples/so100_to_so100_EE/record.py @@ -27,7 +27,6 @@ from lerobot.processor.converters import ( transition_to_observation, transition_to_robot_action, ) -from lerobot.record import record_loop from lerobot.robots.so100_follower.config_so100_follower import SO100FollowerConfig from lerobot.robots.so100_follower.robot_kinematic_processor import ( EEBoundsAndSafety, @@ -35,6 +34,7 @@ from lerobot.robots.so100_follower.robot_kinematic_processor import ( InverseKinematicsEEToJoints, ) from lerobot.robots.so100_follower.so100_follower import SO100Follower +from lerobot.scripts.lerobot_record import record_loop from lerobot.teleoperators.so100_leader.config_so100_leader import SO100LeaderConfig from lerobot.teleoperators.so100_leader.so100_leader import SO100Leader from lerobot.utils.control_utils import init_keyboard_listener diff --git a/pyproject.toml b/pyproject.toml index 0a4096a40..69c0fa2b8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -165,7 +165,7 @@ all = [ lerobot-calibrate="lerobot.calibrate:main" lerobot-find-cameras="lerobot.scripts.lerobot_find_cameras:main" lerobot-find-port="lerobot.scripts.lerobot_find_port:main" -lerobot-record="lerobot.record:main" +lerobot-record="lerobot.scripts.lerobot_record:main" lerobot-replay="lerobot.replay:main" lerobot-setup-motors="lerobot.setup_motors:main" lerobot-teleoperate="lerobot.scripts.lerobot_teleoperate:main" diff --git a/src/lerobot/record.py b/src/lerobot/scripts/lerobot_record.py similarity index 100% rename from src/lerobot/record.py rename to src/lerobot/scripts/lerobot_record.py diff --git a/tests/test_control_robot.py b/tests/test_control_robot.py index 8df71e040..239f6a0e3 100644 --- a/tests/test_control_robot.py +++ b/tests/test_control_robot.py @@ -17,8 +17,8 @@ from unittest.mock import patch from lerobot.calibrate import CalibrateConfig, calibrate -from lerobot.record import DatasetRecordConfig, RecordConfig, record from lerobot.replay import DatasetReplayConfig, ReplayConfig, replay +from lerobot.scripts.lerobot_record import DatasetRecordConfig, RecordConfig, record from lerobot.scripts.lerobot_teleoperate import TeleoperateConfig, teleoperate from tests.fixtures.constants import DUMMY_REPO_ID from tests.mocks.mock_robot import MockRobotConfig From acbc14f60a56d5138f57721c15d71cee45baa4e7 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 14:06:48 +0200 Subject: [PATCH 15/26] chore(scripts): move calibrate to scripts (#2024) Signed-off-by: Steven Palma --- pyproject.toml | 2 +- src/lerobot/{calibrate.py => scripts/lerobot_calibrate.py} | 0 tests/test_control_robot.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/lerobot/{calibrate.py => scripts/lerobot_calibrate.py} (100%) diff --git a/pyproject.toml b/pyproject.toml index 69c0fa2b8..893d637f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -162,7 +162,7 @@ all = [ ] [project.scripts] -lerobot-calibrate="lerobot.calibrate:main" +lerobot-calibrate="lerobot.scripts.lerobot_calibrate:main" lerobot-find-cameras="lerobot.scripts.lerobot_find_cameras:main" lerobot-find-port="lerobot.scripts.lerobot_find_port:main" lerobot-record="lerobot.scripts.lerobot_record:main" diff --git a/src/lerobot/calibrate.py b/src/lerobot/scripts/lerobot_calibrate.py similarity index 100% rename from src/lerobot/calibrate.py rename to src/lerobot/scripts/lerobot_calibrate.py diff --git a/tests/test_control_robot.py b/tests/test_control_robot.py index 239f6a0e3..a1dd33286 100644 --- a/tests/test_control_robot.py +++ b/tests/test_control_robot.py @@ -16,8 +16,8 @@ from unittest.mock import patch -from lerobot.calibrate import CalibrateConfig, calibrate from lerobot.replay import DatasetReplayConfig, ReplayConfig, replay +from lerobot.scripts.lerobot_calibrate import CalibrateConfig, calibrate from lerobot.scripts.lerobot_record import DatasetRecordConfig, RecordConfig, record from lerobot.scripts.lerobot_teleoperate import TeleoperateConfig, teleoperate from tests.fixtures.constants import DUMMY_REPO_ID From 13010647bc5579dcf30753ec26b92db2cd91207f Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 14:06:58 +0200 Subject: [PATCH 16/26] chore(scripts): move setup_motors to scripts (#2020) Signed-off-by: Steven Palma --- pyproject.toml | 2 +- .../{setup_motors.py => scripts/lerobot_setup_motors.py} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename src/lerobot/{setup_motors.py => scripts/lerobot_setup_motors.py} (100%) diff --git a/pyproject.toml b/pyproject.toml index 893d637f6..f2be357e9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -167,7 +167,7 @@ lerobot-find-cameras="lerobot.scripts.lerobot_find_cameras:main" lerobot-find-port="lerobot.scripts.lerobot_find_port:main" lerobot-record="lerobot.scripts.lerobot_record:main" lerobot-replay="lerobot.replay:main" -lerobot-setup-motors="lerobot.setup_motors:main" +lerobot-setup-motors="lerobot.scripts.lerobot_setup_motors:main" lerobot-teleoperate="lerobot.scripts.lerobot_teleoperate:main" lerobot-eval="lerobot.scripts.eval:main" lerobot-train="lerobot.scripts.train:main" diff --git a/src/lerobot/setup_motors.py b/src/lerobot/scripts/lerobot_setup_motors.py similarity index 100% rename from src/lerobot/setup_motors.py rename to src/lerobot/scripts/lerobot_setup_motors.py From 7359e18eb65e33649951c5f7c959cc8fc8cf2ab2 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 14:48:23 +0200 Subject: [PATCH 17/26] chore(scripts): move replay to scripts (#2021) Signed-off-by: Steven Palma --- pyproject.toml | 2 +- src/lerobot/{replay.py => scripts/lerobot_replay.py} | 0 tests/test_control_robot.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/lerobot/{replay.py => scripts/lerobot_replay.py} (100%) diff --git a/pyproject.toml b/pyproject.toml index f2be357e9..dbc25805d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -166,7 +166,7 @@ lerobot-calibrate="lerobot.scripts.lerobot_calibrate:main" lerobot-find-cameras="lerobot.scripts.lerobot_find_cameras:main" lerobot-find-port="lerobot.scripts.lerobot_find_port:main" lerobot-record="lerobot.scripts.lerobot_record:main" -lerobot-replay="lerobot.replay:main" +lerobot-replay="lerobot.scripts.lerobot_replay:main" lerobot-setup-motors="lerobot.scripts.lerobot_setup_motors:main" lerobot-teleoperate="lerobot.scripts.lerobot_teleoperate:main" lerobot-eval="lerobot.scripts.eval:main" diff --git a/src/lerobot/replay.py b/src/lerobot/scripts/lerobot_replay.py similarity index 100% rename from src/lerobot/replay.py rename to src/lerobot/scripts/lerobot_replay.py diff --git a/tests/test_control_robot.py b/tests/test_control_robot.py index a1dd33286..ace0aea49 100644 --- a/tests/test_control_robot.py +++ b/tests/test_control_robot.py @@ -16,9 +16,9 @@ from unittest.mock import patch -from lerobot.replay import DatasetReplayConfig, ReplayConfig, replay from lerobot.scripts.lerobot_calibrate import CalibrateConfig, calibrate from lerobot.scripts.lerobot_record import DatasetRecordConfig, RecordConfig, record +from lerobot.scripts.lerobot_replay import DatasetReplayConfig, ReplayConfig, replay from lerobot.scripts.lerobot_teleoperate import TeleoperateConfig, teleoperate from tests.fixtures.constants import DUMMY_REPO_ID from tests.mocks.mock_robot import MockRobotConfig From 1cba47da20482f81016e162925063180da8dbbf6 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 14:49:37 +0200 Subject: [PATCH 18/26] chore(async): move async related code to its directory at top level (#2003) * chore(async): move async related code to its directory at top level * chore(style): apply pre-commit to renamed headers * test(async): fix async imports * docs(async): update async headers doc --- docs/source/async.mdx | 16 ++++++++-------- .../server => async_inference}/configs.py | 3 ++- .../server => async_inference}/constants.py | 0 .../server => async_inference}/helpers.py | 0 .../policy_server.py | 19 ++++++++++--------- .../robot_client.py | 19 ++++++++++--------- tests/async_inference/test_e2e.py | 8 ++++---- tests/async_inference/test_helpers.py | 4 ++-- tests/async_inference/test_policy_server.py | 8 ++++---- tests/async_inference/test_robot_client.py | 8 ++++---- 10 files changed, 44 insertions(+), 41 deletions(-) rename src/lerobot/{scripts/server => async_inference}/configs.py (99%) rename src/lerobot/{scripts/server => async_inference}/constants.py (100%) rename src/lerobot/{scripts/server => async_inference}/helpers.py (100%) rename src/lerobot/{scripts/server => async_inference}/policy_server.py (98%) rename src/lerobot/{scripts/server => async_inference}/robot_client.py (98%) diff --git a/docs/source/async.mdx b/docs/source/async.mdx index 397c513cf..c66cdb143 100644 --- a/docs/source/async.mdx +++ b/docs/source/async.mdx @@ -31,7 +31,7 @@ Then, spin up a policy server (in one terminal, or in a separate machine) specif You can spin up a policy server running: ```shell -python src/lerobot/scripts/server/policy_server.py \ +python src/lerobot/async_inference/policy_server.py \ --host=127.0.0.1 \ --port=8080 \ ``` @@ -39,7 +39,7 @@ python src/lerobot/scripts/server/policy_server.py \ This will start a policy server listening on `127.0.0.1:8080` (`localhost`, port 8080). At this stage, the policy server is empty, as all information related to which policy to run and with which parameters are specified during the first handshake with the client. Spin up a client with: ```shell -python src/lerobot/scripts/server/robot_client.py \ +python src/lerobot/async_inference/robot_client.py \ --server_address=127.0.0.1:8080 \ # SERVER: the host address and port of the policy server --robot.type=so100_follower \ # ROBOT: your robot type --robot.port=/dev/tty.usbmodem585A0076841 \ # ROBOT: your robot port @@ -122,8 +122,8 @@ python -m lerobot.scripts.server.policy_server \ ```python -from lerobot.scripts.server.configs import PolicyServerConfig -from lerobot.scripts.server.policy_server import serve +from lerobot.async_inference.configs import PolicyServerConfig +from lerobot.async_inference.policy_server import serve config = PolicyServerConfig( host="localhost", @@ -148,7 +148,7 @@ The `RobotClient` streams observations to the `PolicyServer`, and receives actio ```bash -python src/lerobot/scripts/server/robot_client.py \ +python src/lerobot/async_inference/robot_client.py \ --server_address=127.0.0.1:8080 \ # SERVER: the host address and port of the policy server --robot.type=so100_follower \ # ROBOT: your robot type --robot.port=/dev/tty.usbmodem585A0076841 \ # ROBOT: your robot port @@ -171,9 +171,9 @@ python src/lerobot/scripts/server/robot_client.py \ import threading from lerobot.robots.so100_follower import SO100FollowerConfig from lerobot.cameras.opencv.configuration_opencv import OpenCVCameraConfig -from lerobot.scripts.server.configs import RobotClientConfig -from lerobot.scripts.server.robot_client import RobotClient -from lerobot.scripts.server.helpers import visualize_action_queue_size +from lerobot.async_inference.configs import RobotClientConfig +from lerobot.async_inference.robot_client import RobotClient +from lerobot.async_inference.helpers import visualize_action_queue_size # 1. Create the robot instance """Check out the cameras available in your setup by running `python lerobot/find_cameras.py`""" diff --git a/src/lerobot/scripts/server/configs.py b/src/lerobot/async_inference/configs.py similarity index 99% rename from src/lerobot/scripts/server/configs.py rename to src/lerobot/async_inference/configs.py index 5be46485e..24f889df1 100644 --- a/src/lerobot/scripts/server/configs.py +++ b/src/lerobot/async_inference/configs.py @@ -18,7 +18,8 @@ from dataclasses import dataclass, field import torch from lerobot.robots.config import RobotConfig -from lerobot.scripts.server.constants import ( + +from .constants import ( DEFAULT_FPS, DEFAULT_INFERENCE_LATENCY, DEFAULT_OBS_QUEUE_TIMEOUT, diff --git a/src/lerobot/scripts/server/constants.py b/src/lerobot/async_inference/constants.py similarity index 100% rename from src/lerobot/scripts/server/constants.py rename to src/lerobot/async_inference/constants.py diff --git a/src/lerobot/scripts/server/helpers.py b/src/lerobot/async_inference/helpers.py similarity index 100% rename from src/lerobot/scripts/server/helpers.py rename to src/lerobot/async_inference/helpers.py diff --git a/src/lerobot/scripts/server/policy_server.py b/src/lerobot/async_inference/policy_server.py similarity index 98% rename from src/lerobot/scripts/server/policy_server.py rename to src/lerobot/async_inference/policy_server.py index 0ed446d3a..125727060 100644 --- a/src/lerobot/scripts/server/policy_server.py +++ b/src/lerobot/async_inference/policy_server.py @@ -15,7 +15,7 @@ """ Example: ```shell -python src/lerobot/scripts/server/policy_server.py \ +python src/lerobot/async_inference/policy_server.py \ --host=127.0.0.1 \ --port=8080 \ --fps=30 \ @@ -38,9 +38,15 @@ import grpc import torch from lerobot.policies.factory import get_policy_class -from lerobot.scripts.server.configs import PolicyServerConfig -from lerobot.scripts.server.constants import SUPPORTED_POLICIES -from lerobot.scripts.server.helpers import ( +from lerobot.transport import ( + services_pb2, # type: ignore + services_pb2_grpc, # type: ignore +) +from lerobot.transport.utils import receive_bytes_in_chunks + +from .configs import PolicyServerConfig +from .constants import SUPPORTED_POLICIES +from .helpers import ( FPSTracker, Observation, RemotePolicyConfig, @@ -50,11 +56,6 @@ from lerobot.scripts.server.helpers import ( observations_similar, raw_observation_to_observation, ) -from lerobot.transport import ( - services_pb2, # type: ignore - services_pb2_grpc, # type: ignore -) -from lerobot.transport.utils import receive_bytes_in_chunks class PolicyServer(services_pb2_grpc.AsyncInferenceServicer): diff --git a/src/lerobot/scripts/server/robot_client.py b/src/lerobot/async_inference/robot_client.py similarity index 98% rename from src/lerobot/scripts/server/robot_client.py rename to src/lerobot/async_inference/robot_client.py index 939d5cea8..c969bc605 100644 --- a/src/lerobot/scripts/server/robot_client.py +++ b/src/lerobot/async_inference/robot_client.py @@ -15,7 +15,7 @@ """ Example command: ```shell -python src/lerobot/scripts/server/robot_client.py \ +python src/lerobot/async_inference/robot_client.py \ --robot.type=so100_follower \ --robot.port=/dev/tty.usbmodem58760431541 \ --robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 1920, height: 1080, fps: 30}}" \ @@ -57,9 +57,15 @@ from lerobot.robots import ( # noqa: F401 so100_follower, so101_follower, ) -from lerobot.scripts.server.configs import RobotClientConfig -from lerobot.scripts.server.constants import SUPPORTED_ROBOTS -from lerobot.scripts.server.helpers import ( +from lerobot.transport import ( + services_pb2, # type: ignore + services_pb2_grpc, # type: ignore +) +from lerobot.transport.utils import grpc_channel_options, send_bytes_in_chunks + +from .configs import RobotClientConfig +from .constants import SUPPORTED_ROBOTS +from .helpers import ( Action, FPSTracker, Observation, @@ -72,11 +78,6 @@ from lerobot.scripts.server.helpers import ( validate_robot_cameras_for_policy, visualize_action_queue_size, ) -from lerobot.transport import ( - services_pb2, # type: ignore - services_pb2_grpc, # type: ignore -) -from lerobot.transport.utils import grpc_channel_options, send_bytes_in_chunks class RobotClient: diff --git a/tests/async_inference/test_e2e.py b/tests/async_inference/test_e2e.py index 1c0400e66..2689f0618 100644 --- a/tests/async_inference/test_e2e.py +++ b/tests/async_inference/test_e2e.py @@ -48,11 +48,11 @@ def test_async_inference_e2e(monkeypatch): # Import grpc-dependent modules inside the test function import grpc + from lerobot.async_inference.configs import PolicyServerConfig, RobotClientConfig + from lerobot.async_inference.helpers import map_robot_keys_to_lerobot_features + from lerobot.async_inference.policy_server import PolicyServer + from lerobot.async_inference.robot_client import RobotClient from lerobot.robots.utils import make_robot_from_config - from lerobot.scripts.server.configs import PolicyServerConfig, RobotClientConfig - from lerobot.scripts.server.helpers import map_robot_keys_to_lerobot_features - from lerobot.scripts.server.policy_server import PolicyServer - from lerobot.scripts.server.robot_client import RobotClient from lerobot.transport import ( services_pb2, # type: ignore services_pb2_grpc, # type: ignore diff --git a/tests/async_inference/test_helpers.py b/tests/async_inference/test_helpers.py index e0b797371..f1c7636e2 100644 --- a/tests/async_inference/test_helpers.py +++ b/tests/async_inference/test_helpers.py @@ -19,8 +19,7 @@ import time import numpy as np import torch -from lerobot.configs.types import FeatureType, PolicyFeature -from lerobot.scripts.server.helpers import ( +from lerobot.async_inference.helpers import ( FPSTracker, TimedAction, TimedObservation, @@ -30,6 +29,7 @@ from lerobot.scripts.server.helpers import ( raw_observation_to_observation, resize_robot_observation_image, ) +from lerobot.configs.types import FeatureType, PolicyFeature # --------------------------------------------------------------------- # FPSTracker diff --git a/tests/async_inference/test_policy_server.py b/tests/async_inference/test_policy_server.py index 5c795e7ec..c5c52460f 100644 --- a/tests/async_inference/test_policy_server.py +++ b/tests/async_inference/test_policy_server.py @@ -65,8 +65,8 @@ class MockPolicy: def policy_server(): """Fresh `PolicyServer` instance with a stubbed-out policy model.""" # Import only when the test actually runs (after decorator check) - from lerobot.scripts.server.configs import PolicyServerConfig - from lerobot.scripts.server.policy_server import PolicyServer + from lerobot.async_inference.configs import PolicyServerConfig + from lerobot.async_inference.policy_server import PolicyServer test_config = PolicyServerConfig(host="localhost", port=9999) server = PolicyServer(test_config) @@ -95,7 +95,7 @@ def policy_server(): def _make_obs(state: torch.Tensor, timestep: int = 0, must_go: bool = False): """Create a TimedObservation with a given state vector.""" # Import only when needed - from lerobot.scripts.server.helpers import TimedObservation + from lerobot.async_inference.helpers import TimedObservation return TimedObservation( observation={ @@ -191,7 +191,7 @@ def test_obs_sanity_checks(policy_server): def test_predict_action_chunk(monkeypatch, policy_server): """End-to-end test of `_predict_action_chunk` with a stubbed _get_action_chunk.""" # Import only when needed - from lerobot.scripts.server.policy_server import PolicyServer + from lerobot.async_inference.policy_server import PolicyServer # Force server to act-style policy; patch method to return deterministic tensor policy_server.policy_type = "act" diff --git a/tests/async_inference/test_robot_client.py b/tests/async_inference/test_robot_client.py index 51db2c3a7..dfdb8ce42 100644 --- a/tests/async_inference/test_robot_client.py +++ b/tests/async_inference/test_robot_client.py @@ -38,8 +38,8 @@ def robot_client(): """Fresh `RobotClient` instance for each test case (no threads started). Uses DummyRobot.""" # Import only when the test actually runs (after decorator check) - from lerobot.scripts.server.configs import RobotClientConfig - from lerobot.scripts.server.robot_client import RobotClient + from lerobot.async_inference.configs import RobotClientConfig + from lerobot.async_inference.robot_client import RobotClient from tests.mocks.mock_robot import MockRobotConfig test_config = MockRobotConfig() @@ -73,7 +73,7 @@ def robot_client(): def _make_actions(start_ts: float, start_t: int, count: int): """Generate `count` consecutive TimedAction objects starting at timestep `start_t`.""" - from lerobot.scripts.server.helpers import TimedAction + from lerobot.async_inference.helpers import TimedAction fps = 30 # emulates most common frame-rate actions = [] @@ -124,7 +124,7 @@ def test_aggregate_action_queues_combines_actions_in_overlap( ): """`_aggregate_action_queues` must combine actions on overlapping timesteps according to the provided aggregate_fn, here tested with multiple coefficients.""" - from lerobot.scripts.server.helpers import TimedAction + from lerobot.async_inference.helpers import TimedAction robot_client.chunks_received = 0 From cdd2bf1c4e060e9ef3d43701a2346e36949041ce Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 15:46:44 +0200 Subject: [PATCH 19/26] chore(ci): update stale message (#2027) --- .github/workflows/stale.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index acd1ae53a..af91c9f58 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -31,11 +31,11 @@ env: Feel free to reopen if is still relevant, or to ping a collaborator if you have any questions. WARN_ISSUE_MESSAGE: > This issue has been automatically marked as stale because it has not had - recent activity (1 year). It will be closed if no further activity occurs. + recent activity (6 months). It will be closed if no further activity occurs. Thank you for your contributions. WARN_PR_MESSAGE: > This PR has been automatically marked as stale because it has not had - recent activity (1 year). It will be closed if no further activity occurs. + recent activity (6 months). It will be closed if no further activity occurs. Thank you for your contributions. jobs: From 163df97c0cd15fe4e15bae05fa637664b71e1209 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 16:17:39 +0200 Subject: [PATCH 20/26] fix(docs): update outdated links (#2026) --- docs/source/koch.mdx | 2 +- docs/source/lekiwi.mdx | 2 +- docs/source/smolvla.mdx | 4 ++-- docs/source/so100.mdx | 2 +- docs/source/so101.mdx | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/source/koch.mdx b/docs/source/koch.mdx index 3e94899a8..813b9bd67 100644 --- a/docs/source/koch.mdx +++ b/docs/source/koch.mdx @@ -277,7 +277,7 @@ leader.disconnect() -Congrats 🎉, your robot is all set to learn a task on its own. Start training it by following this tutorial: [Getting started with real-world robots](./getting_started_real_world_robot) +Congrats 🎉, your robot is all set to learn a task on its own. Start training it by following this tutorial: [Getting started with real-world robots](./il_robots) > [!TIP] > If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb). diff --git a/docs/source/lekiwi.mdx b/docs/source/lekiwi.mdx index 14c06e444..875394d71 100644 --- a/docs/source/lekiwi.mdx +++ b/docs/source/lekiwi.mdx @@ -323,7 +323,7 @@ To replay an episode run the API example below, make sure to change `remote_ip`, python examples/lekiwi/replay.py ``` -Congrats 🎉, your robot is all set to learn a task on its own. Start training it by the training part of this tutorial: [Getting started with real-world robots](./getting_started_real_world_robot) +Congrats 🎉, your robot is all set to learn a task on its own. Start training it by the training part of this tutorial: [Getting started with real-world robots](./il_robots) ## Evaluate your policy diff --git a/docs/source/smolvla.mdx b/docs/source/smolvla.mdx index 89c475a90..a28e7cb44 100644 --- a/docs/source/smolvla.mdx +++ b/docs/source/smolvla.mdx @@ -29,7 +29,7 @@ SmolVLA is Hugging Face’s lightweight foundation model for robotics. Designed ## Collect a dataset SmolVLA is a base model, so fine-tuning on your own data is required for optimal performance in your setup. -We recommend recording ~50 episodes of your task as a starting point. Follow our guide to get started: [Recording a Dataset](https://huggingface.co/docs/lerobot/getting_started_real_world_robot#record-a-dataset) +We recommend recording ~50 episodes of your task as a starting point. Follow our guide to get started: [Recording a Dataset](./il_robots) @@ -93,7 +93,7 @@ lerobot-train --help ## Evaluate the finetuned model and run it in real-time -Similarly for when recording an episode, it is recommended that you are logged in to the HuggingFace Hub. You can follow the corresponding steps: [Record a dataset](./getting_started_real_world_robot#record-a-dataset). +Similarly for when recording an episode, it is recommended that you are logged in to the HuggingFace Hub. You can follow the corresponding steps: [Record a dataset](./il_robots). Once you are logged in, you can run inference in your setup by doing: ```bash diff --git a/docs/source/so100.mdx b/docs/source/so100.mdx index 8578e1e8d..3c73ae801 100644 --- a/docs/source/so100.mdx +++ b/docs/source/so100.mdx @@ -634,7 +634,7 @@ leader.disconnect() -Congrats 🎉, your robot is all set to learn a task on its own. Start training it by following this tutorial: [Getting started with real-world robots](./getting_started_real_world_robot) +Congrats 🎉, your robot is all set to learn a task on its own. Start training it by following this tutorial: [Getting started with real-world robots](./il_robots) > [!TIP] > If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb). diff --git a/docs/source/so101.mdx b/docs/source/so101.mdx index b9fb9cab4..00ec3eb74 100644 --- a/docs/source/so101.mdx +++ b/docs/source/so101.mdx @@ -430,7 +430,7 @@ leader.disconnect() -Congrats 🎉, your robot is all set to learn a task on its own. Start training it by following this tutorial: [Getting started with real-world robots](./getting_started_real_world_robot) +Congrats 🎉, your robot is all set to learn a task on its own. Start training it by following this tutorial: [Getting started with real-world robots](./il_robots) > [!TIP] > If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb). From af1760f1757aa1436716422264acaeac11e7e320 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 16:46:38 +0200 Subject: [PATCH 21/26] chore(utils): move benchmark and buffer to their respective modules (#2028) --- {src/lerobot/utils => benchmarks/video}/benchmark.py | 0 benchmarks/video/run_video_benchmark.py | 2 +- src/lerobot/{utils => rl}/buffer.py | 0 src/lerobot/rl/learner.py | 2 +- tests/utils/test_replay_buffer.py | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) rename {src/lerobot/utils => benchmarks/video}/benchmark.py (100%) rename src/lerobot/{utils => rl}/buffer.py (100%) diff --git a/src/lerobot/utils/benchmark.py b/benchmarks/video/benchmark.py similarity index 100% rename from src/lerobot/utils/benchmark.py rename to benchmarks/video/benchmark.py diff --git a/benchmarks/video/run_video_benchmark.py b/benchmarks/video/run_video_benchmark.py index 5472551f5..f041a9066 100644 --- a/benchmarks/video/run_video_benchmark.py +++ b/benchmarks/video/run_video_benchmark.py @@ -35,12 +35,12 @@ import torch from skimage.metrics import mean_squared_error, peak_signal_noise_ratio, structural_similarity from tqdm import tqdm +from benchmarks.video.benchmark import TimeBenchmark from lerobot.datasets.lerobot_dataset import LeRobotDataset from lerobot.datasets.video_utils import ( decode_video_frames_torchvision, encode_video_frames, ) -from lerobot.utils.benchmark import TimeBenchmark BASE_ENCODING = OrderedDict( [ diff --git a/src/lerobot/utils/buffer.py b/src/lerobot/rl/buffer.py similarity index 100% rename from src/lerobot/utils/buffer.py rename to src/lerobot/rl/buffer.py diff --git a/src/lerobot/rl/learner.py b/src/lerobot/rl/learner.py index 8d6831286..6fd9fb86e 100644 --- a/src/lerobot/rl/learner.py +++ b/src/lerobot/rl/learner.py @@ -66,6 +66,7 @@ from lerobot.datasets.factory import make_dataset from lerobot.datasets.lerobot_dataset import LeRobotDataset from lerobot.policies.factory import make_policy from lerobot.policies.sac.modeling_sac import SACPolicy +from lerobot.rl.buffer import ReplayBuffer, concatenate_batch_transitions from lerobot.robots import so100_follower # noqa: F401 from lerobot.teleoperators import gamepad, so101_leader # noqa: F401 from lerobot.teleoperators.utils import TeleopEvents @@ -76,7 +77,6 @@ from lerobot.transport.utils import ( bytes_to_transitions, state_to_bytes, ) -from lerobot.utils.buffer import ReplayBuffer, concatenate_batch_transitions from lerobot.utils.constants import ( CHECKPOINTS_DIR, LAST_CHECKPOINT_LINK, diff --git a/tests/utils/test_replay_buffer.py b/tests/utils/test_replay_buffer.py index 8781c5c0d..b5254f393 100644 --- a/tests/utils/test_replay_buffer.py +++ b/tests/utils/test_replay_buffer.py @@ -21,7 +21,7 @@ import pytest import torch from lerobot.datasets.lerobot_dataset import LeRobotDataset -from lerobot.utils.buffer import BatchTransition, ReplayBuffer, random_crop_vectorized +from lerobot.rl.buffer import BatchTransition, ReplayBuffer, random_crop_vectorized from tests.fixtures.constants import DUMMY_REPO_ID From ec63225dc150a713cfd576cdfbcac4bd069114a4 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 16:47:37 +0200 Subject: [PATCH 22/26] chore(utils): move encoding utils and process to their respective modules (#2029) Signed-off-by: Steven Palma --- src/lerobot/motors/dynamixel/dynamixel.py | 2 +- src/lerobot/{utils => motors}/encoding_utils.py | 0 src/lerobot/motors/feetech/feetech.py | 2 +- src/lerobot/rl/actor.py | 2 +- src/lerobot/rl/learner.py | 2 +- src/lerobot/{utils => rl}/process.py | 0 tests/motors/test_dynamixel.py | 2 +- tests/motors/test_feetech.py | 2 +- tests/utils/test_encoding_utils.py | 2 +- tests/utils/test_process.py | 2 +- 10 files changed, 8 insertions(+), 8 deletions(-) rename src/lerobot/{utils => motors}/encoding_utils.py (100%) rename src/lerobot/{utils => rl}/process.py (100%) diff --git a/src/lerobot/motors/dynamixel/dynamixel.py b/src/lerobot/motors/dynamixel/dynamixel.py index 1113ec0f7..e1d4e0963 100644 --- a/src/lerobot/motors/dynamixel/dynamixel.py +++ b/src/lerobot/motors/dynamixel/dynamixel.py @@ -22,7 +22,7 @@ import logging from copy import deepcopy from enum import Enum -from lerobot.utils.encoding_utils import decode_twos_complement, encode_twos_complement +from lerobot.motors.encoding_utils import decode_twos_complement, encode_twos_complement from ..motors_bus import Motor, MotorCalibration, MotorsBus, NameOrID, Value, get_address from .tables import ( diff --git a/src/lerobot/utils/encoding_utils.py b/src/lerobot/motors/encoding_utils.py similarity index 100% rename from src/lerobot/utils/encoding_utils.py rename to src/lerobot/motors/encoding_utils.py diff --git a/src/lerobot/motors/feetech/feetech.py b/src/lerobot/motors/feetech/feetech.py index 88d45ba39..2ea57af12 100644 --- a/src/lerobot/motors/feetech/feetech.py +++ b/src/lerobot/motors/feetech/feetech.py @@ -17,7 +17,7 @@ from copy import deepcopy from enum import Enum from pprint import pformat -from lerobot.utils.encoding_utils import decode_sign_magnitude, encode_sign_magnitude +from lerobot.motors.encoding_utils import decode_sign_magnitude, encode_sign_magnitude from ..motors_bus import Motor, MotorCalibration, MotorsBus, NameOrID, Value, get_address from .tables import ( diff --git a/src/lerobot/rl/actor.py b/src/lerobot/rl/actor.py index b38858ca6..2606481d3 100644 --- a/src/lerobot/rl/actor.py +++ b/src/lerobot/rl/actor.py @@ -63,6 +63,7 @@ from lerobot.configs.train import TrainRLServerPipelineConfig from lerobot.policies.factory import make_policy from lerobot.policies.sac.modeling_sac import SACPolicy from lerobot.processor import TransitionKey +from lerobot.rl.process import ProcessSignalHandler from lerobot.robots import so100_follower # noqa: F401 from lerobot.teleoperators import gamepad, so101_leader # noqa: F401 from lerobot.teleoperators.utils import TeleopEvents @@ -75,7 +76,6 @@ from lerobot.transport.utils import ( send_bytes_in_chunks, transitions_to_bytes, ) -from lerobot.utils.process import ProcessSignalHandler from lerobot.utils.queue import get_last_item_from_queue from lerobot.utils.random_utils import set_seed from lerobot.utils.robot_utils import busy_wait diff --git a/src/lerobot/rl/learner.py b/src/lerobot/rl/learner.py index 6fd9fb86e..1ff343760 100644 --- a/src/lerobot/rl/learner.py +++ b/src/lerobot/rl/learner.py @@ -67,6 +67,7 @@ from lerobot.datasets.lerobot_dataset import LeRobotDataset from lerobot.policies.factory import make_policy from lerobot.policies.sac.modeling_sac import SACPolicy from lerobot.rl.buffer import ReplayBuffer, concatenate_batch_transitions +from lerobot.rl.process import ProcessSignalHandler from lerobot.robots import so100_follower # noqa: F401 from lerobot.teleoperators import gamepad, so101_leader # noqa: F401 from lerobot.teleoperators.utils import TeleopEvents @@ -83,7 +84,6 @@ from lerobot.utils.constants import ( PRETRAINED_MODEL_DIR, TRAINING_STATE_DIR, ) -from lerobot.utils.process import ProcessSignalHandler from lerobot.utils.random_utils import set_seed from lerobot.utils.train_utils import ( get_step_checkpoint_dir, diff --git a/src/lerobot/utils/process.py b/src/lerobot/rl/process.py similarity index 100% rename from src/lerobot/utils/process.py rename to src/lerobot/rl/process.py diff --git a/tests/motors/test_dynamixel.py b/tests/motors/test_dynamixel.py index e0dbe713a..8b02d4330 100644 --- a/tests/motors/test_dynamixel.py +++ b/tests/motors/test_dynamixel.py @@ -24,7 +24,7 @@ import pytest from lerobot.motors import Motor, MotorCalibration, MotorNormMode from lerobot.motors.dynamixel import MODEL_NUMBER_TABLE, DynamixelMotorsBus from lerobot.motors.dynamixel.tables import X_SERIES_CONTROL_TABLE -from lerobot.utils.encoding_utils import encode_twos_complement +from lerobot.motors.encoding_utils import encode_twos_complement try: import dynamixel_sdk as dxl diff --git a/tests/motors/test_feetech.py b/tests/motors/test_feetech.py index 31e4a9018..673276e05 100644 --- a/tests/motors/test_feetech.py +++ b/tests/motors/test_feetech.py @@ -22,9 +22,9 @@ from unittest.mock import MagicMock, patch import pytest from lerobot.motors import Motor, MotorCalibration, MotorNormMode +from lerobot.motors.encoding_utils import encode_sign_magnitude from lerobot.motors.feetech import MODEL_NUMBER, MODEL_NUMBER_TABLE, FeetechMotorsBus from lerobot.motors.feetech.tables import STS_SMS_SERIES_CONTROL_TABLE -from lerobot.utils.encoding_utils import encode_sign_magnitude try: import scservo_sdk as scs diff --git a/tests/utils/test_encoding_utils.py b/tests/utils/test_encoding_utils.py index 813942862..8a0231221 100644 --- a/tests/utils/test_encoding_utils.py +++ b/tests/utils/test_encoding_utils.py @@ -16,7 +16,7 @@ import pytest -from lerobot.utils.encoding_utils import ( +from lerobot.motors.encoding_utils import ( decode_sign_magnitude, decode_twos_complement, encode_sign_magnitude, diff --git a/tests/utils/test_process.py b/tests/utils/test_process.py index 61e6e2c73..e2b00cae9 100644 --- a/tests/utils/test_process.py +++ b/tests/utils/test_process.py @@ -22,7 +22,7 @@ from unittest.mock import patch import pytest -from lerobot.utils.process import ProcessSignalHandler +from lerobot.rl.process import ProcessSignalHandler # Fixture to reset shutdown_event_counter and original signal handlers before and after each test From 853cc70194381794d5f810848f64f28643034daf Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 17:10:27 +0200 Subject: [PATCH 23/26] chore(utils): remove unused utils legacy functions + rename init_rerun (#2031) --- docs/source/il_robots.mdx | 8 ++--- examples/lekiwi/evaluate.py | 4 +-- examples/lekiwi/record.py | 4 +-- examples/lekiwi/teleoperate.py | 4 +-- examples/phone_to_so100/evaluate.py | 4 +-- examples/phone_to_so100/record.py | 4 +-- examples/phone_to_so100/teleoperate.py | 4 +-- examples/so100_to_so100_EE/evaluate.py | 4 +-- examples/so100_to_so100_EE/record.py | 4 +-- examples/so100_to_so100_EE/teleoperate.py | 4 +-- src/lerobot/scripts/lerobot_record.py | 4 +-- src/lerobot/scripts/lerobot_teleoperate.py | 4 +-- src/lerobot/utils/robot_utils.py | 14 -------- src/lerobot/utils/train_utils.py | 6 ---- src/lerobot/utils/utils.py | 39 +--------------------- src/lerobot/utils/visualization_utils.py | 2 +- 16 files changed, 28 insertions(+), 85 deletions(-) diff --git a/docs/source/il_robots.mdx b/docs/source/il_robots.mdx index 19b62167e..91df14028 100644 --- a/docs/source/il_robots.mdx +++ b/docs/source/il_robots.mdx @@ -200,7 +200,7 @@ from lerobot.teleoperators.so100_leader.config_so100_leader import SO100LeaderCo from lerobot.teleoperators.so100_leader.so100_leader import SO100Leader from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say -from lerobot.utils.visualization_utils import _init_rerun +from lerobot.utils.visualization_utils import init_rerun from lerobot.record import record_loop NUM_EPISODES = 5 @@ -237,7 +237,7 @@ dataset = LeRobotDataset.create( # Initialize the keyboard listener and rerun visualization _, events = init_keyboard_listener() -_init_rerun(session_name="recording") +init_rerun(session_name="recording") # Connect the robot and teleoperator robot.connect() @@ -517,7 +517,7 @@ from lerobot.robots.so100_follower.config_so100_follower import SO100FollowerCon from lerobot.robots.so100_follower.so100_follower import SO100Follower from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say -from lerobot.utils.visualization_utils import _init_rerun +from lerobot.utils.visualization_utils import init_rerun from lerobot.record import record_loop from lerobot.policies.factory import make_processor @@ -557,7 +557,7 @@ dataset = LeRobotDataset.create( # Initialize the keyboard listener and rerun visualization _, events = init_keyboard_listener() -_init_rerun(session_name="recording") +init_rerun(session_name="recording") # Connect the robot robot.connect() diff --git a/examples/lekiwi/evaluate.py b/examples/lekiwi/evaluate.py index 8993a5e14..32a5e0a2b 100644 --- a/examples/lekiwi/evaluate.py +++ b/examples/lekiwi/evaluate.py @@ -23,7 +23,7 @@ from lerobot.robots.lekiwi import LeKiwiClient, LeKiwiClientConfig from lerobot.scripts.lerobot_record import record_loop from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say -from lerobot.utils.visualization_utils import _init_rerun +from lerobot.utils.visualization_utils import init_rerun NUM_EPISODES = 2 FPS = 30 @@ -73,7 +73,7 @@ teleop_action_processor, robot_action_processor, robot_observation_processor = m # Initialize the keyboard listener and rerun visualization listener, events = init_keyboard_listener() -_init_rerun(session_name="lekiwi_evaluate") +init_rerun(session_name="lekiwi_evaluate") if not robot.is_connected: raise ValueError("Robot is not connected!") diff --git a/examples/lekiwi/record.py b/examples/lekiwi/record.py index f59093b26..30f34e718 100644 --- a/examples/lekiwi/record.py +++ b/examples/lekiwi/record.py @@ -24,7 +24,7 @@ from lerobot.teleoperators.keyboard import KeyboardTeleop, KeyboardTeleopConfig from lerobot.teleoperators.so100_leader import SO100Leader, SO100LeaderConfig from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say -from lerobot.utils.visualization_utils import _init_rerun +from lerobot.utils.visualization_utils import init_rerun NUM_EPISODES = 2 FPS = 30 @@ -69,7 +69,7 @@ keyboard.connect() # Initialize the keyboard listener and rerun visualization listener, events = init_keyboard_listener() -_init_rerun(session_name="lekiwi_record") +init_rerun(session_name="lekiwi_record") if not robot.is_connected or not leader_arm.is_connected or not keyboard.is_connected: raise ValueError("Robot or teleop is not connected!") diff --git a/examples/lekiwi/teleoperate.py b/examples/lekiwi/teleoperate.py index cde4000df..6b430df48 100644 --- a/examples/lekiwi/teleoperate.py +++ b/examples/lekiwi/teleoperate.py @@ -20,7 +20,7 @@ from lerobot.robots.lekiwi import LeKiwiClient, LeKiwiClientConfig from lerobot.teleoperators.keyboard.teleop_keyboard import KeyboardTeleop, KeyboardTeleopConfig from lerobot.teleoperators.so100_leader import SO100Leader, SO100LeaderConfig from lerobot.utils.robot_utils import busy_wait -from lerobot.utils.visualization_utils import _init_rerun, log_rerun_data +from lerobot.utils.visualization_utils import init_rerun, log_rerun_data FPS = 30 @@ -41,7 +41,7 @@ leader_arm.connect() keyboard.connect() # Init rerun viewer -_init_rerun(session_name="lekiwi_teleop") +init_rerun(session_name="lekiwi_teleop") if not robot.is_connected or not leader_arm.is_connected or not keyboard.is_connected: raise ValueError("Robot or teleop is not connected!") diff --git a/examples/phone_to_so100/evaluate.py b/examples/phone_to_so100/evaluate.py index c7d6eb240..0d53f1177 100644 --- a/examples/phone_to_so100/evaluate.py +++ b/examples/phone_to_so100/evaluate.py @@ -43,7 +43,7 @@ from lerobot.robots.so100_follower.so100_follower import SO100Follower from lerobot.scripts.lerobot_record import record_loop from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say -from lerobot.utils.visualization_utils import _init_rerun +from lerobot.utils.visualization_utils import init_rerun NUM_EPISODES = 5 FPS = 30 @@ -137,7 +137,7 @@ robot.connect() # Initialize the keyboard listener and rerun visualization listener, events = init_keyboard_listener() -_init_rerun(session_name="phone_so100_evaluate") +init_rerun(session_name="phone_so100_evaluate") if not robot.is_connected: raise ValueError("Robot is not connected!") diff --git a/examples/phone_to_so100/record.py b/examples/phone_to_so100/record.py index 6681017a0..bb2e2f5f7 100644 --- a/examples/phone_to_so100/record.py +++ b/examples/phone_to_so100/record.py @@ -41,7 +41,7 @@ from lerobot.teleoperators.phone.phone_processor import MapPhoneActionToRobotAct from lerobot.teleoperators.phone.teleop_phone import Phone from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say -from lerobot.utils.visualization_utils import _init_rerun +from lerobot.utils.visualization_utils import init_rerun NUM_EPISODES = 2 FPS = 30 @@ -143,7 +143,7 @@ phone.connect() # Initialize the keyboard listener and rerun visualization listener, events = init_keyboard_listener() -_init_rerun(session_name="phone_so100_record") +init_rerun(session_name="phone_so100_record") if not robot.is_connected or not phone.is_connected: raise ValueError("Robot or teleop is not connected!") diff --git a/examples/phone_to_so100/teleoperate.py b/examples/phone_to_so100/teleoperate.py index eb5ed3526..6c49a8453 100644 --- a/examples/phone_to_so100/teleoperate.py +++ b/examples/phone_to_so100/teleoperate.py @@ -33,7 +33,7 @@ from lerobot.teleoperators.phone.config_phone import PhoneConfig, PhoneOS from lerobot.teleoperators.phone.phone_processor import MapPhoneActionToRobotAction from lerobot.teleoperators.phone.teleop_phone import Phone from lerobot.utils.robot_utils import busy_wait -from lerobot.utils.visualization_utils import _init_rerun, log_rerun_data +from lerobot.utils.visualization_utils import init_rerun, log_rerun_data FPS = 30 @@ -87,7 +87,7 @@ robot.connect() teleop_device.connect() # Init rerun viewer -_init_rerun(session_name="phone_so100_teleop") +init_rerun(session_name="phone_so100_teleop") if not robot.is_connected or not teleop_device.is_connected: raise ValueError("Robot or teleop is not connected!") diff --git a/examples/so100_to_so100_EE/evaluate.py b/examples/so100_to_so100_EE/evaluate.py index f47a216d6..53a385442 100644 --- a/examples/so100_to_so100_EE/evaluate.py +++ b/examples/so100_to_so100_EE/evaluate.py @@ -43,7 +43,7 @@ from lerobot.robots.so100_follower.so100_follower import SO100Follower from lerobot.scripts.lerobot_record import record_loop from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say -from lerobot.utils.visualization_utils import _init_rerun +from lerobot.utils.visualization_utils import init_rerun NUM_EPISODES = 5 FPS = 30 @@ -138,7 +138,7 @@ robot.connect() # Initialize the keyboard listener and rerun visualization listener, events = init_keyboard_listener() -_init_rerun(session_name="so100_so100_evaluate") +init_rerun(session_name="so100_so100_evaluate") if not robot.is_connected: raise ValueError("Robot is not connected!") diff --git a/examples/so100_to_so100_EE/record.py b/examples/so100_to_so100_EE/record.py index 60c96835f..6c38553e2 100644 --- a/examples/so100_to_so100_EE/record.py +++ b/examples/so100_to_so100_EE/record.py @@ -39,7 +39,7 @@ from lerobot.teleoperators.so100_leader.config_so100_leader import SO100LeaderCo from lerobot.teleoperators.so100_leader.so100_leader import SO100Leader from lerobot.utils.control_utils import init_keyboard_listener from lerobot.utils.utils import log_say -from lerobot.utils.visualization_utils import _init_rerun +from lerobot.utils.visualization_utils import init_rerun NUM_EPISODES = 2 FPS = 30 @@ -143,7 +143,7 @@ follower.connect() # Initialize the keyboard listener and rerun visualization listener, events = init_keyboard_listener() -_init_rerun(session_name="recording_phone") +init_rerun(session_name="recording_phone") if not leader.is_connected or not follower.is_connected: raise ValueError("Robot or teleop is not connected!") diff --git a/examples/so100_to_so100_EE/teleoperate.py b/examples/so100_to_so100_EE/teleoperate.py index ab54e7236..aa9755788 100644 --- a/examples/so100_to_so100_EE/teleoperate.py +++ b/examples/so100_to_so100_EE/teleoperate.py @@ -33,7 +33,7 @@ from lerobot.robots.so100_follower.so100_follower import SO100Follower from lerobot.teleoperators.so100_leader.config_so100_leader import SO100LeaderConfig from lerobot.teleoperators.so100_leader.so100_leader import SO100Leader from lerobot.utils.robot_utils import busy_wait -from lerobot.utils.visualization_utils import _init_rerun, log_rerun_data +from lerobot.utils.visualization_utils import init_rerun, log_rerun_data FPS = 30 @@ -95,7 +95,7 @@ follower.connect() leader.connect() # Init rerun viewer -_init_rerun(session_name="so100_so100_EE_teleop") +init_rerun(session_name="so100_so100_EE_teleop") print("Starting teleop loop...") while True: diff --git a/src/lerobot/scripts/lerobot_record.py b/src/lerobot/scripts/lerobot_record.py index d09b017e4..dd4984fab 100644 --- a/src/lerobot/scripts/lerobot_record.py +++ b/src/lerobot/scripts/lerobot_record.py @@ -122,7 +122,7 @@ from lerobot.utils.utils import ( init_logging, log_say, ) -from lerobot.utils.visualization_utils import _init_rerun, log_rerun_data +from lerobot.utils.visualization_utils import init_rerun, log_rerun_data @dataclass @@ -378,7 +378,7 @@ def record(cfg: RecordConfig) -> LeRobotDataset: init_logging() logging.info(pformat(asdict(cfg))) if cfg.display_data: - _init_rerun(session_name="recording") + init_rerun(session_name="recording") robot = make_robot_from_config(cfg.robot) teleop = make_teleoperator_from_config(cfg.teleop) if cfg.teleop is not None else None diff --git a/src/lerobot/scripts/lerobot_teleoperate.py b/src/lerobot/scripts/lerobot_teleoperate.py index 62c243e95..ab9a6361d 100644 --- a/src/lerobot/scripts/lerobot_teleoperate.py +++ b/src/lerobot/scripts/lerobot_teleoperate.py @@ -90,7 +90,7 @@ from lerobot.teleoperators import ( # noqa: F401 ) from lerobot.utils.robot_utils import busy_wait from lerobot.utils.utils import init_logging, move_cursor_up -from lerobot.utils.visualization_utils import _init_rerun, log_rerun_data +from lerobot.utils.visualization_utils import init_rerun, log_rerun_data @dataclass @@ -185,7 +185,7 @@ def teleoperate(cfg: TeleoperateConfig): init_logging() logging.info(pformat(asdict(cfg))) if cfg.display_data: - _init_rerun(session_name="teleoperation") + init_rerun(session_name="teleoperation") teleop = make_teleoperator_from_config(cfg.teleop) robot = make_robot_from_config(cfg.robot) diff --git a/src/lerobot/utils/robot_utils.py b/src/lerobot/utils/robot_utils.py index 8069b3662..42abcdda4 100644 --- a/src/lerobot/utils/robot_utils.py +++ b/src/lerobot/utils/robot_utils.py @@ -27,17 +27,3 @@ def busy_wait(seconds): # On Linux time.sleep is accurate if seconds > 0: time.sleep(seconds) - - -def safe_disconnect(func): - # TODO(aliberts): Allow to pass custom exceptions - # (e.g. ThreadServiceExit, KeyboardInterrupt, SystemExit, UnpluggedError, DynamixelCommError) - def wrapper(robot, *args, **kwargs): - try: - return func(robot, *args, **kwargs) - except Exception as e: - if robot.is_connected: - robot.disconnect() - raise e - - return wrapper diff --git a/src/lerobot/utils/train_utils.py b/src/lerobot/utils/train_utils.py index 08d1bcc9d..3ebe31971 100644 --- a/src/lerobot/utils/train_utils.py +++ b/src/lerobot/utils/train_utils.py @@ -13,10 +13,8 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. -import logging from pathlib import Path -from termcolor import colored from torch.optim import Optimizer from torch.optim.lr_scheduler import LRScheduler @@ -36,10 +34,6 @@ from lerobot.utils.constants import ( from lerobot.utils.random_utils import load_rng_state, save_rng_state -def log_output_dir(out_dir): - logging.info(colored("Output dir:", "yellow", attrs=["bold"]) + f" {out_dir}") - - def get_step_identifier(step: int, total_steps: int) -> str: num_digits = max(6, len(str(total_steps))) return f"{step:0{num_digits}d}" diff --git a/src/lerobot/utils/utils.py b/src/lerobot/utils/utils.py index 107606fda..523a5e4d2 100644 --- a/src/lerobot/utils/utils.py +++ b/src/lerobot/utils/utils.py @@ -15,14 +15,13 @@ # limitations under the License. import logging import os -import os.path as osp import platform import select import subprocess import sys import time from copy import copy, deepcopy -from datetime import datetime, timezone +from datetime import datetime from pathlib import Path from statistics import mean @@ -30,12 +29,6 @@ import numpy as np import torch -def none_or_int(value): - if value == "None": - return None - return int(value) - - def inside_slurm(): """Check whether the python process was launched through slurm""" # TODO(rcadene): return False for interactive mode `--pty bash` @@ -165,36 +158,6 @@ def format_big_number(num, precision=0): return num -def _relative_path_between(path1: Path, path2: Path) -> Path: - """Returns path1 relative to path2.""" - path1 = path1.absolute() - path2 = path2.absolute() - try: - return path1.relative_to(path2) - except ValueError: # most likely because path1 is not a subpath of path2 - common_parts = Path(osp.commonpath([path1, path2])).parts - return Path( - "/".join([".."] * (len(path2.parts) - len(common_parts)) + list(path1.parts[len(common_parts) :])) - ) - - -def print_cuda_memory_usage(): - """Use this function to locate and debug memory leak.""" - import gc - - gc.collect() - # Also clear the cache if you want to fully release the memory - torch.cuda.empty_cache() - print(f"Current GPU Memory Allocated: {torch.cuda.memory_allocated(0) / 1024**2:.2f} MB") - print(f"Maximum GPU Memory Allocated: {torch.cuda.max_memory_allocated(0) / 1024**2:.2f} MB") - print(f"Current GPU Memory Reserved: {torch.cuda.memory_reserved(0) / 1024**2:.2f} MB") - print(f"Maximum GPU Memory Reserved: {torch.cuda.max_memory_reserved(0) / 1024**2:.2f} MB") - - -def capture_timestamp_utc(): - return datetime.now(timezone.utc) - - def say(text: str, blocking: bool = False): system = platform.system() diff --git a/src/lerobot/utils/visualization_utils.py b/src/lerobot/utils/visualization_utils.py index e6acc87de..7fc881f26 100644 --- a/src/lerobot/utils/visualization_utils.py +++ b/src/lerobot/utils/visualization_utils.py @@ -20,7 +20,7 @@ import numpy as np import rerun as rr -def _init_rerun(session_name: str = "lerobot_control_loop") -> None: +def init_rerun(session_name: str = "lerobot_control_loop") -> None: """Initializes the Rerun SDK for visualizing the control loop.""" batch_size = os.getenv("RERUN_FLUSH_NUM_BYTES", "8000") os.environ["RERUN_FLUSH_NUM_BYTES"] = batch_size From 170c09e7f63660934d8e784df202d04bea2e77bc Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 17:10:52 +0200 Subject: [PATCH 24/26] chore(utils): move queue utils and wandb_utils to their respective modules (#2030) * chore(utils): move queue utils and wandb_utils to their respective modules * fix(rl): remove double imports --------- Signed-off-by: Steven Palma --- src/lerobot/rl/actor.py | 2 +- src/lerobot/rl/learner.py | 4 ++-- src/lerobot/rl/learner_service.py | 2 +- src/lerobot/{utils => rl}/queue.py | 0 src/lerobot/{utils => rl}/wandb_utils.py | 0 src/lerobot/scripts/train.py | 2 +- tests/{utils => rl}/test_queue.py | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename src/lerobot/{utils => rl}/queue.py (100%) rename src/lerobot/{utils => rl}/wandb_utils.py (100%) rename tests/{utils => rl}/test_queue.py (98%) diff --git a/src/lerobot/rl/actor.py b/src/lerobot/rl/actor.py index 2606481d3..3c025a05d 100644 --- a/src/lerobot/rl/actor.py +++ b/src/lerobot/rl/actor.py @@ -64,6 +64,7 @@ from lerobot.policies.factory import make_policy from lerobot.policies.sac.modeling_sac import SACPolicy from lerobot.processor import TransitionKey from lerobot.rl.process import ProcessSignalHandler +from lerobot.rl.queue import get_last_item_from_queue from lerobot.robots import so100_follower # noqa: F401 from lerobot.teleoperators import gamepad, so101_leader # noqa: F401 from lerobot.teleoperators.utils import TeleopEvents @@ -76,7 +77,6 @@ from lerobot.transport.utils import ( send_bytes_in_chunks, transitions_to_bytes, ) -from lerobot.utils.queue import get_last_item_from_queue from lerobot.utils.random_utils import set_seed from lerobot.utils.robot_utils import busy_wait from lerobot.utils.transition import ( diff --git a/src/lerobot/rl/learner.py b/src/lerobot/rl/learner.py index 1ff343760..0faa460ef 100644 --- a/src/lerobot/rl/learner.py +++ b/src/lerobot/rl/learner.py @@ -68,6 +68,7 @@ from lerobot.policies.factory import make_policy from lerobot.policies.sac.modeling_sac import SACPolicy from lerobot.rl.buffer import ReplayBuffer, concatenate_batch_transitions from lerobot.rl.process import ProcessSignalHandler +from lerobot.rl.wandb_utils import WandBLogger from lerobot.robots import so100_follower # noqa: F401 from lerobot.teleoperators import gamepad, so101_leader # noqa: F401 from lerobot.teleoperators.utils import TeleopEvents @@ -97,7 +98,6 @@ from lerobot.utils.utils import ( get_safe_torch_device, init_logging, ) -from lerobot.utils.wandb_utils import WandBLogger from .learner_service import MAX_WORKERS, SHUTDOWN_TIMEOUT, LearnerService @@ -153,7 +153,7 @@ def train(cfg: TrainRLServerPipelineConfig, job_name: str | None = None): # Setup WandB logging if enabled if cfg.wandb.enable and cfg.wandb.project: - from lerobot.utils.wandb_utils import WandBLogger + from lerobot.rl.wandb_utils import WandBLogger wandb_logger = WandBLogger(cfg) else: diff --git a/src/lerobot/rl/learner_service.py b/src/lerobot/rl/learner_service.py index b07c296e6..7ef38119b 100644 --- a/src/lerobot/rl/learner_service.py +++ b/src/lerobot/rl/learner_service.py @@ -19,9 +19,9 @@ import logging import time from multiprocessing import Event, Queue +from lerobot.rl.queue import get_last_item_from_queue from lerobot.transport import services_pb2, services_pb2_grpc from lerobot.transport.utils import receive_bytes_in_chunks, send_bytes_in_chunks -from lerobot.utils.queue import get_last_item_from_queue MAX_WORKERS = 3 # Stream parameters, send transitions and interactions SHUTDOWN_TIMEOUT = 10 diff --git a/src/lerobot/utils/queue.py b/src/lerobot/rl/queue.py similarity index 100% rename from src/lerobot/utils/queue.py rename to src/lerobot/rl/queue.py diff --git a/src/lerobot/utils/wandb_utils.py b/src/lerobot/rl/wandb_utils.py similarity index 100% rename from src/lerobot/utils/wandb_utils.py rename to src/lerobot/rl/wandb_utils.py diff --git a/src/lerobot/scripts/train.py b/src/lerobot/scripts/train.py index 21da62bbb..df33f1dbe 100644 --- a/src/lerobot/scripts/train.py +++ b/src/lerobot/scripts/train.py @@ -35,6 +35,7 @@ from lerobot.optim.factory import make_optimizer_and_scheduler from lerobot.policies.factory import make_policy, make_pre_post_processors from lerobot.policies.pretrained import PreTrainedPolicy from lerobot.policies.utils import get_device_from_parameters +from lerobot.rl.wandb_utils import WandBLogger from lerobot.scripts.eval import eval_policy_all from lerobot.utils.logging_utils import AverageMeter, MetricsTracker from lerobot.utils.random_utils import set_seed @@ -51,7 +52,6 @@ from lerobot.utils.utils import ( has_method, init_logging, ) -from lerobot.utils.wandb_utils import WandBLogger def update_policy( diff --git a/tests/utils/test_queue.py b/tests/rl/test_queue.py similarity index 98% rename from tests/utils/test_queue.py rename to tests/rl/test_queue.py index 6e42acdb7..b6716fbd6 100644 --- a/tests/utils/test_queue.py +++ b/tests/rl/test_queue.py @@ -20,7 +20,7 @@ from queue import Queue from torch.multiprocessing import Queue as TorchMPQueue -from lerobot.utils.queue import get_last_item_from_queue +from lerobot.rl.queue import get_last_item_from_queue def test_get_last_item_single_item(): From a87d4c9a749da72d782fe4f37fdb9d498979e1d1 Mon Sep 17 00:00:00 2001 From: Jade Choghari Date: Wed, 24 Sep 2025 17:30:32 +0200 Subject: [PATCH 25/26] (docs): small change in dataset name (#2032) * small change Signed-off-by: Jade Choghari * update Signed-off-by: Jade Choghari --------- Signed-off-by: Jade Choghari --- docs/source/libero.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/source/libero.mdx b/docs/source/libero.mdx index 488c02ce0..17e12d45e 100644 --- a/docs/source/libero.mdx +++ b/docs/source/libero.mdx @@ -33,7 +33,7 @@ To Install LIBERO, after following LeRobot official instructions, just do: Evaluate a policy on one LIBERO suite: ```bash -python src/lerobot/scripts/eval.py \ +lerobot-eval \ --policy.path="your-policy-id" \ --env.type=libero \ --env.task=libero_object \ @@ -52,7 +52,7 @@ python src/lerobot/scripts/eval.py \ Benchmark a policy across multiple suites at once: ```bash -python src/lerobot/scripts/eval.py \ +lerobot-eval \ --policy.path="your-policy-id" \ --env.type=libero \ --env.task=libero_object,libero_spatial \ @@ -103,10 +103,10 @@ For reference, here is the **original dataset** published by Physical Intelligen ### Example training command ```bash -python src/lerobot/scripts/train.py \ +lerobot-train \ --policy.type=smolvla \ --policy.repo_id=${HF_USER}/libero-test \ - --dataset.repo_id=jadechoghari/smol-libero3 \ + --dataset.repo_id=HuggingFaceVLA/libero \ --env.type=libero \ --env.task=libero_10 \ --output_dir=./outputs/ \ From ddba994d73e6315e78c76173cd4fa90d471fc662 Mon Sep 17 00:00:00 2001 From: Steven Palma Date: Wed, 24 Sep 2025 18:29:58 +0200 Subject: [PATCH 26/26] chore(scripts): rename eval and train scripts (#2033) --- pyproject.toml | 4 ++-- src/lerobot/scripts/{eval.py => lerobot_eval.py} | 0 src/lerobot/scripts/{train.py => lerobot_train.py} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename src/lerobot/scripts/{eval.py => lerobot_eval.py} (100%) rename src/lerobot/scripts/{train.py => lerobot_train.py} (99%) diff --git a/pyproject.toml b/pyproject.toml index dbc25805d..d2f1e502a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -169,8 +169,8 @@ lerobot-record="lerobot.scripts.lerobot_record:main" lerobot-replay="lerobot.scripts.lerobot_replay:main" lerobot-setup-motors="lerobot.scripts.lerobot_setup_motors:main" lerobot-teleoperate="lerobot.scripts.lerobot_teleoperate:main" -lerobot-eval="lerobot.scripts.eval:main" -lerobot-train="lerobot.scripts.train:main" +lerobot-eval="lerobot.scripts.lerobot_eval:main" +lerobot-train="lerobot.scripts.lerobot_train:main" lerobot-dataset-viz="lerobot.scripts.lerobot_dataset_viz:main" lerobot-info="lerobot.scripts.lerobot_info:main" lerobot-find-joint-limits="lerobot.scripts.lerobot_find_joint_limits:main" diff --git a/src/lerobot/scripts/eval.py b/src/lerobot/scripts/lerobot_eval.py similarity index 100% rename from src/lerobot/scripts/eval.py rename to src/lerobot/scripts/lerobot_eval.py diff --git a/src/lerobot/scripts/train.py b/src/lerobot/scripts/lerobot_train.py similarity index 99% rename from src/lerobot/scripts/train.py rename to src/lerobot/scripts/lerobot_train.py index df33f1dbe..5ef8c7263 100644 --- a/src/lerobot/scripts/train.py +++ b/src/lerobot/scripts/lerobot_train.py @@ -36,7 +36,7 @@ from lerobot.policies.factory import make_policy, make_pre_post_processors from lerobot.policies.pretrained import PreTrainedPolicy from lerobot.policies.utils import get_device_from_parameters from lerobot.rl.wandb_utils import WandBLogger -from lerobot.scripts.eval import eval_policy_all +from lerobot.scripts.lerobot_eval import eval_policy_all from lerobot.utils.logging_utils import AverageMeter, MetricsTracker from lerobot.utils.random_utils import set_seed from lerobot.utils.train_utils import (