# Machine Learning LeRobot avec SO-ARM101

### Installation et prérequis

- Une carte graphique NVidia et une installation de Cuda ?
- Comparaison cartes graphiques (un peu dépassé car ne prend pas en compte les dernières génération type 5090) [https://www.geeksforgeeks.org/machine-learning/choosing-the-right-gpu-for-your-machine-learning/](https://www.geeksforgeeks.org/machine-learning/choosing-the-right-gpu-for-your-machine-learning/)
- Puissance de calcul dispo à l'Innov'Lab TPS [https://www.innovlab-tps.net/calcul-et-stockage.html](https://www.innovlab-tps.net/calcul-et-stockage.html)
    - <span style="color: #2a2a2a;">Pour l'**entraînement** des modèles : Serveur de calcul Apollo 6500 doté de **4 GPU HGX A100, 80Go**</span>
    - <span style="color: #2a2a2a;">Pour l'**inférence** des modèles : Terminaux de calcul dotés GPU Nvidia **RTX 4090, 24Go**</span>

Prérequis pour l'exécution d'un modèle d'IA :

- Config minimum : L'exécution semble résulter en un mouvement saccadé du robot sur une Quadro P620 (2 GB GDDR5).
- Config recommandée : 4-8 GB GDDR, testé avec RTX 2080 Super de 2019 (8 GB GDDR6)
- Il faut au moins 16 GB de RAM (CPU) sinon elle sature pendant l'enregistrement du dataset d'évaluation.

Prérequis pour l'entraînement d'un modèle d'IA :

- L'entrainement avec 100 épisodes et 100 000 steps a mis 12H sur une RTX 2080 Super de 2019 
    - mais `batch_size=8` alors qu'il faut un minimum de 16, et dans l'idéal 64. Cela résulte sans doute en des mouvements saccadés et une mauvaise généralisation du modèle (variation de la position de la pile).
    - Il n'aboutit pas au bout de plus de 24H sur une Quadro P620 (via WSL2 et Docker)
- Config minimum pour ACT : `batch_size=16`
    - Tesla T4 (gratuit 5H / mois sur Google Colab) on a 15G de RAM qui permet donc un `batch_size=15`
    - [https://github.com/huggingface/lerobot/issues/2213](https://github.com/huggingface/lerobot/issues/2213)
- Config recommandée pour ACT : `batch_size=64`
    - avec A100 (12€ les 100 compute units, 70 = ~5H sur Google Colab) on a 40G de RAM ou 80G de RAM (extra RAM)
    - [https://github.com/huggingface/lerobot/blob/main/docs/source/notebooks.mdx#training-act](https://github.com/huggingface/lerobot/blob/main/docs/source/notebooks.mdx#training-act)
    - [https://colab.research.google.com/github/antonilo/real\_world\_robot\_learning\_sp25/blob/main/\_tutorials/lerobot\_tutorial/lerobot\_tutorial.ipynb#scrollTo=ff7eafe4](https://colab.research.google.com/github/antonilo/real_world_robot_learning_sp25/blob/main/_tutorials/lerobot_tutorial/lerobot_tutorial.ipynb#scrollTo=ff7eafe4)
    - avec un `batch_size=64` la RAM consommée était d'environ 50G, l'entraînement a mis 7H environ pour environ 80 compute units, soit environ 10€
    - [https://huggingface.co/gautz/act\_so101\_pick\_red\_18650\_drop\_black\_box\_test2\_100ep\_64batch\_60ksteps](https://huggingface.co/gautz/act_so101_pick_red_18650_drop_black_box_test2_100ep_64batch_60ksteps)
    - [https://wandb.ai/hentz-robotics/lerobot/runs/niiti0v3?nw=nwusergautz](https://wandb.ai/hentz-robotics/lerobot/runs/niiti0v3?nw=nwusergautz)

#### Installation sous Linux

- [Installer Miniconda pour Linux](https://www.anaconda.com/docs/getting-started/miniconda/install#linux-terminal-installer) : l'environnement de développement Python

```
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
# Vérifier que la clé SHA256 de Miniconda3-latest-Linux-x86_64.sh ici : https://repo.anaconda.com/miniconda/ correspond à :
sha256sum ~/Miniconda3-latest-Linux-x86_64.sh
bash ~/Miniconda3-latest-Linux-x86_64.sh
source ~/.bashrc
```

- Créer et activer l'environnement Conda

```
conda create -y -n lerobot python=3.10
conda activate lerobot
git clone https://github.com/huggingface/lerobot.git ~/lerobot
conda install ffmpeg=7.1.1 -c conda-forge
cd ~/lerobot && pip install -e ".[feetech]"
```

- A chaque ouverture de Terminal l'environnement python conda est activé, voir au bas du `~/.bashrc`
- Pour éviter les conflits, on propose d'avoir un fichier `~/.bashrc_conda` pour conda et un `~/.bashrc_ros` pour ros

Astuces pour activer/désactiver l'environnement conda sans passer par la modification du `~/.bashrc` :

- Ne pas activer conda au démarrage : `conda config --set auto_activate_base false`
- Ne pas configurer le shell pour initialiser conda au démarrage : `conda init --reverse $SHELL`

#### Installation Windows

- Le compte utilisateur doit avoir les droits pour créer des raccourcis (liens symboliques) dans les sous-dossiers de `C:\Users\$USER\lerobot\outputs\train\`
- Ils seront utilisés lors de l'entraînement pour créer un lien entre le dossier `last` et le dossier du dernier Checkpoint par ex. `100000`
    - Le plus sûr est de **travailler avec un compte administrateur**
    - Il faut peut-être aussi les droits dans le dossier `C:\Users\$USER\.cache\huggingface\lerobot\$HUGGINGFACE_USER`
- [Installer Miniconda pour Windows](https://www.anaconda.com/docs/getting-started/miniconda/install#windows-installation) : l'environnement de développement Python
- Ouvrir `Anaconda PowerShell Prompt`
- Créer et activer l'environnement Conda

```
conda create -y -n lerobot python=3.10
conda activate lerobot
git clone https://github.com/huggingface/lerobot.git ~/lerobot
```

- Installer Pytorch pour la version de Cuda installée sur votre système (testé avec une version Cuda 127 installée et la version cu128 de Pytorch) et autres dépendances nécessaires

```bash
cd ~/lerobot
# pip install av poetry-core
conda install ffmpeg=7.1.1 -c conda-forge
pip3 install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
pip install -e ".[feetech]"
```


#### Débuguer l'installation si les scripts basculent sur le `cpu`

S'assurer que Pytorch a été installé, cela installe Cuda :

`pip3 install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128`

Récupérer les infos système :

- `python lerobot/scripts/display_sys_info.py`
- `python -m torch.utils.collect_env`
- `python -c "import torch; print(torch.cuda.is_available())" && nvcc -V`
- cf. [https://github.com/huggingface/lerobot/issues/928](https://github.com/huggingface/lerobot/issues/928) &gt; Here for additional information of my full installation.

#### Créer un compte HuggingFace et se login via un token

- Se créer un compte sur [https://huggingface.co/settings/tokens](https://huggingface.co/settings/tokens)
- Aller dans le menu &gt; Access Tokens
- Récupérer un `TOKEN` avec des droits en écriture
- Ouvrir un Anaconda PowerShell lerobot  
    `(lerobot) PS C:\Users\gauthier.hentz\github\lerobot>`
- Login avec le Token  
    `huggingface-cli.exe login --token TOKEN`

Vous pouvez maintenant uploader et downloaded des DataSets et Modèles vers le Hub HuggingFace pour collaborer avec des experts du Machine Learning.

### Google Colab

Pour avoir accès à un GPU avec suffisamment de mémoire (16G recommandé et 64G dans l'idéal) on peut utiliser Google Colab

- Avec Tesla T4 (gratuit 5H / mois) on a 15G de RAM qui permet donc un `batch_size=15`
- Avec A100 (12€ les 70 crédits) on a 80G de RAM qui permet donc un `batch_size=64`

- Ouvrir le Notebook : [https://colab.research.google.com/github/huggingface/notebooks/blob/main/lerobot/training-act.ipynb#scrollTo=NQUk3Y0WwYZ4](https://colab.research.google.com/github/huggingface/notebooks/blob/main/lerobot/training-act.ipynb#scrollTo=NQUk3Y0WwYZ4)
- Voir aussi [https://colab.research.google.com/github/antonilo/real\_world\_robot\_learning\_sp25/blob/main/\_tutorials/lerobot\_tutorial/lerobot\_tutorial.ipynb#scrollTo=ff7eafe4](https://colab.research.google.com/github/antonilo/real_world_robot_learning_sp25/blob/main/_tutorials/lerobot_tutorial/lerobot_tutorial.ipynb#scrollTo=ff7eafe4)
- Change runtime type

[![image.png](https://innovation.iha.unistra.fr/uploads/images/gallery/2025-10/scaled-1680-/zk0image.png)](https://innovation.iha.unistra.fr/uploads/images/gallery/2025-10/zk0image.png)

- Install conda
- Install LeRobot
- Login avec un jeton d'API Weights &amp; Biases
- Login avec un jeton d'API Hugging Face Hub
- Modifier la commande d'entrainement et l'exécuter :

```bash
!cd lerobot && python src/lerobot/scripts/lerobot_train.py \
  --dataset.repo_id=gautz/so101_pick_red_18650_drop_black_box_test2_100ep \
  --policy.type=act \
  --output_dir=outputs/train/act_so101_pick_red_18650_drop_black_box_test2_100ep_64batch \
  --job_name=act_so101_pick_red_18650_drop_black_box_test2_100ep_64batch \
  --policy.device=cuda \
  --policy.push_to_hub=True \
  --policy.repo_id=gautz/act_so101_pick_red_18650_drop_black_box_test2_100ep_64batch \
  --batch_size=64 \
  --wandb.enable=true
```

- Surveiller l'éxecution depuis le runtime ou WanDB
- Ouvrir un Terminal et lancer la commande pour uploader le dernier Checkpoint du modèle :

<div id="bkmrk-huggingface-cli-uplo" style="color: #000000; background-color: #ffffff; font-family: monospace, 'Droid Sans Mono', 'monospace', monospace; font-weight: normal; font-size: 14px; line-height: 19px; white-space: pre;"><div>`<span style="color: #000000;">huggingface-cli upload ${HF_USER}/act_so101_pick_red_18650_drop_black_box_test2_100ep_64batch \</span>`</div><div>`<span style="color: #000000;"> /content/lerobot/outputs/train/act_so101_pick_red_18650_drop_black_box_test2_100ep_64batch/checkpoints/last/pretrained_model</span>`</div></div>Astuces et Erreurs :

- Si vous utilisez Colab avec un compte gratuit, il faut utiliser l'extension Colab Auto Reconnect pour ne pas être déconnecté au boût de 1H. Il est probable que le runtime soit déconnecté par manque de crédit gratuit avant d'arriver à un checkpoint. Faire des CheckPoint plus souvent, ou passer à un compte payant.
- Si vous utilisez un compte payant, vous ne serez pas déconnecté mais il faut surveiller pour déconnecter le Runtime à la fin de l'entraînement (ou d'un Checkpoint)
- [https://github.com/huggingface/lerobot/issues/1532](https://github.com/huggingface/lerobot/issues/1532)

```
   18  cd /content/
   20  cd lerobot/
   24  python
   25              from huggingface_hub import HfApi
   26              hub_api = HfApi()
   27              hub_api.create_tag("gautz/so101_pick_red_18650_drop_black_box_test2_100ep", tag="v2.1", repo_type="dataset"
   30  cd src/
   32  cd lerobot
   34  python -m lerobot.datasets.v30.convert_dataset_v21_to_v30 --repo-id=gautz/so101_pick_red_18650_drop_black_box_test2_100ep
```

- [https://stackoverflow.com/questions/78448832/colab-how-to-increase-the-num-workers-in-dataloader](https://stackoverflow.com/questions/78448832/colab-how-to-increase-the-num-workers-in-dataloader)

Voir le rapport : [https://api.wandb.ai/links/hentz-robotics/wdsr4k2r](https://api.wandb.ai/links/hentz-robotics/wdsr4k2r) <span aria-hidden="true" style="border-block: unset; border-inline: unset; border-start-start-radius: unset; border-start-end-radius: unset; border-end-start-radius: unset; border-end-end-radius: unset; overflow-block: unset; overflow-inline: unset; overscroll-behavior-block: unset; overscroll-behavior-inline: unset; margin-block: unset; margin-inline: unset; scroll-margin-block: unset; scroll-margin-inline: unset; padding-block: unset; padding-inline: unset; scroll-padding-block: unset; scroll-padding-inline: unset; inset-block: unset; inset-inline: unset; block-size: unset; min-block-size: unset; max-block-size: unset; inline-size: unset; min-inline-size: unset; max-inline-size: unset; contain-intrinsic-block-size: unset; contain-intrinsic-inline-size: unset; background: unset; background-blend-mode: unset; border: unset; border-radius: unset; box-decoration-break: unset; -moz-float-edge: unset; display: unset; position: fixed; float: unset; clear: unset; vertical-align: unset; baseline-source: unset; overflow: unset; overflow-anchor: unset; transform: unset; rotate: unset; scale: unset; translate: unset; offset: unset; scroll-behavior: unset; scroll-snap-align: unset; scroll-snap-type: unset; scroll-snap-stop: unset; overscroll-behavior: unset; isolation: unset; break-after: unset; break-before: unset; break-inside: unset; resize: unset; perspective: unset; perspective-origin: unset; backface-visibility: unset; transform-box: unset; transform-style: unset; transform-origin: unset; contain: unset; content-visibility: unset; container: unset; appearance: unset; -moz-orient: unset; will-change: unset; shape-image-threshold: unset; shape-margin: unset; shape-outside: unset; touch-action: unset; -webkit-line-clamp: unset; scrollbar-gutter: unset; zoom: unset; columns: unset; column-fill: unset; column-rule: unset; column-span: unset; content: unset; counter-increment: unset; counter-reset: unset; counter-set: unset; opacity: unset; box-shadow: unset; clip: rect(0px, 0px, 0px, 0px); filter: unset; backdrop-filter: unset; mix-blend-mode: unset; font: unset; font-synthesis: unset; font-palette: unset; math-depth: unset; math-style: unset; visibility: unset; writing-mode: unset; text-orientation: unset; print-color-adjust: unset; image-rendering: unset; image-orientation: unset; dominant-baseline: unset; text-anchor: unset; color-interpolation: unset; color-interpolation-filters: unset; fill: unset; fill-opacity: unset; fill-rule: unset; shape-rendering: unset; stroke: unset; stroke-width: unset; stroke-linecap: unset; stroke-linejoin: unset; stroke-miterlimit: unset; stroke-opacity: unset; stroke-dasharray: unset; stroke-dashoffset: unset; clip-rule: unset; marker: unset; paint-order: unset; border-collapse: unset; empty-cells: unset; caption-side: unset; border-spacing: unset; color: unset; text-transform: unset; hyphens: unset; -moz-text-size-adjust: unset; text-indent: unset; overflow-wrap: unset; word-break: unset; text-justify: unset; text-align-last: unset; text-align: unset; letter-spacing: unset; word-spacing: unset; white-space: pre; text-shadow: unset; text-emphasis: unset; text-emphasis-position: unset; tab-size: unset; line-break: unset; -webkit-text-fill-color: unset; -webkit-text-stroke: unset; ruby-align: unset; ruby-position: unset; text-combine-upright: unset; text-rendering: unset; text-underline-offset: unset; text-underline-position: unset; text-decoration-skip-ink: unset; hyphenate-character: unset; forced-color-adjust: unset; -webkit-text-security: unset; hyphenate-limit-chars: unset; text-wrap-style: unset; cursor: unset; pointer-events: unset; caret-color: unset; accent-color: unset; color-scheme: unset; scrollbar-color: unset; list-style: unset; quotes: unset; margin: unset; overflow-clip-margin: unset; scroll-margin: unset; outline: unset; outline-offset: unset; padding: unset; scroll-padding: unset; page: unset; top: 0px; right: unset; bottom: unset; left: unset; z-index: unset; flex-flow: unset; place-content: unset; place-items: unset; flex: unset; place-self: unset; order: unset; height: unset; min-height: unset; max-height: unset; width: unset; min-width: unset; max-width: unset; box-sizing: unset; object-fit: unset; object-position: unset; grid-area: unset; grid: unset; gap: unset; aspect-ratio: unset; contain-intrinsic-size: unset; vector-effect: unset; stop-color: unset; stop-opacity: unset; flood-color: unset; flood-opacity: unset; lighting-color: unset; mask-type: unset; clip-path: unset; mask: unset; x: unset; y: unset; cx: unset; cy: unset; rx: unset; ry: unset; r: unset; d: unset; table-layout: unset; text-overflow: unset; text-decoration: unset; ime-mode: unset; scrollbar-width: unset; user-select: text; -moz-force-broken-image-icon: unset; transition: unset; animation: unset; animation-composition: unset; -moz-box-align: unset; -moz-box-direction: unset; -moz-box-flex: unset; -moz-box-orient: unset; -moz-box-pack: unset; -moz-box-ordinal-group: unset;">https://api.wandb.ai/links/hentz-robotics/wdsr4k2r</span><span aria-hidden="true" style="border-block: unset; border-inline: unset; border-start-start-radius: unset; border-start-end-radius: unset; border-end-start-radius: unset; border-end-end-radius: unset; overflow-block: unset; overflow-inline: unset; overscroll-behavior-block: unset; overscroll-behavior-inline: unset; margin-block: unset; margin-inline: unset; scroll-margin-block: unset; scroll-margin-inline: unset; padding-block: unset; padding-inline: unset; scroll-padding-block: unset; scroll-padding-inline: unset; inset-block: unset; inset-inline: unset; block-size: unset; min-block-size: unset; max-block-size: unset; inline-size: unset; min-inline-size: unset; max-inline-size: unset; contain-intrinsic-block-size: unset; contain-intrinsic-inline-size: unset; background: unset; background-blend-mode: unset; border: unset; border-radius: unset; box-decoration-break: unset; -moz-float-edge: unset; display: unset; position: fixed; float: unset; clear: unset; vertical-align: unset; baseline-source: unset; overflow: unset; overflow-anchor: unset; transform: unset; rotate: unset; scale: unset; translate: unset; offset: unset; scroll-behavior: unset; scroll-snap-align: unset; scroll-snap-type: unset; scroll-snap-stop: unset; overscroll-behavior: unset; isolation: unset; break-after: unset; break-before: unset; break-inside: unset; resize: unset; perspective: unset; perspective-origin: unset; backface-visibility: unset; transform-box: unset; transform-style: unset; transform-origin: unset; contain: unset; content-visibility: unset; container: unset; appearance: unset; -moz-orient: unset; will-change: unset; shape-image-threshold: unset; shape-margin: unset; shape-outside: unset; touch-action: unset; -webkit-line-clamp: unset; scrollbar-gutter: unset; zoom: unset; columns: unset; column-fill: unset; column-rule: unset; column-span: unset; content: unset; counter-increment: unset; counter-reset: unset; counter-set: unset; opacity: unset; box-shadow: unset; clip: rect(0px, 0px, 0px, 0px); filter: unset; backdrop-filter: unset; mix-blend-mode: unset; font: unset; font-synthesis: unset; font-palette: unset; math-depth: unset; math-style: unset; visibility: unset; writing-mode: unset; text-orientation: unset; print-color-adjust: unset; image-rendering: unset; image-orientation: unset; dominant-baseline: unset; text-anchor: unset; color-interpolation: unset; color-interpolation-filters: unset; fill: unset; fill-opacity: unset; fill-rule: unset; shape-rendering: unset; stroke: unset; stroke-width: unset; stroke-linecap: unset; stroke-linejoin: unset; stroke-miterlimit: unset; stroke-opacity: unset; stroke-dasharray: unset; stroke-dashoffset: unset; clip-rule: unset; marker: unset; paint-order: unset; border-collapse: unset; empty-cells: unset; caption-side: unset; border-spacing: unset; color: unset; text-transform: unset; hyphens: unset; -moz-text-size-adjust: unset; text-indent: unset; overflow-wrap: unset; word-break: unset; text-justify: unset; text-align-last: unset; text-align: unset; letter-spacing: unset; word-spacing: unset; white-space: pre; text-shadow: unset; text-emphasis: unset; text-emphasis-position: unset; tab-size: unset; line-break: unset; -webkit-text-fill-color: unset; -webkit-text-stroke: unset; ruby-align: unset; ruby-position: unset; text-combine-upright: unset; text-rendering: unset; text-underline-offset: unset; text-underline-position: unset; text-decoration-skip-ink: unset; hyphenate-character: unset; forced-color-adjust: unset; -webkit-text-security: unset; hyphenate-limit-chars: unset; text-wrap-style: unset; cursor: unset; pointer-events: unset; caret-color: unset; accent-color: unset; color-scheme: unset; scrollbar-color: unset; list-style: unset; quotes: unset; margin: unset; overflow-clip-margin: unset; scroll-margin: unset; outline: unset; outline-offset: unset; padding: unset; scroll-padding: unset; page: unset; top: 0px; right: unset; bottom: unset; left: unset; z-index: unset; flex-flow: unset; place-content: unset; place-items: unset; flex: unset; place-self: unset; order: unset; height: unset; min-height: unset; max-height: unset; width: unset; min-width: unset; max-width: unset; box-sizing: unset; object-fit: unset; object-position: unset; grid-area: unset; grid: unset; gap: unset; aspect-ratio: unset; contain-intrinsic-size: unset; vector-effect: unset; stop-color: unset; stop-opacity: unset; flood-color: unset; flood-opacity: unset; lighting-color: unset; mask-type: unset; clip-path: unset; mask: unset; x: unset; y: unset; cx: unset; cy: unset; rx: unset; ry: unset; r: unset; d: unset; table-layout: unset; text-overflow: unset; text-decoration: unset; ime-mode: unset; scrollbar-width: unset; user-select: text; -moz-force-broken-image-icon: unset; transition: unset; animation: unset; animation-composition: unset; -moz-box-align: unset; -moz-box-direction: unset; -moz-box-flex: unset; -moz-box-orient: unset; -moz-box-pack: unset; -moz-box-ordinal-group: unset;">https://api.wandb.ai/links/hentz-robotics/wdsr4k2r</span><span aria-hidden="true" style="border-block: unset; border-inline: unset; border-start-start-radius: unset; border-start-end-radius: unset; border-end-start-radius: unset; border-end-end-radius: unset; overflow-block: unset; overflow-inline: unset; overscroll-behavior-block: unset; overscroll-behavior-inline: unset; margin-block: unset; margin-inline: unset; scroll-margin-block: unset; scroll-margin-inline: unset; padding-block: unset; padding-inline: unset; scroll-padding-block: unset; scroll-padding-inline: unset; inset-block: unset; inset-inline: unset; block-size: unset; min-block-size: unset; max-block-size: unset; inline-size: unset; min-inline-size: unset; max-inline-size: unset; contain-intrinsic-block-size: unset; contain-intrinsic-inline-size: unset; background: unset; background-blend-mode: unset; border: unset; border-radius: unset; box-decoration-break: unset; -moz-float-edge: unset; display: unset; position: fixed; float: unset; clear: unset; vertical-align: unset; baseline-source: unset; overflow: unset; overflow-anchor: unset; transform: unset; rotate: unset; scale: unset; translate: unset; offset: unset; scroll-behavior: unset; scroll-snap-align: unset; scroll-snap-type: unset; scroll-snap-stop: unset; overscroll-behavior: unset; isolation: unset; break-after: unset; break-before: unset; break-inside: unset; resize: unset; perspective: unset; perspective-origin: unset; backface-visibility: unset; transform-box: unset; transform-style: unset; transform-origin: unset; contain: unset; content-visibility: unset; container: unset; appearance: unset; -moz-orient: unset; will-change: unset; shape-image-threshold: unset; shape-margin: unset; shape-outside: unset; touch-action: unset; -webkit-line-clamp: unset; scrollbar-gutter: unset; zoom: unset; columns: unset; column-fill: unset; column-rule: unset; column-span: unset; content: unset; counter-increment: unset; counter-reset: unset; counter-set: unset; opacity: unset; box-shadow: unset; clip: rect(0px, 0px, 0px, 0px); filter: unset; backdrop-filter: unset; mix-blend-mode: unset; font: unset; font-synthesis: unset; font-palette: unset; math-depth: unset; math-style: unset; visibility: unset; writing-mode: unset; text-orientation: unset; print-color-adjust: unset; image-rendering: unset; image-orientation: unset; dominant-baseline: unset; text-anchor: unset; color-interpolation: unset; color-interpolation-filters: unset; fill: unset; fill-opacity: unset; fill-rule: unset; shape-rendering: unset; stroke: unset; stroke-width: unset; stroke-linecap: unset; stroke-linejoin: unset; stroke-miterlimit: unset; stroke-opacity: unset; stroke-dasharray: unset; stroke-dashoffset: unset; clip-rule: unset; marker: unset; paint-order: unset; border-collapse: unset; empty-cells: unset; caption-side: unset; border-spacing: unset; color: unset; text-transform: unset; hyphens: unset; -moz-text-size-adjust: unset; text-indent: unset; overflow-wrap: unset; word-break: unset; text-justify: unset; text-align-last: unset; text-align: unset; letter-spacing: unset; word-spacing: unset; white-space: pre; text-shadow: unset; text-emphasis: unset; text-emphasis-position: unset; tab-size: unset; line-break: unset; -webkit-text-fill-color: unset; -webkit-text-stroke: unset; ruby-align: unset; ruby-position: unset; text-combine-upright: unset; text-rendering: unset; text-underline-offset: unset; text-underline-position: unset; text-decoration-skip-ink: unset; hyphenate-character: unset; forced-color-adjust: unset; -webkit-text-security: unset; hyphenate-limit-chars: unset; text-wrap-style: unset; cursor: unset; pointer-events: unset; caret-color: unset; accent-color: unset; color-scheme: unset; scrollbar-color: unset; list-style: unset; quotes: unset; margin: unset; overflow-clip-margin: unset; scroll-margin: unset; outline: unset; outline-offset: unset; padding: unset; scroll-padding: unset; page: unset; top: 0px; right: unset; bottom: unset; left: unset; z-index: unset; flex-flow: unset; place-content: unset; place-items: unset; flex: unset; place-self: unset; order: unset; height: unset; min-height: unset; max-height: unset; width: unset; min-width: unset; max-width: unset; box-sizing: unset; object-fit: unset; object-position: unset; grid-area: unset; grid: unset; gap: unset; aspect-ratio: unset; contain-intrinsic-size: unset; vector-effect: unset; stop-color: unset; stop-opacity: unset; flood-color: unset; flood-opacity: unset; lighting-color: unset; mask-type: unset; clip-path: unset; mask: unset; x: unset; y: unset; cx: unset; cy: unset; rx: unset; ry: unset; r: unset; d: unset; table-layout: unset; text-overflow: unset; text-decoration: unset; ime-mode: unset; scrollbar-width: unset; user-select: text; -moz-force-broken-image-icon: unset; transition: unset; animation: unset; animation-composition: unset; -moz-box-align: unset; -moz-box-direction: unset; -moz-box-flex: unset; -moz-box-orient: unset; -moz-box-pack: unset; -moz-box-ordinal-group: unset;">https://api.wandb.ai/links/hentz-robotics/wdsr4k2r</span>

### Utilisation de LeRobot avec le bash Linux

- Activer l'environnement conda lerobot  
    `cd ~/lerobot`  
    `conda activate lerobot`

`lerobot-find-port`

A chaque connexion du robot : `sudo chmod 666 /dev/ttyACM1`

`lerobot-find-cameras opencv`

`lerobot-calibrate     --robot.type=so101_follower     --robot.port=/dev/ttyACM0     --robot.id=follower_arm_fan1`

`lerobot-calibrate     --teleop.type=so101_leader     --teleop.port=/dev/ttyACM1     --teleop.id=leader_arm_fan1`

`lerobot-teleoperate     --robot.type=so101_follower     --robot.port=/dev/ttyACM0     --robot.id=follower_arm_fan1     --teleop.type=so101_leader     --teleop.port=/dev/ttyACM1     --teleop.id=leader_arm_fan1`

`lerobot-dataset-viz     --repo-id gautz/so101_pick_red_18650_drop_black_box_test2_100ep     --episode-index 0`

`lerobot-record   --robot.type=so101_follower   --robot.port=/dev/ttyACM0   --robot.id=follower_arm_fan1   --robot.cameras="{ top: {type: opencv, index_or_path: 4, width: 800, height: 600, fps: 20},follower: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 20}}"   --display_data=true   --dataset.push_to_hub=False   --dataset.repo_id=gautz/eval_act_so101_pick_red_18650_drop_black_box_test2_100ep_64batch_60ksteps   --dataset.num_episodes=10   --dataset.single_task="Pick red 18650 battery place black box"   --policy.path=gautz/act_so101_pick_red_18650_drop_black_box_test2_100ep_64batch_60ksteps`

`--resume=true`

`lerobot-train   --dataset.repo_id=gautz/so101_pick_red_18650_drop_black_box_test2_100ep   --policy.type=act   --output_dir=outputs/train/act_so101_pick_red_18650_drop_black_box_test2_100ep_m620   --job_name=act_so101_pick_red_18650_drop_black_box_test2_100ep_m620   --policy.device=cuda   --wandb.enable=false   --policy.repo_id=gautz/act_so101_pick_red_18650_drop_black_box_test2_100ep_m620 --batch_size=2`

nano lerobot/common/robot\_devices/robots/configs.py

python lerobot/scripts/control\_robot.py --robot.type=so101 --robot.cameras='{}' --control.type=teleoperate

`lerobot-record     --robot.type=so101_follower     --robot.port=/dev/ttyACM0     --robot.id=follower_arm_fan1 --robot.cameras="{ top: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 20},follower: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 20}}"   --dataset.push_to_hub=False   --dataset.repo_id=gautz/eval_act_so101_pick_battery_place_ifixit_test1_50ep_rtx507016_chkpt100kter --dataset.num_episodes=10   --dataset.single_task="Eval Pick battery place ifixit" --policy.path=outputs/train/act_so101_pick_battery_place_ifixit_test1_50ep_rtx507016/checkpoints/100000/pretrained_model --display_data=false`

#### Server inference

`pip install 'lerobot[feetech,async]'`

`python -m lerobot.async_inference.robot_client     --server_address=127.0.0.1:8080     --robot.type=so101_follower     --robot.port=/dev/ttyACM0     --robot.id=follower_arm_fan1     --robot.cameras="{ top: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 20},follower: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 20}}"     --task="Eval Pick battery place ifixit"     --policy_type=act     --pretrained_name_or_path=gautz/act_so101_pick_battery_place_ifixit_test1_50ep_rtx507016_chkpt100000     --policy_device=cuda     --actions_per_chunk=50     --chunk_size_threshold=0.5     --aggregate_fn_name=weighted_average     --debug_visualize_queue_size=True`

#### Calibration robot et configuration caméras

`python -m lerobot.calibrate     --teleop.type=so101_leader  --teleop.port=/dev/ttyACM0 --teleop.id=leader_arm_fan1`

`python -m lerobot.calibrate     --robot.type=so101_follower     --robot.port=/dev/ttyUSB0 --robot.id=follower_arm_fan1`

#### Téléopération

```
python -m lerobot.teleoperate \
    --robot.type=so101_follower \
    --robot.port=/dev/ttyUSB0 \
    --robot.id=follower_arm_fan1 \
    --robot.cameras="{ top: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30},follower: {type: opencv, index_or_path: 4, width: 640, height: 480, fps: 30}}" \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM0 \
    --teleop.id=leader_arm_fan1 \
    --display_data=true
```

Rejouer dataset en local :

```
python -m lerobot.replay \
    --robot.type=so101_follower \
    --robot.port=/dev/ttyUSB0 \
    --robot.id=follower_arm_fan1 \
    --dataset.repo_id=gautz/18650-test1-10ep \
    --dataset.episode=0 # choose the episode you want to replay
```

#### Machine Learning

Enregistrer dataset en local :

```bash
python -m lerobot.record \
    --robot.type=so101_follower \
    --robot.port=/dev/ttyUSB0 \
    --robot.id=follower_arm_fan1 \
    --robot.cameras="{ top: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30},follower: {type: opencv, index_or_path: 4, width: 640, height: 480, fps: 30}}" \
    --teleop.type=so101_leader \
    --teleop.port=/dev/ttyACM0 \
    --teleop.id=leader_arm_fan1 \
    --display_data=true \
    --dataset.repo_id=gautz/18650-test1-10ep \
    --dataset.episode_time_s=10 \
    --dataset.reset_time_s=10 \
    --dataset.num_episodes=10 \
    --dataset.single_task="Pick red 18650 battery place black box" \
    --dataset.push_to_hub=False
```

Entrainer en local avec le CPU

```bash
python lerobot/scripts/train.py \
  --dataset.repo_id=gautz/18650-test1-10ep \
  --policy.type=act \
  --output_dir=outputs/train/act_so101_18650-test1-10ep \
  --job_name=act_so101_18650-test1-10ep \
  --policy.device=cpu # \
  --wandb.enable=false # true
```

Entrainer en local avec le GPU NVidia

```bash
python lerobot/scripts/train.py \
  --dataset.repo_id=gautz/18650-test1-10ep \
  --policy.type=act \
  --output_dir=outputs/train/act_so101_18650-test1-10ep \
  --job_name=act_so101_18650-test1-10ep \
  --policy.device=cuda \
  --wandb.enable=false
```

Enregistrer un dataset d'évaluation d'un modèle à un checkpoint donné :

```
python -m lerobot.record  \
--robot.type=so101_follower \
--robot.port=/dev/ttyUSB0 \
--robot.cameras="{ top: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 4, width: 800, height: 600, fps: 30}}" \
--robot.id=follower_arm_fan1 \
--display_data=false \
--dataset.repo_id=gautz/eval_act_18650-test2-100ep \
--dataset.single_task="Pick red 18650 battery place black box" \
--policy.path=outputs/train/act_so101_18650-test2-100ep/checkpoints/last/pretrained_model \
--dataset.push_to_hub=False
```

### Utilisation de LeRobot avec Anaconda Powershell Prompt

#### Calibration des robots

`python -m lerobot.setup_motors --robot.type=so101_follower --robot.port=COM13`  
`python -m lerobot.setup_motors --robot.type=so101_leader --robot.port=COM14`



#### Machine Learning

Collecte de données :

Uploader les données vers le Hub HuggingFace :

[https://huggingface.co/docs/lerobot/en/il\_robots#dataset-upload](https://huggingface.co/docs/lerobot/en/il_robots#dataset-upload)

`huggingface-cli.exe upload gautz/so101_pick_red_18650_drop_black_box_test2_100ep ..\.cache\huggingface\lerobot\gautz\18650-test2-100ep\ --repo-type dataset`

Entrainer un modèle sur un Dataset (sur `IHA-QLIOVR-1`, compte admin) :

```powershell
cd ..\gauthier.hentz\lerobot\
conda activate lerobot
cd .\lerobot\
conda create -y -n lerobot python=3.10
conda activate lerobot
conda install ffmpeg -c conda-forge
ffmpeg -encoders
conda install ffmpeg=7.1.1 -c conda-forge
pip install av poetry-core 
pip3 install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
pip install -e .
python lerobot/scripts/train.py --dataset.repo_id=gautz/18650-test2-100ep --policy.type=act --output_dir=outputs/train/act_so101_18650-test2-100ep --job_name=act_so101_18650-test2-100ep --policy.device=cuda --wandb.enable=false

```

Enregistrer un dataset d'évaluation d'un modèle à un checkpoint donné :

`python -m lerobot.record  --robot.type=so101_follower --robot.port=/dev/ttyUSB0 --robot.cameras="{ top: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 4, width: 800, height: 600, fps: 30}}" --robot.id=follower_arm_fan1 --display_data=false --dataset.repo_id=gautz/eval_act_18650-test2-100ep --dataset.single_task="Pick red 18650 battery place black box" --policy.path=outputs/train/act_so101_18650-test2-100ep/checkpoints/last/pretrained_model --dataset.push_to_hub=False`

#### Uploader un modèle vers HuggingFace

[https://github.com/huggingface/lerobot/?tab=readme-ov-file#add-a-pretrained-policy](https://github.com/huggingface/lerobot/?tab=readme-ov-file#add-a-pretrained-policy)

- Rechercher le dossier du Checkpoint voulu, par ex.  
    `C:\Users\User\github\lerobot\outputs\train\act_so101_18650-test2-100ep\checkpoints\100000`
- Définir le User HuggingFace (qui doit être Login via un Token) `gautz` et le Repo `act_so101_pick_red_18650_drop_black_box_test2_100ep_100000` , puis uploader le Checkpoint :  
    `huggingface-cli.exe upload gautz/act_so101_pick_red_18650_drop_black_box_test2_100ep_100000 .\outputs\train\act_so101_18650-test2-100ep\checkpoints\100000`

#### Historique du Terminal complet

```powershell
wget "https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe" -outfile ".\Downloads\Miniconda3-latest-Windows-x86_64.exe"
cd .\github\lerobot\
conda create -y -n lerobot python=3.10
conda activate lerobot
conda install ffmpeg -c conda-forge
conda install ffmpeg=7.1.1 -c conda-forge
wsl --shutdown
pip install -e .
pip install -e ".[feetech]" # or "[dynamixel]" for example
python lerobot/find_port.py
python lerobot/find_cameras.py opencv 
python -m lerobot.setup_motors --robot.type=so101_follower --robot.port=COM13`
python -m lerobot.record  --robot.type=so101_follower --robot.port=COM13 --robot.cameras="{ top: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 4, width: 800, height: 600, fps: 30}}" --robot.id=follower_arm_fan1 --display_data=false --dataset.repo_id=gautz/eval_act_18650-test2-100ep --dataset.single_task="Pick red 18650 battery place black box" --policy.path=outputs/train/act_so101_18650-test2-100ep/checkpoints/last/pretrained_model --dataset.push_to_hub=False
python -m lerobot.calibrate     --teleop.type=so101_leader  --teleop.port=COM14 --teleop.id=leader_arm_fan1`
python -m lerobot.calibrate     --robot.type=so101_follower  --robot.port=COM13 --robot.id=follower_arm_fan1
python -m lerobot.teleoperate   --robot.type=so101_follower   --robot.port=COM13   --robot.id=follower_arm_fan1   --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 640, height: 480, fps: 30},follower: {type: opencv, index_or_path: 2, width: 640, height: 480, fps: 30}}"   --teleop.type=so101_leader   --teleop.port=COM14   --teleop.id=leader_arm_fan1   --display_data=true
python lerobot/find_cameras.py opencv 
python -m lerobot.teleoperate   --robot.type=so101_follower   --robot.port=COM13   --robot.id=follower_arm_fan1   --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 30}}"   --teleop.type=so101_leader   --teleop.port=COM14   --teleop.id=leader_arm_fan1   --display_data=true
pip install -e .
python lerobot/find_cameras.py opencv 
python -m lerobot.teleoperate   --robot.type=so101_follower   --robot.port=COM13   --robot.id=follower_arm_fan1   --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30}}"   --teleop.type=so101_leader   --teleop.port=COM14   --teleop.id=leader_arm_fan1   --display_data=true
python -m lerobot.record  --robot.type=so101_follower --robot.port=COM13 --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30}}" --robot.id=follower_arm_fan1 --display_data=false --dataset.repo_id=gautz/eval_act_18650-test2-100ep --dataset.single_task="Pick red 18650 battery place black box" --policy.path=outputs/train/act_so101_18650-test2-100ep/checkpoints/last/pretrained_model --dataset.push_to_hub=False
python lerobot/scripts/display_sys_info.py
python -m torch.utils.collect_env
python -c "import torch; print(torch.cuda.is_available())" && nvcc -V
python -c "import torch; print(torch.cuda.is_available())"
pip3 install --pre torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu128
python -m lerobot.record  --robot.type=so101_follower --robot.port=COM13 --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30}}" --robot.id=follower_arm_fan1 --display_data=false --dataset.repo_id=gautz/eval_act_18650-test2-100ep --dataset.single_task="Pick red 18650 battery place black box" --policy.path=outputs/train/act_so101_18650-test2-100ep/checkpoints/last/pretrained_model --dataset.push_to_hub=False --wandb.enable=false
python -m lerobot.record  --robot.type=so101_follower --robot.port=COM13 --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30}}" --robot.id=follower_arm_fan1 --display_data=false --dataset.repo_id=gautz/eval_act_18650-test2-100ep --dataset.single_task="Pick red 18650 battery place black box" --policy.path=outputs/train/act_so101_18650-test2-100ep/checkpoints/last/pretrained_model --dataset.push_to_hub=False     --dataset.episode_time_s=10  --dataset.reset_time_s=10    --dataset.num_episodes=10
exit
cd .\github\lerobot\
conda activate lerobot
python -m lerobot.record  --robot.type=so101_follower --robot.port=COM13 --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30}}" --robot.id=follower_arm_fan1 --display_data=false --dataset.repo_id=gautz/eval_act_18650-test2-100ep --dataset.single_task="Pick red 18650 battery place black box" --policy.path=outputs/train/act_so101_18650-test2-100ep/checkpoints/last/pretrained_model --dataset.push_to_hub=False     --dataset.episode_time_s=15  --dataset.reset_time_s=10    --dataset.num_episodes=10
python -m lerobot.teleoperate   --robot.type=so101_follower   --robot.port=COM13   --robot.id=follower_arm_fan1   --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30}}"   --teleop.type=so101_leader   --teleop.port=COM14   --teleop.id=leader_arm_fan1   --display_data=true
exit
cd .\github\lerobot\
conda activate lerobot
python -m lerobot.teleoperate   --robot.type=so101_follower   --robot.port=COM13   --robot.id=follower_arm_fan1   --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30}}"   --teleop.type=so101_leader   --teleop.port=COM14   --teleop.id=leader_arm_fan1   --display_data=true
python lerobot/find_port.py
python -m lerobot.teleoperate   --robot.type=so101_follower   --robot.port=COM15   --robot.id=follower_arm_fan1   --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30}}"   --teleop.type=so101_leader   --teleop.port=COM14   --teleop.id=leader_arm_fan1   --display_data=true
python lerobot/find_cameras.py opencv 
python -m lerobot.teleoperate   --robot.type=so101_follower   --robot.port=COM15   --robot.id=follower_arm_fan1   --robot.cameras="{ top: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 30}}"   --teleop.type=so101_leader   --teleop.port=COM14   --teleop.id=leader_arm_fan1   --display_data=true
python -m lerobot.record  --robot.type=so101_follower --robot.port=COM15 --robot.cameras="{ top: {type: opencv, index_or_path: 1, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30}}" --robot.id=follower_arm_fan1 --display_data=false --dataset.repo_id=gautz/eval_act_18650-test2-100ep --dataset.single_task="Pick red 18650 battery place black box" --policy.path=outputs/train/act_so101_18650-test2-100ep/checkpoints/last/pretrained_model --dataset.push_to_hub=False     --dataset.episode_time_s=15  --dataset.reset_time_s=10    --dataset.num_episodes=10
python -m lerobot.record  --robot.type=so101_follower --robot.port=COM15 --robot.cameras="{ top: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 30}}" --robot.id=follower_arm_fan1 --display_data=false --dataset.repo_id=gautz/eval_act_18650-test2-100ep --dataset.single_task="Pick red 18650 battery place black box" --policy.path=outputs/train/act_so101_18650-test2-100ep/checkpoints/last/pretrained_model --dataset.push_to_hub=False     --dataset.episode_time_s=15  --dataset.reset_time_s=10    --dataset.num_episodes=10
python -m lerobot.teleoperate   --robot.type=so101_follower   --robot.port=COM15   --robot.id=follower_arm_fan1   --robot.cameras="{ top: {type: opencv, index_or_path: 0, width: 800, height: 600, fps: 30},follower: {type: opencv, index_or_path: 2, width: 800, height: 600, fps: 30}}"   --teleop.type=so101_leader   --teleop.port=COM14   --teleop.id=leader_arm_fan1   --display_data=true
cd .\github\lerobot\
cd ..
cd .\.cache\
cd .\huggingface\ls
cd .\huggingface\lerobot\calibration\cd ..
cd .\huggingface\lerobot\
cd .\gautz\
cd ..
cd .\github\lerobot\
cd .\outputs\train\
cd .\act_so101_18650-test2-100ep\
cd .\checkpoints\
```

### Migration dataset v2.1 to v3

[https://github.com/huggingface/lerobot/blob/main/docs/source/lerobot-dataset-v3.mdx#migrate-v21--v30](https://github.com/huggingface/lerobot/blob/main/docs/source/lerobot-dataset-v3.mdx#migrate-v21--v30)

### Sources

[https://wiki.seeedstudio.com/lerobot\_so100m/](https://wiki.seeedstudio.com/lerobot_so100m/)

[https://huggingface.co/spaces/lerobot/visualize\_dataset?path=%2Fsebastiandavidlee%2Fbimanual-so101-handover-plushie%2Fepisode\_40](https://huggingface.co/spaces/lerobot/visualize_dataset?path=%2Fsebastiandavidlee%2Fbimanual-so101-handover-plushie%2Fepisode_40)

[https://huggingface.co/blog/sherryxychen/train-act-on-so-101](https://huggingface.co/blog/sherryxychen/train-act-on-so-101)

[https://github.com/sherrychen1120/so101\_bench](https://github.com/sherrychen1120/so101_bench)

[https://www.linkedin.com/posts/sherryxychen\_robotics-machinelearning-ai-ugcPost-7378831270207954944-WsI5?utm\_source=share&amp;utm\_medium=member\_desktop&amp;rcm=ACoAAA1icaQBkYXRoM1Oslzrh8psuL0MmHpaT\_4](https://www.linkedin.com/posts/sherryxychen_robotics-machinelearning-ai-ugcPost-7378831270207954944-WsI5?utm_source=share&utm_medium=member_desktop&rcm=ACoAAA1icaQBkYXRoM1Oslzrh8psuL0MmHpaT_4)