Delete docs
Browse files- docs/README.md +0 -137
- docs/source/_toctree.yml +0 -44
- docs/source/backwardcomp.mdx +0 -82
- docs/source/cameras.mdx +0 -173
- docs/source/contributing.md +0 -305
- docs/source/hilserl.mdx +0 -547
- docs/source/hilserl_sim.mdx +0 -120
- docs/source/il_robots.mdx +0 -315
- docs/source/il_sim.mdx +0 -152
- docs/source/index.mdx +0 -19
- docs/source/installation.mdx +0 -72
- docs/source/integrate_hardware.mdx +0 -318
- docs/source/koch.mdx +0 -258
- docs/source/lekiwi.mdx +0 -300
- docs/source/notebooks.mdx +0 -29
- docs/source/smolvla.mdx +0 -97
- docs/source/so100.mdx +0 -486
- docs/source/so101.mdx +0 -381
docs/README.md
DELETED
|
@@ -1,137 +0,0 @@
|
|
| 1 |
-
<!---
|
| 2 |
-
Copyright 2020 The HuggingFace Team. All rights reserved.
|
| 3 |
-
|
| 4 |
-
Licensed under the Apache License, Version 2.0 (the "License");
|
| 5 |
-
you may not use this file except in compliance with the License.
|
| 6 |
-
You may obtain a copy of the License at
|
| 7 |
-
|
| 8 |
-
http://www.apache.org/licenses/LICENSE-2.0
|
| 9 |
-
|
| 10 |
-
Unless required by applicable law or agreed to in writing, software
|
| 11 |
-
distributed under the License is distributed on an "AS IS" BASIS,
|
| 12 |
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
| 13 |
-
See the License for the specific language governing permissions and
|
| 14 |
-
limitations under the License.
|
| 15 |
-
-->
|
| 16 |
-
|
| 17 |
-
# Generating the documentation
|
| 18 |
-
|
| 19 |
-
To generate the documentation, you first have to build it. Several packages are necessary to build the doc,
|
| 20 |
-
you can install them with the following command, at the root of the code repository:
|
| 21 |
-
|
| 22 |
-
```bash
|
| 23 |
-
pip install -e ".[docs]"
|
| 24 |
-
```
|
| 25 |
-
|
| 26 |
-
You will also need `nodejs`. Please refer to their [installation page](https://nodejs.org/en/download)
|
| 27 |
-
|
| 28 |
-
---
|
| 29 |
-
**NOTE**
|
| 30 |
-
|
| 31 |
-
You only need to generate the documentation to inspect it locally (if you're planning changes and want to
|
| 32 |
-
check how they look before committing for instance). You don't have to `git commit` the built documentation.
|
| 33 |
-
|
| 34 |
-
---
|
| 35 |
-
|
| 36 |
-
## Building the documentation
|
| 37 |
-
|
| 38 |
-
Once you have setup the `doc-builder` and additional packages, you can generate the documentation by
|
| 39 |
-
typing the following command:
|
| 40 |
-
|
| 41 |
-
```bash
|
| 42 |
-
doc-builder build lerobot docs/source/ --build_dir ~/tmp/test-build
|
| 43 |
-
```
|
| 44 |
-
|
| 45 |
-
You can adapt the `--build_dir` to set any temporary folder that you prefer. This command will create it and generate
|
| 46 |
-
the MDX files that will be rendered as the documentation on the main website. You can inspect them in your favorite
|
| 47 |
-
Markdown editor.
|
| 48 |
-
|
| 49 |
-
## Previewing the documentation
|
| 50 |
-
|
| 51 |
-
To preview the docs, first install the `watchdog` module with:
|
| 52 |
-
|
| 53 |
-
```bash
|
| 54 |
-
pip install watchdog
|
| 55 |
-
```
|
| 56 |
-
|
| 57 |
-
Then run the following command:
|
| 58 |
-
|
| 59 |
-
```bash
|
| 60 |
-
doc-builder preview lerobot docs/source/
|
| 61 |
-
```
|
| 62 |
-
|
| 63 |
-
The docs will be viewable at [http://localhost:3000](http://localhost:3000). You can also preview the docs once you have opened a PR. You will see a bot add a comment to a link where the documentation with your changes lives.
|
| 64 |
-
|
| 65 |
-
---
|
| 66 |
-
**NOTE**
|
| 67 |
-
|
| 68 |
-
The `preview` command only works with existing doc files. When you add a completely new file, you need to update `_toctree.yml` & restart `preview` command (`ctrl-c` to stop it & call `doc-builder preview ...` again).
|
| 69 |
-
|
| 70 |
-
---
|
| 71 |
-
|
| 72 |
-
## Adding a new element to the navigation bar
|
| 73 |
-
|
| 74 |
-
Accepted files are Markdown (.md).
|
| 75 |
-
|
| 76 |
-
Create a file with its extension and put it in the source directory. You can then link it to the toc-tree by putting
|
| 77 |
-
the filename without the extension in the [`_toctree.yml`](https://github.com/huggingface/lerobot/blob/main/docs/source/_toctree.yml) file.
|
| 78 |
-
|
| 79 |
-
## Renaming section headers and moving sections
|
| 80 |
-
|
| 81 |
-
It helps to keep the old links working when renaming the section header and/or moving sections from one document to another. This is because the old links are likely to be used in Issues, Forums, and Social media and it'd make for a much more superior user experience if users reading those months later could still easily navigate to the originally intended information.
|
| 82 |
-
|
| 83 |
-
Therefore, we simply keep a little map of moved sections at the end of the document where the original section was. The key is to preserve the original anchor.
|
| 84 |
-
|
| 85 |
-
So if you renamed a section from: "Section A" to "Section B", then you can add at the end of the file:
|
| 86 |
-
|
| 87 |
-
```
|
| 88 |
-
Sections that were moved:
|
| 89 |
-
|
| 90 |
-
[ <a href="#section-b">Section A</a><a id="section-a"></a> ]
|
| 91 |
-
```
|
| 92 |
-
and of course, if you moved it to another file, then:
|
| 93 |
-
|
| 94 |
-
```
|
| 95 |
-
Sections that were moved:
|
| 96 |
-
|
| 97 |
-
[ <a href="../new-file#section-b">Section A</a><a id="section-a"></a> ]
|
| 98 |
-
```
|
| 99 |
-
|
| 100 |
-
Use the relative style to link to the new file so that the versioned docs continue to work.
|
| 101 |
-
|
| 102 |
-
For an example of a rich moved sections set please see the very end of [the transformers Trainer doc](https://github.com/huggingface/transformers/blob/main/docs/source/en/main_classes/trainer.md).
|
| 103 |
-
|
| 104 |
-
### Adding a new tutorial
|
| 105 |
-
|
| 106 |
-
Adding a new tutorial or section is done in two steps:
|
| 107 |
-
|
| 108 |
-
- Add a new file under `./source`. This file can either be ReStructuredText (.rst) or Markdown (.md).
|
| 109 |
-
- Link that file in `./source/_toctree.yml` on the correct toc-tree.
|
| 110 |
-
|
| 111 |
-
Make sure to put your new file under the proper section. If you have a doubt, feel free to ask in a Github Issue or PR.
|
| 112 |
-
|
| 113 |
-
### Writing source documentation
|
| 114 |
-
|
| 115 |
-
Values that should be put in `code` should either be surrounded by backticks: \`like so\`. Note that argument names
|
| 116 |
-
and objects like True, None or any strings should usually be put in `code`.
|
| 117 |
-
|
| 118 |
-
#### Writing a multi-line code block
|
| 119 |
-
|
| 120 |
-
Multi-line code blocks can be useful for displaying examples. They are done between two lines of three backticks as usual in Markdown:
|
| 121 |
-
|
| 122 |
-
|
| 123 |
-
````
|
| 124 |
-
```
|
| 125 |
-
# first line of code
|
| 126 |
-
# second line
|
| 127 |
-
# etc
|
| 128 |
-
```
|
| 129 |
-
````
|
| 130 |
-
|
| 131 |
-
#### Adding an image
|
| 132 |
-
|
| 133 |
-
Due to the rapidly growing repository, it is important to make sure that no files that would significantly weigh down the repository are added. This includes images, videos, and other non-text files. We prefer to leverage a hf.co hosted `dataset` like
|
| 134 |
-
the ones hosted on [`hf-internal-testing`](https://huggingface.co/hf-internal-testing) in which to place these files and reference
|
| 135 |
-
them by URL. We recommend putting them in the following dataset: [huggingface/documentation-images](https://huggingface.co/datasets/huggingface/documentation-images).
|
| 136 |
-
If an external contribution, feel free to add the images to your PR and ask a Hugging Face member to migrate your images
|
| 137 |
-
to this dataset.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/_toctree.yml
DELETED
|
@@ -1,44 +0,0 @@
|
|
| 1 |
-
- sections:
|
| 2 |
-
- local: index
|
| 3 |
-
title: LeRobot
|
| 4 |
-
- local: installation
|
| 5 |
-
title: Installation
|
| 6 |
-
title: Get started
|
| 7 |
-
- sections:
|
| 8 |
-
- local: il_robots
|
| 9 |
-
title: Imitation Learning for Robots
|
| 10 |
-
- local: il_sim
|
| 11 |
-
title: Imitation Learning in Sim
|
| 12 |
-
- local: cameras
|
| 13 |
-
title: Cameras
|
| 14 |
-
- local: integrate_hardware
|
| 15 |
-
title: Bring Your Own Hardware
|
| 16 |
-
- local: hilserl
|
| 17 |
-
title: Train a Robot with RL
|
| 18 |
-
- local: hilserl_sim
|
| 19 |
-
title: Train RL in Simulation
|
| 20 |
-
title: "Tutorials"
|
| 21 |
-
- sections:
|
| 22 |
-
- local: smolvla
|
| 23 |
-
title: Finetune SmolVLA
|
| 24 |
-
title: "Policies"
|
| 25 |
-
- sections:
|
| 26 |
-
- local: so101
|
| 27 |
-
title: SO-101
|
| 28 |
-
- local: so100
|
| 29 |
-
title: SO-100
|
| 30 |
-
- local: koch
|
| 31 |
-
title: Koch v1.1
|
| 32 |
-
- local: lekiwi
|
| 33 |
-
title: LeKiwi
|
| 34 |
-
title: "Robots"
|
| 35 |
-
- sections:
|
| 36 |
-
- local: notebooks
|
| 37 |
-
title: Notebooks
|
| 38 |
-
title: "Resources"
|
| 39 |
-
- sections:
|
| 40 |
-
- local: contributing
|
| 41 |
-
title: Contribute to LeRobot
|
| 42 |
-
- local: backwardcomp
|
| 43 |
-
title: Backward compatibility
|
| 44 |
-
title: "About"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/backwardcomp.mdx
DELETED
|
@@ -1,82 +0,0 @@
|
|
| 1 |
-
# Backward compatibility
|
| 2 |
-
|
| 3 |
-
## Hardware API redesign
|
| 4 |
-
|
| 5 |
-
PR [#777](https://github.com/huggingface/lerobot/pull/777) improves the LeRobot calibration but is **not backward-compatible**. Below is a overview of what changed and how you can continue to work with datasets created before this pull request.
|
| 6 |
-
|
| 7 |
-
### What changed?
|
| 8 |
-
|
| 9 |
-
| | Before PR #777 | After PR #777 |
|
| 10 |
-
| --------------------------------- | ------------------------------------------------- | --------------------------------------------------------------------------- |
|
| 11 |
-
| **Joint range** | Degrees `-180...180°` | **Normalised range** Joints: `–100...100` Gripper: `0...100` |
|
| 12 |
-
| **Zero position (SO100 / SO101)** | Arm fully extended horizontally | **In middle of the range for each joint** |
|
| 13 |
-
| **Boundary handling** | Software safeguards to detect ±180 ° wrap-arounds | No wrap-around logic needed due to mid-range zero |
|
| 14 |
-
|
| 15 |
-
---
|
| 16 |
-
|
| 17 |
-
### Impact on existing datasets
|
| 18 |
-
|
| 19 |
-
* Recorded trajectories created **before** PR #777 will replay incorrectly if loaded directly:
|
| 20 |
-
* Joint angles are offset and incorrectly normalized.
|
| 21 |
-
* Any models directly finetuned or trained on the old data will need their inputs and outputs converted.
|
| 22 |
-
|
| 23 |
-
### Using datasets made with the previous calibration system
|
| 24 |
-
We provide a migration example script for replaying an episode recorded with the previous calibration here: `examples/backward_compatibility/replay.py`.
|
| 25 |
-
Below we take you through the modifications that are done in the example script to make the previous calibration datasets work.
|
| 26 |
-
|
| 27 |
-
```diff
|
| 28 |
-
+ key = f"{name.removeprefix('main_')}.pos"
|
| 29 |
-
action[key] = action_array[i].item()
|
| 30 |
-
+ action["shoulder_lift.pos"] = -(action["shoulder_lift.pos"] - 90)
|
| 31 |
-
+ action["elbow_flex.pos"] -= 90
|
| 32 |
-
```
|
| 33 |
-
|
| 34 |
-
Let's break this down.
|
| 35 |
-
New codebase uses `.pos` suffix for the position observations and we have removed `main_` prefix:
|
| 36 |
-
```python
|
| 37 |
-
key = f"{name.removeprefix('main_')}.pos"
|
| 38 |
-
```
|
| 39 |
-
|
| 40 |
-
For `"shoulder_lift"` (id = 2), the 0 position is changed by -90 degrees and the direction is reversed compared to old calibration/code.
|
| 41 |
-
```python
|
| 42 |
-
action["shoulder_lift.pos"] = -(action["shoulder_lift.pos"] - 90)
|
| 43 |
-
```
|
| 44 |
-
For `"elbow_flex"` (id = 3), the 0 position is changed by -90 degrees compared to old calibration/code.
|
| 45 |
-
```python
|
| 46 |
-
action["elbow_flex.pos"] -= 90
|
| 47 |
-
```
|
| 48 |
-
|
| 49 |
-
To use degrees normalization we then set the `--robot.use_degrees` option to `true`.
|
| 50 |
-
```diff
|
| 51 |
-
python examples/backward_compatibility/replay.py \
|
| 52 |
-
--robot.type=so101_follower \
|
| 53 |
-
--robot.port=/dev/tty.usbmodem5A460814411 \
|
| 54 |
-
--robot.id=blue \
|
| 55 |
-
+ --robot.use_degrees=true \
|
| 56 |
-
--dataset.repo_id=my_dataset_id \
|
| 57 |
-
--dataset.episode=0
|
| 58 |
-
```
|
| 59 |
-
|
| 60 |
-
### Using policies trained with the previous calibration system
|
| 61 |
-
|
| 62 |
-
Policies output actions in the same format as the datasets (`torch.Tensors`). Therefore, the same transformations should be applied.
|
| 63 |
-
|
| 64 |
-
To find these transformations, we recommend to first try and and replay an episode of the dataset your policy was trained on using the section above.
|
| 65 |
-
Then, add these same transformations on your inference script (shown here in the `record.py` script):
|
| 66 |
-
```diff
|
| 67 |
-
action_values = predict_action(
|
| 68 |
-
observation_frame,
|
| 69 |
-
policy,
|
| 70 |
-
get_safe_torch_device(policy.config.device),
|
| 71 |
-
policy.config.use_amp,
|
| 72 |
-
task=single_task,
|
| 73 |
-
robot_type=robot.robot_type,
|
| 74 |
-
)
|
| 75 |
-
action = {key: action_values[i].item() for i, key in enumerate(robot.action_features)}
|
| 76 |
-
|
| 77 |
-
+ action["shoulder_lift.pos"] = -(action["shoulder_lift.pos"] - 90)
|
| 78 |
-
+ action["elbow_flex.pos"] -= 90
|
| 79 |
-
robot.send_action(action)
|
| 80 |
-
```
|
| 81 |
-
|
| 82 |
-
If you have questions or run into migration issues, feel free to ask them on [Discord](https://discord.gg/s3KuuzsPFb)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/cameras.mdx
DELETED
|
@@ -1,173 +0,0 @@
|
|
| 1 |
-
# Cameras
|
| 2 |
-
|
| 3 |
-
LeRobot offers multiple options for video capture, including phone cameras, built-in laptop cameras, external webcams, and Intel RealSense cameras. To efficiently record frames from most cameras, you can use either the `OpenCVCamera` or `RealSenseCamera` class. For additional compatibility details on the `OpenCVCamera` class, refer to the [Video I/O with OpenCV Overview](https://docs.opencv.org/4.x/d0/da7/videoio_overview.html).
|
| 4 |
-
|
| 5 |
-
### Finding your camera
|
| 6 |
-
|
| 7 |
-
To instantiate a camera, you need a camera identifier. This identifier might change if you reboot your computer or re-plug your camera, a behavior mostly dependant on your operating system.
|
| 8 |
-
|
| 9 |
-
To find the camera indices of the cameras plugged into your system, run the following script:
|
| 10 |
-
```bash
|
| 11 |
-
python lerobot/find_cameras.py opencv # or realsense for Intel Realsense cameras
|
| 12 |
-
```
|
| 13 |
-
|
| 14 |
-
The output will look something like this if you have two cameras connected:
|
| 15 |
-
```
|
| 16 |
-
--- Detected Cameras ---
|
| 17 |
-
Camera #0:
|
| 18 |
-
Name: OpenCV Camera @ 0
|
| 19 |
-
Type: OpenCV
|
| 20 |
-
Id: 0
|
| 21 |
-
Backend api: AVFOUNDATION
|
| 22 |
-
Default stream profile:
|
| 23 |
-
Format: 16.0
|
| 24 |
-
Width: 1920
|
| 25 |
-
Height: 1080
|
| 26 |
-
Fps: 15.0
|
| 27 |
-
--------------------
|
| 28 |
-
(more cameras ...)
|
| 29 |
-
```
|
| 30 |
-
|
| 31 |
-
> [!WARNING]
|
| 32 |
-
> When using Intel RealSense cameras in `macOS`, you could get this [error](https://github.com/IntelRealSense/librealsense/issues/12307): `Error finding RealSense cameras: failed to set power state`, this can be solved by running the same command with `sudo` permissions. Note that using RealSense cameras in `macOS` is unstable.
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
## Use Cameras
|
| 36 |
-
|
| 37 |
-
Below are two examples, demonstrating how to work with the API.
|
| 38 |
-
|
| 39 |
-
- **Asynchronous frame capture** using an OpenCV-based camera
|
| 40 |
-
- **Color and depth capture** using an Intel RealSense camera
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
<hfoptions id="shell_restart">
|
| 44 |
-
<hfoption id="Open CV Camera">
|
| 45 |
-
|
| 46 |
-
```python
|
| 47 |
-
from lerobot.common.cameras.opencv.configuration_opencv import OpenCVCameraConfig
|
| 48 |
-
from lerobot.common.cameras.opencv.camera_opencv import OpenCVCamera
|
| 49 |
-
from lerobot.common.cameras.configs import ColorMode, Cv2Rotation
|
| 50 |
-
|
| 51 |
-
# Construct an `OpenCVCameraConfig` with your desired FPS, resolution, color mode, and rotation.
|
| 52 |
-
config = OpenCVCameraConfig(
|
| 53 |
-
index_or_path=0,
|
| 54 |
-
fps=15,
|
| 55 |
-
width=1920,
|
| 56 |
-
height=1080,
|
| 57 |
-
color_mode=ColorMode.RGB,
|
| 58 |
-
rotation=Cv2Rotation.NO_ROTATION
|
| 59 |
-
)
|
| 60 |
-
|
| 61 |
-
# Instantiate and connect an `OpenCVCamera`, performing a warm-up read (default).
|
| 62 |
-
camera = OpenCVCamera(config)
|
| 63 |
-
camera.connect()
|
| 64 |
-
|
| 65 |
-
# Read frames asynchronously in a loop via `async_read(timeout_ms)`
|
| 66 |
-
try:
|
| 67 |
-
for i in range(10):
|
| 68 |
-
frame = camera.async_read(timeout_ms=200)
|
| 69 |
-
print(f"Async frame {i} shape:", frame.shape)
|
| 70 |
-
finally:
|
| 71 |
-
camera.disconnect()
|
| 72 |
-
```
|
| 73 |
-
|
| 74 |
-
</hfoption>
|
| 75 |
-
<hfoption id="Intel Realsense Camera">
|
| 76 |
-
|
| 77 |
-
```python
|
| 78 |
-
from lerobot.common.cameras.realsense.configuration_realsense import RealSenseCameraConfig
|
| 79 |
-
from lerobot.common.cameras.realsense.camera_realsense import RealSenseCamera
|
| 80 |
-
from lerobot.common.cameras.configs import ColorMode, Cv2Rotation
|
| 81 |
-
|
| 82 |
-
# Create a `RealSenseCameraConfig` specifying your camera’s serial number and enabling depth.
|
| 83 |
-
config = RealSenseCameraConfig(
|
| 84 |
-
serial_number_or_name="233522074606",
|
| 85 |
-
fps=15,
|
| 86 |
-
width=640,
|
| 87 |
-
height=480,
|
| 88 |
-
color_mode=ColorMode.RGB,
|
| 89 |
-
use_depth=True,
|
| 90 |
-
rotation=Cv2Rotation.NO_ROTATION
|
| 91 |
-
)
|
| 92 |
-
|
| 93 |
-
# Instantiate and connect a `RealSenseCamera` with warm-up read (default).
|
| 94 |
-
camera = RealSenseCamera(config)
|
| 95 |
-
camera.connect()
|
| 96 |
-
|
| 97 |
-
# Capture a color frame via `read()` and a depth map via `read_depth()`.
|
| 98 |
-
try:
|
| 99 |
-
color_frame = camera.read()
|
| 100 |
-
depth_map = camera.read_depth()
|
| 101 |
-
print("Color frame shape:", color_frame.shape)
|
| 102 |
-
print("Depth map shape:", depth_map.shape)
|
| 103 |
-
finally:
|
| 104 |
-
camera.disconnect()
|
| 105 |
-
```
|
| 106 |
-
</hfoption>
|
| 107 |
-
</hfoptions>
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
## Use your phone
|
| 111 |
-
<hfoptions id="use phone">
|
| 112 |
-
<hfoption id="Mac">
|
| 113 |
-
|
| 114 |
-
To use your iPhone as a camera on macOS, enable the Continuity Camera feature:
|
| 115 |
-
- Ensure your Mac is running macOS 13 or later, and your iPhone is on iOS 16 or later.
|
| 116 |
-
- Sign in both devices with the same Apple ID.
|
| 117 |
-
- Connect your devices with a USB cable or turn on Wi-Fi and Bluetooth for a wireless connection.
|
| 118 |
-
|
| 119 |
-
For more details, visit [Apple support](https://support.apple.com/en-gb/guide/mac-help/mchl77879b8a/mac).
|
| 120 |
-
|
| 121 |
-
Your iPhone should be detected automatically when running the camera setup script in the next section.
|
| 122 |
-
|
| 123 |
-
</hfoption>
|
| 124 |
-
<hfoption id="Linux">
|
| 125 |
-
|
| 126 |
-
If you want to use your phone as a camera on Linux, follow these steps to set up a virtual camera
|
| 127 |
-
|
| 128 |
-
1. *Install `v4l2loopback-dkms` and `v4l-utils`*. Those packages are required to create virtual camera devices (`v4l2loopback`) and verify their settings with the `v4l2-ctl` utility from `v4l-utils`. Install them using:
|
| 129 |
-
```python
|
| 130 |
-
sudo apt install v4l2loopback-dkms v4l-utils
|
| 131 |
-
```
|
| 132 |
-
2. *Install [DroidCam](https://droidcam.app) on your phone*. This app is available for both iOS and Android.
|
| 133 |
-
3. *Install [OBS Studio](https://obsproject.com)*. This software will help you manage the camera feed. Install it using [Flatpak](https://flatpak.org):
|
| 134 |
-
```python
|
| 135 |
-
flatpak install flathub com.obsproject.Studio
|
| 136 |
-
```
|
| 137 |
-
4. *Install the DroidCam OBS plugin*. This plugin integrates DroidCam with OBS Studio. Install it with:
|
| 138 |
-
```python
|
| 139 |
-
flatpak install flathub com.obsproject.Studio.Plugin.DroidCam
|
| 140 |
-
```
|
| 141 |
-
5. *Start OBS Studio*. Launch with:
|
| 142 |
-
```python
|
| 143 |
-
flatpak run com.obsproject.Studio
|
| 144 |
-
```
|
| 145 |
-
6. *Add your phone as a source*. Follow the instructions [here](https://droidcam.app/obs/usage). Be sure to set the resolution to `640x480`.
|
| 146 |
-
7. *Adjust resolution settings*. In OBS Studio, go to `File > Settings > Video`. Change the `Base(Canvas) Resolution` and the `Output(Scaled) Resolution` to `640x480` by manually typing it in.
|
| 147 |
-
8. *Start virtual camera*. In OBS Studio, follow the instructions [here](https://obsproject.com/kb/virtual-camera-guide).
|
| 148 |
-
9. *Verify the virtual camera setup*. Use `v4l2-ctl` to list the devices:
|
| 149 |
-
```python
|
| 150 |
-
v4l2-ctl --list-devices
|
| 151 |
-
```
|
| 152 |
-
You should see an entry like:
|
| 153 |
-
```
|
| 154 |
-
VirtualCam (platform:v4l2loopback-000):
|
| 155 |
-
/dev/video1
|
| 156 |
-
```
|
| 157 |
-
10. *Check the camera resolution*. Use `v4l2-ctl` to ensure that the virtual camera output resolution is `640x480`. Change `/dev/video1` to the port of your virtual camera from the output of `v4l2-ctl --list-devices`.
|
| 158 |
-
```python
|
| 159 |
-
v4l2-ctl -d /dev/video1 --get-fmt-video
|
| 160 |
-
```
|
| 161 |
-
You should see an entry like:
|
| 162 |
-
```
|
| 163 |
-
>>> Format Video Capture:
|
| 164 |
-
>>> Width/Height : 640/480
|
| 165 |
-
>>> Pixel Format : 'YUYV' (YUYV 4:2:2)
|
| 166 |
-
```
|
| 167 |
-
|
| 168 |
-
Troubleshooting: If the resolution is not correct you will have to delete the Virtual Camera port and try again as it cannot be changed.
|
| 169 |
-
|
| 170 |
-
If everything is set up correctly, you can proceed with the rest of the tutorial.
|
| 171 |
-
|
| 172 |
-
</hfoption>
|
| 173 |
-
</hfoptions>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/contributing.md
DELETED
|
@@ -1,305 +0,0 @@
|
|
| 1 |
-
# How to contribute to 🤗 LeRobot?
|
| 2 |
-
|
| 3 |
-
Everyone is welcome to contribute, and we value everybody's contribution. Code
|
| 4 |
-
is thus not the only way to help the community. Answering questions, helping
|
| 5 |
-
others, reaching out and improving the documentations are immensely valuable to
|
| 6 |
-
the community.
|
| 7 |
-
|
| 8 |
-
It also helps us if you spread the word: reference the library from blog posts
|
| 9 |
-
on the awesome projects it made possible, shout out on Twitter when it has
|
| 10 |
-
helped you, or simply ⭐️ the repo to say "thank you".
|
| 11 |
-
|
| 12 |
-
Whichever way you choose to contribute, please be mindful to respect our
|
| 13 |
-
[code of conduct](https://github.com/huggingface/lerobot/blob/main/CODE_OF_CONDUCT.md).
|
| 14 |
-
|
| 15 |
-
## You can contribute in so many ways!
|
| 16 |
-
|
| 17 |
-
Some of the ways you can contribute to 🤗 LeRobot:
|
| 18 |
-
* Fixing outstanding issues with the existing code.
|
| 19 |
-
* Implementing new models, datasets or simulation environments.
|
| 20 |
-
* Contributing to the examples or to the documentation.
|
| 21 |
-
* Submitting issues related to bugs or desired new features.
|
| 22 |
-
|
| 23 |
-
Following the guides below, feel free to open issues and PRs and to coordinate your efforts with the community on our [Discord Channel](https://discord.gg/VjFz58wn3R). For specific inquiries, reach out to [Remi Cadene](mailto:remi.cadene@huggingface.co).
|
| 24 |
-
|
| 25 |
-
If you are not sure how to contribute or want to know the next features we working on, look on this project page: [LeRobot TODO](https://github.com/orgs/huggingface/projects/46)
|
| 26 |
-
|
| 27 |
-
## Submitting a new issue or feature request
|
| 28 |
-
|
| 29 |
-
Do your best to follow these guidelines when submitting an issue or a feature
|
| 30 |
-
request. It will make it easier for us to come back to you quickly and with good
|
| 31 |
-
feedback.
|
| 32 |
-
|
| 33 |
-
### Did you find a bug?
|
| 34 |
-
|
| 35 |
-
The 🤗 LeRobot library is robust and reliable thanks to the users who notify us of
|
| 36 |
-
the problems they encounter. So thank you for reporting an issue.
|
| 37 |
-
|
| 38 |
-
First, we would really appreciate it if you could **make sure the bug was not
|
| 39 |
-
already reported** (use the search bar on Github under Issues).
|
| 40 |
-
|
| 41 |
-
Did not find it? :( So we can act quickly on it, please follow these steps:
|
| 42 |
-
|
| 43 |
-
* Include your **OS type and version**, the versions of **Python** and **PyTorch**.
|
| 44 |
-
* A short, self-contained, code snippet that allows us to reproduce the bug in
|
| 45 |
-
less than 30s.
|
| 46 |
-
* The full traceback if an exception is raised.
|
| 47 |
-
* Attach any other additional information, like screenshots, you think may help.
|
| 48 |
-
|
| 49 |
-
### Do you want a new feature?
|
| 50 |
-
|
| 51 |
-
A good feature request addresses the following points:
|
| 52 |
-
|
| 53 |
-
1. Motivation first:
|
| 54 |
-
* Is it related to a problem/frustration with the library? If so, please explain
|
| 55 |
-
why. Providing a code snippet that demonstrates the problem is best.
|
| 56 |
-
* Is it related to something you would need for a project? We'd love to hear
|
| 57 |
-
about it!
|
| 58 |
-
* Is it something you worked on and think could benefit the community?
|
| 59 |
-
Awesome! Tell us what problem it solved for you.
|
| 60 |
-
2. Write a *paragraph* describing the feature.
|
| 61 |
-
3. Provide a **code snippet** that demonstrates its future use.
|
| 62 |
-
4. In case this is related to a paper, please attach a link.
|
| 63 |
-
5. Attach any additional information (drawings, screenshots, etc.) you think may help.
|
| 64 |
-
|
| 65 |
-
If your issue is well written we're already 80% of the way there by the time you
|
| 66 |
-
post it.
|
| 67 |
-
|
| 68 |
-
## Adding new policies, datasets or environments
|
| 69 |
-
|
| 70 |
-
Look at our implementations for [datasets](./lerobot/common/datasets/), [policies](./lerobot/common/policies/),
|
| 71 |
-
environments ([aloha](https://github.com/huggingface/gym-aloha),
|
| 72 |
-
[xarm](https://github.com/huggingface/gym-xarm),
|
| 73 |
-
[pusht](https://github.com/huggingface/gym-pusht))
|
| 74 |
-
and follow the same api design.
|
| 75 |
-
|
| 76 |
-
When implementing a new dataset loadable with LeRobotDataset follow these steps:
|
| 77 |
-
- Update `available_datasets_per_env` in `lerobot/__init__.py`
|
| 78 |
-
|
| 79 |
-
When implementing a new environment (e.g. `gym_aloha`), follow these steps:
|
| 80 |
-
- Update `available_tasks_per_env` and `available_datasets_per_env` in `lerobot/__init__.py`
|
| 81 |
-
|
| 82 |
-
When implementing a new policy class (e.g. `DiffusionPolicy`) follow these steps:
|
| 83 |
-
- Update `available_policies` and `available_policies_per_env`, in `lerobot/__init__.py`
|
| 84 |
-
- Set the required `name` class attribute.
|
| 85 |
-
- Update variables in `tests/test_available.py` by importing your new Policy class
|
| 86 |
-
|
| 87 |
-
## Submitting a pull request (PR)
|
| 88 |
-
|
| 89 |
-
Before writing code, we strongly advise you to search through the existing PRs or
|
| 90 |
-
issues to make sure that nobody is already working on the same thing. If you are
|
| 91 |
-
unsure, it is always a good idea to open an issue to get some feedback.
|
| 92 |
-
|
| 93 |
-
You will need basic `git` proficiency to be able to contribute to
|
| 94 |
-
🤗 LeRobot. `git` is not the easiest tool to use but it has the greatest
|
| 95 |
-
manual. Type `git --help` in a shell and enjoy. If you prefer books, [Pro
|
| 96 |
-
Git](https://git-scm.com/book/en/v2) is a very good reference.
|
| 97 |
-
|
| 98 |
-
Follow these steps to start contributing:
|
| 99 |
-
|
| 100 |
-
1. Fork the [repository](https://github.com/huggingface/lerobot) by
|
| 101 |
-
clicking on the 'Fork' button on the repository's page. This creates a copy of the code
|
| 102 |
-
under your GitHub user account.
|
| 103 |
-
|
| 104 |
-
2. Clone your fork to your local disk, and add the base repository as a remote. The following command
|
| 105 |
-
assumes you have your public SSH key uploaded to GitHub. See the following guide for more
|
| 106 |
-
[information](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository).
|
| 107 |
-
|
| 108 |
-
```bash
|
| 109 |
-
git clone git@github.com:<your Github handle>/lerobot.git
|
| 110 |
-
cd lerobot
|
| 111 |
-
git remote add upstream https://github.com/huggingface/lerobot.git
|
| 112 |
-
```
|
| 113 |
-
|
| 114 |
-
3. Create a new branch to hold your development changes, and do this for every new PR you work on.
|
| 115 |
-
|
| 116 |
-
Start by synchronizing your `main` branch with the `upstream/main` branch (more details in the [GitHub Docs](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/syncing-a-fork)):
|
| 117 |
-
|
| 118 |
-
```bash
|
| 119 |
-
git checkout main
|
| 120 |
-
git fetch upstream
|
| 121 |
-
git rebase upstream/main
|
| 122 |
-
```
|
| 123 |
-
|
| 124 |
-
Once your `main` branch is synchronized, create a new branch from it:
|
| 125 |
-
|
| 126 |
-
```bash
|
| 127 |
-
git checkout -b a-descriptive-name-for-my-changes
|
| 128 |
-
```
|
| 129 |
-
|
| 130 |
-
🚨 **Do not** work on the `main` branch.
|
| 131 |
-
|
| 132 |
-
4. for development, we advise to use a tool like `poetry` or `uv` instead of just `pip` to easily track our dependencies.
|
| 133 |
-
Follow the instructions to [install poetry](https://python-poetry.org/docs/#installation) (use a version >=2.1.0) or to [install uv](https://docs.astral.sh/uv/getting-started/installation/#installation-methods) if you don't have one of them already.
|
| 134 |
-
|
| 135 |
-
Set up a development environment with conda or miniconda:
|
| 136 |
-
```bash
|
| 137 |
-
conda create -y -n lerobot-dev python=3.10 && conda activate lerobot-dev
|
| 138 |
-
```
|
| 139 |
-
|
| 140 |
-
If you're using `uv`, it can manage python versions so you can instead do:
|
| 141 |
-
```bash
|
| 142 |
-
uv venv --python 3.10 && source .venv/bin/activate
|
| 143 |
-
```
|
| 144 |
-
|
| 145 |
-
To develop on 🤗 LeRobot, you will at least need to install the `dev` and `test` extras dependencies along with the core library:
|
| 146 |
-
|
| 147 |
-
using `poetry`
|
| 148 |
-
```bash
|
| 149 |
-
poetry sync --extras "dev test"
|
| 150 |
-
```
|
| 151 |
-
|
| 152 |
-
using `uv`
|
| 153 |
-
```bash
|
| 154 |
-
uv sync --extra dev --extra test
|
| 155 |
-
```
|
| 156 |
-
|
| 157 |
-
You can also install the project with all its dependencies (including environments):
|
| 158 |
-
|
| 159 |
-
using `poetry`
|
| 160 |
-
```bash
|
| 161 |
-
poetry sync --all-extras
|
| 162 |
-
```
|
| 163 |
-
|
| 164 |
-
using `uv`
|
| 165 |
-
```bash
|
| 166 |
-
uv sync --all-extras
|
| 167 |
-
```
|
| 168 |
-
|
| 169 |
-
> **Note:** If you don't install simulation environments with `--all-extras`, the tests that require them will be skipped when running the pytest suite locally. However, they *will* be tested in the CI. In general, we advise you to install everything and test locally before pushing.
|
| 170 |
-
|
| 171 |
-
Whichever command you chose to install the project (e.g. `poetry sync --all-extras`), you should run it again when pulling code with an updated version of `pyproject.toml` and `poetry.lock` in order to synchronize your virtual environment with the new dependencies.
|
| 172 |
-
|
| 173 |
-
The equivalent of `pip install some-package`, would just be:
|
| 174 |
-
|
| 175 |
-
using `poetry`
|
| 176 |
-
```bash
|
| 177 |
-
poetry add some-package
|
| 178 |
-
```
|
| 179 |
-
|
| 180 |
-
using `uv`
|
| 181 |
-
```bash
|
| 182 |
-
uv add some-package
|
| 183 |
-
```
|
| 184 |
-
|
| 185 |
-
When making changes to the poetry sections of the `pyproject.toml`, you should run the following command to lock dependencies.
|
| 186 |
-
using `poetry`
|
| 187 |
-
```bash
|
| 188 |
-
poetry lock
|
| 189 |
-
```
|
| 190 |
-
|
| 191 |
-
using `uv`
|
| 192 |
-
```bash
|
| 193 |
-
uv lock
|
| 194 |
-
```
|
| 195 |
-
|
| 196 |
-
|
| 197 |
-
5. Develop the features on your branch.
|
| 198 |
-
|
| 199 |
-
As you work on the features, you should make sure that the test suite
|
| 200 |
-
passes. You should run the tests impacted by your changes like this (see
|
| 201 |
-
below an explanation regarding the environment variable):
|
| 202 |
-
|
| 203 |
-
```bash
|
| 204 |
-
pytest tests/<TEST_TO_RUN>.py
|
| 205 |
-
```
|
| 206 |
-
|
| 207 |
-
6. Follow our style.
|
| 208 |
-
|
| 209 |
-
`lerobot` relies on `ruff` to format its source code
|
| 210 |
-
consistently. Set up [`pre-commit`](https://pre-commit.com/) to run these checks
|
| 211 |
-
automatically as Git commit hooks.
|
| 212 |
-
|
| 213 |
-
Install `pre-commit` hooks:
|
| 214 |
-
```bash
|
| 215 |
-
pre-commit install
|
| 216 |
-
```
|
| 217 |
-
|
| 218 |
-
You can run these hooks whenever you need on staged files with:
|
| 219 |
-
```bash
|
| 220 |
-
pre-commit
|
| 221 |
-
```
|
| 222 |
-
|
| 223 |
-
Once you're happy with your changes, add changed files using `git add` and
|
| 224 |
-
make a commit with `git commit` to record your changes locally:
|
| 225 |
-
|
| 226 |
-
```bash
|
| 227 |
-
git add modified_file.py
|
| 228 |
-
git commit
|
| 229 |
-
```
|
| 230 |
-
|
| 231 |
-
Note, if you already committed some changes that have a wrong formatting, you can use:
|
| 232 |
-
```bash
|
| 233 |
-
pre-commit run --all-files
|
| 234 |
-
```
|
| 235 |
-
|
| 236 |
-
Please write [good commit messages](https://chris.beams.io/posts/git-commit/).
|
| 237 |
-
|
| 238 |
-
It is a good idea to sync your copy of the code with the original
|
| 239 |
-
repository regularly. This way you can quickly account for changes:
|
| 240 |
-
|
| 241 |
-
```bash
|
| 242 |
-
git fetch upstream
|
| 243 |
-
git rebase upstream/main
|
| 244 |
-
```
|
| 245 |
-
|
| 246 |
-
Push the changes to your account using:
|
| 247 |
-
|
| 248 |
-
```bash
|
| 249 |
-
git push -u origin a-descriptive-name-for-my-changes
|
| 250 |
-
```
|
| 251 |
-
|
| 252 |
-
6. Once you are satisfied (**and the checklist below is happy too**), go to the
|
| 253 |
-
webpage of your fork on GitHub. Click on 'Pull request' to send your changes
|
| 254 |
-
to the project maintainers for review.
|
| 255 |
-
|
| 256 |
-
7. It's ok if maintainers ask you for changes. It happens to core contributors
|
| 257 |
-
too! So everyone can see the changes in the Pull request, work in your local
|
| 258 |
-
branch and push the changes to your fork. They will automatically appear in
|
| 259 |
-
the pull request.
|
| 260 |
-
|
| 261 |
-
|
| 262 |
-
### Checklist
|
| 263 |
-
|
| 264 |
-
1. The title of your pull request should be a summary of its contribution;
|
| 265 |
-
2. If your pull request addresses an issue, please mention the issue number in
|
| 266 |
-
the pull request description to make sure they are linked (and people
|
| 267 |
-
consulting the issue know you are working on it);
|
| 268 |
-
3. To indicate a work in progress please prefix the title with `[WIP]`, or preferably mark
|
| 269 |
-
the PR as a draft PR. These are useful to avoid duplicated work, and to differentiate
|
| 270 |
-
it from PRs ready to be merged;
|
| 271 |
-
4. Make sure existing tests pass;
|
| 272 |
-
|
| 273 |
-
### Tests
|
| 274 |
-
|
| 275 |
-
An extensive test suite is included to test the library behavior and several examples. Library tests can be found in the [tests folder](https://github.com/huggingface/lerobot/tree/main/tests).
|
| 276 |
-
|
| 277 |
-
Install [git lfs](https://git-lfs.com/) to retrieve test artifacts (if you don't have it already).
|
| 278 |
-
|
| 279 |
-
On Mac:
|
| 280 |
-
```bash
|
| 281 |
-
brew install git-lfs
|
| 282 |
-
git lfs install
|
| 283 |
-
```
|
| 284 |
-
|
| 285 |
-
On Ubuntu:
|
| 286 |
-
```bash
|
| 287 |
-
sudo apt-get install git-lfs
|
| 288 |
-
git lfs install
|
| 289 |
-
```
|
| 290 |
-
|
| 291 |
-
Pull artifacts if they're not in [tests/artifacts](tests/artifacts)
|
| 292 |
-
```bash
|
| 293 |
-
git lfs pull
|
| 294 |
-
```
|
| 295 |
-
|
| 296 |
-
We use `pytest` in order to run the tests. From the root of the
|
| 297 |
-
repository, here's how to run tests with `pytest` for the library:
|
| 298 |
-
|
| 299 |
-
```bash
|
| 300 |
-
python -m pytest -sv ./tests
|
| 301 |
-
```
|
| 302 |
-
|
| 303 |
-
|
| 304 |
-
You can specify a smaller set of tests in order to test only the feature
|
| 305 |
-
you're working on.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/hilserl.mdx
DELETED
|
@@ -1,547 +0,0 @@
|
|
| 1 |
-
# HIL-SERL Real Robot Training Workflow Guide
|
| 2 |
-
|
| 3 |
-
In this tutorial you will go through the full Human-in-the-Loop Sample-Efficient Reinforcement Learning (HIL-SERL) workflow using LeRobot. You will master training a policy with RL on a real robot in just a few hours.
|
| 4 |
-
|
| 5 |
-
HIL-SERL is a sample-efficient reinforcement learning algorithm that combines human demonstrations with online learning and human interventions. The approach starts from a small set of human demonstrations, uses them to train a reward classifier, and then employs an actor-learner architecture where humans can intervene during policy execution to guide exploration and correct unsafe behaviors. In this tutorial, you'll use a gamepad to provide interventions and control the robot during the learning process.
|
| 6 |
-
|
| 7 |
-
It combines three key ingredients:
|
| 8 |
-
1. **Offline demonstrations & reward classifier:** a handful of human-teleop episodes plus a vision-based success detector give the policy a shaped starting point.
|
| 9 |
-
2. **On-robot actor / learner loop with human interventions:** a distributed Soft Actor Critic (SAC) learner updates the policy while an actor explores on the physical robot; the human can jump in at any time to correct dangerous or unproductive behaviour.
|
| 10 |
-
3. **Safety & efficiency tools:** joint/end-effector (EE) bounds, crop region of interest (ROI) preprocessing and WandB monitoring keep the data useful and the hardware safe.
|
| 11 |
-
|
| 12 |
-
Together these elements let HIL-SERL reach near-perfect task success and faster cycle times than imitation-only baselines.
|
| 13 |
-
|
| 14 |
-
<p align="center">
|
| 15 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/hilserl-main-figure.png" alt="HIL-SERL workflow" title="HIL-SERL workflow" width="100%"></img>
|
| 16 |
-
</p>
|
| 17 |
-
|
| 18 |
-
<p align="center"><i>HIL-SERL workflow, Luo et al. 2024</i></p>
|
| 19 |
-
|
| 20 |
-
This guide provides step-by-step instructions for training a robot policy using LeRobot's HilSerl implementation to train on a real robot.
|
| 21 |
-
|
| 22 |
-
## What do I need?
|
| 23 |
-
|
| 24 |
-
- A gamepad (recommended) or keyboard to control the robot
|
| 25 |
-
- A Nvidia GPU
|
| 26 |
-
- A real robot with a follower and leader arm (optional if you use the keyboard or the gamepad)
|
| 27 |
-
|
| 28 |
-
## What kind of tasks can I train?
|
| 29 |
-
|
| 30 |
-
One can use HIL-SERL to train on a variety of manipulation tasks. Some recommendations:
|
| 31 |
-
- Start with a simple task to understand how the system works.
|
| 32 |
-
- Push cube to a goal region
|
| 33 |
-
- Pick and lift cube with the gripper
|
| 34 |
-
- Avoid extremely long horizon tasks. Focus on tasks that can be completed in 5-10 seconds.
|
| 35 |
-
- Once you have a good idea of how the system works, you can try more complex tasks and longer horizons.
|
| 36 |
-
- Pick and place cube
|
| 37 |
-
- Bimanual tasks to pick objects with two arms
|
| 38 |
-
- Hand-over tasks to transfer objects from one arm to another
|
| 39 |
-
- Go crazy!
|
| 40 |
-
|
| 41 |
-
## Install LeRobot with HIL-SERL
|
| 42 |
-
|
| 43 |
-
To install LeRobot with HIL-SERL, you need to install the `hilserl` extra.
|
| 44 |
-
|
| 45 |
-
```bash
|
| 46 |
-
pip install -e ".[hilserl]"
|
| 47 |
-
```
|
| 48 |
-
|
| 49 |
-
## Real Robot Training Workflow
|
| 50 |
-
|
| 51 |
-
### Understanding Configuration
|
| 52 |
-
|
| 53 |
-
The training process begins with proper configuration for the HILSerl environment. The configuration class of interest is `HILSerlRobotEnvConfig` in `lerobot/common/envs/configs.py`. Which is defined as:
|
| 54 |
-
|
| 55 |
-
```python
|
| 56 |
-
class HILSerlRobotEnvConfig(EnvConfig):
|
| 57 |
-
robot: RobotConfig | None = None # Main robot agent (defined in `lerobot/common/robots`)
|
| 58 |
-
teleop: TeleoperatorConfig | None = None # Teleoperator agent, e.g., gamepad or leader arm, (defined in `lerobot/common/teleoperators`)
|
| 59 |
-
wrapper: EnvTransformConfig | None = None # Environment wrapper settings; check `lerobot/scripts/server/gym_manipulator.py`
|
| 60 |
-
fps: int = 10 # Control frequency
|
| 61 |
-
name: str = "real_robot" # Environment name
|
| 62 |
-
mode: str = None # "record", "replay", or None (for training)
|
| 63 |
-
repo_id: str | None = None # LeRobot dataset repository ID
|
| 64 |
-
dataset_root: str | None = None # Local dataset root (optional)
|
| 65 |
-
task: str = "" # Task identifier
|
| 66 |
-
num_episodes: int = 10 # Number of episodes for recording
|
| 67 |
-
episode: int = 0 # episode index for replay
|
| 68 |
-
device: str = "cuda" # Compute device
|
| 69 |
-
push_to_hub: bool = True # Whether to push the recorded datasets to Hub
|
| 70 |
-
pretrained_policy_name_or_path: str | None = None # For policy loading
|
| 71 |
-
reward_classifier_pretrained_path: str | None = None # For reward model
|
| 72 |
-
number_of_steps_after_success: int = 0 # For reward classifier, collect more positive examples after a success to train a classifier
|
| 73 |
-
```
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
### Finding Robot Workspace Bounds
|
| 77 |
-
|
| 78 |
-
Before collecting demonstrations, you need to determine the appropriate operational bounds for your robot.
|
| 79 |
-
|
| 80 |
-
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.
|
| 81 |
-
|
| 82 |
-
**Using find_joint_limits.py**
|
| 83 |
-
|
| 84 |
-
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.
|
| 85 |
-
Bounding the action space will reduce the redundant exploration of the agent and guarantees safety.
|
| 86 |
-
|
| 87 |
-
```bash
|
| 88 |
-
python -m lerobot.scripts.find_joint_limits \
|
| 89 |
-
--robot.type=so100_follower \
|
| 90 |
-
--robot.port=/dev/tty.usbmodem58760431541 \
|
| 91 |
-
--robot.id=black \
|
| 92 |
-
--teleop.type=so100_leader \
|
| 93 |
-
--teleop.port=/dev/tty.usbmodem58760431551 \
|
| 94 |
-
--teleop.id=blue
|
| 95 |
-
```
|
| 96 |
-
|
| 97 |
-
**Workflow**
|
| 98 |
-
|
| 99 |
-
1. Run the script and move the robot through the space that solves the task
|
| 100 |
-
2. The script will record the minimum and maximum end-effector positions and the joint angles and prints them to the console, for example:
|
| 101 |
-
```
|
| 102 |
-
Max ee position [0.2417 0.2012 0.1027]
|
| 103 |
-
Min ee position [0.1663 -0.0823 0.0336]
|
| 104 |
-
Max joint positions [-20.0, -20.0, -20.0, -20.0, -20.0, -20.0]
|
| 105 |
-
Min joint positions [50.0, 50.0, 50.0, 50.0, 50.0, 50.0]
|
| 106 |
-
```
|
| 107 |
-
3. Use these values in the configuration of your teleoperation device (TeleoperatorConfig) under the `end_effector_bounds` field
|
| 108 |
-
|
| 109 |
-
**Example Configuration**
|
| 110 |
-
|
| 111 |
-
```json
|
| 112 |
-
"end_effector_bounds": {
|
| 113 |
-
"max": [0.24, 0.20, 0.10],
|
| 114 |
-
"min": [0.16, -0.08, 0.03]
|
| 115 |
-
}
|
| 116 |
-
```
|
| 117 |
-
|
| 118 |
-
### Collecting Demonstrations
|
| 119 |
-
|
| 120 |
-
With the bounds defined, you can safely collect demonstrations for training. Training RL with off-policy algorithm allows us to use offline datasets collected in order to improve the efficiency of the learning process.
|
| 121 |
-
|
| 122 |
-
**Setting Up Record Mode**
|
| 123 |
-
|
| 124 |
-
Create a configuration file for recording demonstrations (or edit an existing one like [env_config_so100.json](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/env_config_so100.json)):
|
| 125 |
-
|
| 126 |
-
1. Set `mode` to `"record"`
|
| 127 |
-
2. Specify a unique `repo_id` for your dataset (e.g., "username/task_name")
|
| 128 |
-
3. Set `num_episodes` to the number of demonstrations you want to collect
|
| 129 |
-
4. Set `crop_params_dict` to `null` initially (we'll determine crops later)
|
| 130 |
-
5. Configure `robot`, `cameras`, and other hardware settings
|
| 131 |
-
|
| 132 |
-
Example configuration section:
|
| 133 |
-
```json
|
| 134 |
-
"mode": "record",
|
| 135 |
-
"repo_id": "username/pick_lift_cube",
|
| 136 |
-
"dataset_root": null,
|
| 137 |
-
"task": "pick_and_lift",
|
| 138 |
-
"num_episodes": 15,
|
| 139 |
-
"episode": 0,
|
| 140 |
-
"push_to_hub": true
|
| 141 |
-
```
|
| 142 |
-
|
| 143 |
-
### Using a Teleoperation Device
|
| 144 |
-
|
| 145 |
-
Along with your robot, you will need a teleoperation device to control it in order to collect datasets of your task and perform interventions during the online training.
|
| 146 |
-
We support using a gamepad or a keyboard or the leader arm of the robot.
|
| 147 |
-
|
| 148 |
-
HIL-Serl learns actions in the end-effector space of the robot. Therefore, the teleoperation will control the end-effector's x,y,z displacements.
|
| 149 |
-
|
| 150 |
-
For that we need to define a version of the robot that takes actions in the end-effector space. Check the robot class `SO100FollowerEndEffector` and its configuration `SO100FollowerEndEffectorConfig` for the default parameters related to the end-effector space.
|
| 151 |
-
|
| 152 |
-
```python
|
| 153 |
-
class SO100FollowerEndEffectorConfig(SO100FollowerConfig):
|
| 154 |
-
"""Configuration for the SO100FollowerEndEffector robot."""
|
| 155 |
-
|
| 156 |
-
# Default bounds for the end-effector position (in meters)
|
| 157 |
-
end_effector_bounds: dict[str, list[float]] = field( # bounds for the end-effector in x,y,z direction
|
| 158 |
-
default_factory=lambda: {
|
| 159 |
-
"min": [-1.0, -1.0, -1.0], # min x, y, z
|
| 160 |
-
"max": [1.0, 1.0, 1.0], # max x, y, z
|
| 161 |
-
}
|
| 162 |
-
)
|
| 163 |
-
|
| 164 |
-
max_gripper_pos: float = 50 # maximum gripper position that the gripper will be open at
|
| 165 |
-
|
| 166 |
-
end_effector_step_sizes: dict[str, float] = field( # maximum step size for the end-effector in x,y,z direction
|
| 167 |
-
default_factory=lambda: {
|
| 168 |
-
"x": 0.02,
|
| 169 |
-
"y": 0.02,
|
| 170 |
-
"z": 0.02,
|
| 171 |
-
}
|
| 172 |
-
)
|
| 173 |
-
```
|
| 174 |
-
|
| 175 |
-
The `Teleoperator` defines the teleoperation device. You can check the list of available teleoperators in `lerobot/common/teleoperators`.
|
| 176 |
-
|
| 177 |
-
**Setting up the Gamepad**
|
| 178 |
-
|
| 179 |
-
The gamepad provides a very convenient way to control the robot and the episode state.
|
| 180 |
-
|
| 181 |
-
To setup the gamepad, you need to set the `control_mode` to `"gamepad"` and define the `teleop` section in the configuration file.
|
| 182 |
-
|
| 183 |
-
```json
|
| 184 |
-
"teleop": {
|
| 185 |
-
"type": "gamepad",
|
| 186 |
-
"use_gripper": true
|
| 187 |
-
},
|
| 188 |
-
```
|
| 189 |
-
|
| 190 |
-
<p align="center">
|
| 191 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/gamepad_guide.jpg?raw=true" alt="Figure shows the control mappings on a Logitech gamepad." title="Gamepad Control Mapping" width="100%"></img>
|
| 192 |
-
</p>
|
| 193 |
-
<p align="center"><i>Gamepad button mapping for robot control and episode management</i></p>
|
| 194 |
-
|
| 195 |
-
**Setting up the SO101 leader**
|
| 196 |
-
|
| 197 |
-
The SO101 leader arm has reduced gears that allows it to move and track the follower arm during exploration. Therefore, taking over is much smoother than the gearless SO100.
|
| 198 |
-
|
| 199 |
-
To setup the SO101 leader, you need to set the `control_mode` to `"leader"` and define the `teleop` section in the configuration file.
|
| 200 |
-
|
| 201 |
-
```json
|
| 202 |
-
"teleop": {
|
| 203 |
-
"type": "so101_leader",
|
| 204 |
-
"port": "/dev/tty.usbmodem585A0077921", # check your port number
|
| 205 |
-
"use_degrees": true
|
| 206 |
-
},
|
| 207 |
-
```
|
| 208 |
-
|
| 209 |
-
In order to annotate the success/failure of the episode, **you will need** to use a keyboard to press `s` for success, `esc` for failure.
|
| 210 |
-
During the online training, press `space` to take over the policy and `space` again to give the control back to the policy.
|
| 211 |
-
|
| 212 |
-
<details>
|
| 213 |
-
<summary><strong>Video: SO101 leader teleoperation</strong></summary>
|
| 214 |
-
|
| 215 |
-
<div class="video-container">
|
| 216 |
-
<video controls width="600">
|
| 217 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so101_leader_tutorial.mp4" type="video/mp4" />
|
| 218 |
-
</video>
|
| 219 |
-
</div>
|
| 220 |
-
|
| 221 |
-
<p align="center"><i>SO101 leader teleoperation example, the leader tracks the follower, press `space` to intervene</i></p>
|
| 222 |
-
</details>
|
| 223 |
-
|
| 224 |
-
**Recording Demonstrations**
|
| 225 |
-
|
| 226 |
-
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):
|
| 227 |
-
|
| 228 |
-
```bash
|
| 229 |
-
python lerobot/scripts/rl/gym_manipulator.py --config_path lerobot/configs/env_config_so100.json
|
| 230 |
-
```
|
| 231 |
-
|
| 232 |
-
During recording:
|
| 233 |
-
1. The robot will reset to the initial position defined in the configuration file `fixed_reset_joint_positions`
|
| 234 |
-
2. Complete the task successfully
|
| 235 |
-
3. The episode ends with a reward of 1 when you press the "success" button
|
| 236 |
-
4. If the time limit is reached, or the fail button is pressed, the episode ends with a reward of 0
|
| 237 |
-
5. You can rerecord an episode by pressing the "rerecord" button
|
| 238 |
-
6. The process automatically continues to the next episode
|
| 239 |
-
7. After recording all episodes, the dataset is pushed to the Hugging Face Hub (optional) and saved locally
|
| 240 |
-
|
| 241 |
-
|
| 242 |
-
### Processing the Dataset
|
| 243 |
-
|
| 244 |
-
After collecting demonstrations, process them to determine optimal camera crops.
|
| 245 |
-
Reinforcement learning is sensitive to background distractions, so it is important to crop the images to the relevant workspace area.
|
| 246 |
-
|
| 247 |
-
Visual RL algorithms learn directly from pixel inputs, making them vulnerable to irrelevant visual information. Background elements like changing lighting, shadows, people moving, or objects outside the workspace can confuse the learning process. Good ROI selection should:
|
| 248 |
-
- Include only the essential workspace where the task happens
|
| 249 |
-
- Capture the robot's end-effector and all objects involved in the task
|
| 250 |
-
- Exclude unnecessary background elements and distractions
|
| 251 |
-
|
| 252 |
-
Note: If you already know the crop parameters, you can skip this step and just set the `crop_params_dict` in the configuration file during recording.
|
| 253 |
-
|
| 254 |
-
**Determining Crop Parameters**
|
| 255 |
-
|
| 256 |
-
Use the `crop_dataset_roi.py` script to interactively select regions of interest in your camera images:
|
| 257 |
-
|
| 258 |
-
```bash
|
| 259 |
-
python lerobot/scripts/rl/crop_dataset_roi.py --repo-id username/pick_lift_cube
|
| 260 |
-
```
|
| 261 |
-
|
| 262 |
-
1. For each camera view, the script will display the first frame
|
| 263 |
-
2. Draw a rectangle around the relevant workspace area
|
| 264 |
-
3. Press 'c' to confirm the selection
|
| 265 |
-
4. Repeat for all camera views
|
| 266 |
-
5. The script outputs cropping parameters and creates a new cropped dataset
|
| 267 |
-
|
| 268 |
-
Example output:
|
| 269 |
-
```
|
| 270 |
-
Selected Rectangular Regions of Interest (top, left, height, width):
|
| 271 |
-
observation.images.side: [180, 207, 180, 200]
|
| 272 |
-
observation.images.front: [180, 250, 120, 150]
|
| 273 |
-
```
|
| 274 |
-
|
| 275 |
-
<p align="center">
|
| 276 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/crop_dataset.gif" width="600"/>
|
| 277 |
-
</p>
|
| 278 |
-
|
| 279 |
-
<p align="center"><i>Interactive cropping tool for selecting regions of interest</i></p>
|
| 280 |
-
|
| 281 |
-
|
| 282 |
-
**Updating Configuration**
|
| 283 |
-
|
| 284 |
-
Add these crop parameters to your training configuration:
|
| 285 |
-
|
| 286 |
-
```json
|
| 287 |
-
"crop_params_dict": {
|
| 288 |
-
"observation.images.side": [180, 207, 180, 200],
|
| 289 |
-
"observation.images.front": [180, 250, 120, 150]
|
| 290 |
-
},
|
| 291 |
-
"resize_size": [128, 128]
|
| 292 |
-
```
|
| 293 |
-
|
| 294 |
-
**Recommended image resolution**
|
| 295 |
-
|
| 296 |
-
Most vision-based policies have been validated on square inputs of either **128×128** (default) or **64×64** pixels. We therefore advise setting the resize_size parameter to [128, 128] – or [64, 64] if you need to save GPU memory and bandwidth. Other resolutions are possible but have not been extensively tested.
|
| 297 |
-
|
| 298 |
-
|
| 299 |
-
### Training a Reward Classifier
|
| 300 |
-
|
| 301 |
-
The reward classifier plays an important role in the HIL-SERL workflow by automating reward assignment and automatically detecting episode success. Instead of manually defining reward functions or relying on human feedback for every timestep, the reward classifier learns to predict success/failure from visual observations. This enables the RL algorithm to learn efficiently by providing consistent and automated reward signals based on the robot's camera inputs.
|
| 302 |
-
|
| 303 |
-
This guide explains how to train a reward classifier for human-in-the-loop reinforcement learning implementation of LeRobot. Reward classifiers learn to predict the reward value given a state which can be used in an RL setup to train a policy.
|
| 304 |
-
|
| 305 |
-
**Note**: Training a reward classifier is optional. You can start the first round of RL experiments by annotating the success manually with your gamepad or keyboard device.
|
| 306 |
-
|
| 307 |
-
The reward classifier implementation in `modeling_classifier.py` uses a pretrained vision model to process the images. It can output either a single value for binary rewards to predict success/fail cases or multiple values for multi-class settings.
|
| 308 |
-
|
| 309 |
-
**Collecting a Dataset for the reward classifier**
|
| 310 |
-
|
| 311 |
-
Before training, you need to collect a dataset with labeled examples. The `record_dataset` function in `gym_manipulator.py` enables the process of collecting a dataset of observations, actions, and rewards.
|
| 312 |
-
|
| 313 |
-
To collect a dataset, you need to modify some parameters in the environment configuration based on HILSerlRobotEnvConfig.
|
| 314 |
-
|
| 315 |
-
```bash
|
| 316 |
-
python lerobot/scripts/rl/gym_manipulator.py --config_path lerobot/configs/reward_classifier_train_config.json
|
| 317 |
-
```
|
| 318 |
-
|
| 319 |
-
**Key Parameters for Data Collection**
|
| 320 |
-
|
| 321 |
-
- **mode**: set it to `"record"` to collect a dataset
|
| 322 |
-
- **repo_id**: `"hf_username/dataset_name"`, name of the dataset and repo on the hub
|
| 323 |
-
- **num_episodes**: Number of episodes to record
|
| 324 |
-
- **number_of_steps_after_success**: Number of additional frames to record after a success (reward=1) is detected
|
| 325 |
-
- **fps**: Number of frames per second to record
|
| 326 |
-
- **push_to_hub**: Whether to push the dataset to the hub
|
| 327 |
-
|
| 328 |
-
The `number_of_steps_after_success` parameter is crucial as it allows you to collect more positive examples. When a success is detected, the system will continue recording for the specified number of steps while maintaining the reward=1 label. Otherwise, there won't be enough states in the dataset labeled to 1 to train a good classifier.
|
| 329 |
-
|
| 330 |
-
Example configuration section for data collection:
|
| 331 |
-
|
| 332 |
-
```json
|
| 333 |
-
{
|
| 334 |
-
"mode": "record",
|
| 335 |
-
"repo_id": "hf_username/dataset_name",
|
| 336 |
-
"dataset_root": "data/your_dataset",
|
| 337 |
-
"num_episodes": 20,
|
| 338 |
-
"push_to_hub": true,
|
| 339 |
-
"fps": 10,
|
| 340 |
-
"number_of_steps_after_success": 15
|
| 341 |
-
}
|
| 342 |
-
```
|
| 343 |
-
|
| 344 |
-
**Reward Classifier Configuration**
|
| 345 |
-
|
| 346 |
-
The reward classifier is configured using `configuration_classifier.py`. Here are the key parameters:
|
| 347 |
-
|
| 348 |
-
- **model_name**: Base model architecture (e.g., we mainly use `"helper2424/resnet10"`)
|
| 349 |
-
- **model_type**: `"cnn"` or `"transformer"`
|
| 350 |
-
- **num_cameras**: Number of camera inputs
|
| 351 |
-
- **num_classes**: Number of output classes (typically 2 for binary success/failure)
|
| 352 |
-
- **hidden_dim**: Size of hidden representation
|
| 353 |
-
- **dropout_rate**: Regularization parameter
|
| 354 |
-
- **learning_rate**: Learning rate for optimizer
|
| 355 |
-
|
| 356 |
-
Example configuration for training the [reward classifier](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/reward_classifier_train_config.json):
|
| 357 |
-
|
| 358 |
-
```json
|
| 359 |
-
{
|
| 360 |
-
"policy": {
|
| 361 |
-
"type": "reward_classifier",
|
| 362 |
-
"model_name": "helper2424/resnet10",
|
| 363 |
-
"model_type": "cnn",
|
| 364 |
-
"num_cameras": 2,
|
| 365 |
-
"num_classes": 2,
|
| 366 |
-
"hidden_dim": 256,
|
| 367 |
-
"dropout_rate": 0.1,
|
| 368 |
-
"learning_rate": 1e-4,
|
| 369 |
-
"device": "cuda",
|
| 370 |
-
"use_amp": true,
|
| 371 |
-
"input_features": {
|
| 372 |
-
"observation.images.front": {
|
| 373 |
-
"type": "VISUAL",
|
| 374 |
-
"shape": [3, 128, 128]
|
| 375 |
-
},
|
| 376 |
-
"observation.images.side": {
|
| 377 |
-
"type": "VISUAL",
|
| 378 |
-
"shape": [3, 128, 128]
|
| 379 |
-
}
|
| 380 |
-
}
|
| 381 |
-
}
|
| 382 |
-
}
|
| 383 |
-
```
|
| 384 |
-
|
| 385 |
-
**Training the Classifier**
|
| 386 |
-
|
| 387 |
-
To train the classifier, use the `train.py` script with your configuration:
|
| 388 |
-
|
| 389 |
-
```bash
|
| 390 |
-
python lerobot/scripts/train.py --config_path path/to/reward_classifier_train_config.json
|
| 391 |
-
```
|
| 392 |
-
|
| 393 |
-
**Deploying and Testing the Model**
|
| 394 |
-
|
| 395 |
-
To use your trained reward classifier, configure the `HILSerlRobotEnvConfig` to use your model:
|
| 396 |
-
|
| 397 |
-
```python
|
| 398 |
-
env_config = HILSerlRobotEnvConfig(
|
| 399 |
-
reward_classifier_pretrained_path="path_to_your_pretrained_trained_model",
|
| 400 |
-
# Other environment parameters
|
| 401 |
-
)
|
| 402 |
-
```
|
| 403 |
-
or set the argument in the json config file.
|
| 404 |
-
|
| 405 |
-
```json
|
| 406 |
-
{
|
| 407 |
-
"reward_classifier_pretrained_path": "path_to_your_pretrained_model"
|
| 408 |
-
}
|
| 409 |
-
```
|
| 410 |
-
|
| 411 |
-
Run `gym_manipulator.py` to test the model.
|
| 412 |
-
```bash
|
| 413 |
-
python lerobot/scripts/rl/gym_manipulator.py --config_path path/to/env_config.json
|
| 414 |
-
```
|
| 415 |
-
|
| 416 |
-
The reward classifier will automatically provide rewards based on the visual input from the robot's cameras.
|
| 417 |
-
|
| 418 |
-
**Example Workflow for training the reward classifier**
|
| 419 |
-
|
| 420 |
-
1. **Create the configuration files**:
|
| 421 |
-
Create the necessary json configuration files for the reward classifier and the environment. Check the examples [here](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/tree/main).
|
| 422 |
-
|
| 423 |
-
2. **Collect a dataset**:
|
| 424 |
-
```bash
|
| 425 |
-
python lerobot/scripts/rl/gym_manipulator.py --config_path lerobot/configs/env_config.json
|
| 426 |
-
```
|
| 427 |
-
|
| 428 |
-
3. **Train the classifier**:
|
| 429 |
-
```bash
|
| 430 |
-
python lerobot/scripts/train.py --config_path lerobot/configs/reward_classifier_train_config.json
|
| 431 |
-
```
|
| 432 |
-
|
| 433 |
-
4. **Test the classifier**:
|
| 434 |
-
```bash
|
| 435 |
-
python lerobot/scripts/rl/gym_manipulator.py --config_path lerobot/configs/env_config.json
|
| 436 |
-
```
|
| 437 |
-
|
| 438 |
-
### Training with Actor-Learner
|
| 439 |
-
|
| 440 |
-
The LeRobot system uses a distributed actor-learner architecture for training. This architecture decouples robot interactions from the learning process, allowing them to run concurrently without blocking each other. The actor server handles robot observations and actions, sending interaction data to the learner server. The learner server performs gradient descent and periodically updates the actor's policy weights. You will need to start two processes: a learner and an actor.
|
| 441 |
-
|
| 442 |
-
**Configuration Setup**
|
| 443 |
-
|
| 444 |
-
Create a training configuration file (example available [here](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/train_config_hilserl_so100.json)). The training config is based on the main `TrainRLServerPipelineConfig` class in `lerobot/configs/train.py`.
|
| 445 |
-
|
| 446 |
-
1. Configure the policy settings (`type="sac"`, `device`, etc.)
|
| 447 |
-
2. Set `dataset` to your cropped dataset
|
| 448 |
-
3. Configure environment settings with crop parameters
|
| 449 |
-
4. Check the other parameters related to SAC in [configuration_sac.py](https://github.com/huggingface/lerobot/blob/19bb621a7d0a31c20cd3cc08b1dbab68d3031454/lerobot/common/policies/sac/configuration_sac.py#L79).
|
| 450 |
-
5. Verify that the `policy` config is correct with the right `input_features` and `output_features` for your task.
|
| 451 |
-
|
| 452 |
-
**Starting the Learner**
|
| 453 |
-
|
| 454 |
-
First, start the learner server process:
|
| 455 |
-
|
| 456 |
-
```bash
|
| 457 |
-
python lerobot/scripts/rl/learner.py --config_path lerobot/configs/train_config_hilserl_so100.json
|
| 458 |
-
```
|
| 459 |
-
|
| 460 |
-
The learner:
|
| 461 |
-
- Initializes the policy network
|
| 462 |
-
- Prepares replay buffers
|
| 463 |
-
- Opens a `gRPC` server to communicate with actors
|
| 464 |
-
- Processes transitions and updates the policy
|
| 465 |
-
|
| 466 |
-
**Starting the Actor**
|
| 467 |
-
|
| 468 |
-
In a separate terminal, start the actor process with the same configuration:
|
| 469 |
-
|
| 470 |
-
```bash
|
| 471 |
-
python lerobot/scripts/rl/actor.py --config_path lerobot/configs/train_config_hilserl_so100.json
|
| 472 |
-
```
|
| 473 |
-
|
| 474 |
-
The actor:
|
| 475 |
-
- Connects to the learner via `gRPC`
|
| 476 |
-
- Initializes the environment
|
| 477 |
-
- Execute rollouts of the policy to collect experience
|
| 478 |
-
- Sends transitions to the learner
|
| 479 |
-
- Receives updated policy parameters
|
| 480 |
-
|
| 481 |
-
**Training Flow**
|
| 482 |
-
|
| 483 |
-
The training proceeds automatically:
|
| 484 |
-
|
| 485 |
-
1. The actor executes the policy in the environment
|
| 486 |
-
2. Transitions are collected and sent to the learner
|
| 487 |
-
3. The learner updates the policy based on these transitions
|
| 488 |
-
4. Updated policy parameters are sent back to the actor
|
| 489 |
-
5. The process continues until the specified step limit is reached
|
| 490 |
-
|
| 491 |
-
**Human in the Loop**
|
| 492 |
-
|
| 493 |
-
- The key to learning efficiently is to have human interventions to provide corrective feedback and completing the task to aide the policy learning and exploration.
|
| 494 |
-
- To perform human interventions, you can press the upper right trigger button on the gamepad (or the `space` key on the keyboard). This will pause the policy actions and allow you to take over.
|
| 495 |
-
- A successful experiment is one where the human has to intervene at the start but then reduces the amount of interventions as the policy improves. You can monitor the intervention rate in the `wandb` dashboard.
|
| 496 |
-
|
| 497 |
-
<p align="center">
|
| 498 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/hil_effect.png?raw=true" alt="Figure shows the control mappings on a Logitech gamepad." title="Gamepad Control Mapping" width="100%"></img>
|
| 499 |
-
</p>
|
| 500 |
-
|
| 501 |
-
<p align="center"><i>Example showing how human interventions help guide policy learning over time</i></p>
|
| 502 |
-
|
| 503 |
-
- The figure shows the plot of the episodic reward over interaction step. The figure shows the effect of human interventions on the policy learning.
|
| 504 |
-
- The orange curve is an experiment without any human interventions. While the pink and blue curves are experiments with human interventions.
|
| 505 |
-
- We can observe that the number of steps where the policy starts achieving the maximum reward is cut by a quarter when human interventions are present.
|
| 506 |
-
|
| 507 |
-
**Monitoring and Debugging**
|
| 508 |
-
|
| 509 |
-
If you have `wandb.enable` set to `true` in your configuration, you can monitor training progress in real-time through the [Weights & Biases](https://wandb.ai/site/) dashboard.
|
| 510 |
-
|
| 511 |
-
### Guide to Human Interventions
|
| 512 |
-
The learning process is very sensitive to the intervention strategy. It will takes a few runs to understand how to intervene effectively. Some tips and hints:
|
| 513 |
-
- Allow the policy to explore for a few episodes at the start of training.
|
| 514 |
-
- Avoid intervening for long periods of time. Try to intervene in situation to correct the robot's behaviour when it goes off track.
|
| 515 |
-
- Once the policy starts achieving the task, even if its not perfect, you can limit your interventions to simple quick actions like a simple grasping commands.
|
| 516 |
-
|
| 517 |
-
The ideal behaviour is that your intervention rate should drop gradually during training as shown in the figure below.
|
| 518 |
-
|
| 519 |
-
<p align="center">
|
| 520 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/intervention_rate_tutorial_rl.png?raw=true" alt="Intervention rate" title="Intervention rate during training" width="100%"></img>
|
| 521 |
-
</p>
|
| 522 |
-
|
| 523 |
-
<p align="center"><i>Plot of the intervention rate during a training run on a pick and lift cube task</i></p>
|
| 524 |
-
|
| 525 |
-
### Key hyperparameters to tune
|
| 526 |
-
|
| 527 |
-
Some configuration values have a disproportionate impact on training stability and speed:
|
| 528 |
-
|
| 529 |
-
- **`temperature_init`** (`policy.temperature_init`) – initial entropy temperature in SAC. Higher values encourage more exploration; lower values make the policy more deterministic early on. A good starting point is `1e-2`. We observed that setting it too high can make human interventions ineffective and slow down learning.
|
| 530 |
-
- **`policy_parameters_push_frequency`** (`policy.actor_learner_config.policy_parameters_push_frequency`) – interval in *seconds* between two weight pushes from the learner to the actor. The default is `4 s`. Decrease to **1-2 s** to provide fresher weights (at the cost of more network traffic); increase only if your connection is slow, as this will reduce sample efficiency.
|
| 531 |
-
- **`storage_device`** (`policy.storage_device`) – device on which the learner keeps the policy parameters. If you have spare GPU memory, set this to `"cuda"` (instead of the default `"cpu"`). Keeping the weights on-GPU removes CPU→GPU transfer overhead and can significantly increase the number of learner updates per second.
|
| 532 |
-
|
| 533 |
-
|
| 534 |
-
Congrats 🎉, you have finished this tutorial!
|
| 535 |
-
|
| 536 |
-
> [!TIP]
|
| 537 |
-
> If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb).
|
| 538 |
-
|
| 539 |
-
Paper citation:
|
| 540 |
-
```
|
| 541 |
-
@article{luo2024precise,
|
| 542 |
-
title={Precise and Dexterous Robotic Manipulation via Human-in-the-Loop Reinforcement Learning},
|
| 543 |
-
author={Luo, Jianlan and Xu, Charles and Wu, Jeffrey and Levine, Sergey},
|
| 544 |
-
journal={arXiv preprint arXiv:2410.21845},
|
| 545 |
-
year={2024}
|
| 546 |
-
}
|
| 547 |
-
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/hilserl_sim.mdx
DELETED
|
@@ -1,120 +0,0 @@
|
|
| 1 |
-
# Train RL in Simulation
|
| 2 |
-
|
| 3 |
-
This guide explains how to use the `gym_hil` simulation environments as an alternative to real robots when working with the LeRobot framework for Human-In-the-Loop (HIL) reinforcement learning.
|
| 4 |
-
|
| 5 |
-
`gym_hil` is a package that provides Gymnasium-compatible simulation environments specifically designed for Human-In-the-Loop reinforcement learning. These environments allow you to:
|
| 6 |
-
|
| 7 |
-
- Train policies in simulation to test the RL stack before training on real robots
|
| 8 |
-
|
| 9 |
-
- Collect demonstrations in sim using external devices like gamepads or keyboards
|
| 10 |
-
- Perform human interventions during policy learning
|
| 11 |
-
|
| 12 |
-
Currently, the main environment is a Franka Panda robot simulation based on MuJoCo, with tasks like picking up a cube.
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
## Installation
|
| 16 |
-
|
| 17 |
-
First, install the `gym_hil` package within the LeRobot environment:
|
| 18 |
-
|
| 19 |
-
```bash
|
| 20 |
-
pip install -e ".[hilserl]"
|
| 21 |
-
```
|
| 22 |
-
|
| 23 |
-
## What do I need?
|
| 24 |
-
|
| 25 |
-
- A gamepad or keyboard to control the robot
|
| 26 |
-
- A Nvidia GPU
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
## Configuration
|
| 31 |
-
|
| 32 |
-
To use `gym_hil` with LeRobot, you need to create a configuration file. An example is provided [here](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/gym_hil_env.json). Key configuration sections include:
|
| 33 |
-
|
| 34 |
-
### Environment Type and Task
|
| 35 |
-
|
| 36 |
-
```json
|
| 37 |
-
{
|
| 38 |
-
"type": "hil",
|
| 39 |
-
"name": "franka_sim",
|
| 40 |
-
"task": "PandaPickCubeGamepad-v0",
|
| 41 |
-
"device": "cuda"
|
| 42 |
-
}
|
| 43 |
-
```
|
| 44 |
-
|
| 45 |
-
Available tasks:
|
| 46 |
-
- `PandaPickCubeBase-v0`: Basic environment
|
| 47 |
-
- `PandaPickCubeGamepad-v0`: With gamepad control
|
| 48 |
-
- `PandaPickCubeKeyboard-v0`: With keyboard control
|
| 49 |
-
|
| 50 |
-
### Gym Wrappers Configuration
|
| 51 |
-
|
| 52 |
-
```json
|
| 53 |
-
"wrapper": {
|
| 54 |
-
"gripper_penalty": -0.02,
|
| 55 |
-
"control_time_s": 15.0,
|
| 56 |
-
"use_gripper": true,
|
| 57 |
-
"fixed_reset_joint_positions": [0.0, 0.195, 0.0, -2.43, 0.0, 2.62, 0.785],
|
| 58 |
-
"end_effector_step_sizes": {
|
| 59 |
-
"x": 0.025,
|
| 60 |
-
"y": 0.025,
|
| 61 |
-
"z": 0.025
|
| 62 |
-
},
|
| 63 |
-
"control_mode": "gamepad"
|
| 64 |
-
}
|
| 65 |
-
```
|
| 66 |
-
|
| 67 |
-
Important parameters:
|
| 68 |
-
- `gripper_penalty`: Penalty for excessive gripper movement
|
| 69 |
-
- `use_gripper`: Whether to enable gripper control
|
| 70 |
-
- `end_effector_step_sizes`: Size of the steps in the x,y,z axes of the end-effector
|
| 71 |
-
- `control_mode`: Set to `"gamepad"` to use a gamepad controller
|
| 72 |
-
|
| 73 |
-
## Running with HIL RL of LeRobot
|
| 74 |
-
|
| 75 |
-
### Basic Usage
|
| 76 |
-
|
| 77 |
-
To run the environment, set mode to null:
|
| 78 |
-
|
| 79 |
-
```python
|
| 80 |
-
python lerobot/scripts/rl/gym_manipulator.py --config_path path/to/gym_hil_env.json
|
| 81 |
-
```
|
| 82 |
-
|
| 83 |
-
### Recording a Dataset
|
| 84 |
-
|
| 85 |
-
To collect a dataset, set the mode to `record` whilst defining the repo_id and number of episodes to record:
|
| 86 |
-
|
| 87 |
-
```python
|
| 88 |
-
python lerobot/scripts/rl/gym_manipulator.py --config_path path/to/gym_hil_env.json
|
| 89 |
-
```
|
| 90 |
-
|
| 91 |
-
### Training a Policy
|
| 92 |
-
|
| 93 |
-
To train a policy, checkout the configuration example available [here](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/train_gym_hil_env.json) and run the actor and learner servers:
|
| 94 |
-
|
| 95 |
-
```python
|
| 96 |
-
python lerobot/scripts/rl/actor.py --config_path path/to/train_gym_hil_env.json
|
| 97 |
-
```
|
| 98 |
-
|
| 99 |
-
In a different terminal, run the learner server:
|
| 100 |
-
|
| 101 |
-
```python
|
| 102 |
-
python lerobot/scripts/rl/learner.py --config_path path/to/train_gym_hil_env.json
|
| 103 |
-
```
|
| 104 |
-
|
| 105 |
-
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.
|
| 106 |
-
|
| 107 |
-
Congrats 🎉, you have finished this tutorial!
|
| 108 |
-
|
| 109 |
-
> [!TIP]
|
| 110 |
-
> If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb).
|
| 111 |
-
|
| 112 |
-
Paper citation:
|
| 113 |
-
```
|
| 114 |
-
@article{luo2024precise,
|
| 115 |
-
title={Precise and Dexterous Robotic Manipulation via Human-in-the-Loop Reinforcement Learning},
|
| 116 |
-
author={Luo, Jianlan and Xu, Charles and Wu, Jeffrey and Levine, Sergey},
|
| 117 |
-
journal={arXiv preprint arXiv:2410.21845},
|
| 118 |
-
year={2024}
|
| 119 |
-
}
|
| 120 |
-
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/il_robots.mdx
DELETED
|
@@ -1,315 +0,0 @@
|
|
| 1 |
-
# Imitation Learning on Real-World Robots
|
| 2 |
-
|
| 3 |
-
This tutorial will explain how to train a neural network to control a real robot autonomously.
|
| 4 |
-
|
| 5 |
-
**You'll learn:**
|
| 6 |
-
1. How to record and visualize your dataset.
|
| 7 |
-
2. How to train a policy using your data and prepare it for evaluation.
|
| 8 |
-
3. How to evaluate your policy and visualize the results.
|
| 9 |
-
|
| 10 |
-
By following these steps, you'll be able to replicate tasks, such as picking up a Lego block and placing it in a bin with a high success rate, as shown in the video below.
|
| 11 |
-
|
| 12 |
-
<details>
|
| 13 |
-
<summary><strong>Video: pickup lego block task</strong></summary>
|
| 14 |
-
|
| 15 |
-
<div class="video-container">
|
| 16 |
-
<video controls width="600">
|
| 17 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/lerobot_task.mp4" type="video/mp4" />
|
| 18 |
-
</video>
|
| 19 |
-
</div>
|
| 20 |
-
|
| 21 |
-
</details>
|
| 22 |
-
|
| 23 |
-
This tutorial isn’t tied to a specific robot: we walk you through the commands and API snippets you can adapt for any supported platform.
|
| 24 |
-
|
| 25 |
-
During data collection, you’ll use a “teloperation” device, such as a leader arm or keyboard to teleoperate the robot and record its motion trajectories.
|
| 26 |
-
|
| 27 |
-
Once you’ve gathered enough trajectories, you’ll train a neural network to imitate these trajectories and deploy the trained model so your robot can perform the task autonomously.
|
| 28 |
-
|
| 29 |
-
If you run into any issues at any point, jump into our [Discord community](https://discord.com/invite/s3KuuzsPFb) for support.
|
| 30 |
-
|
| 31 |
-
## Set up and Calibrate
|
| 32 |
-
|
| 33 |
-
If you haven't yet set up and calibrated your robot and teleop device, please do so by following the robot-specific tutorial.
|
| 34 |
-
|
| 35 |
-
## Teleoperate
|
| 36 |
-
|
| 37 |
-
In this example, we’ll demonstrate how to teleoperate the SO101 robot. For each command, we also provide a corresponding API example.
|
| 38 |
-
|
| 39 |
-
Note that the `id` associated with a robot is used to store the calibration file. It's important to use the same `id` when teleoperating, recording, and evaluating when using the same setup.
|
| 40 |
-
|
| 41 |
-
<hfoptions id="teleoperate_so101">
|
| 42 |
-
<hfoption id="Command">
|
| 43 |
-
```bash
|
| 44 |
-
python -m lerobot.teleoperate \
|
| 45 |
-
--robot.type=so101_follower \
|
| 46 |
-
--robot.port=/dev/tty.usbmodem58760431541 \
|
| 47 |
-
--robot.id=my_awesome_follower_arm \
|
| 48 |
-
--teleop.type=so101_leader \
|
| 49 |
-
--teleop.port=/dev/tty.usbmodem58760431551 \
|
| 50 |
-
--teleop.id=my_awesome_leader_arm
|
| 51 |
-
```
|
| 52 |
-
</hfoption>
|
| 53 |
-
<hfoption id="API example">
|
| 54 |
-
```python
|
| 55 |
-
from lerobot.common.teleoperators.so101_leader import SO101LeaderConfig, SO101Leader
|
| 56 |
-
from lerobot.common.robots.so101_follower import SO101FollowerConfig, SO101Follower
|
| 57 |
-
|
| 58 |
-
robot_config = SO101FollowerConfig(
|
| 59 |
-
port="/dev/tty.usbmodem58760431541",
|
| 60 |
-
id="my_red_robot_arm",
|
| 61 |
-
)
|
| 62 |
-
|
| 63 |
-
teleop_config = SO101LeaderConfig(
|
| 64 |
-
port="/dev/tty.usbmodem58760431551",
|
| 65 |
-
id="my_blue_leader_arm",
|
| 66 |
-
)
|
| 67 |
-
|
| 68 |
-
robot = SO101Follower(robot_config)
|
| 69 |
-
teleop_device = SO101Leader(teleop_config)
|
| 70 |
-
robot.connect()
|
| 71 |
-
teleop_device.connect()
|
| 72 |
-
|
| 73 |
-
while True:
|
| 74 |
-
action = teleop_device.get_action()
|
| 75 |
-
robot.send_action(action)
|
| 76 |
-
```
|
| 77 |
-
</hfoption>
|
| 78 |
-
</hfoptions>
|
| 79 |
-
|
| 80 |
-
The teleoperate command will automatically:
|
| 81 |
-
1. Identify any missing calibrations and initiate the calibration procedure.
|
| 82 |
-
2. Connect the robot and teleop device and start teleoperation.
|
| 83 |
-
|
| 84 |
-
## Cameras
|
| 85 |
-
|
| 86 |
-
To add cameras to your setup, follow this [Guide](./cameras#setup-cameras).
|
| 87 |
-
|
| 88 |
-
## Teleoperate with cameras
|
| 89 |
-
|
| 90 |
-
With `rerun`, you can teleoperate again while simultaneously visualizing the camera feeds and joint positions. In this example, we’re using the Koch arm.
|
| 91 |
-
|
| 92 |
-
<hfoptions id="teleoperate_koch_camera">
|
| 93 |
-
<hfoption id="Command">
|
| 94 |
-
```bash
|
| 95 |
-
python -m lerobot.teleoperate \
|
| 96 |
-
--robot.type=koch_follower \
|
| 97 |
-
--robot.port=/dev/tty.usbmodem58760431541 \
|
| 98 |
-
--robot.id=my_awesome_follower_arm \
|
| 99 |
-
--robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 1920, height: 1080, fps: 30}}" \
|
| 100 |
-
--teleop.type=koch_leader \
|
| 101 |
-
--teleop.port=/dev/tty.usbmodem58760431551 \
|
| 102 |
-
--teleop.id=my_awesome_leader_arm \
|
| 103 |
-
--display_data=true
|
| 104 |
-
```
|
| 105 |
-
</hfoption>
|
| 106 |
-
<hfoption id="API example">
|
| 107 |
-
```python
|
| 108 |
-
from lerobot.common.cameras.opencv.configuration_opencv import OpenCVCameraConfig
|
| 109 |
-
from lerobot.common.teleoperators.koch_leader import KochLeaderConfig, KochLeader
|
| 110 |
-
from lerobot.common.robots.koch_follower import KochFollowerConfig, KochFollower
|
| 111 |
-
|
| 112 |
-
camera_config = {
|
| 113 |
-
"front": OpenCVCameraConfig(index_or_path=0, width=1920, height=1080, fps=30)
|
| 114 |
-
}
|
| 115 |
-
|
| 116 |
-
robot_config = KochFollowerConfig(
|
| 117 |
-
port="/dev/tty.usbmodem585A0076841",
|
| 118 |
-
id="my_red_robot_arm",
|
| 119 |
-
cameras=camera_config
|
| 120 |
-
)
|
| 121 |
-
|
| 122 |
-
teleop_config = KochLeaderConfig(
|
| 123 |
-
port="/dev/tty.usbmodem58760431551",
|
| 124 |
-
id="my_blue_leader_arm",
|
| 125 |
-
)
|
| 126 |
-
|
| 127 |
-
robot = KochFollower(robot_config)
|
| 128 |
-
teleop_device = KochLeader(teleop_config)
|
| 129 |
-
robot.connect()
|
| 130 |
-
teleop_device.connect()
|
| 131 |
-
|
| 132 |
-
while True:
|
| 133 |
-
observation = robot.get_observation()
|
| 134 |
-
action = teleop_device.get_action()
|
| 135 |
-
robot.send_action(action)
|
| 136 |
-
```
|
| 137 |
-
</hfoption>
|
| 138 |
-
</hfoptions>
|
| 139 |
-
|
| 140 |
-
## Record a dataset
|
| 141 |
-
|
| 142 |
-
Once you're familiar with teleoperation, you can record your first dataset.
|
| 143 |
-
|
| 144 |
-
We use the Hugging Face hub features for uploading your dataset. If you haven't previously used the Hub, make sure you can login via the cli using a write-access token, this token can be generated from the [Hugging Face settings](https://huggingface.co/settings/tokens).
|
| 145 |
-
|
| 146 |
-
Add your token to the CLI by running this command:
|
| 147 |
-
```bash
|
| 148 |
-
huggingface-cli login --token ${HUGGINGFACE_TOKEN} --add-to-git-credential
|
| 149 |
-
```
|
| 150 |
-
|
| 151 |
-
Then store your Hugging Face repository name in a variable:
|
| 152 |
-
```bash
|
| 153 |
-
HF_USER=$(huggingface-cli whoami | head -n 1)
|
| 154 |
-
echo $HF_USER
|
| 155 |
-
```
|
| 156 |
-
|
| 157 |
-
Now you can record a dataset. To record 2 episodes and upload your dataset to the hub, execute this command tailored to the SO101.
|
| 158 |
-
```bash
|
| 159 |
-
python -m lerobot.record \
|
| 160 |
-
--robot.type=so101_follower \
|
| 161 |
-
--robot.port=/dev/tty.usbmodem585A0076841 \
|
| 162 |
-
--robot.id=my_awesome_follower_arm \
|
| 163 |
-
--robot.cameras="{ front: {type: opencv, index_or_path: 0, width: 1920, height: 1080, fps: 30}}" \
|
| 164 |
-
--teleop.type=so101_leader \
|
| 165 |
-
--teleop.port=/dev/tty.usbmodem58760431551 \
|
| 166 |
-
--teleop.id=my_awesome_leader_arm \
|
| 167 |
-
--display_data=true \
|
| 168 |
-
--dataset.repo_id=${HF_USER}/record-test \
|
| 169 |
-
--dataset.num_episodes=2 \
|
| 170 |
-
--dataset.single_task="Grab the black cube"
|
| 171 |
-
```
|
| 172 |
-
|
| 173 |
-
#### Dataset upload
|
| 174 |
-
Locally, your dataset is stored in this folder: `~/.cache/huggingface/lerobot/{repo-id}`. At the end of data recording, your dataset will be uploaded on your Hugging Face page (e.g. https://huggingface.co/datasets/cadene/so101_test) that you can obtain by running:
|
| 175 |
-
```bash
|
| 176 |
-
echo https://huggingface.co/datasets/${HF_USER}/so101_test
|
| 177 |
-
```
|
| 178 |
-
Your dataset will be automatically tagged with `LeRobot` for the community to find it easily, and you can also add custom tags (in this case `tutorial` for example).
|
| 179 |
-
|
| 180 |
-
You can look for other LeRobot datasets on the hub by searching for `LeRobot` [tags](https://huggingface.co/datasets?other=LeRobot).
|
| 181 |
-
|
| 182 |
-
#### Record function
|
| 183 |
-
|
| 184 |
-
The `record` function provides a suite of tools for capturing and managing data during robot operation:
|
| 185 |
-
|
| 186 |
-
##### 1. Data Storage
|
| 187 |
-
- Data is stored using the `LeRobotDataset` format and is stored on disk during recording.
|
| 188 |
-
- By default, the dataset is pushed to your Hugging Face page after recording.
|
| 189 |
-
- To disable uploading, use `--dataset.push_to_hub=False`.
|
| 190 |
-
|
| 191 |
-
##### 2. Checkpointing and Resuming
|
| 192 |
-
- Checkpoints are automatically created during recording.
|
| 193 |
-
- If an issue occurs, you can resume by re-running the same command with `--resume=true`.
|
| 194 |
-
- To start recording from scratch, **manually delete** the dataset directory.
|
| 195 |
-
|
| 196 |
-
##### 3. Recording Parameters
|
| 197 |
-
Set the flow of data recording using command-line arguments:
|
| 198 |
-
- `--dataset.episode_time_s=60`
|
| 199 |
-
Duration of each data recording episode (default: **60 seconds**).
|
| 200 |
-
- `--dataset.reset_time_s=60`
|
| 201 |
-
Duration for resetting the environment after each episode (default: **60 seconds**).
|
| 202 |
-
- `--dataset.num_episodes=50`
|
| 203 |
-
Total number of episodes to record (default: **50**).
|
| 204 |
-
|
| 205 |
-
##### 4. Keyboard Controls During Recording
|
| 206 |
-
Control the data recording flow using keyboard shortcuts:
|
| 207 |
-
- Press **Right Arrow (`→`)**: Early stop the current episode or reset time and move to the next.
|
| 208 |
-
- Press **Left Arrow (`←`)**: Cancel the current episode and re-record it.
|
| 209 |
-
- Press **Escape (`ESC`)**: Immediately stop the session, encode videos, and upload the dataset.
|
| 210 |
-
|
| 211 |
-
#### Tips for gathering data
|
| 212 |
-
|
| 213 |
-
Once you're comfortable with data recording, you can create a larger dataset for training. A good starting task is grasping an object at different locations and placing it in a bin. We suggest recording at least 50 episodes, with 10 episodes per location. Keep the cameras fixed and maintain consistent grasping behavior throughout the recordings. Also make sure the object you are manipulating is visible on the camera's. A good rule of thumb is you should be able to do the task yourself by only looking at the camera images.
|
| 214 |
-
|
| 215 |
-
In the following sections, you’ll train your neural network. After achieving reliable grasping performance, you can start introducing more variations during data collection, such as additional grasp locations, different grasping techniques, and altering camera positions.
|
| 216 |
-
|
| 217 |
-
Avoid adding too much variation too quickly, as it may hinder your results.
|
| 218 |
-
|
| 219 |
-
If you want to dive deeper into this important topic, you can check out the [blog post](https://huggingface.co/blog/lerobot-datasets#what-makes-a-good-dataset) we wrote on what makes a good dataset.
|
| 220 |
-
|
| 221 |
-
|
| 222 |
-
#### Troubleshooting:
|
| 223 |
-
- On Linux, if the left and right arrow keys and escape key don't have any effect during data recording, make sure you've set the `$DISPLAY` environment variable. See [pynput limitations](https://pynput.readthedocs.io/en/latest/limitations.html#linux).
|
| 224 |
-
|
| 225 |
-
## Visualize a dataset
|
| 226 |
-
|
| 227 |
-
If you uploaded your dataset to the hub with `--control.push_to_hub=true`, you can [visualize your dataset online](https://huggingface.co/spaces/lerobot/visualize_dataset) by copy pasting your repo id given by:
|
| 228 |
-
```bash
|
| 229 |
-
echo ${HF_USER}/so101_test
|
| 230 |
-
```
|
| 231 |
-
|
| 232 |
-
## Replay an episode
|
| 233 |
-
|
| 234 |
-
A useful feature is the `replay` function, which allows you to replay any episode that you've recorded or episodes from any dataset out there. This function helps you test the repeatability of your robot's actions and assess transferability across robots of the same model.
|
| 235 |
-
|
| 236 |
-
You can replay the first episode on your robot with:
|
| 237 |
-
```bash
|
| 238 |
-
python -m lerobot.replay \
|
| 239 |
-
--robot.type=so101_follower \
|
| 240 |
-
--robot.port=/dev/tty.usbmodem58760431541 \
|
| 241 |
-
--robot.id=my_awesome_follower_arm \
|
| 242 |
-
--dataset.repo_id=${HF_USER}/record-test \
|
| 243 |
-
--dataset.episode=0 # choose the episode you want to replay
|
| 244 |
-
```
|
| 245 |
-
|
| 246 |
-
Your robot should replicate movements similar to those you recorded. For example, check out [this video](https://x.com/RemiCadene/status/1793654950905680090) where we use `replay` on a Aloha robot from [Trossen Robotics](https://www.trossenrobotics.com).
|
| 247 |
-
|
| 248 |
-
## Train a policy
|
| 249 |
-
|
| 250 |
-
To train a policy to control your robot, use the [`python lerobot/scripts/train.py`](../lerobot/scripts/train.py) script. A few arguments are required. Here is an example command:
|
| 251 |
-
```bash
|
| 252 |
-
python lerobot/scripts/train.py \
|
| 253 |
-
--dataset.repo_id=${HF_USER}/so101_test \
|
| 254 |
-
--policy.type=act \
|
| 255 |
-
--output_dir=outputs/train/act_so101_test \
|
| 256 |
-
--job_name=act_so101_test \
|
| 257 |
-
--policy.device=cuda \
|
| 258 |
-
--wandb.enable=true
|
| 259 |
-
```
|
| 260 |
-
|
| 261 |
-
Let's explain the command:
|
| 262 |
-
1. We provided the dataset as argument with `--dataset.repo_id=${HF_USER}/so101_test`.
|
| 263 |
-
2. We provided the policy with `policy.type=act`. This loads configurations from [`configuration_act.py`](../lerobot/common/policies/act/configuration_act.py). Importantly, this policy will automatically adapt to the number of motor states, motor actions and cameras of your robot (e.g. `laptop` and `phone`) which have been saved in your dataset.
|
| 264 |
-
4. We provided `policy.device=cuda` since we are training on a Nvidia GPU, but you could use `policy.device=mps` to train on Apple silicon.
|
| 265 |
-
5. We provided `wandb.enable=true` to use [Weights and Biases](https://docs.wandb.ai/quickstart) for visualizing training plots. This is optional but if you use it, make sure you are logged in by running `wandb login`.
|
| 266 |
-
|
| 267 |
-
Training should take several hours. You will find checkpoints in `outputs/train/act_so101_test/checkpoints`.
|
| 268 |
-
|
| 269 |
-
To resume training from a checkpoint, below is an example command to resume from `last` checkpoint of the `act_so101_test` policy:
|
| 270 |
-
```bash
|
| 271 |
-
python lerobot/scripts/train.py \
|
| 272 |
-
--config_path=outputs/train/act_so101_test/checkpoints/last/pretrained_model/train_config.json \
|
| 273 |
-
--resume=true
|
| 274 |
-
```
|
| 275 |
-
|
| 276 |
-
#### Train using Collab
|
| 277 |
-
If your local computer doesn't have a powerful GPU you could utilize Google Collab to train your model by following the [ACT training notebook](./notebooks#training-act).
|
| 278 |
-
|
| 279 |
-
#### Upload policy checkpoints
|
| 280 |
-
|
| 281 |
-
Once training is done, upload the latest checkpoint with:
|
| 282 |
-
```bash
|
| 283 |
-
huggingface-cli upload ${HF_USER}/act_so101_test \
|
| 284 |
-
outputs/train/act_so101_test/checkpoints/last/pretrained_model
|
| 285 |
-
```
|
| 286 |
-
|
| 287 |
-
You can also upload intermediate checkpoints with:
|
| 288 |
-
```bash
|
| 289 |
-
CKPT=010000
|
| 290 |
-
huggingface-cli upload ${HF_USER}/act_so101_test${CKPT} \
|
| 291 |
-
outputs/train/act_so101_test/checkpoints/${CKPT}/pretrained_model
|
| 292 |
-
```
|
| 293 |
-
|
| 294 |
-
## Evaluate your policy
|
| 295 |
-
|
| 296 |
-
You can use the `record` script from [`lerobot/record.py`](https://github.com/huggingface/lerobot/blob/main/lerobot/record.py) but with a policy checkpoint as input. For instance, run this command to record 10 evaluation episodes:
|
| 297 |
-
```bash
|
| 298 |
-
python -m lerobot.record \
|
| 299 |
-
--robot.type=so100_follower \
|
| 300 |
-
--robot.port=/dev/ttyACM1 \
|
| 301 |
-
--robot.cameras="{ up: {type: opencv, index_or_path: /dev/video10, width: 640, height: 480, fps: 30}, side: {type: intelrealsense, serial_number_or_name: 233522074606, width: 640, height: 480, fps: 30}}" \
|
| 302 |
-
--robot.id=my_awesome_follower_arm \
|
| 303 |
-
--display_data=false \
|
| 304 |
-
--dataset.repo_id=${HF_USER}/eval_so100 \
|
| 305 |
-
--dataset.single_task="Put lego brick into the transparent box" \
|
| 306 |
-
# <- Teleop optional if you want to teleoperate in between episodes \
|
| 307 |
-
# --teleop.type=so100_leader \
|
| 308 |
-
# --teleop.port=/dev/ttyACM0 \
|
| 309 |
-
# --teleop.id=my_awesome_leader_arm \
|
| 310 |
-
--policy.path=${HF_USER}/my_policy
|
| 311 |
-
```
|
| 312 |
-
|
| 313 |
-
As you can see, it's almost the same command as previously used to record your training dataset. Two things changed:
|
| 314 |
-
1. There is an additional `--control.policy.path` argument which indicates the path to your policy checkpoint with (e.g. `outputs/train/eval_act_so101_test/checkpoints/last/pretrained_model`). You can also use the model repository if you uploaded a model checkpoint to the hub (e.g. `${HF_USER}/act_so101_test`).
|
| 315 |
-
2. The name of dataset begins by `eval` to reflect that you are running inference (e.g. `${HF_USER}/eval_act_so101_test`).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/il_sim.mdx
DELETED
|
@@ -1,152 +0,0 @@
|
|
| 1 |
-
# Imitation Learning in Sim
|
| 2 |
-
|
| 3 |
-
This tutorial will explain how to train a neural network to control a robot in simulation with imitation learning.
|
| 4 |
-
|
| 5 |
-
**You'll learn:**
|
| 6 |
-
1. How to record a dataset in simulation with [gym-hil](https://github.com/huggingface/gym-hil) and visualize the dataset.
|
| 7 |
-
2. How to train a policy using your data.
|
| 8 |
-
3. How to evaluate your policy in simulation and visualize the results.
|
| 9 |
-
|
| 10 |
-
For the simulation environment we use the same [repo](https://github.com/huggingface/gym-hil) that is also being used by the Human-In-the-Loop (HIL) reinforcement learning algorithm.
|
| 11 |
-
This environment is based on [MuJoCo](https://mujoco.org) and allows you to record datasets in LeRobotDataset format.
|
| 12 |
-
Teleoperation is easiest with a controller like the Logitech F710, but you can also use your keyboard if you are up for the challenge.
|
| 13 |
-
|
| 14 |
-
## Installation
|
| 15 |
-
|
| 16 |
-
First, install the `gym_hil` package within the LeRobot environment, go to your LeRobot folder and run this command:
|
| 17 |
-
|
| 18 |
-
```bash
|
| 19 |
-
pip install -e ".[hilserl]"
|
| 20 |
-
```
|
| 21 |
-
|
| 22 |
-
## Teleoperate and Record a Dataset
|
| 23 |
-
|
| 24 |
-
To use `gym_hil` with LeRobot, you need to use a configuration file. An example config file can be found [here](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/env_config_gym_hil_il.json).
|
| 25 |
-
|
| 26 |
-
To teleoperate and collect a dataset, we need to modify this config file and you should add your `repo_id` here: `"repo_id": "il_gym",` and `"num_episodes": 30,` and make sure you set `mode` to `record`, "mode": "record".
|
| 27 |
-
|
| 28 |
-
If you do not have a Nvidia GPU also change `"device": "cuda"` parameter in the config file (for example to `mps` for MacOS).
|
| 29 |
-
|
| 30 |
-
By default the config file assumes you use a controller. To use your keyboard please change the envoirment specified at `"task"` in the config file and set it to `"PandaPickCubeKeyboard-v0"`.
|
| 31 |
-
|
| 32 |
-
Then we can run this command to start:
|
| 33 |
-
|
| 34 |
-
<hfoptions id="teleop_sim">
|
| 35 |
-
<hfoption id="Linux">
|
| 36 |
-
|
| 37 |
-
```bash
|
| 38 |
-
python lerobot/scripts/rl/gym_manipulator.py --config_path path/to/env_config_gym_hil_il.json
|
| 39 |
-
```
|
| 40 |
-
|
| 41 |
-
</hfoption>
|
| 42 |
-
<hfoption id="MacOS">
|
| 43 |
-
|
| 44 |
-
```bash
|
| 45 |
-
mjpython lerobot/scripts/rl/gym_manipulator.py --config_path path/to/env_config_gym_hil_il.json
|
| 46 |
-
```
|
| 47 |
-
|
| 48 |
-
</hfoption>
|
| 49 |
-
</hfoptions>
|
| 50 |
-
|
| 51 |
-
Once rendered you can teleoperate the robot with the gamepad or keyboard, below you can find the gamepad/keyboard controls.
|
| 52 |
-
|
| 53 |
-
Note that to teleoperate the robot you have to hold the "Human Take Over Pause Policy" Button `RB` to enable control!
|
| 54 |
-
|
| 55 |
-
**Gamepad Controls**
|
| 56 |
-
|
| 57 |
-
<p align="center">
|
| 58 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/gamepad_guide.jpg?raw=true" alt="Figure shows the control mappings on a Logitech gamepad." title="Gamepad Control Mapping" width="100%"></img>
|
| 59 |
-
</p>
|
| 60 |
-
<p align="center"><i>Gamepad button mapping for robot control and episode management</i></p>
|
| 61 |
-
|
| 62 |
-
**Keyboard controls**
|
| 63 |
-
|
| 64 |
-
For keyboard controls use the `spacebar` to enable control and the following keys to move the robot:
|
| 65 |
-
```bash
|
| 66 |
-
Arrow keys: Move in X-Y plane
|
| 67 |
-
Shift and Shift_R: Move in Z axis
|
| 68 |
-
Right Ctrl and Left Ctrl: Open and close gripper
|
| 69 |
-
ESC: Exit
|
| 70 |
-
```
|
| 71 |
-
|
| 72 |
-
## Visualize a dataset
|
| 73 |
-
|
| 74 |
-
If you uploaded your dataset to the hub you can [visualize your dataset online](https://huggingface.co/spaces/lerobot/visualize_dataset) by copy pasting your repo id.
|
| 75 |
-
|
| 76 |
-
<p align="center">
|
| 77 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/dataset_visualizer_sim.png" alt="Figure shows the dataset visualizer" title="Dataset visualization" width="100%"></img>
|
| 78 |
-
</p>
|
| 79 |
-
<p align="center"><i>Dataset visualizer</i></p>
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
## Train a policy
|
| 83 |
-
|
| 84 |
-
To train a policy to control your robot, use the [`python lerobot/scripts/train.py`](../lerobot/scripts/train.py) script. A few arguments are required. Here is an example command:
|
| 85 |
-
```bash
|
| 86 |
-
python lerobot/scripts/train.py \
|
| 87 |
-
--dataset.repo_id=${HF_USER}/il_gym \
|
| 88 |
-
--policy.type=act \
|
| 89 |
-
--output_dir=outputs/train/il_sim_test \
|
| 90 |
-
--job_name=il_sim_test \
|
| 91 |
-
--policy.device=cuda \
|
| 92 |
-
--wandb.enable=true
|
| 93 |
-
```
|
| 94 |
-
|
| 95 |
-
Let's explain the command:
|
| 96 |
-
1. We provided the dataset as argument with `--dataset.repo_id=${HF_USER}/il_gym`.
|
| 97 |
-
2. We provided the policy with `policy.type=act`. This loads configurations from [`configuration_act.py`](../lerobot/common/policies/act/configuration_act.py). Importantly, this policy will automatically adapt to the number of motor states, motor actions and cameras of your robot (e.g. `laptop` and `phone`) which have been saved in your dataset.
|
| 98 |
-
4. We provided `policy.device=cuda` since we are training on a Nvidia GPU, but you could use `policy.device=mps` to train on Apple silicon.
|
| 99 |
-
5. We provided `wandb.enable=true` to use [Weights and Biases](https://docs.wandb.ai/quickstart) for visualizing training plots. This is optional but if you use it, make sure you are logged in by running `wandb login`.
|
| 100 |
-
|
| 101 |
-
Training should take several hours, 100k steps (which is the default) will take about 1h on Nvidia A100. You will find checkpoints in `outputs/train/il_sim_test/checkpoints`.
|
| 102 |
-
|
| 103 |
-
#### Train using Collab
|
| 104 |
-
If your local computer doesn't have a powerful GPU you could utilize Google Collab to train your model by following the [ACT training notebook](./notebooks#training-act).
|
| 105 |
-
|
| 106 |
-
#### Upload policy checkpoints
|
| 107 |
-
|
| 108 |
-
Once training is done, upload the latest checkpoint with:
|
| 109 |
-
```bash
|
| 110 |
-
huggingface-cli upload ${HF_USER}/il_sim_test \
|
| 111 |
-
outputs/train/il_sim_test/checkpoints/last/pretrained_model
|
| 112 |
-
```
|
| 113 |
-
|
| 114 |
-
You can also upload intermediate checkpoints with:
|
| 115 |
-
```bash
|
| 116 |
-
CKPT=010000
|
| 117 |
-
huggingface-cli upload ${HF_USER}/il_sim_test${CKPT} \
|
| 118 |
-
outputs/train/il_sim_test/checkpoints/${CKPT}/pretrained_model
|
| 119 |
-
```
|
| 120 |
-
|
| 121 |
-
## Evaluate your policy in Sim
|
| 122 |
-
|
| 123 |
-
To evaluate your policy we have to use the config file that can be found [here](https://huggingface.co/datasets/aractingi/lerobot-example-config-files/blob/main/eval_config_gym_hil.json).
|
| 124 |
-
|
| 125 |
-
Make sure to replace the `repo_id` with the dataset you trained on, for example `pepijn223/il_sim_dataset` and replace the `pretrained_policy_name_or_path` with your model id, for example `pepijn223/il_sim_model`
|
| 126 |
-
|
| 127 |
-
Then you can run this command to visualize your trained policy
|
| 128 |
-
|
| 129 |
-
<hfoptions id="eval_policy">
|
| 130 |
-
<hfoption id="Linux">
|
| 131 |
-
|
| 132 |
-
```bash
|
| 133 |
-
python lerobot/scripts/rl/eval_policy.py --config_path=path/to/eval_config_gym_hil.json
|
| 134 |
-
```
|
| 135 |
-
|
| 136 |
-
</hfoption>
|
| 137 |
-
<hfoption id="MacOS">
|
| 138 |
-
|
| 139 |
-
```bash
|
| 140 |
-
mjpython lerobot/scripts/rl/eval_policy.py --config_path=path/to/eval_config_gym_hil.json
|
| 141 |
-
```
|
| 142 |
-
|
| 143 |
-
</hfoption>
|
| 144 |
-
</hfoptions>
|
| 145 |
-
|
| 146 |
-
> [!WARNING]
|
| 147 |
-
> While the main workflow of training ACT in simulation is straightforward, there is significant room for exploring how to set up the task, define the initial state of the environment, and determine the type of data required during collection to learn the most effective policy. If your trained policy doesn't perform well, investigate the quality of the dataset it was trained on using our visualizers, as well as the action values and various hyperparameters related to ACT and the simulation.
|
| 148 |
-
|
| 149 |
-
Congrats 🎉, you have finished this tutorial. If you want to continue with using LeRobot in simulation follow this [Tutorial on reinforcement learning in sim with HIL-SERL](https://huggingface.co/docs/lerobot/hilserl_sim)
|
| 150 |
-
|
| 151 |
-
> [!TIP]
|
| 152 |
-
> If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/index.mdx
DELETED
|
@@ -1,19 +0,0 @@
|
|
| 1 |
-
<div class="flex justify-center">
|
| 2 |
-
<a target="_blank" href="https://huggingface.co/lerobot">
|
| 3 |
-
<img alt="HuggingFace Expert Acceleration Program" src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/lerobot-logo-thumbnail.png" style="width: 100%"></img>
|
| 4 |
-
</a>
|
| 5 |
-
</div>
|
| 6 |
-
|
| 7 |
-
# LeRobot
|
| 8 |
-
|
| 9 |
-
**State-of-the-art machine learning for real-world robotics**
|
| 10 |
-
|
| 11 |
-
🤗 LeRobot aims to provide models, datasets, and tools for real-world robotics in PyTorch. The goal is to lower the barrier for entry to robotics so that everyone can contribute and benefit from sharing datasets and pretrained models.
|
| 12 |
-
|
| 13 |
-
🤗 LeRobot contains state-of-the-art approaches that have been shown to transfer to the real-world with a focus on imitation learning and reinforcement learning.
|
| 14 |
-
|
| 15 |
-
🤗 LeRobot already provides a set of pretrained models, datasets with human collected demonstrations, and simulated environments so that everyone can get started.
|
| 16 |
-
|
| 17 |
-
🤗 LeRobot hosts pretrained models and datasets on the LeRobot HuggingFace page.
|
| 18 |
-
|
| 19 |
-
Join the LeRobot community on [Discord](https://discord.gg/s3KuuzsPFb)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/installation.mdx
DELETED
|
@@ -1,72 +0,0 @@
|
|
| 1 |
-
# Installation
|
| 2 |
-
|
| 3 |
-
## Install LeRobot
|
| 4 |
-
|
| 5 |
-
Currently only available from source.
|
| 6 |
-
|
| 7 |
-
Download our source code:
|
| 8 |
-
```bash
|
| 9 |
-
git clone https://github.com/huggingface/lerobot.git
|
| 10 |
-
cd lerobot
|
| 11 |
-
```
|
| 12 |
-
|
| 13 |
-
Create a virtual environment with Python 3.10, using [`Miniconda`](https://docs.anaconda.com/miniconda/install/#quick-command-line-install)
|
| 14 |
-
```bash
|
| 15 |
-
conda create -y -n lerobot python=3.10
|
| 16 |
-
```
|
| 17 |
-
|
| 18 |
-
Then activate your conda environment, you have to do this each time you open a shell to use lerobot:
|
| 19 |
-
```bash
|
| 20 |
-
conda activate lerobot
|
| 21 |
-
```
|
| 22 |
-
|
| 23 |
-
When using `miniconda`, install `ffmpeg` in your environment:
|
| 24 |
-
```bash
|
| 25 |
-
conda install ffmpeg -c conda-forge
|
| 26 |
-
```
|
| 27 |
-
|
| 28 |
-
> [!TIP]
|
| 29 |
-
> This usually installs `ffmpeg 7.X` for your platform compiled with the `libsvtav1` encoder. If `libsvtav1` is not supported (check supported encoders with `ffmpeg -encoders`), you can:
|
| 30 |
-
> - _[On any platform]_ Explicitly install `ffmpeg 7.X` using:
|
| 31 |
-
> ```bash
|
| 32 |
-
> conda install ffmpeg=7.1.1 -c conda-forge
|
| 33 |
-
> ```
|
| 34 |
-
> - _[On Linux only]_ If you want to bring your own ffmpeg: Install [ffmpeg build dependencies](https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu#GettheDependencies) and [compile ffmpeg from source with libsvtav1](https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu#libsvtav1), and make sure you use the corresponding ffmpeg binary to your install with `which ffmpeg`.
|
| 35 |
-
|
| 36 |
-
Install 🤗 LeRobot:
|
| 37 |
-
```bash
|
| 38 |
-
pip install -e .
|
| 39 |
-
```
|
| 40 |
-
|
| 41 |
-
### Troubleshooting
|
| 42 |
-
If you encounter build errors, you may need to install additional dependencies: `cmake`, `build-essential`, and `ffmpeg libs`.
|
| 43 |
-
To install these for linux run:
|
| 44 |
-
```bash
|
| 45 |
-
sudo apt-get install cmake build-essential python-dev pkg-config libavformat-dev libavcodec-dev libavdevice-dev libavutil-dev libswscale-dev libswresample-dev libavfilter-dev pkg-config
|
| 46 |
-
```
|
| 47 |
-
For other systems, see: [Compiling PyAV](https://pyav.org/docs/develop/overview/installation.html#bring-your-own-ffmpeg)
|
| 48 |
-
|
| 49 |
-
## Optional dependencies
|
| 50 |
-
|
| 51 |
-
LeRobot provides optional extras for specific functionalities. Multiple extras can be combined (e.g., `.[aloha,feetech]`). For all available extras, refer to `pyproject.toml`.
|
| 52 |
-
|
| 53 |
-
### Simulations
|
| 54 |
-
Install environment packages: `aloha` ([gym-aloha](https://github.com/huggingface/gym-aloha)), `xarm` ([gym-xarm](https://github.com/huggingface/gym-xarm)), or `pusht` ([gym-pusht](https://github.com/huggingface/gym-pusht))
|
| 55 |
-
Example:
|
| 56 |
-
```bash
|
| 57 |
-
pip install -e ".[aloha]" # or "[pusht]" for example
|
| 58 |
-
```
|
| 59 |
-
|
| 60 |
-
### Motor Control
|
| 61 |
-
For Koch v1.1 install the Dynamixel SDK, for SO100/SO101/Moss install the Feetech SDK.
|
| 62 |
-
```bash
|
| 63 |
-
pip install -e ".[feetech]" # or "[dynamixel]" for example
|
| 64 |
-
```
|
| 65 |
-
|
| 66 |
-
### Experiment Tracking
|
| 67 |
-
To use [Weights and Biases](https://docs.wandb.ai/quickstart) for experiment tracking, log in with
|
| 68 |
-
```bash
|
| 69 |
-
wandb login
|
| 70 |
-
```
|
| 71 |
-
|
| 72 |
-
You can now assemble your robot if it's not ready yet, look for your robot type on the left. Then follow the link below to use Lerobot with your robot.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/integrate_hardware.mdx
DELETED
|
@@ -1,318 +0,0 @@
|
|
| 1 |
-
# Bring Your Own Hardware
|
| 2 |
-
|
| 3 |
-
This tutorial will explain how to integrate your own robot design into the LeRobot ecosystem and have it access all of our tools (data collection, control pipelines, policy training and inference).
|
| 4 |
-
|
| 5 |
-
To that end, we provide the [`Robot`](https://github.com/huggingface/lerobot/blob/main/lerobot/common/robots/robot.py) base class in the LeRobot which specifies a standard interface for physical robot integration. Let's see how to implement it.
|
| 6 |
-
|
| 7 |
-
## Prerequisites
|
| 8 |
-
|
| 9 |
-
- Your own robot which exposes a communication interface (e.g. serial, CAN, TCP)
|
| 10 |
-
- A way to read sensor data and send motor commands programmatically, e.g. manufacturer's SDK or API, or your own protocol implementation.
|
| 11 |
-
- LeRobot installed in your environment. Follow our [Installation Guide](./installation).
|
| 12 |
-
|
| 13 |
-
## Choose your motors
|
| 14 |
-
|
| 15 |
-
If you're using Feetech or Dynamixel motors, LeRobot provides built-in bus interfaces:
|
| 16 |
-
|
| 17 |
-
- [`FeetechMotorsBus`](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/feetech/feetech.py) – for controlling Feetech servos
|
| 18 |
-
- [`DynamixelMotorsBus`](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/dynamixel/dynamixel.py) – for controlling Dynamixel servos
|
| 19 |
-
|
| 20 |
-
Please refer to the [`MotorsBus`](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/motors_bus.py) abstract class to learn about its API.
|
| 21 |
-
For a good example of how it can be used, you can have a look at our own [SO101 follower implementation](https://github.com/huggingface/lerobot/blob/main/lerobot/common/robots/so101_follower/so101_follower.py)
|
| 22 |
-
|
| 23 |
-
Use these if compatible. Otherwise, you'll need to find or write a Python interface (not covered in this tutorial):
|
| 24 |
-
- Find an existing SDK in Python (or use bindings to C/C++)
|
| 25 |
-
- Or implement a basic communication wrapper (e.g., via pyserial, socket, or CANopen)
|
| 26 |
-
|
| 27 |
-
You're not alone—many community contributions use custom boards or firmware!
|
| 28 |
-
|
| 29 |
-
For Feetech and Dynamixel, we currently support these servos:
|
| 30 |
-
- Feetech:
|
| 31 |
-
- STS & SMS series (protocol 0): `sts3215`, `sts3250`, `sm8512bl`
|
| 32 |
-
- SCS series (protocol 1): `scs0009`
|
| 33 |
-
- Dynamixel (protocol 2.0 only): `xl330-m077`, `xl330-m288`, `xl430-w250`, `xm430-w350`, `xm540-w270`, `xc430-w150`
|
| 34 |
-
|
| 35 |
-
If you are using Feetech or Dynamixel servos that are not in this list, you can add those in the [Feetech table](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/feetech/tables.py) or [Dynamixel table](https://github.com/huggingface/lerobot/blob/main/lerobot/common/motors/dynamixel/tables.py). Depending on the model, this will require you to add model-specific information. In most cases though, there shouldn't be a lot of additions to do.
|
| 36 |
-
|
| 37 |
-
In the next sections, we'll use a `FeetechMotorsBus` as the motors interface for the examples. Replace it and adapt to your motors if necessary.
|
| 38 |
-
|
| 39 |
-
## Step 1: Subclass the `Robot` Interface
|
| 40 |
-
|
| 41 |
-
You’ll first need to specify the config class and a string identifier (`name`) for your robot. If your robot has special needs that you'd like to be able to change easily, it should go here (e.g. port/address, baudrate).
|
| 42 |
-
|
| 43 |
-
Here, we'll add the port name and one camera by default for our robot:
|
| 44 |
-
```python
|
| 45 |
-
from dataclasses import dataclass, field
|
| 46 |
-
|
| 47 |
-
from lerobot.common.cameras import CameraConfig
|
| 48 |
-
from lerobot.common.cameras.opencv import OpenCVCameraConfig
|
| 49 |
-
from lerobot.common.robots import RobotConfig
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
@RobotConfig.register_subclass("my_cool_robot")
|
| 53 |
-
@dataclass
|
| 54 |
-
class MyCoolRobotConfig(RobotConfig):
|
| 55 |
-
port: str
|
| 56 |
-
cameras: dict[str, CameraConfig] = field(
|
| 57 |
-
default_factory={
|
| 58 |
-
"cam_1": OpenCVCameraConfig(
|
| 59 |
-
index_or_path=2,
|
| 60 |
-
fps=30,
|
| 61 |
-
width=480,
|
| 62 |
-
height=640,
|
| 63 |
-
),
|
| 64 |
-
}
|
| 65 |
-
)
|
| 66 |
-
```
|
| 67 |
-
|
| 68 |
-
Have a look at our [Cameras tutorial](./cameras) to understand how to detect and add your camera.
|
| 69 |
-
|
| 70 |
-
Next, we'll create our actual robot class which inherits from `Robot`. This abstract class defines a contract you must follow for your robot to be usable with the rest of the LeRobot tools.
|
| 71 |
-
|
| 72 |
-
Here we'll create a simple 5-DoF robot with one camera. It could be a simple arm but notice that the `Robot` abstract class does not assume anything on your robot's form factor. You can let you imagination run wild when designing new robots!
|
| 73 |
-
|
| 74 |
-
```python
|
| 75 |
-
from lerobot.common.cameras import make_cameras_from_configs
|
| 76 |
-
from lerobot.common.motors import Motor, MotorNormMode
|
| 77 |
-
from lerobot.common.motors.feetech import FeetechMotorsBus
|
| 78 |
-
from lerobot.common.robots import Robot
|
| 79 |
-
|
| 80 |
-
class MyCoolRobot(Robot):
|
| 81 |
-
config_class = MyCoolRobotConfig
|
| 82 |
-
name = "my_cool_robot"
|
| 83 |
-
|
| 84 |
-
def __init__(self, config: MyCoolRobotConfig):
|
| 85 |
-
super().__init__(config)
|
| 86 |
-
self.bus = FeetechMotorsBus(
|
| 87 |
-
port=self.config.port,
|
| 88 |
-
motors={
|
| 89 |
-
"joint_1": Motor(1, "sts3250", MotorNormMode.RANGE_M100_100),
|
| 90 |
-
"joint_2": Motor(2, "sts3215", MotorNormMode.RANGE_M100_100),
|
| 91 |
-
"joint_3": Motor(3, "sts3215", MotorNormMode.RANGE_M100_100),
|
| 92 |
-
"joint_4": Motor(4, "sts3215", MotorNormMode.RANGE_M100_100),
|
| 93 |
-
"joint_5": Motor(5, "sts3215", MotorNormMode.RANGE_M100_100),
|
| 94 |
-
},
|
| 95 |
-
calibration=self.calibration,
|
| 96 |
-
)
|
| 97 |
-
self.cameras = make_cameras_from_configs(config.cameras)
|
| 98 |
-
```
|
| 99 |
-
|
| 100 |
-
## Step 2: Define Observation and Action Features
|
| 101 |
-
|
| 102 |
-
These two properties define the *interface contract* between your robot and tools that consume it (such as data collection or learning pipelines).
|
| 103 |
-
|
| 104 |
-
> [!WARNING]
|
| 105 |
-
> Note that these properties must be callable even if the robot is not yet connected, so avoid relying on runtime hardware state to define them.
|
| 106 |
-
|
| 107 |
-
### `observation_features`
|
| 108 |
-
|
| 109 |
-
This property should return a dictionary describing the structure of sensor outputs from your robot. The keys match what `get_observation()` returns, and the values describe either the shape (for arrays/images) or the type (for simple values).
|
| 110 |
-
|
| 111 |
-
Example for our 5-DoF arm with one camera:
|
| 112 |
-
```python
|
| 113 |
-
@property
|
| 114 |
-
def _motors_ft(self) -> dict[str, type]:
|
| 115 |
-
return {
|
| 116 |
-
"joint_1.pos": float,
|
| 117 |
-
"joint_2.pos": float,
|
| 118 |
-
"joint_3.pos": float,
|
| 119 |
-
"joint_4.pos": float,
|
| 120 |
-
"joint_5.pos": float,
|
| 121 |
-
}
|
| 122 |
-
|
| 123 |
-
@property
|
| 124 |
-
def _cameras_ft(self) -> dict[str, tuple]:
|
| 125 |
-
return {
|
| 126 |
-
cam: (self.cameras[cam].height, self.cameras[cam].width, 3) for cam in self.cameras
|
| 127 |
-
}
|
| 128 |
-
|
| 129 |
-
@property
|
| 130 |
-
def observation_features(self) -> dict:
|
| 131 |
-
return {**self._motors_ft, **self._cameras_ft}
|
| 132 |
-
```
|
| 133 |
-
In this case, observations consist of a simple dict storing each motor's position and a camera image.
|
| 134 |
-
|
| 135 |
-
### `action_features`
|
| 136 |
-
|
| 137 |
-
This property describes the commands your robot expects via `send_action()`. Again, keys must match the expected input format, and values define the shape/type of each command.
|
| 138 |
-
|
| 139 |
-
Here, we simply use the same joints proprioceptive features (`self._motors_ft`) as with `observation_features`: the action sent will simply the goal position for each motor.
|
| 140 |
-
```python
|
| 141 |
-
def action_features(self) -> dict:
|
| 142 |
-
return self._motors_ft
|
| 143 |
-
```
|
| 144 |
-
|
| 145 |
-
## Step 3: Handle Connection and Disconnection
|
| 146 |
-
|
| 147 |
-
These methods should handle opening and closing communication with your hardware (e.g. serial ports, CAN interfaces, USB devices, cameras).
|
| 148 |
-
|
| 149 |
-
### `is_connected`
|
| 150 |
-
|
| 151 |
-
This property should simply reflect that communication with the robot's hardware is established. When this property is `True`, it should be possible to read and write to the hardware using `get_observation()` and `send_action()`.
|
| 152 |
-
|
| 153 |
-
```python
|
| 154 |
-
@property
|
| 155 |
-
def is_connected(self) -> bool:
|
| 156 |
-
return self.bus.is_connected and all(cam.is_connected for cam in self.cameras.values())
|
| 157 |
-
```
|
| 158 |
-
|
| 159 |
-
### `connect()`
|
| 160 |
-
|
| 161 |
-
This method should establish communication with the hardware. Moreover, if your robot needs calibration and is not calibrated, it should start a calibration procedure by default. If your robot needs some specific configuration, this should also be called here.
|
| 162 |
-
|
| 163 |
-
```python
|
| 164 |
-
def connect(self, calibrate: bool = True) -> None:
|
| 165 |
-
self.bus.connect()
|
| 166 |
-
if not self.is_calibrated and calibrate:
|
| 167 |
-
self.calibrate()
|
| 168 |
-
|
| 169 |
-
for cam in self.cameras.values():
|
| 170 |
-
cam.connect()
|
| 171 |
-
|
| 172 |
-
self.configure()
|
| 173 |
-
```
|
| 174 |
-
|
| 175 |
-
### `disconnect()`
|
| 176 |
-
|
| 177 |
-
This method should gracefully terminate communication with the hardware: free any related resources (threads or processes), close ports, etc.
|
| 178 |
-
|
| 179 |
-
Here, we already handle this in our `MotorsBus` and `Camera` classes so we just need to call their own `disconnect()` methods:
|
| 180 |
-
```python
|
| 181 |
-
def disconnect(self) -> None:
|
| 182 |
-
self.bus.disconnect()
|
| 183 |
-
for cam in self.cameras.values():
|
| 184 |
-
cam.disconnect()
|
| 185 |
-
```
|
| 186 |
-
|
| 187 |
-
## Step 4: Support Calibration and Configuration
|
| 188 |
-
|
| 189 |
-
LeRobot supports saving and loading calibration data automatically. This is useful for joint offsets, zero positions, or sensor alignment.
|
| 190 |
-
|
| 191 |
-
> Note that depending on your hardware, this may not apply. If that's the case, you can simply leave these methods as no-ops:
|
| 192 |
-
> ```python
|
| 193 |
-
> @property
|
| 194 |
-
> def is_calibrated(self) -> bool:
|
| 195 |
-
> return True
|
| 196 |
-
>
|
| 197 |
-
> def calibrate(self) -> None:
|
| 198 |
-
> pass
|
| 199 |
-
> ```
|
| 200 |
-
|
| 201 |
-
### `is_calibrated`
|
| 202 |
-
|
| 203 |
-
This should reflect whether your robot has the required calibration loaded.
|
| 204 |
-
|
| 205 |
-
```python
|
| 206 |
-
@property
|
| 207 |
-
def is_calibrated(self) -> bool:
|
| 208 |
-
return self.bus.is_calibrated
|
| 209 |
-
```
|
| 210 |
-
|
| 211 |
-
### `calibrate()`
|
| 212 |
-
|
| 213 |
-
The goal of the calibration is twofold:
|
| 214 |
-
- Know the physical range of motion of each motors in order to only send commands within this range.
|
| 215 |
-
- Normalize raw motors positions to sensible continuous values (e.g. percentages, degrees) instead of arbitrary discrete value dependant on the specific motor used that will not replicate elsewhere.
|
| 216 |
-
|
| 217 |
-
It should implement the logic for calibration (if relevant) and update the `self.calibration` dictionary. If you are using Feetech or Dynamixel motors, our bus interfaces already include methods to help with this.
|
| 218 |
-
|
| 219 |
-
```python
|
| 220 |
-
def calibrate(self) -> None:
|
| 221 |
-
self.bus.disable_torque()
|
| 222 |
-
for motor in self.bus.motors:
|
| 223 |
-
self.bus.write("Operating_Mode", motor, OperatingMode.POSITION.value)
|
| 224 |
-
|
| 225 |
-
input(f"Move {self} to the middle of its range of motion and press ENTER....")
|
| 226 |
-
homing_offsets = self.bus.set_half_turn_homings()
|
| 227 |
-
|
| 228 |
-
print(
|
| 229 |
-
"Move all joints sequentially through their entire ranges "
|
| 230 |
-
"of motion.\nRecording positions. Press ENTER to stop..."
|
| 231 |
-
)
|
| 232 |
-
range_mins, range_maxes = self.bus.record_ranges_of_motion()
|
| 233 |
-
|
| 234 |
-
self.calibration = {}
|
| 235 |
-
for motor, m in self.bus.motors.items():
|
| 236 |
-
self.calibration[motor] = MotorCalibration(
|
| 237 |
-
id=m.id,
|
| 238 |
-
drive_mode=0,
|
| 239 |
-
homing_offset=homing_offsets[motor],
|
| 240 |
-
range_min=range_mins[motor],
|
| 241 |
-
range_max=range_maxes[motor],
|
| 242 |
-
)
|
| 243 |
-
|
| 244 |
-
self.bus.write_calibration(self.calibration)
|
| 245 |
-
self._save_calibration()
|
| 246 |
-
print("Calibration saved to", self.calibration_fpath)
|
| 247 |
-
```
|
| 248 |
-
|
| 249 |
-
### `configure()`
|
| 250 |
-
|
| 251 |
-
Use this to set up any configuration for your hardware (servos control modes, controller gains, etc.). This should usually be run at connection time and be idempotent.
|
| 252 |
-
|
| 253 |
-
```python
|
| 254 |
-
def configure(self) -> None:
|
| 255 |
-
with self.bus.torque_disabled():
|
| 256 |
-
self.bus.configure_motors()
|
| 257 |
-
for motor in self.bus.motors:
|
| 258 |
-
self.bus.write("Operating_Mode", motor, OperatingMode.POSITION.value)
|
| 259 |
-
self.bus.write("P_Coefficient", motor, 16)
|
| 260 |
-
self.bus.write("I_Coefficient", motor, 0)
|
| 261 |
-
self.bus.write("D_Coefficient", motor, 32)
|
| 262 |
-
```
|
| 263 |
-
|
| 264 |
-
## Step 5: Implement Sensors Reading and Action Sending
|
| 265 |
-
|
| 266 |
-
These are the most important runtime functions: the core I/O loop.
|
| 267 |
-
|
| 268 |
-
### `get_observation()`
|
| 269 |
-
|
| 270 |
-
Returns a dictionary of sensor values from the robot. These typically include motor states, camera frames, various sensors, etc. In the LeRobot framework, these observations are what will be fed to a policy in order to predict the actions to take. The dictionary keys and structure must match `observation_features`.
|
| 271 |
-
|
| 272 |
-
```python
|
| 273 |
-
def get_observation(self) -> dict[str, Any]:
|
| 274 |
-
if not self.is_connected:
|
| 275 |
-
raise ConnectionError(f"{self} is not connected.")
|
| 276 |
-
|
| 277 |
-
# Read arm position
|
| 278 |
-
obs_dict = self.bus.sync_read("Present_Position")
|
| 279 |
-
obs_dict = {f"{motor}.pos": val for motor, val in obs_dict.items()}
|
| 280 |
-
|
| 281 |
-
# Capture images from cameras
|
| 282 |
-
for cam_key, cam in self.cameras.items():
|
| 283 |
-
obs_dict[cam_key] = cam.async_read()
|
| 284 |
-
|
| 285 |
-
return obs_dict
|
| 286 |
-
```
|
| 287 |
-
|
| 288 |
-
### `send_action()`
|
| 289 |
-
|
| 290 |
-
Takes a dictionary that matches `action_features`, and sends it to your hardware. You can add safety limits (clipping, smoothing) and return what was actually sent.
|
| 291 |
-
|
| 292 |
-
For simplicity, we won't be adding any modification of the actions in our example here.
|
| 293 |
-
|
| 294 |
-
```python
|
| 295 |
-
def send_action(self, action: dict[str, Any]) -> dict[str, Any]:
|
| 296 |
-
goal_pos = {key.removesuffix(".pos"): val for key, val in action.items()}
|
| 297 |
-
|
| 298 |
-
# Send goal position to the arm
|
| 299 |
-
self.bus.sync_write("Goal_Position", goal_pos)
|
| 300 |
-
|
| 301 |
-
return action
|
| 302 |
-
```
|
| 303 |
-
|
| 304 |
-
## Adding a Teleoperator
|
| 305 |
-
|
| 306 |
-
For implementing teleoperation devices, we also provide a [`Teleoperator`](https://github.com/huggingface/lerobot/blob/main/lerobot/common/teleoperators/teleoperator.py) base class. This class is very similar to the `Robot` base class and also doesn't assume anything on form factor.
|
| 307 |
-
|
| 308 |
-
The main differences are in the I/O functions: a teleoperator allows you to produce action via `get_action` and can receive feedback actions via `send_feedback`. Feedback could be anything controllable on the teleoperation device that could help the person controlling it understand the consequences of the actions sent. Think motion/force feedback on a leader arm, vibrations on a gamepad controller for example. To implement a teleoperator, you can follow this same tutorial and adapt it for these two methods.
|
| 309 |
-
|
| 310 |
-
## Wrapping Up
|
| 311 |
-
|
| 312 |
-
Once your robot class is complete, you can leverage the LeRobot ecosystem:
|
| 313 |
-
|
| 314 |
-
- Control your robot with available teleoperators or integrate directly your teleoperating device
|
| 315 |
-
- Record training data and visualize it
|
| 316 |
-
- Integrate it into RL or imitation learning pipelines
|
| 317 |
-
|
| 318 |
-
Don't hesitate to reach out to the community for help on our [Discord](https://discord.gg/s3KuuzsPFb) 🤗
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/koch.mdx
DELETED
|
@@ -1,258 +0,0 @@
|
|
| 1 |
-
# Koch v1.1
|
| 2 |
-
|
| 3 |
-
In the steps below, we explain how to assemble the Koch v1.1 robot.
|
| 4 |
-
|
| 5 |
-
## Order and assemble the parts
|
| 6 |
-
|
| 7 |
-
Follow the sourcing and assembling instructions provided in this [README](https://github.com/jess-moss/koch-v1-1). This will guide you through setting up both the follower and leader arms, as shown in the image below.
|
| 8 |
-
|
| 9 |
-
For a visual walkthrough of the assembly process, you can refer to [this video tutorial](https://youtu.be/8nQIg9BwwTk).
|
| 10 |
-
|
| 11 |
-
> [!WARNING]
|
| 12 |
-
> Since the production of this video, we simplified the configuration phase. Because of this, two things differ from the instructions in that video:
|
| 13 |
-
> - Don't plug in all the motor cables right away and wait to be instructed to do so in [Configure the motors](#configure-the-motors).
|
| 14 |
-
> - Don't screw in the controller board (PCB) to the base right away and wait for being instructed to do so in [Configure the motors](#configure-the-motors).
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
## Install LeRobot 🤗
|
| 18 |
-
|
| 19 |
-
To install LeRobot follow, our [Installation Guide](./installation)
|
| 20 |
-
|
| 21 |
-
In addition to these instructions, you need to install the Dynamixel SDK:
|
| 22 |
-
```bash
|
| 23 |
-
pip install -e ".[dynamixel]"
|
| 24 |
-
```
|
| 25 |
-
|
| 26 |
-
## Configure the motors
|
| 27 |
-
|
| 28 |
-
### 1. Find the USB ports associated with each arm
|
| 29 |
-
|
| 30 |
-
To find the port for each bus servo adapter, run this script:
|
| 31 |
-
```bash
|
| 32 |
-
python lerobot/find_port.py
|
| 33 |
-
```
|
| 34 |
-
|
| 35 |
-
<hfoptions id="example">
|
| 36 |
-
<hfoption id="Mac">
|
| 37 |
-
|
| 38 |
-
Example output:
|
| 39 |
-
|
| 40 |
-
```
|
| 41 |
-
Finding all available ports for the MotorBus.
|
| 42 |
-
['/dev/tty.usbmodem575E0032081', '/dev/tty.usbmodem575E0031751']
|
| 43 |
-
Remove the USB cable from your MotorsBus and press Enter when done.
|
| 44 |
-
|
| 45 |
-
[...Disconnect corresponding leader or follower arm and press Enter...]
|
| 46 |
-
|
| 47 |
-
The port of this MotorsBus is /dev/tty.usbmodem575E0032081
|
| 48 |
-
Reconnect the USB cable.
|
| 49 |
-
```
|
| 50 |
-
|
| 51 |
-
Where the found port is: `/dev/tty.usbmodem575E0032081` corresponding to your leader or follower arm.
|
| 52 |
-
|
| 53 |
-
</hfoption>
|
| 54 |
-
<hfoption id="Linux">
|
| 55 |
-
|
| 56 |
-
On Linux, you might need to give access to the USB ports by running:
|
| 57 |
-
```bash
|
| 58 |
-
sudo chmod 666 /dev/ttyACM0
|
| 59 |
-
sudo chmod 666 /dev/ttyACM1
|
| 60 |
-
```
|
| 61 |
-
|
| 62 |
-
Example output:
|
| 63 |
-
|
| 64 |
-
```
|
| 65 |
-
Finding all available ports for the MotorBus.
|
| 66 |
-
['/dev/ttyACM0', '/dev/ttyACM1']
|
| 67 |
-
Remove the usb cable from your MotorsBus and press Enter when done.
|
| 68 |
-
|
| 69 |
-
[...Disconnect corresponding leader or follower arm and press Enter...]
|
| 70 |
-
|
| 71 |
-
The port of this MotorsBus is /dev/ttyACM1
|
| 72 |
-
Reconnect the USB cable.
|
| 73 |
-
```
|
| 74 |
-
|
| 75 |
-
Where the found port is: `/dev/ttyACM1` corresponding to your leader or follower arm.
|
| 76 |
-
|
| 77 |
-
</hfoption>
|
| 78 |
-
</hfoptions>
|
| 79 |
-
|
| 80 |
-
### 2. Set the motors ids and baudrates
|
| 81 |
-
|
| 82 |
-
Each motor is identified by a unique id on the bus. When brand new, motors usually come with a default id of `1`. For the communication to work properly between the motors and the controller, we first need to set a unique, different id to each motor. Additionally, the speed at which data is transmitted on the bus is determined by the baudrate. In order to talk to each other, the controller and all the motors need to be configured with the same baudrate.
|
| 83 |
-
|
| 84 |
-
To that end, we first need to connect to each motor individually with the controller in order to set these. Since we will write these parameters in the non-volatile section of the motors' internal memory (EEPROM), we'll only need to do this once.
|
| 85 |
-
|
| 86 |
-
If you are repurposing motors from another robot, you will probably also need to perform this step, as the ids and baudrate likely won't match.
|
| 87 |
-
|
| 88 |
-
#### Follower
|
| 89 |
-
|
| 90 |
-
Connect the usb cable from your computer and the 5V power supply to the follower arm's controller board. Then, run the following command or run the API example with the port you got from the previous step. You'll also need to give your leader arm a name with the `id` parameter.
|
| 91 |
-
|
| 92 |
-
For a visual reference on how to set the motor ids please refer to [this video](https://huggingface.co/docs/lerobot/en/so101#setup-motors-video) where we follow the process for the SO101 arm.
|
| 93 |
-
|
| 94 |
-
<hfoptions id="setup_motors">
|
| 95 |
-
<hfoption id="Command">
|
| 96 |
-
|
| 97 |
-
```bash
|
| 98 |
-
python -m lerobot.setup_motors \
|
| 99 |
-
--robot.type=koch_follower \
|
| 100 |
-
--robot.port=/dev/tty.usbmodem575E0031751 # <- paste here the port found at previous step
|
| 101 |
-
```
|
| 102 |
-
</hfoption>
|
| 103 |
-
<hfoption id="API example">
|
| 104 |
-
|
| 105 |
-
```python
|
| 106 |
-
from lerobot.common.robots.koch_follower import KochFollower, KochFollowerConfig
|
| 107 |
-
|
| 108 |
-
config = KochFollowerConfig(
|
| 109 |
-
port="/dev/tty.usbmodem575E0031751",
|
| 110 |
-
id="my_awesome_follower_arm",
|
| 111 |
-
)
|
| 112 |
-
follower = KochFollower(config)
|
| 113 |
-
follower.setup_motors()
|
| 114 |
-
```
|
| 115 |
-
</hfoption>
|
| 116 |
-
</hfoptions>
|
| 117 |
-
|
| 118 |
-
You should see the following instruction.
|
| 119 |
-
```
|
| 120 |
-
Connect the controller board to the 'gripper' motor only and press enter.
|
| 121 |
-
```
|
| 122 |
-
|
| 123 |
-
As instructed, plug the gripper's motor. Make sure it's the only motor connected to the board, and that the motor itself is not yet daisy-chained to any other motor. As you press `[Enter]`, the script will automatically set the id and baudrate for that motor.
|
| 124 |
-
|
| 125 |
-
<details>
|
| 126 |
-
<summary>Troubleshooting</summary>
|
| 127 |
-
|
| 128 |
-
If you get an error at that point, check your cables and make sure they are plugged in properly:
|
| 129 |
-
<ul>
|
| 130 |
-
<li>Power supply</li>
|
| 131 |
-
<li>USB cable between your computer and the controller board</li>
|
| 132 |
-
<li>The 3-pin cable from the controller board to the motor</li>
|
| 133 |
-
</ul>
|
| 134 |
-
|
| 135 |
-
If you are using a Waveshare controller board, make sure that the two jumpers are set on the `B` channel (USB).
|
| 136 |
-
</details>
|
| 137 |
-
|
| 138 |
-
You should then see the following message:
|
| 139 |
-
```
|
| 140 |
-
'gripper' motor id set to 6
|
| 141 |
-
```
|
| 142 |
-
|
| 143 |
-
Followed by the next instruction:
|
| 144 |
-
```
|
| 145 |
-
Connect the controller board to the 'wrist_roll' motor only and press enter.
|
| 146 |
-
```
|
| 147 |
-
|
| 148 |
-
You can disconnect the 3-pin cable from the controller board but you can leave it connected to the gripper motor on the other end as it will already be in the right place. Now, plug in another 3-pin cable to the wrist roll motor and connect it to the controller board. As with the previous motor, make sure it is the only motor connected to the board and that the motor itself isn't connected to any other one.
|
| 149 |
-
|
| 150 |
-
Repeat the operation for each motor as instructed.
|
| 151 |
-
|
| 152 |
-
> [!TIP]
|
| 153 |
-
> Check your cabling at each step before pressing Enter. For instance, the power supply cable might disconnect as you manipulate the board.
|
| 154 |
-
|
| 155 |
-
When you are done, the script will simply finish, at which point the motors are ready to be used. You can now plug the 3-pin cable from each motor to the next one, and the cable from the first motor (the 'shoulder pan' with id=1) to the controller board, which can now be attached to the base of the arm.
|
| 156 |
-
|
| 157 |
-
#### Leader
|
| 158 |
-
Do the same steps for the leader arm but modify the command or script accordingly.
|
| 159 |
-
|
| 160 |
-
<hfoptions id="setup_motors">
|
| 161 |
-
<hfoption id="Command">
|
| 162 |
-
|
| 163 |
-
```bash
|
| 164 |
-
python -m lerobot.setup_motors \
|
| 165 |
-
--teleop.type=koch_leader \
|
| 166 |
-
--teleop.port=/dev/tty.usbmodem575E0031751 \ # <- paste here the port found at previous step
|
| 167 |
-
```
|
| 168 |
-
</hfoption>
|
| 169 |
-
<hfoption id="API example">
|
| 170 |
-
|
| 171 |
-
```python
|
| 172 |
-
from lerobot.common.teleoperators.koch_leader import KochLeader, KochLeaderConfig
|
| 173 |
-
|
| 174 |
-
config = KochLeaderConfig(
|
| 175 |
-
port="/dev/tty.usbmodem575E0031751",
|
| 176 |
-
id="my_awesome_leader_arm",
|
| 177 |
-
)
|
| 178 |
-
leader = KochLeader(config)
|
| 179 |
-
leader.setup_motors()
|
| 180 |
-
```
|
| 181 |
-
</hfoption>
|
| 182 |
-
</hfoptions>
|
| 183 |
-
|
| 184 |
-
## Calibrate
|
| 185 |
-
|
| 186 |
-
Next, you'll need to calibrate your robot to ensure that the leader and follower arms have the same position values when they are in the same physical position.
|
| 187 |
-
The calibration process is very important because it allows a neural network trained on one robot to work on another.
|
| 188 |
-
|
| 189 |
-
#### Follower
|
| 190 |
-
|
| 191 |
-
Run the following command or API example to calibrate the follower arm:
|
| 192 |
-
|
| 193 |
-
<hfoptions id="calibrate_follower">
|
| 194 |
-
<hfoption id="Command">
|
| 195 |
-
|
| 196 |
-
```bash
|
| 197 |
-
python -m lerobot.calibrate \
|
| 198 |
-
--robot.type=koch_follower \
|
| 199 |
-
--robot.port=/dev/tty.usbmodem58760431551 \ # <- The port of your robot
|
| 200 |
-
--robot.id=my_awesome_follower_arm # <- Give the robot a unique name
|
| 201 |
-
```
|
| 202 |
-
</hfoption>
|
| 203 |
-
<hfoption id="API example">
|
| 204 |
-
|
| 205 |
-
```python
|
| 206 |
-
from lerobot.common.robots.koch_follower import KochFollowerConfig, KochFollower
|
| 207 |
-
|
| 208 |
-
config = KochFollowerConfig(
|
| 209 |
-
port="/dev/tty.usbmodem585A0076891",
|
| 210 |
-
id="my_awesome_follower_arm",
|
| 211 |
-
)
|
| 212 |
-
|
| 213 |
-
follower = KochFollower(config)
|
| 214 |
-
follower.connect(calibrate=False)
|
| 215 |
-
follower.calibrate()
|
| 216 |
-
follower.disconnect()
|
| 217 |
-
```
|
| 218 |
-
</hfoption>
|
| 219 |
-
</hfoptions>
|
| 220 |
-
|
| 221 |
-
We unified the calibration method for most robots. Thus, the calibration steps for this Koch arm are the same as the steps for the SO100 and SO101. First, we have to move the robot to the position where each joint is in the middle of its range, then we press `Enter`. Secondly, we move all joints through their full range of motion. A video of this same process for the SO101 as reference can be found [here](https://huggingface.co/docs/lerobot/en/so101#calibration-video).
|
| 222 |
-
|
| 223 |
-
#### Leader
|
| 224 |
-
|
| 225 |
-
Do the same steps to calibrate the leader arm, run the following command or API example:
|
| 226 |
-
|
| 227 |
-
<hfoptions id="calibrate_leader">
|
| 228 |
-
<hfoption id="Command">
|
| 229 |
-
|
| 230 |
-
```bash
|
| 231 |
-
python -m lerobot.calibrate \
|
| 232 |
-
--teleop.type=koch_leader \
|
| 233 |
-
--teleop.port=/dev/tty.usbmodem58760431551 \ # <- The port of your robot
|
| 234 |
-
--teleop.id=my_awesome_leader_arm # <- Give the robot a unique name
|
| 235 |
-
```
|
| 236 |
-
</hfoption>
|
| 237 |
-
<hfoption id="API example">
|
| 238 |
-
|
| 239 |
-
```python
|
| 240 |
-
from lerobot.common.teleoperators.koch_leader import KochLeaderConfig, KochLeader
|
| 241 |
-
|
| 242 |
-
config = KochLeaderConfig(
|
| 243 |
-
port="/dev/tty.usbmodem575E0031751",
|
| 244 |
-
id="my_awesome_leader_arm",
|
| 245 |
-
)
|
| 246 |
-
|
| 247 |
-
leader = KochLeader(config)
|
| 248 |
-
leader.connect(calibrate=False)
|
| 249 |
-
leader.calibrate()
|
| 250 |
-
leader.disconnect()
|
| 251 |
-
```
|
| 252 |
-
</hfoption>
|
| 253 |
-
</hfoptions>
|
| 254 |
-
|
| 255 |
-
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)
|
| 256 |
-
|
| 257 |
-
> [!TIP]
|
| 258 |
-
> If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/lekiwi.mdx
DELETED
|
@@ -1,300 +0,0 @@
|
|
| 1 |
-
# LeKiwi
|
| 2 |
-
|
| 3 |
-
In the steps below, we explain how to assemble the LeKiwi mobile robot.
|
| 4 |
-
|
| 5 |
-
## Source the parts
|
| 6 |
-
|
| 7 |
-
Follow this [README](https://github.com/SIGRobotics-UIUC/LeKiwi). It contains the bill of materials, with a link to source the parts, as well as the instructions to 3D print the parts.
|
| 8 |
-
And advise if it's your first time printing or if you don't own a 3D printer.
|
| 9 |
-
|
| 10 |
-
### Wired version
|
| 11 |
-
If you have the **wired** LeKiwi version, you can skip the installation of the Raspberry Pi and setting up SSH. You can also run all commands directly on your PC for both the LeKiwi scripts and the leader arm scripts for teleoperating.
|
| 12 |
-
|
| 13 |
-
## Install software on Pi
|
| 14 |
-
Now we have to set up the remote PC that will run on the LeKiwi Robot. This is normally a Raspberry Pi, but can be any PC that can run on 5V and has enough usb ports (2 or more) for the cameras and motor control board.
|
| 15 |
-
|
| 16 |
-
### Install OS
|
| 17 |
-
For setting up the Raspberry Pi and its SD-card see: [Setup PI](https://www.raspberrypi.com/documentation/computers/getting-started.html). Here is explained how to download the [Imager](https://www.raspberrypi.com/software/) to install Raspberry Pi OS or Ubuntu.
|
| 18 |
-
|
| 19 |
-
### Setup SSH
|
| 20 |
-
After setting up your Pi, you should enable and set up [SSH](https://www.raspberrypi.com/news/coding-on-raspberry-pi-remotely-with-visual-studio-code/) (Secure Shell Protocol) so you can log in to the Pi from your laptop without requiring a screen, keyboard, and mouse on the Pi. A great tutorial on how to do this can be found [here](https://www.raspberrypi.com/documentation/computers/remote-access.html#ssh). Logging into your Pi can be done in your Command Prompt (cmd) or, if you use VSCode you can use [this](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh) extension.
|
| 21 |
-
|
| 22 |
-
### Install LeRobot on Pi 🤗
|
| 23 |
-
|
| 24 |
-
On your Raspberry Pi install LeRobot using our [Installation Guide](./installation)
|
| 25 |
-
|
| 26 |
-
In addition to these instructions, you need to install the Feetech sdk on your Pi:
|
| 27 |
-
```bash
|
| 28 |
-
pip install -e ".[feetech]"
|
| 29 |
-
```
|
| 30 |
-
|
| 31 |
-
## Install LeRobot locally
|
| 32 |
-
If you already have installed LeRobot on your laptop/pc you can skip this step; otherwise, please follow along as we do the same steps we did on the Pi.
|
| 33 |
-
|
| 34 |
-
Follow our [Installation Guide](./installation)
|
| 35 |
-
|
| 36 |
-
Great :hugs:! You are now done installing LeRobot, and we can begin assembling the SO100/SO101 arms and the mobile base :robot:.
|
| 37 |
-
Every time you now want to use LeRobot, you can go to the `~/lerobot` folder where we installed LeRobot and run one of the commands.
|
| 38 |
-
|
| 39 |
-
# Step-by-Step Assembly Instructions
|
| 40 |
-
|
| 41 |
-
First, we will assemble the two SO100/SO101 arms. One to attach to the mobile base and one for teleoperation. Then we will assemble the mobile base. The instructions for assembling can be found on these two pages:
|
| 42 |
-
|
| 43 |
-
- [Assemble SO101](./so101#step-by-step-assembly-instructions)
|
| 44 |
-
- [Assemble LeKiwi](https://github.com/SIGRobotics-UIUC/LeKiwi/blob/main/Assembly.md)
|
| 45 |
-
|
| 46 |
-
### Find the USB ports associated with motor board
|
| 47 |
-
|
| 48 |
-
To find the port for each bus servo adapter, run this script:
|
| 49 |
-
```bash
|
| 50 |
-
python lerobot/find_port.py
|
| 51 |
-
```
|
| 52 |
-
|
| 53 |
-
<hfoptions id="example">
|
| 54 |
-
<hfoption id="Mac">
|
| 55 |
-
|
| 56 |
-
Example output:
|
| 57 |
-
|
| 58 |
-
```
|
| 59 |
-
Finding all available ports for the MotorBus.
|
| 60 |
-
['/dev/tty.usbmodem575E0032081']
|
| 61 |
-
Remove the USB cable from your MotorsBus and press Enter when done.
|
| 62 |
-
|
| 63 |
-
[...Disconnect corresponding leader or follower arm and press Enter...]
|
| 64 |
-
|
| 65 |
-
The port of this MotorsBus is /dev/tty.usbmodem575E0032081
|
| 66 |
-
Reconnect the USB cable.
|
| 67 |
-
```
|
| 68 |
-
|
| 69 |
-
Where the found port is: `/dev/tty.usbmodem575E0032081` corresponding to your board.
|
| 70 |
-
|
| 71 |
-
</hfoption>
|
| 72 |
-
<hfoption id="Linux">
|
| 73 |
-
|
| 74 |
-
On Linux, you might need to give access to the USB ports by running:
|
| 75 |
-
```bash
|
| 76 |
-
sudo chmod 666 /dev/ttyACM0
|
| 77 |
-
sudo chmod 666 /dev/ttyACM1
|
| 78 |
-
```
|
| 79 |
-
|
| 80 |
-
Example output:
|
| 81 |
-
|
| 82 |
-
```
|
| 83 |
-
Finding all available ports for the MotorBus.
|
| 84 |
-
['/dev/ttyACM0']
|
| 85 |
-
Remove the usb cable from your MotorsBus and press Enter when done.
|
| 86 |
-
|
| 87 |
-
[...Disconnect corresponding leader or follower arm and press Enter...]
|
| 88 |
-
|
| 89 |
-
The port of this MotorsBus is /dev/ttyACM0
|
| 90 |
-
Reconnect the USB cable.
|
| 91 |
-
```
|
| 92 |
-
|
| 93 |
-
Where the found port is: `/dev/ttyACM0` corresponding to your board.
|
| 94 |
-
|
| 95 |
-
</hfoption>
|
| 96 |
-
</hfoptions>
|
| 97 |
-
|
| 98 |
-
### Configure motors
|
| 99 |
-
The instructions for configuring the motors can be found in the SO101 [docs](./so101#configure-the-motors). Besides the ids for the arm motors, we also need to set the motor ids for the mobile base. These need to be in a specific order to work. Below an image of the motor ids and motor mounting positions for the mobile base. Note that we only use one Motor Control board on LeKiwi. This means the motor ids for the wheels are 7, 8 and 9.
|
| 100 |
-
|
| 101 |
-
You can run this command to setup motors for LeKiwi. It will first setup the motors for arm (id 6..1) and then setup motors for wheels (9,8,7)
|
| 102 |
-
|
| 103 |
-
```bash
|
| 104 |
-
python -m lerobot.setup_motors \
|
| 105 |
-
--robot.type=lekiwi \
|
| 106 |
-
--robot.port=/dev/tty.usbmodem58760431551 # <- paste here the port found at previous step
|
| 107 |
-
```
|
| 108 |
-
|
| 109 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/motor_ids.webp" alt="Motor ID's for mobile robot" title="Motor ID's for mobile robot" width="60%">
|
| 110 |
-
|
| 111 |
-
### Troubleshoot communication
|
| 112 |
-
|
| 113 |
-
If you are having trouble connecting to the Mobile SO100, follow these steps to diagnose and resolve the issue.
|
| 114 |
-
|
| 115 |
-
#### 1. Verify IP Address Configuration
|
| 116 |
-
Make sure that the correct IP for the Pi is used in the commands or in your code. To check the Raspberry Pi's IP address, run (on the Pi command line):
|
| 117 |
-
```bash
|
| 118 |
-
hostname -I
|
| 119 |
-
```
|
| 120 |
-
|
| 121 |
-
#### 2. Check if Pi is reachable from laptop/pc
|
| 122 |
-
Try pinging the Raspberry Pi from your laptop:
|
| 123 |
-
```bach
|
| 124 |
-
ping <your_pi_ip_address>
|
| 125 |
-
```
|
| 126 |
-
|
| 127 |
-
If the ping fails:
|
| 128 |
-
- Ensure the Pi is powered on and connected to the same network.
|
| 129 |
-
- Check if SSH is enabled on the Pi.
|
| 130 |
-
|
| 131 |
-
#### 3. Try SSH connection
|
| 132 |
-
If you can't SSH into the Pi, it might not be properly connected. Use:
|
| 133 |
-
```bash
|
| 134 |
-
ssh <your_pi_user_name>@<your_pi_ip_address>
|
| 135 |
-
```
|
| 136 |
-
If you get a connection error:
|
| 137 |
-
- Ensure SSH is enabled on the Pi by running:
|
| 138 |
-
```bash
|
| 139 |
-
sudo raspi-config
|
| 140 |
-
```
|
| 141 |
-
Then navigate to: **Interfacing Options -> SSH** and enable it.
|
| 142 |
-
|
| 143 |
-
### Calibration
|
| 144 |
-
|
| 145 |
-
Now we have to calibrate the leader arm and the follower arm. The wheel motors don't have to be calibrated.
|
| 146 |
-
The calibration process is very important because it allows a neural network trained on one robot to work on another.
|
| 147 |
-
|
| 148 |
-
### Calibrate follower arm (on mobile base)
|
| 149 |
-
|
| 150 |
-
Make sure the arm is connected to the Raspberry Pi and run this script or API example (on the Raspberry Pi via SSH) to launch calibration of the follower arm:
|
| 151 |
-
|
| 152 |
-
```bash
|
| 153 |
-
python -m lerobot.calibrate \
|
| 154 |
-
--robot.type=lekiwi \
|
| 155 |
-
--robot.id=my_awesome_kiwi # <- Give the robot a unique name
|
| 156 |
-
```
|
| 157 |
-
|
| 158 |
-
We unified the calibration method for most robots, thus, the calibration steps for this SO100 arm are the same as the steps for the Koch and SO101. First, we have to move the robot to the position where each joint is in the middle of its range, then we press `Enter`. Secondly, we move all joints through their full range of motion. A video of this same process for the SO101 as reference can be found [here](https://huggingface.co/docs/lerobot/en/so101#calibration-video).
|
| 159 |
-
|
| 160 |
-
### Wired version
|
| 161 |
-
If you have the **wired** LeKiwi version, please run all commands on your laptop.
|
| 162 |
-
|
| 163 |
-
### Calibrate leader arm
|
| 164 |
-
Then, to calibrate the leader arm (which is attached to the laptop/pc). Run the following command of API example on your laptop:
|
| 165 |
-
<hfoptions id="calibrate_leader">
|
| 166 |
-
<hfoption id="Command">
|
| 167 |
-
|
| 168 |
-
```bash
|
| 169 |
-
python -m lerobot.calibrate \
|
| 170 |
-
--teleop.type=so100_leader \
|
| 171 |
-
--teleop.port=/dev/tty.usbmodem58760431551 \ # <- The port of your robot
|
| 172 |
-
--teleop.id=my_awesome_leader_arm # <- Give the robot a unique name
|
| 173 |
-
```
|
| 174 |
-
</hfoption>
|
| 175 |
-
<hfoption id="API example">
|
| 176 |
-
|
| 177 |
-
```python
|
| 178 |
-
from lerobot.common.teleoperators.so100_leader import SO100LeaderConfig, SO100Leader
|
| 179 |
-
|
| 180 |
-
config = SO100LeaderConfig(
|
| 181 |
-
port="/dev/tty.usbmodem58760431551",
|
| 182 |
-
id="my_awesome_leader_arm",
|
| 183 |
-
)
|
| 184 |
-
|
| 185 |
-
leader = SO100Leader(config)
|
| 186 |
-
leader.connect(calibrate=False)
|
| 187 |
-
leader.calibrate()
|
| 188 |
-
leader.disconnect()
|
| 189 |
-
```
|
| 190 |
-
</hfoption>
|
| 191 |
-
</hfoptions>
|
| 192 |
-
|
| 193 |
-
## Teleoperate LeKiwi
|
| 194 |
-
|
| 195 |
-
> [!TIP]
|
| 196 |
-
> If you're using a Mac, you might need to give Terminal permission to access your keyboard for teleoperation. Go to System Preferences > Security & Privacy > Input Monitoring and check the box for Terminal.
|
| 197 |
-
|
| 198 |
-
To teleoperate, SSH into your Raspberry Pi, and run `conda activate lerobot` and this command:
|
| 199 |
-
```bash
|
| 200 |
-
python -m lerobot.common.robots.lekiwi.lekiwi_host --robot.id=my_awesome_kiwi
|
| 201 |
-
```
|
| 202 |
-
|
| 203 |
-
Then on your laptop, also run `conda activate lerobot` and run the API example, make sure you set the correct `remote_ip` and `port` in `examples/lekiwi/teleoperate.py`.
|
| 204 |
-
|
| 205 |
-
```bash
|
| 206 |
-
python examples/lekiwi/teleoperate.py
|
| 207 |
-
```
|
| 208 |
-
|
| 209 |
-
You should see on your laptop something like this: ```[INFO] Connected to remote robot at tcp://172.17.133.91:5555 and video stream at tcp://172.17.133.91:5556.``` Now you can move the leader arm and use the keyboard (w,a,s,d) to drive forward, left, backwards, right. And use (z,x) to turn left or turn right. You can use (r,f) to increase and decrease the speed of the mobile robot. There are three speed modes, see the table below:
|
| 210 |
-
|
| 211 |
-
| Speed Mode | Linear Speed (m/s) | Rotation Speed (deg/s) |
|
| 212 |
-
| ---------- | ------------------ | ---------------------- |
|
| 213 |
-
| Fast | 0.4 | 90 |
|
| 214 |
-
| Medium | 0.25 | 60 |
|
| 215 |
-
| Slow | 0.1 | 30 |
|
| 216 |
-
|
| 217 |
-
|
| 218 |
-
| Key | Action |
|
| 219 |
-
| --- | -------------- |
|
| 220 |
-
| W | Move forward |
|
| 221 |
-
| A | Move left |
|
| 222 |
-
| S | Move backward |
|
| 223 |
-
| D | Move right |
|
| 224 |
-
| Z | Turn left |
|
| 225 |
-
| X | Turn right |
|
| 226 |
-
| R | Increase speed |
|
| 227 |
-
| F | Decrease speed |
|
| 228 |
-
|
| 229 |
-
> [!TIP]
|
| 230 |
-
> If you use a different keyboard, you can change the keys for each command in the [`LeKiwiConfig`](../lerobot/common/robot_devices/robots/configs.py).
|
| 231 |
-
|
| 232 |
-
### Wired version
|
| 233 |
-
If you have the **wired** LeKiwi version, please run all commands on your laptop.
|
| 234 |
-
|
| 235 |
-
## Record a dataset
|
| 236 |
-
|
| 237 |
-
Once you're familiar with teleoperation, you can record your first dataset.
|
| 238 |
-
|
| 239 |
-
We use the Hugging Face hub features for uploading your dataset. If you haven't previously used the Hub, make sure you can login via the cli using a write-access token, this token can be generated from the [Hugging Face settings](https://huggingface.co/settings/tokens).
|
| 240 |
-
|
| 241 |
-
Add your token to the CLI by running this command:
|
| 242 |
-
```bash
|
| 243 |
-
huggingface-cli login --token ${HUGGINGFACE_TOKEN} --add-to-git-credential
|
| 244 |
-
```
|
| 245 |
-
|
| 246 |
-
Then store your Hugging Face repository name in a variable:
|
| 247 |
-
```bash
|
| 248 |
-
HF_USER=$(huggingface-cli whoami | head -n 1)
|
| 249 |
-
echo $HF_USER
|
| 250 |
-
```
|
| 251 |
-
|
| 252 |
-
Now you can record a dataset. To record episodes and upload your dataset to the hub, execute this API example tailored for LeKiwi. Make sure to first adapt the `remote_ip`, `repo_id`, `port` and `task` in the script. If you would like to run the script for longer you can increase `NB_CYCLES_CLIENT_CONNECTION`.
|
| 253 |
-
```bash
|
| 254 |
-
python examples/lekiwi/record.py
|
| 255 |
-
```
|
| 256 |
-
|
| 257 |
-
#### Dataset upload
|
| 258 |
-
Locally, your dataset is stored in this folder: `~/.cache/huggingface/lerobot/{repo-id}`. At the end of data recording, your dataset will be uploaded on your Hugging Face page (e.g. https://huggingface.co/datasets/cadene/so101_test) that you can obtain by running:
|
| 259 |
-
```bash
|
| 260 |
-
echo https://huggingface.co/datasets/${HF_USER}/so101_test
|
| 261 |
-
```
|
| 262 |
-
Your dataset will be automatically tagged with `LeRobot` for the community to find it easily, and you can also add custom tags (in this case `tutorial` for example).
|
| 263 |
-
|
| 264 |
-
You can look for other LeRobot datasets on the hub by searching for `LeRobot` [tags](https://huggingface.co/datasets?other=LeRobot).
|
| 265 |
-
|
| 266 |
-
#### Tips for gathering data
|
| 267 |
-
|
| 268 |
-
Once you're comfortable with data recording, you can create a larger dataset for training. A good starting task is grasping an object at different locations and placing it in a bin. We suggest recording at least 50 episodes, with 10 episodes per location. Keep the cameras fixed and maintain consistent grasping behavior throughout the recordings. Also make sure the object you are manipulating is visible on the camera's. A good rule of thumb is you should be able to do the task yourself by only looking at the camera images.
|
| 269 |
-
|
| 270 |
-
In the following sections, you’ll train your neural network. After achieving reliable grasping performance, you can start introducing more variations during data collection, such as additional grasp locations, different grasping techniques, and altering camera positions.
|
| 271 |
-
|
| 272 |
-
Avoid adding too much variation too quickly, as it may hinder your results.
|
| 273 |
-
|
| 274 |
-
If you want to dive deeper into this important topic, you can check out the [blog post](https://huggingface.co/blog/lerobot-datasets#what-makes-a-good-dataset) we wrote on what makes a good dataset.
|
| 275 |
-
|
| 276 |
-
#### Troubleshooting:
|
| 277 |
-
- On Linux, if the left and right arrow keys and escape key don't have any effect during data recording, make sure you've set the `$DISPLAY` environment variable. See [pynput limitations](https://pynput.readthedocs.io/en/latest/limitations.html#linux).
|
| 278 |
-
|
| 279 |
-
|
| 280 |
-
## Replay an episode
|
| 281 |
-
|
| 282 |
-
To replay an episode run the API example below, make sure to change `remote_ip`, `port`, LeRobotDatasetId and episode index.
|
| 283 |
-
|
| 284 |
-
|
| 285 |
-
```bash
|
| 286 |
-
python examples/lekiwi/replay.py
|
| 287 |
-
```
|
| 288 |
-
|
| 289 |
-
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)
|
| 290 |
-
|
| 291 |
-
## Evaluate your policy
|
| 292 |
-
|
| 293 |
-
To evaluate your policy run the `evaluate.py` API example, make sure to change `remote_ip`, `port`, model..
|
| 294 |
-
|
| 295 |
-
```bash
|
| 296 |
-
python examples/lekiwi/evaluate.py
|
| 297 |
-
```
|
| 298 |
-
|
| 299 |
-
> [!TIP]
|
| 300 |
-
> If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/notebooks.mdx
DELETED
|
@@ -1,29 +0,0 @@
|
|
| 1 |
-
# 🤗 LeRobot Notebooks
|
| 2 |
-
|
| 3 |
-
This repository contains example notebooks for using LeRobot. These notebooks demonstrate how to train policies on real or simulation datasets using standardized policies.
|
| 4 |
-
|
| 5 |
-
---
|
| 6 |
-
|
| 7 |
-
### Training ACT
|
| 8 |
-
|
| 9 |
-
[ACT](https://huggingface.co/papers/2304.13705) (Action Chunking Transformer) is a transformer-based policy architecture for imitation learning that processes robot states and camera inputs to generate smooth, chunked action sequences.
|
| 10 |
-
|
| 11 |
-
We provide a ready-to-run Google Colab notebook to help you train ACT policies using datasets from the Hugging Face Hub, with optional logging to Weights & Biases.
|
| 12 |
-
|
| 13 |
-
| Notebook | Colab |
|
| 14 |
-
|:---------|:------|
|
| 15 |
-
| [Train ACT with LeRobot](https://github.com/huggingface/notebooks/blob/main/lerobot/training-act.ipynb) | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/lerobot/training-act.ipynb) |
|
| 16 |
-
|
| 17 |
-
Expected training time for 100k steps: ~1.5 hours on an NVIDIA A100 GPU with batch size of `64`.
|
| 18 |
-
|
| 19 |
-
### Training SmolVLA
|
| 20 |
-
|
| 21 |
-
[SmolVLA](https://huggingface.co/papers/2506.01844) is a small but efficient Vision-Language-Action model. It is compact in size with 450 M-parameter and is developed by Hugging Face.
|
| 22 |
-
|
| 23 |
-
We provide a ready-to-run Google Colab notebook to help you train SmolVLA policies using datasets from the Hugging Face Hub, with optional logging to Weights & Biases.
|
| 24 |
-
|
| 25 |
-
| Notebook | Colab |
|
| 26 |
-
| :-------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
| 27 |
-
| [Train SmolVLA with LeRobot](https://github.com/huggingface/notebooks/blob/main/lerobot/training-smolvla.ipynb) | [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/lerobot/training-smolvla.ipynb) |
|
| 28 |
-
|
| 29 |
-
Expected training time for 20k steps: ~5 hours on an NVIDIA A100 GPU with batch size of `64`.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/smolvla.mdx
DELETED
|
@@ -1,97 +0,0 @@
|
|
| 1 |
-
# Finetune SmolVLA
|
| 2 |
-
|
| 3 |
-
SmolVLA is Hugging Face’s lightweight foundation model for robotics. Designed for easy fine-tuning on LeRobot datasets, it helps accelerate your development!
|
| 4 |
-
|
| 5 |
-
<p align="center">
|
| 6 |
-
<img src="https://cdn-uploads.huggingface.co/production/uploads/640e21ef3c82bd463ee5a76d/aooU0a3DMtYmy_1IWMaIM.png" alt="SmolVLA architecture." width="500"/>
|
| 7 |
-
<br/>
|
| 8 |
-
<em>Figure 1. SmolVLA takes as input (i) multiple cameras views, (ii) the robot’s current sensorimotor state, and (iii) a natural language instruction, encoded into contextual features used to condition the action expert when generating an action chunk.</em>
|
| 9 |
-
</p>
|
| 10 |
-
|
| 11 |
-
## Set Up Your Environment
|
| 12 |
-
|
| 13 |
-
1. Install LeRobot by following our [Installation Guide](./installation).
|
| 14 |
-
2. Install SmolVLA dependencies by running:
|
| 15 |
-
|
| 16 |
-
```bash
|
| 17 |
-
pip install -e ".[smolvla]"
|
| 18 |
-
```
|
| 19 |
-
|
| 20 |
-
## Collect a dataset
|
| 21 |
-
|
| 22 |
-
SmolVLA is a base model, so fine-tuning on your own data is required for optimal performance in your setup.
|
| 23 |
-
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)
|
| 24 |
-
|
| 25 |
-
<Tip>
|
| 26 |
-
|
| 27 |
-
In your dataset, make sure to have enough demonstrations per each variation (e.g. the cube position on the table if it is cube pick-place task) you are introducing.
|
| 28 |
-
|
| 29 |
-
We recommend checking out the dataset linked below for reference that was used in the [SmolVLA paper](https://huggingface.co/papers/2506.01844):
|
| 30 |
-
|
| 31 |
-
🔗 [SVLA SO100 PickPlace](https://huggingface.co/spaces/lerobot/visualize_dataset?path=%2Flerobot%2Fsvla_so100_pickplace%2Fepisode_0)
|
| 32 |
-
|
| 33 |
-
In this dataset, we recorded 50 episodes across 5 distinct cube positions. For each position, we collected 10 episodes of pick-and-place interactions. This structure, repeating each variation several times, helped the model generalize better. We tried similar dataset with 25 episodes, and it was not enough leading to a bad performance. So, the data quality and quantity is definitely a key.
|
| 34 |
-
After you have your dataset available on the Hub, you are good to go to use our finetuning script to adapt SmolVLA to your application.
|
| 35 |
-
</Tip>
|
| 36 |
-
|
| 37 |
-
## Finetune SmolVLA on your data
|
| 38 |
-
|
| 39 |
-
Use [`smolvla_base`](https://hf.co/lerobot/smolvla_base), our pretrained 450M model, and fine-tune it on your data.
|
| 40 |
-
Training the model for 20k steps will roughly take ~4 hrs on a single A100 GPU. You should tune the number of steps based on performance and your use-case.
|
| 41 |
-
|
| 42 |
-
If you don't have a gpu device, you can train using our notebook on [](https://colab.research.google.com/github/huggingface/notebooks/blob/main/lerobot/training-smolvla.ipynb)
|
| 43 |
-
|
| 44 |
-
Pass your dataset to the training script using `--dataset.repo_id`. If you want to test your installation, run the following command where we use one of the datasets we collected for the [SmolVLA Paper](https://huggingface.co/papers/2506.01844).
|
| 45 |
-
|
| 46 |
-
```bash
|
| 47 |
-
cd lerobot && python lerobot/scripts/train.py \
|
| 48 |
-
--policy.path=lerobot/smolvla_base \
|
| 49 |
-
--dataset.repo_id=${HF_USER}/mydataset \
|
| 50 |
-
--batch_size=64 \
|
| 51 |
-
--steps=20000 \
|
| 52 |
-
--output_dir=outputs/train/my_smolvla \
|
| 53 |
-
--job_name=my_smolvla_training \
|
| 54 |
-
--policy.device=cuda \
|
| 55 |
-
--wandb.enable=true
|
| 56 |
-
```
|
| 57 |
-
|
| 58 |
-
<Tip>
|
| 59 |
-
You can start with a small batch size and increase it incrementally, if the GPU allows it, as long as loading times remain short.
|
| 60 |
-
</Tip>
|
| 61 |
-
|
| 62 |
-
Fine-tuning is an art. For a complete overview of the options for finetuning, run
|
| 63 |
-
|
| 64 |
-
```bash
|
| 65 |
-
python lerobot/scripts/train.py --help
|
| 66 |
-
```
|
| 67 |
-
|
| 68 |
-
<p align="center">
|
| 69 |
-
<img src="https://cdn-uploads.huggingface.co/production/uploads/640e21ef3c82bd463ee5a76d/S-3vvVCulChREwHDkquoc.gif" alt="Comparison of SmolVLA across task variations." width="500"/>
|
| 70 |
-
<br/>
|
| 71 |
-
<em>Figure 2: Comparison of SmolVLA across task variations. From left to right: (1) pick-place cube counting, (2) pick-place cube counting, (3) pick-place cube counting under perturbations, and (4) generalization on pick-and-place of the lego block with real-world SO101.</em>
|
| 72 |
-
</p>
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
## Evaluate the finetuned model and run it in real-time
|
| 76 |
-
|
| 77 |
-
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).
|
| 78 |
-
Once you are logged in, you can run inference in your setup by doing:
|
| 79 |
-
|
| 80 |
-
```bash
|
| 81 |
-
python -m lerobot.record \
|
| 82 |
-
--robot.type=so101_follower \
|
| 83 |
-
--robot.port=/dev/ttyACM0 \ # <- Use your port
|
| 84 |
-
--robot.id=my_blue_follower_arm \ # <- Use your robot id
|
| 85 |
-
--robot.cameras="{ front: {type: opencv, index_or_path: 8, width: 640, height: 480, fps: 30}}" \ # <- Use your cameras
|
| 86 |
-
--dataset.single_task="Grasp a lego block and put it in the bin." \ # <- Use the same task description you used in your dataset recording
|
| 87 |
-
--dataset.repo_id=${HF_USER}/eval_DATASET_NAME_test \ # <- This will be the dataset name on HF Hub
|
| 88 |
-
--dataset.episode_time_s=50 \
|
| 89 |
-
--dataset.num_episodes=10 \
|
| 90 |
-
# <- Teleop optional if you want to teleoperate in between episodes \
|
| 91 |
-
# --teleop.type=so100_leader \
|
| 92 |
-
# --teleop.port=/dev/ttyACM0 \
|
| 93 |
-
# --teleop.id=my_red_leader_arm \
|
| 94 |
-
--policy.path=HF_USER/FINETUNE_MODEL_NAME # <- Use your fine-tuned model
|
| 95 |
-
```
|
| 96 |
-
|
| 97 |
-
Depending on your evaluation setup, you can configure the duration and the number of episodes to record for your evaluation suite.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/so100.mdx
DELETED
|
@@ -1,486 +0,0 @@
|
|
| 1 |
-
# SO-100
|
| 2 |
-
|
| 3 |
-
In the steps below, we explain how to assemble the SO-100 robot.
|
| 4 |
-
|
| 5 |
-
## Source the parts
|
| 6 |
-
|
| 7 |
-
Follow this [README](https://github.com/TheRobotStudio/SO-ARM100/blob/main/SO100.md). It contains the bill of materials, with a link to source the parts, as well as the instructions to 3D print the parts. And advise if it's your first time printing or if you don't own a 3D printer.
|
| 8 |
-
|
| 9 |
-
## Install LeRobot 🤗
|
| 10 |
-
|
| 11 |
-
To install LeRobot, follow our [Installation Guide](./installation)
|
| 12 |
-
|
| 13 |
-
In addition to these instructions, you need to install the Feetech SDK:
|
| 14 |
-
```bash
|
| 15 |
-
pip install -e ".[feetech]"
|
| 16 |
-
```
|
| 17 |
-
|
| 18 |
-
## Step-by-Step Assembly Instructions
|
| 19 |
-
|
| 20 |
-
## Remove the gears of the 6 leader motors
|
| 21 |
-
|
| 22 |
-
<details>
|
| 23 |
-
<summary><strong>Video removing gears</strong></summary>
|
| 24 |
-
|
| 25 |
-
<div class="video-container">
|
| 26 |
-
<video controls width="600">
|
| 27 |
-
<source src="https://github.com/user-attachments/assets/0c95b88c-5b85-413d-ba19-aee2f864f2a7" type="video/mp4" />
|
| 28 |
-
</video>
|
| 29 |
-
</div>
|
| 30 |
-
|
| 31 |
-
</details>
|
| 32 |
-
|
| 33 |
-
Follow the video for removing gears. You need to remove the gear for the motors of the leader arm. As a result, you will only use the position encoding of the motor and reduce friction to more easily operate the leader arm.
|
| 34 |
-
|
| 35 |
-
### Clean Parts
|
| 36 |
-
Remove all support material from the 3D-printed parts. The easiest way to do this is using a small screwdriver to get underneath the support material.
|
| 37 |
-
|
| 38 |
-
### Additional Guidance
|
| 39 |
-
|
| 40 |
-
<details>
|
| 41 |
-
<summary><strong>Video assembling arms</strong></summary>
|
| 42 |
-
|
| 43 |
-
<div class="video-container">
|
| 44 |
-
<video controls width="600">
|
| 45 |
-
<source src="https://github.com/user-attachments/assets/488a39de-0189-4461-9de3-05b015f90cca" type="video/mp4" />
|
| 46 |
-
</video>
|
| 47 |
-
</div>
|
| 48 |
-
|
| 49 |
-
</details>
|
| 50 |
-
|
| 51 |
-
**Note:**
|
| 52 |
-
This video provides visual guidance for assembling the arms, but it doesn't specify when or how to do the wiring. Inserting the cables beforehand is much easier than doing it afterward. The first arm may take a bit more than 1 hour to assemble, but once you get used to it, you can assemble the second arm in under 1 hour.
|
| 53 |
-
|
| 54 |
-
---
|
| 55 |
-
|
| 56 |
-
### First Motor
|
| 57 |
-
|
| 58 |
-
**Step 2: Insert Wires**
|
| 59 |
-
- Insert two wires into the first motor.
|
| 60 |
-
|
| 61 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_1.webp" style="height:300px;"/>
|
| 62 |
-
|
| 63 |
-
**Step 3: Install in Base**
|
| 64 |
-
- Place the first motor into the base.
|
| 65 |
-
|
| 66 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_2.webp" style="height:300px;"/>
|
| 67 |
-
|
| 68 |
-
**Step 4: Secure Motor**
|
| 69 |
-
- Fasten the motor with 4 screws. Two from the bottom and two from top.
|
| 70 |
-
|
| 71 |
-
**Step 5: Attach Motor Holder**
|
| 72 |
-
- Slide over the first motor holder and fasten it using two screws (one on each side).
|
| 73 |
-
|
| 74 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_4.webp" style="height:300px;"/>
|
| 75 |
-
|
| 76 |
-
**Step 6: Attach Motor Horns**
|
| 77 |
-
- Install both motor horns, securing the top horn with a screw. Try not to move the motor position when attaching the motor horn, especially for the leader arms, where we removed the gears.
|
| 78 |
-
|
| 79 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_5.webp" style="height:300px;"/>
|
| 80 |
-
|
| 81 |
-
<details>
|
| 82 |
-
<summary><strong>Video adding motor horn</strong></summary>
|
| 83 |
-
<video src="https://github.com/user-attachments/assets/ef3391a4-ad05-4100-b2bd-1699bf86c969"></video>
|
| 84 |
-
</details>
|
| 85 |
-
|
| 86 |
-
**Step 7: Attach Shoulder Part**
|
| 87 |
-
- Route one wire to the back of the robot and the other to the left or towards you (see photo).
|
| 88 |
-
- Attach the shoulder part.
|
| 89 |
-
|
| 90 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_6.webp" style="height:300px;"/>
|
| 91 |
-
|
| 92 |
-
**Step 8: Secure Shoulder**
|
| 93 |
-
- Tighten the shoulder part with 4 screws on top and 4 on the bottom
|
| 94 |
-
*(access bottom holes by turning the shoulder).*
|
| 95 |
-
|
| 96 |
-
---
|
| 97 |
-
|
| 98 |
-
### Second Motor Assembly
|
| 99 |
-
|
| 100 |
-
**Step 9: Install Motor 2**
|
| 101 |
-
- Slide the second motor in from the top and link the wire from motor 1 to motor 2.
|
| 102 |
-
|
| 103 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_8.webp" style="height:300px;"/>
|
| 104 |
-
|
| 105 |
-
**Step 10: Attach Shoulder Holder**
|
| 106 |
-
- Add the shoulder motor holder.
|
| 107 |
-
- Ensure the wire from motor 1 to motor 2 goes behind the holder while the other wire is routed upward (see photo).
|
| 108 |
-
- This part can be tight to assemble, you can use a workbench like the image or a similar setup to push the part around the motor.
|
| 109 |
-
|
| 110 |
-
<div style="display: flex;">
|
| 111 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_9.webp" style="height:250px;"/>
|
| 112 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_10.webp" style="height:250px;"/>
|
| 113 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_12.webp" style="height:250px;"/>
|
| 114 |
-
</div>
|
| 115 |
-
|
| 116 |
-
**Step 11: Secure Motor 2**
|
| 117 |
-
- Fasten the second motor with 4 screws.
|
| 118 |
-
|
| 119 |
-
**Step 12: Attach Motor Horn**
|
| 120 |
-
- Attach both motor horns to motor 2, again use the horn screw.
|
| 121 |
-
|
| 122 |
-
**Step 13: Attach Base**
|
| 123 |
-
- Install the base attachment using 2 screws.
|
| 124 |
-
|
| 125 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_11.webp" style="height:300px;">
|
| 126 |
-
|
| 127 |
-
**Step 14: Attach Upper Arm**
|
| 128 |
-
- Attach the upper arm with 4 screws on each side.
|
| 129 |
-
|
| 130 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_13.webp" style="height:300px;">
|
| 131 |
-
|
| 132 |
-
---
|
| 133 |
-
|
| 134 |
-
### Third Motor Assembly
|
| 135 |
-
|
| 136 |
-
**Step 15: Install Motor 3**
|
| 137 |
-
- Route the motor cable from motor 2 through the cable holder to motor 3, then secure motor 3 with 4 screws.
|
| 138 |
-
|
| 139 |
-
**Step 16: Attach Motor Horn**
|
| 140 |
-
- Attach both motor horns to motor 3 and secure one again with a horn screw.
|
| 141 |
-
|
| 142 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_14.webp" style="height:300px;"/>
|
| 143 |
-
|
| 144 |
-
**Step 17: Attach Forearm**
|
| 145 |
-
- Connect the forearm to motor 3 using 4 screws on each side.
|
| 146 |
-
|
| 147 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_15.webp" style="height:300px;"/>
|
| 148 |
-
|
| 149 |
-
---
|
| 150 |
-
|
| 151 |
-
### Fourth Motor Assembly
|
| 152 |
-
|
| 153 |
-
**Step 18: Install Motor 4**
|
| 154 |
-
- Slide in motor 4, attach the cable from motor 3, and secure the cable in its holder with a screw.
|
| 155 |
-
|
| 156 |
-
<div style="display: flex;">
|
| 157 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_16.webp" style="height:300px;"/>
|
| 158 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_19.webp" style="height:300px;"/>
|
| 159 |
-
</div>
|
| 160 |
-
|
| 161 |
-
**Step 19: Attach Motor Holder 4**
|
| 162 |
-
- Install the fourth motor holder (a tight fit). Ensure one wire is routed upward and the wire from motor 3 is routed downward (see photo).
|
| 163 |
-
|
| 164 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_17.webp" style="height:300px;"/>
|
| 165 |
-
|
| 166 |
-
**Step 20: Secure Motor 4 & Attach Horn**
|
| 167 |
-
- Fasten motor 4 with 4 screws and attach its motor horns, use for one a horn screw.
|
| 168 |
-
|
| 169 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_18.webp" style="height:300px;"/>
|
| 170 |
-
|
| 171 |
-
---
|
| 172 |
-
|
| 173 |
-
### Wrist Assembly
|
| 174 |
-
|
| 175 |
-
**Step 21: Install Motor 5**
|
| 176 |
-
- Insert motor 5 into the wrist holder and secure it with 2 front screws.
|
| 177 |
-
|
| 178 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_20.webp" style="height:300px;"/>
|
| 179 |
-
|
| 180 |
-
**Step 22: Attach Wrist**
|
| 181 |
-
- Connect the wire from motor 4 to motor 5. And already insert the other wire for the gripper.
|
| 182 |
-
- Secure the wrist to motor 4 using 4 screws on both sides.
|
| 183 |
-
|
| 184 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_22.webp" style="height:300px;"/>
|
| 185 |
-
|
| 186 |
-
**Step 23: Attach Wrist Horn**
|
| 187 |
-
- Install only one motor horn on the wrist motor and secure it with a horn screw.
|
| 188 |
-
|
| 189 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_23.webp" style="height:300px;"/>
|
| 190 |
-
|
| 191 |
-
---
|
| 192 |
-
|
| 193 |
-
### Follower Configuration
|
| 194 |
-
|
| 195 |
-
**Step 24: Attach Gripper**
|
| 196 |
-
- Attach the gripper to motor 5.
|
| 197 |
-
|
| 198 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_24.webp" style="height:300px;"/>
|
| 199 |
-
|
| 200 |
-
**Step 25: Install Gripper Motor**
|
| 201 |
-
- Insert the gripper motor, connect the motor wire from motor 5 to motor 6, and secure it with 3 screws on each side.
|
| 202 |
-
|
| 203 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_25.webp" style="height:300px;"/>
|
| 204 |
-
|
| 205 |
-
**Step 26: Attach Gripper Horn & Claw**
|
| 206 |
-
- Attach the motor horns and again use a horn screw.
|
| 207 |
-
- Install the gripper claw and secure it with 4 screws on both sides.
|
| 208 |
-
|
| 209 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_26.webp" style="height:300px;"/>
|
| 210 |
-
|
| 211 |
-
**Step 27: Mount Controller**
|
| 212 |
-
- Attach the motor controller to the back of the robot.
|
| 213 |
-
|
| 214 |
-
<div style="display: flex;">
|
| 215 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_27.webp" style="height:300px;"/>
|
| 216 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_28.webp" style="height:300px;"/>
|
| 217 |
-
</div>
|
| 218 |
-
|
| 219 |
-
*Assembly complete – proceed to Leader arm assembly.*
|
| 220 |
-
|
| 221 |
-
---
|
| 222 |
-
|
| 223 |
-
### Leader Configuration
|
| 224 |
-
|
| 225 |
-
For the leader configuration, perform **Steps 1–23**. Make sure that you removed the motor gears from the motors.
|
| 226 |
-
|
| 227 |
-
**Step 24: Attach Leader Holder**
|
| 228 |
-
- Mount the leader holder onto the wrist and secure it with a screw.
|
| 229 |
-
|
| 230 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_29.webp" style="height:300px;"/>
|
| 231 |
-
|
| 232 |
-
**Step 25: Attach Handle**
|
| 233 |
-
- Attach the handle to motor 5 using 4 screws.
|
| 234 |
-
|
| 235 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_30.webp" style="height:300px;"/>
|
| 236 |
-
|
| 237 |
-
**Step 26: Install Gripper Motor**
|
| 238 |
-
- Insert the gripper motor, secure it with 3 screws on each side, attach a motor horn using a horn screw, and connect the motor wire.
|
| 239 |
-
|
| 240 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_31.webp" style="height:300px;"/>
|
| 241 |
-
|
| 242 |
-
**Step 27: Attach Trigger**
|
| 243 |
-
- Attach the follower trigger with 4 screws.
|
| 244 |
-
|
| 245 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_32.webp" style="height:300px;"/>
|
| 246 |
-
|
| 247 |
-
**Step 28: Mount Controller**
|
| 248 |
-
- Attach the motor controller to the back of the robot.
|
| 249 |
-
|
| 250 |
-
<div style="display: flex;">
|
| 251 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_27.webp" style="height:300px;"/>
|
| 252 |
-
<img src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/so100_assembly_28.webp" style="height:300px;"/>
|
| 253 |
-
</div>
|
| 254 |
-
|
| 255 |
-
## Configure the motors
|
| 256 |
-
|
| 257 |
-
### 1. Find the USB ports associated with each arm
|
| 258 |
-
|
| 259 |
-
To find the port for each bus servo adapter, run this script:
|
| 260 |
-
```bash
|
| 261 |
-
python lerobot/find_port.py
|
| 262 |
-
```
|
| 263 |
-
|
| 264 |
-
<hfoptions id="example">
|
| 265 |
-
<hfoption id="Mac">
|
| 266 |
-
|
| 267 |
-
Example output:
|
| 268 |
-
|
| 269 |
-
```
|
| 270 |
-
Finding all available ports for the MotorBus.
|
| 271 |
-
['/dev/tty.usbmodem575E0032081', '/dev/tty.usbmodem575E0031751']
|
| 272 |
-
Remove the USB cable from your MotorsBus and press Enter when done.
|
| 273 |
-
|
| 274 |
-
[...Disconnect corresponding leader or follower arm and press Enter...]
|
| 275 |
-
|
| 276 |
-
The port of this MotorsBus is /dev/tty.usbmodem575E0032081
|
| 277 |
-
Reconnect the USB cable.
|
| 278 |
-
```
|
| 279 |
-
|
| 280 |
-
Where the found port is: `/dev/tty.usbmodem575E0032081` corresponding to your leader or follower arm.
|
| 281 |
-
|
| 282 |
-
</hfoption>
|
| 283 |
-
<hfoption id="Linux">
|
| 284 |
-
|
| 285 |
-
On Linux, you might need to give access to the USB ports by running:
|
| 286 |
-
```bash
|
| 287 |
-
sudo chmod 666 /dev/ttyACM0
|
| 288 |
-
sudo chmod 666 /dev/ttyACM1
|
| 289 |
-
```
|
| 290 |
-
|
| 291 |
-
Example output:
|
| 292 |
-
|
| 293 |
-
```
|
| 294 |
-
Finding all available ports for the MotorBus.
|
| 295 |
-
['/dev/ttyACM0', '/dev/ttyACM1']
|
| 296 |
-
Remove the usb cable from your MotorsBus and press Enter when done.
|
| 297 |
-
|
| 298 |
-
[...Disconnect corresponding leader or follower arm and press Enter...]
|
| 299 |
-
|
| 300 |
-
The port of this MotorsBus is /dev/ttyACM1
|
| 301 |
-
Reconnect the USB cable.
|
| 302 |
-
```
|
| 303 |
-
|
| 304 |
-
Where the found port is: `/dev/ttyACM1` corresponding to your leader or follower arm.
|
| 305 |
-
|
| 306 |
-
</hfoption>
|
| 307 |
-
</hfoptions>
|
| 308 |
-
|
| 309 |
-
### 2. Set the motors ids and baudrates
|
| 310 |
-
|
| 311 |
-
Each motor is identified by a unique id on the bus. When brand new, motors usually come with a default id of `1`. For the communication to work properly between the motors and the controller, we first need to set a unique, different id to each motor. Additionally, the speed at which data is transmitted on the bus is determined by the baudrate. In order to talk to each other, the controller and all the motors need to be configured with the same baudrate.
|
| 312 |
-
|
| 313 |
-
To that end, we first need to connect to each motor individually with the controller in order to set these. Since we will write these parameters in the non-volatile section of the motors' internal memory (EEPROM), we'll only need to do this once.
|
| 314 |
-
|
| 315 |
-
If you are repurposing motors from another robot, you will probably also need to perform this step as the ids and baudrate likely won't match.
|
| 316 |
-
|
| 317 |
-
#### Follower
|
| 318 |
-
|
| 319 |
-
Connect the usb cable from your computer and the power supply to the follower arm's controller board. Then, run the following command or run the API example with the port you got from the previous step. You'll also need to give your leader arm a name with the `id` parameter.
|
| 320 |
-
|
| 321 |
-
For a visual reference on how to set the motor ids please refer to [this video](https://huggingface.co/docs/lerobot/en/so101#setup-motors-video) where we follow the process for the SO101 arm.
|
| 322 |
-
|
| 323 |
-
<hfoptions id="setup_motors">
|
| 324 |
-
<hfoption id="Command">
|
| 325 |
-
|
| 326 |
-
```bash
|
| 327 |
-
python -m lerobot.setup_motors \
|
| 328 |
-
--robot.type=so100_follower \
|
| 329 |
-
--robot.port=/dev/tty.usbmodem585A0076841 # <- paste here the port found at previous step
|
| 330 |
-
```
|
| 331 |
-
</hfoption>
|
| 332 |
-
<hfoption id="API example">
|
| 333 |
-
|
| 334 |
-
```python
|
| 335 |
-
from lerobot.common.robots.so100_follower import SO100Follower, SO100FollowerConfig
|
| 336 |
-
|
| 337 |
-
config = SO100FollowerConfig(
|
| 338 |
-
port="/dev/tty.usbmodem585A0076841",
|
| 339 |
-
id="my_awesome_follower_arm",
|
| 340 |
-
)
|
| 341 |
-
follower = SO100Follower(config)
|
| 342 |
-
follower.setup_motors()
|
| 343 |
-
```
|
| 344 |
-
</hfoption>
|
| 345 |
-
</hfoptions>
|
| 346 |
-
|
| 347 |
-
You should see the following instruction
|
| 348 |
-
```
|
| 349 |
-
Connect the controller board to the 'gripper' motor only and press enter.
|
| 350 |
-
```
|
| 351 |
-
|
| 352 |
-
As instructed, plug the gripper's motor. Make sure it's the only motor connected to the board, and that the motor itself is not yet daisy-chained to any other motor. As you press `[Enter]`, the script will automatically set the id and baudrate for that motor.
|
| 353 |
-
|
| 354 |
-
<details>
|
| 355 |
-
<summary>Troubleshooting</summary>
|
| 356 |
-
|
| 357 |
-
If you get an error at that point, check your cables and make sure they are plugged in properly:
|
| 358 |
-
<ul>
|
| 359 |
-
<li>Power supply</li>
|
| 360 |
-
<li>USB cable between your computer and the controller board</li>
|
| 361 |
-
<li>The 3-pin cable from the controller board to the motor</li>
|
| 362 |
-
</ul>
|
| 363 |
-
|
| 364 |
-
If you are using a Waveshare controller board, make sure that the two jumpers are set on the `B` channel (USB).
|
| 365 |
-
</details>
|
| 366 |
-
|
| 367 |
-
You should then see the following message:
|
| 368 |
-
```
|
| 369 |
-
'gripper' motor id set to 6
|
| 370 |
-
```
|
| 371 |
-
|
| 372 |
-
Followed by the next instruction:
|
| 373 |
-
```
|
| 374 |
-
Connect the controller board to the 'wrist_roll' motor only and press enter.
|
| 375 |
-
```
|
| 376 |
-
|
| 377 |
-
You can disconnect the 3-pin cable from the controller board, but you can leave it connected to the gripper motor on the other end, as it will already be in the right place. Now, plug in another 3-pin cable to the wrist roll motor and connect it to the controller board. As with the previous motor, make sure it is the only motor connected to the board and that the motor itself isn't connected to any other one.
|
| 378 |
-
|
| 379 |
-
Repeat the operation for each motor as instructed.
|
| 380 |
-
|
| 381 |
-
> [!TIP]
|
| 382 |
-
> Check your cabling at each step before pressing Enter. For instance, the power supply cable might disconnect as you manipulate the board.
|
| 383 |
-
|
| 384 |
-
When you are done, the script will simply finish, at which point the motors are ready to be used. You can now plug the 3-pin cable from each motor to the next one, and the cable from the first motor (the 'shoulder pan' with id=1) to the controller board, which can now be attached to the base of the arm.
|
| 385 |
-
|
| 386 |
-
#### Leader
|
| 387 |
-
Do the same steps for the leader arm.
|
| 388 |
-
|
| 389 |
-
<hfoptions id="setup_motors">
|
| 390 |
-
<hfoption id="Command">
|
| 391 |
-
```bash
|
| 392 |
-
python -m lerobot.setup_motors \
|
| 393 |
-
--teleop.type=so100_leader \
|
| 394 |
-
--teleop.port=/dev/tty.usbmodem575E0031751 # <- paste here the port found at previous step
|
| 395 |
-
```
|
| 396 |
-
</hfoption>
|
| 397 |
-
<hfoption id="API example">
|
| 398 |
-
|
| 399 |
-
```python
|
| 400 |
-
from lerobot.common.teleoperators.so100_leader import SO100Leader, SO100LeaderConfig
|
| 401 |
-
|
| 402 |
-
config = SO100LeaderConfig(
|
| 403 |
-
port="/dev/tty.usbmodem585A0076841",
|
| 404 |
-
id="my_awesome_leader_arm",
|
| 405 |
-
)
|
| 406 |
-
leader = SO100Leader(config)
|
| 407 |
-
leader.setup_motors()
|
| 408 |
-
```
|
| 409 |
-
</hfoption>
|
| 410 |
-
</hfoptions>
|
| 411 |
-
|
| 412 |
-
## Calibrate
|
| 413 |
-
|
| 414 |
-
Next, you'll need to calibrate your robot to ensure that the leader and follower arms have the same position values when they are in the same physical position.
|
| 415 |
-
The calibration process is very important because it allows a neural network trained on one robot to work on another.
|
| 416 |
-
|
| 417 |
-
#### Follower
|
| 418 |
-
|
| 419 |
-
Run the following command or API example to calibrate the follower arm:
|
| 420 |
-
|
| 421 |
-
<hfoptions id="calibrate_follower">
|
| 422 |
-
<hfoption id="Command">
|
| 423 |
-
|
| 424 |
-
```bash
|
| 425 |
-
python -m lerobot.calibrate \
|
| 426 |
-
--robot.type=so100_follower \
|
| 427 |
-
--robot.port=/dev/tty.usbmodem58760431551 \ # <- The port of your robot
|
| 428 |
-
--robot.id=my_awesome_follower_arm # <- Give the robot a unique name
|
| 429 |
-
```
|
| 430 |
-
</hfoption>
|
| 431 |
-
<hfoption id="API example">
|
| 432 |
-
|
| 433 |
-
```python
|
| 434 |
-
from lerobot.common.robots.so100_follower import SO100FollowerConfig, SO100Follower
|
| 435 |
-
|
| 436 |
-
config = SO100FollowerConfig(
|
| 437 |
-
port="/dev/tty.usbmodem585A0076891",
|
| 438 |
-
id="my_awesome_follower_arm",
|
| 439 |
-
)
|
| 440 |
-
|
| 441 |
-
follower = SO100Follower(config)
|
| 442 |
-
follower.connect(calibrate=False)
|
| 443 |
-
follower.calibrate()
|
| 444 |
-
follower.disconnect()
|
| 445 |
-
```
|
| 446 |
-
</hfoption>
|
| 447 |
-
</hfoptions>
|
| 448 |
-
|
| 449 |
-
We unified the calibration method for most robots. Thus, the calibration steps for this SO100 arm are the same as the steps for the Koch and SO101. First, we have to move the robot to the position where each joint is in the middle of its range, then we press `Enter`. Secondly, we move all joints through their full range of motion. A video of this same process for the SO101 as reference can be found [here](https://huggingface.co/docs/lerobot/en/so101#calibration-video)
|
| 450 |
-
|
| 451 |
-
#### Leader
|
| 452 |
-
|
| 453 |
-
Do the same steps to calibrate the leader arm, run the following command or API example:
|
| 454 |
-
|
| 455 |
-
<hfoptions id="calibrate_leader">
|
| 456 |
-
<hfoption id="Command">
|
| 457 |
-
|
| 458 |
-
```bash
|
| 459 |
-
python -m lerobot.calibrate \
|
| 460 |
-
--teleop.type=so100_leader \
|
| 461 |
-
--teleop.port=/dev/tty.usbmodem58760431551 \ # <- The port of your robot
|
| 462 |
-
--teleop.id=my_awesome_leader_arm # <- Give the robot a unique name
|
| 463 |
-
```
|
| 464 |
-
</hfoption>
|
| 465 |
-
<hfoption id="API example">
|
| 466 |
-
|
| 467 |
-
```python
|
| 468 |
-
from lerobot.common.teleoperators.so100_leader import SO100LeaderConfig, SO100Leader
|
| 469 |
-
|
| 470 |
-
config = SO100LeaderConfig(
|
| 471 |
-
port="/dev/tty.usbmodem58760431551",
|
| 472 |
-
id="my_awesome_leader_arm",
|
| 473 |
-
)
|
| 474 |
-
|
| 475 |
-
leader = SO100Leader(config)
|
| 476 |
-
leader.connect(calibrate=False)
|
| 477 |
-
leader.calibrate()
|
| 478 |
-
leader.disconnect()
|
| 479 |
-
```
|
| 480 |
-
</hfoption>
|
| 481 |
-
</hfoptions>
|
| 482 |
-
|
| 483 |
-
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)
|
| 484 |
-
|
| 485 |
-
> [!TIP]
|
| 486 |
-
> If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
docs/source/so101.mdx
DELETED
|
@@ -1,381 +0,0 @@
|
|
| 1 |
-
# SO-101
|
| 2 |
-
|
| 3 |
-
In the steps below, we explain how to assemble our flagship robot, the SO-101.
|
| 4 |
-
|
| 5 |
-
## Source the parts
|
| 6 |
-
|
| 7 |
-
Follow this [README](https://github.com/TheRobotStudio/SO-ARM100). It contains the bill of materials, with a link to source the parts, as well as the instructions to 3D print the parts.
|
| 8 |
-
And advise if it's your first time printing or if you don't own a 3D printer.
|
| 9 |
-
|
| 10 |
-
## Install LeRobot 🤗
|
| 11 |
-
|
| 12 |
-
To install LeRobot, follow our [Installation Guide](./installation)
|
| 13 |
-
|
| 14 |
-
In addition to these instructions, you need to install the Feetech SDK:
|
| 15 |
-
```bash
|
| 16 |
-
pip install -e ".[feetech]"
|
| 17 |
-
```
|
| 18 |
-
|
| 19 |
-
## Step-by-Step Assembly Instructions
|
| 20 |
-
|
| 21 |
-
The follower arm uses 6x STS3215 motors with 1/345 gearing. The leader, however, uses three differently geared motors to make sure it can both sustain its own weight and it can be moved without requiring much force. Which motor is needed for which joint is shown in the table below.
|
| 22 |
-
|
| 23 |
-
| Leader-Arm Axis | Motor | Gear Ratio |
|
| 24 |
-
|-----------------|:-------:|:----------:|
|
| 25 |
-
| Base / Shoulder Yaw | 1 | 1 / 191 |
|
| 26 |
-
| Shoulder Pitch | 2 | 1 / 345 |
|
| 27 |
-
| Elbow | 3 | 1 / 191 |
|
| 28 |
-
| Wrist Roll | 4 | 1 / 147 |
|
| 29 |
-
| Wrist Pitch | 5 | 1 / 147 |
|
| 30 |
-
| Gripper | 6 | 1 / 147 |
|
| 31 |
-
|
| 32 |
-
### Clean Parts
|
| 33 |
-
Remove all support material from the 3D-printed parts. The easiest way to do this is using a small screwdriver to get underneath the support material.
|
| 34 |
-
|
| 35 |
-
### Joint 1
|
| 36 |
-
|
| 37 |
-
- Place the first motor into the base.
|
| 38 |
-
- Fasten the motor with 4 M2x6mm screws (smallest screws). Two from the top and two from the bottom.
|
| 39 |
-
- Slide over the first motor holder and fasten it using two M2x6mm screws (one on each side).
|
| 40 |
-
- Install both motor horns, securing the top horn with a M3x6mm screw.
|
| 41 |
-
- Attach the shoulder part.
|
| 42 |
-
- Tighten the shoulder part with 4 M3x6mm screws on top and 4 M3x6mm screws on the bottom
|
| 43 |
-
- Add the shoulder motor holder.
|
| 44 |
-
|
| 45 |
-
<div class="video-container">
|
| 46 |
-
<video controls width="600">
|
| 47 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/Joint1_v2.mp4" type="video/mp4" />
|
| 48 |
-
</video>
|
| 49 |
-
</div>
|
| 50 |
-
|
| 51 |
-
### Joint 2
|
| 52 |
-
|
| 53 |
-
- Slide the second motor in from the top.
|
| 54 |
-
- Fasten the second motor with 4 M2x6mm screws.
|
| 55 |
-
- Attach both motor horns to motor 2, again use the M3x6mm horn screw.
|
| 56 |
-
- Attach the upper arm with 4 M3x6mm screws on each side.
|
| 57 |
-
|
| 58 |
-
<div class="video-container">
|
| 59 |
-
<video controls width="600">
|
| 60 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/Joint2_v2.mp4" type="video/mp4" />
|
| 61 |
-
</video>
|
| 62 |
-
</div>
|
| 63 |
-
|
| 64 |
-
### Joint 3
|
| 65 |
-
|
| 66 |
-
- Insert motor 3 and fasten using 4 M2x6mm screws
|
| 67 |
-
- Attach both motor horns to motor 3 and secure one again with a M3x6mm horn screw.
|
| 68 |
-
- Connect the forearm to motor 3 using 4 M3x6mm screws on each side.
|
| 69 |
-
|
| 70 |
-
<div class="video-container">
|
| 71 |
-
<video controls width="600">
|
| 72 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/Joint3_v2.mp4" type="video/mp4" />
|
| 73 |
-
</video>
|
| 74 |
-
</div>
|
| 75 |
-
|
| 76 |
-
### Joint 4
|
| 77 |
-
|
| 78 |
-
- Slide over motor holder 4.
|
| 79 |
-
- Slide in motor 4.
|
| 80 |
-
- Fasten motor 4 with 4 M2x6mm screws and attach its motor horns, use a M3x6mm horn screw.
|
| 81 |
-
|
| 82 |
-
<div class="video-container">
|
| 83 |
-
<video controls width="600">
|
| 84 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/Joint4_v2.mp4" type="video/mp4" />
|
| 85 |
-
</video>
|
| 86 |
-
</div>
|
| 87 |
-
|
| 88 |
-
### Joint 5
|
| 89 |
-
|
| 90 |
-
- Insert motor 5 into the wrist holder and secure it with 2 M2x6mm front screws.
|
| 91 |
-
- Install only one motor horn on the wrist motor and secure it with a M3x6mm horn screw.
|
| 92 |
-
- Secure the wrist to motor 4 using 4 M3x6mm screws on both sides.
|
| 93 |
-
|
| 94 |
-
<div class="video-container">
|
| 95 |
-
<video controls width="600">
|
| 96 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/Joint5_v2.mp4" type="video/mp4" />
|
| 97 |
-
</video>
|
| 98 |
-
</div>
|
| 99 |
-
|
| 100 |
-
### Gripper / Handle
|
| 101 |
-
|
| 102 |
-
<hfoptions id="assembly">
|
| 103 |
-
<hfoption id="Follower">
|
| 104 |
-
|
| 105 |
-
- Attach the gripper to motor 5, attach it to the motor horn on the wrist using 4 M3x6mm screws.
|
| 106 |
-
- Insert the gripper motor and secure it with 2 M2x6mm screws on each side.
|
| 107 |
-
- Attach the motor horns and again use a M3x6mm horn screw.
|
| 108 |
-
- Install the gripper claw and secure it with 4 M3x6mm screws on both sides.
|
| 109 |
-
|
| 110 |
-
<div class="video-container">
|
| 111 |
-
<video controls width="600">
|
| 112 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/Gripper_v2.mp4" type="video/mp4" />
|
| 113 |
-
</video>
|
| 114 |
-
</div>
|
| 115 |
-
|
| 116 |
-
</hfoption>
|
| 117 |
-
<hfoption id="Leader">
|
| 118 |
-
|
| 119 |
-
- Mount the leader holder onto the wrist and secure it with 4 M3x6mm screws.
|
| 120 |
-
- Attach the handle to motor 5 using 1 M2x6mm screw.
|
| 121 |
-
- Insert the gripper motor, secure it with 2 M2x6mm screws on each side, attach a motor horn using a M3x6mm horn screw.
|
| 122 |
-
- Attach the follower trigger with 4 M3x6mm screws.
|
| 123 |
-
|
| 124 |
-
<div class="video-container">
|
| 125 |
-
<video controls width="600">
|
| 126 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/Leader_v2.mp4" type="video/mp4" />
|
| 127 |
-
</video>
|
| 128 |
-
</div>
|
| 129 |
-
|
| 130 |
-
</hfoption>
|
| 131 |
-
</hfoptions>
|
| 132 |
-
|
| 133 |
-
## Configure the motors
|
| 134 |
-
|
| 135 |
-
### 1. Find the USB ports associated with each arm
|
| 136 |
-
|
| 137 |
-
To find the port for each bus servo adapter, run this script:
|
| 138 |
-
```bash
|
| 139 |
-
python lerobot/find_port.py
|
| 140 |
-
```
|
| 141 |
-
|
| 142 |
-
<hfoptions id="example">
|
| 143 |
-
<hfoption id="Mac">
|
| 144 |
-
|
| 145 |
-
Example output:
|
| 146 |
-
|
| 147 |
-
```
|
| 148 |
-
Finding all available ports for the MotorBus.
|
| 149 |
-
['/dev/tty.usbmodem575E0032081', '/dev/tty.usbmodem575E0031751']
|
| 150 |
-
Remove the USB cable from your MotorsBus and press Enter when done.
|
| 151 |
-
|
| 152 |
-
[...Disconnect corresponding leader or follower arm and press Enter...]
|
| 153 |
-
|
| 154 |
-
The port of this MotorsBus is /dev/tty.usbmodem575E0032081
|
| 155 |
-
Reconnect the USB cable.
|
| 156 |
-
```
|
| 157 |
-
|
| 158 |
-
Where the found port is: `/dev/tty.usbmodem575E0032081` corresponding to your leader or follower arm.
|
| 159 |
-
|
| 160 |
-
</hfoption>
|
| 161 |
-
<hfoption id="Linux">
|
| 162 |
-
|
| 163 |
-
On Linux, you might need to give access to the USB ports by running:
|
| 164 |
-
```bash
|
| 165 |
-
sudo chmod 666 /dev/ttyACM0
|
| 166 |
-
sudo chmod 666 /dev/ttyACM1
|
| 167 |
-
```
|
| 168 |
-
|
| 169 |
-
Example output:
|
| 170 |
-
|
| 171 |
-
```
|
| 172 |
-
Finding all available ports for the MotorBus.
|
| 173 |
-
['/dev/ttyACM0', '/dev/ttyACM1']
|
| 174 |
-
Remove the usb cable from your MotorsBus and press Enter when done.
|
| 175 |
-
|
| 176 |
-
[...Disconnect corresponding leader or follower arm and press Enter...]
|
| 177 |
-
|
| 178 |
-
The port of this MotorsBus is /dev/ttyACM1
|
| 179 |
-
Reconnect the USB cable.
|
| 180 |
-
```
|
| 181 |
-
|
| 182 |
-
Where the found port is: `/dev/ttyACM1` corresponding to your leader or follower arm.
|
| 183 |
-
|
| 184 |
-
</hfoption>
|
| 185 |
-
</hfoptions>
|
| 186 |
-
|
| 187 |
-
### 2. Set the motors ids and baudrates
|
| 188 |
-
|
| 189 |
-
Each motor is identified by a unique id on the bus. When brand new, motors usually come with a default id of `1`. For the communication to work properly between the motors and the controller, we first need to set a unique, different id to each motor. Additionally, the speed at which data is transmitted on the bus is determined by the baudrate. In order to talk to each other, the controller and all the motors need to be configured with the same baudrate.
|
| 190 |
-
|
| 191 |
-
To that end, we first need to connect to each motor individually with the controller in order to set these. Since we will write these parameters in the non-volatile section of the motors' internal memory (EEPROM), we'll only need to do this once.
|
| 192 |
-
|
| 193 |
-
If you are repurposing motors from another robot, you will probably also need to perform this step as the ids and baudrate likely won't match.
|
| 194 |
-
|
| 195 |
-
The video below shows the sequence of steps for setting the motor ids.
|
| 196 |
-
|
| 197 |
-
##### Setup motors video
|
| 198 |
-
|
| 199 |
-
<div class="video-container">
|
| 200 |
-
<video controls width="600">
|
| 201 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/setup_motors_so101_2.mp4" type="video/mp4" />
|
| 202 |
-
</video>
|
| 203 |
-
</div>
|
| 204 |
-
|
| 205 |
-
#### Follower
|
| 206 |
-
|
| 207 |
-
Connect the usb cable from your computer and the power supply to the follower arm's controller board. Then, run the following command or run the API example with the port you got from the previous step. You'll also need to give your leader arm a name with the `id` parameter.
|
| 208 |
-
|
| 209 |
-
<hfoptions id="setup_motors">
|
| 210 |
-
<hfoption id="Command">
|
| 211 |
-
|
| 212 |
-
```bash
|
| 213 |
-
python -m lerobot.setup_motors \
|
| 214 |
-
--robot.type=so101_follower \
|
| 215 |
-
--robot.port=/dev/tty.usbmodem585A0076841 # <- paste here the port found at previous step
|
| 216 |
-
```
|
| 217 |
-
</hfoption>
|
| 218 |
-
<hfoption id="API example">
|
| 219 |
-
|
| 220 |
-
```python
|
| 221 |
-
from lerobot.common.robots.so101_follower import SO101Follower, SO101FollowerConfig
|
| 222 |
-
|
| 223 |
-
config = SO101FollowerConfig(
|
| 224 |
-
port="/dev/tty.usbmodem585A0076841",
|
| 225 |
-
id="my_awesome_follower_arm",
|
| 226 |
-
)
|
| 227 |
-
follower = SO101Follower(config)
|
| 228 |
-
follower.setup_motors()
|
| 229 |
-
```
|
| 230 |
-
</hfoption>
|
| 231 |
-
</hfoptions>
|
| 232 |
-
|
| 233 |
-
You should see the following instruction
|
| 234 |
-
```bash
|
| 235 |
-
Connect the controller board to the 'gripper' motor only and press enter.
|
| 236 |
-
```
|
| 237 |
-
|
| 238 |
-
As instructed, plug the gripper's motor. Make sure it's the only motor connected to the board, and that the motor itself is not yet daisy-chained to any other motor. As you press `[Enter]`, the script will automatically set the id and baudrate for that motor.
|
| 239 |
-
|
| 240 |
-
<details>
|
| 241 |
-
<summary>Troubleshooting</summary>
|
| 242 |
-
|
| 243 |
-
If you get an error at that point, check your cables and make sure they are plugged in properly:
|
| 244 |
-
<ul>
|
| 245 |
-
<li>Power supply</li>
|
| 246 |
-
<li>USB cable between your computer and the controller board</li>
|
| 247 |
-
<li>The 3-pin cable from the controller board to the motor</li>
|
| 248 |
-
</ul>
|
| 249 |
-
|
| 250 |
-
If you are using a Waveshare controller board, make sure that the two jumpers are set on the `B` channel (USB).
|
| 251 |
-
</details>
|
| 252 |
-
|
| 253 |
-
You should then see the following message:
|
| 254 |
-
```bash
|
| 255 |
-
'gripper' motor id set to 6
|
| 256 |
-
```
|
| 257 |
-
|
| 258 |
-
Followed by the next instruction:
|
| 259 |
-
```bash
|
| 260 |
-
Connect the controller board to the 'wrist_roll' motor only and press enter.
|
| 261 |
-
```
|
| 262 |
-
|
| 263 |
-
You can disconnect the 3-pin cable from the controller board, but you can leave it connected to the gripper motor on the other end, as it will already be in the right place. Now, plug in another 3-pin cable to the wrist roll motor and connect it to the controller board. As with the previous motor, make sure it is the only motor connected to the board and that the motor itself isn't connected to any other one.
|
| 264 |
-
|
| 265 |
-
Repeat the operation for each motor as instructed.
|
| 266 |
-
|
| 267 |
-
> [!TIP]
|
| 268 |
-
> Check your cabling at each step before pressing Enter. For instance, the power supply cable might disconnect as you manipulate the board.
|
| 269 |
-
|
| 270 |
-
When you are done, the script will simply finish, at which point the motors are ready to be used. You can now plug the 3-pin cable from each motor to the next one, and the cable from the first motor (the 'shoulder pan' with id=1) to the controller board, which can now be attached to the base of the arm.
|
| 271 |
-
|
| 272 |
-
#### Leader
|
| 273 |
-
Do the same steps for the leader arm.
|
| 274 |
-
|
| 275 |
-
<hfoptions id="setup_motors">
|
| 276 |
-
<hfoption id="Command">
|
| 277 |
-
|
| 278 |
-
```bash
|
| 279 |
-
python -m lerobot.setup_motors \
|
| 280 |
-
--teleop.type=so101_leader \
|
| 281 |
-
--teleop.port=/dev/tty.usbmodem575E0031751 # <- paste here the port found at previous step
|
| 282 |
-
```
|
| 283 |
-
</hfoption>
|
| 284 |
-
<hfoption id="API example">
|
| 285 |
-
|
| 286 |
-
```python
|
| 287 |
-
from lerobot.common.teleoperators.so101_leader import SO101Leader, SO101LeaderConfig
|
| 288 |
-
|
| 289 |
-
config = SO101LeaderConfig(
|
| 290 |
-
port="/dev/tty.usbmodem585A0076841",
|
| 291 |
-
id="my_awesome_leader_arm",
|
| 292 |
-
)
|
| 293 |
-
leader = SO101Leader(config)
|
| 294 |
-
leader.setup_motors()
|
| 295 |
-
```
|
| 296 |
-
</hfoption>
|
| 297 |
-
</hfoptions>
|
| 298 |
-
|
| 299 |
-
## Calibrate
|
| 300 |
-
|
| 301 |
-
Next, you'll need to calibrate your robot to ensure that the leader and follower arms have the same position values when they are in the same physical position.
|
| 302 |
-
The calibration process is very important because it allows a neural network trained on one robot to work on another.
|
| 303 |
-
|
| 304 |
-
#### Follower
|
| 305 |
-
|
| 306 |
-
Run the following command or API example to calibrate the follower arm:
|
| 307 |
-
|
| 308 |
-
<hfoptions id="calibrate_follower">
|
| 309 |
-
<hfoption id="Command">
|
| 310 |
-
|
| 311 |
-
```bash
|
| 312 |
-
python -m lerobot.calibrate \
|
| 313 |
-
--robot.type=so101_follower \
|
| 314 |
-
--robot.port=/dev/tty.usbmodem58760431551 \ # <- The port of your robot
|
| 315 |
-
--robot.id=my_awesome_follower_arm # <- Give the robot a unique name
|
| 316 |
-
```
|
| 317 |
-
</hfoption>
|
| 318 |
-
<hfoption id="API example">
|
| 319 |
-
|
| 320 |
-
```python
|
| 321 |
-
from lerobot.common.robots.so101_follower import SO101FollowerConfig, SO101Follower
|
| 322 |
-
|
| 323 |
-
config = SO101FollowerConfig(
|
| 324 |
-
port="/dev/tty.usbmodem585A0076891",
|
| 325 |
-
id="my_awesome_follower_arm",
|
| 326 |
-
)
|
| 327 |
-
|
| 328 |
-
follower = SO101Follower(config)
|
| 329 |
-
follower.connect(calibrate=False)
|
| 330 |
-
follower.calibrate()
|
| 331 |
-
follower.disconnect()
|
| 332 |
-
```
|
| 333 |
-
</hfoption>
|
| 334 |
-
</hfoptions>
|
| 335 |
-
|
| 336 |
-
The video below shows how to perform the calibration. First you need to move the robot to the position where all joints are in the middle of their ranges. Then after pressing enter you have to move each joint through its full range of motion.
|
| 337 |
-
|
| 338 |
-
##### Calibration video
|
| 339 |
-
|
| 340 |
-
<div class="video-container">
|
| 341 |
-
<video controls width="600">
|
| 342 |
-
<source src="https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/lerobot/calibrate_so101_2.mp4" type="video/mp4" />
|
| 343 |
-
</video>
|
| 344 |
-
</div>
|
| 345 |
-
|
| 346 |
-
#### Leader
|
| 347 |
-
|
| 348 |
-
Do the same steps to calibrate the leader arm, run the following command or API example:
|
| 349 |
-
|
| 350 |
-
<hfoptions id="calibrate_leader">
|
| 351 |
-
<hfoption id="Command">
|
| 352 |
-
|
| 353 |
-
```bash
|
| 354 |
-
python -m lerobot.calibrate \
|
| 355 |
-
--teleop.type=so101_leader \
|
| 356 |
-
--teleop.port=/dev/tty.usbmodem58760431551 \ # <- The port of your robot
|
| 357 |
-
--teleop.id=my_awesome_leader_arm # <- Give the robot a unique name
|
| 358 |
-
```
|
| 359 |
-
</hfoption>
|
| 360 |
-
<hfoption id="API example">
|
| 361 |
-
|
| 362 |
-
```python
|
| 363 |
-
from lerobot.common.teleoperators.so101_leader import SO101LeaderConfig, SO101Leader
|
| 364 |
-
|
| 365 |
-
config = SO101LeaderConfig(
|
| 366 |
-
port="/dev/tty.usbmodem58760431551",
|
| 367 |
-
id="my_awesome_leader_arm",
|
| 368 |
-
)
|
| 369 |
-
|
| 370 |
-
leader = SO101Leader(config)
|
| 371 |
-
leader.connect(calibrate=False)
|
| 372 |
-
leader.calibrate()
|
| 373 |
-
leader.disconnect()
|
| 374 |
-
```
|
| 375 |
-
</hfoption>
|
| 376 |
-
</hfoptions>
|
| 377 |
-
|
| 378 |
-
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)
|
| 379 |
-
|
| 380 |
-
> [!TIP]
|
| 381 |
-
> If you have any questions or need help, please reach out on [Discord](https://discord.com/invite/s3KuuzsPFb).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|