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/.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:
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/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/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/docs/source/hilserl.mdx b/docs/source/hilserl.mdx
index f6bac1ffa..bc38408e6 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
@@ -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**
@@ -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_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/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/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/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/docs/source/libero.mdx b/docs/source/libero.mdx
index 2efb9d1b0..24c080023 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/ \
diff --git a/docs/source/smolvla.mdx b/docs/source/smolvla.mdx
index d25bbcd09..a56298b5e 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).
diff --git a/examples/lekiwi/evaluate.py b/examples/lekiwi/evaluate.py
index 3dbb10f56..32a5e0a2b 100644
--- a/examples/lekiwi/evaluate.py
+++ b/examples/lekiwi/evaluate.py
@@ -19,11 +19,11 @@ 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
+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 f5d109d5d..30f34e718 100644
--- a/examples/lekiwi/record.py
+++ b/examples/lekiwi/record.py
@@ -17,14 +17,14 @@
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
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 e76b11350..0d53f1177 100644
--- a/examples/phone_to_so100/evaluate.py
+++ b/examples/phone_to_so100/evaluate.py
@@ -34,16 +34,16 @@ 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
+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 768041d63..bb2e2f5f7 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,12 +35,13 @@ 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
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 fd10bf865..53a385442 100644
--- a/examples/so100_to_so100_EE/evaluate.py
+++ b/examples/so100_to_so100_EE/evaluate.py
@@ -34,16 +34,16 @@ 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
+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 abb8fb99d..6c38553e2 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,11 +34,12 @@ 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
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/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/pyproject.toml b/pyproject.toml
index 54b23ea22..504ce977a 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -162,15 +162,19 @@ all = [
]
[project.scripts]
-lerobot-calibrate="lerobot.calibrate:main"
-lerobot-find-cameras="lerobot.find_cameras:main"
-lerobot-find-port="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-eval="lerobot.scripts.eval:main"
-lerobot-train="lerobot.scripts.train: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"
+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.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"
+lerobot-imgtransform-viz="lerobot.scripts.lerobot_imgtransform_viz:main"
# ---------------- Tool Configurations ----------------
[tool.setuptools.packages.find]
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 99%
rename from src/lerobot/scripts/server/helpers.py
rename to src/lerobot/async_inference/helpers.py
index 28e29a6d1..3e5994e23 100644
--- a/src/lerobot/scripts/server/helpers.py
+++ b/src/lerobot/async_inference/helpers.py
@@ -22,7 +22,6 @@ 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
@@ -35,6 +34,7 @@ from lerobot.policies import ( # noqa: F401
VQBeTConfig,
)
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/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/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/configs/policies.py b/src/lerobot/configs/policies.py
index f5ec7e58b..98dd4df3f 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
@@ -198,11 +198,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/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 96bdc1897..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"
@@ -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
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/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/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/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 3aaae1359..ac76baf9f 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
@@ -47,6 +46,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/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/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
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/scripts/rl/actor.py b/src/lerobot/rl/actor.py
similarity index 98%
rename from src/lerobot/scripts/rl/actor.py
rename to src/lerobot/rl/actor.py
index baa284c4a..3c025a05d 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
@@ -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
@@ -63,13 +63,9 @@ 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.rl.queue import get_last_item_from_queue
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
@@ -81,8 +77,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
from lerobot.utils.transition import (
@@ -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/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/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 98%
rename from src/lerobot/scripts/rl/learner.py
rename to src/lerobot/rl/learner.py
index 5d9953827..0faa460ef 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
@@ -62,18 +62,14 @@ 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
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.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
@@ -83,8 +79,12 @@ from lerobot.transport.utils import (
bytes_to_transitions,
state_to_bytes,
)
-from lerobot.utils.buffer import ReplayBuffer, concatenate_batch_transitions
-from lerobot.utils.process import ProcessSignalHandler
+from lerobot.utils.constants import (
+ CHECKPOINTS_DIR,
+ LAST_CHECKPOINT_LINK,
+ PRETRAINED_MODEL_DIR,
+ TRAINING_STATE_DIR,
+)
from lerobot.utils.random_utils import set_seed
from lerobot.utils.train_utils import (
get_step_checkpoint_dir,
@@ -98,7 +98,8 @@ 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
LOG_PREFIX = "[LEARNER]"
@@ -152,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:
@@ -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 98%
rename from src/lerobot/scripts/rl/learner_service.py
rename to src/lerobot/rl/learner_service.py
index b07c296e6..7ef38119b 100644
--- a/src/lerobot/scripts/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/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/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 99%
rename from src/lerobot/utils/wandb_utils.py
rename to src/lerobot/rl/wandb_utils.py
index 91b4ec95c..b13254421 100644
--- a/src/lerobot/utils/wandb_utils.py
+++ b/src/lerobot/rl/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/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/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/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/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/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/robots/viperx/viperx.py b/src/lerobot/robots/viperx/viperx.py
index 881640cd5..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.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 lerobot.utils.errors import DeviceAlreadyConnectedError, DeviceNotConnectedError
from ..robot import Robot
from ..utils import ensure_safe_goal_position
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/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/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/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/find_cameras.py b/src/lerobot/scripts/lerobot_find_cameras.py
similarity index 99%
rename from src/lerobot/find_cameras.py
rename to src/lerobot/scripts/lerobot_find_cameras.py
index ec8f5ff30..e17dca805 100644
--- a/src/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/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()
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
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/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()
diff --git a/src/lerobot/record.py b/src/lerobot/scripts/lerobot_record.py
similarity index 99%
rename from src/lerobot/record.py
rename to src/lerobot/scripts/lerobot_record.py
index d09b017e4..dd4984fab 100644
--- a/src/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/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/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
diff --git a/src/lerobot/teleoperate.py b/src/lerobot/scripts/lerobot_teleoperate.py
similarity index 98%
rename from src/lerobot/teleoperate.py
rename to src/lerobot/scripts/lerobot_teleoperate.py
index 62c243e95..ab9a6361d 100644
--- a/src/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/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 9e18286f1..21dccf10b 100644
--- a/src/lerobot/scripts/train.py
+++ b/src/lerobot/scripts/lerobot_train.py
@@ -35,7 +35,8 @@ 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.scripts.eval import eval_policy_all
+from lerobot.rl.wandb_utils import WandBLogger
+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 (
@@ -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/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/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/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/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/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/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/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 be2eb8146..3ebe31971 100644
--- a/src/lerobot/utils/train_utils.py
+++ b/src/lerobot/utils/train_utils.py
@@ -13,33 +13,27 @@
# 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
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
-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
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
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/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/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,
)
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")
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/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")
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/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_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/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."""
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():
diff --git a/tests/test_control_robot.py b/tests/test_control_robot.py
index 374f98129..ace0aea49 100644
--- a/tests/test_control_robot.py
+++ b/tests/test_control_robot.py
@@ -16,10 +16,10 @@
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_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 tests.mocks.mock_teleop import MockTeleopConfig
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
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
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,