LeRobot documentation

Simulation : locale ou servie

You are viewing main version, which requires installation from source. If you'd like regular pip install, checkout the latest stable version (v0.7.0).
Hugging Face's logo
Join the Hugging Face community

and get access to the augmented documentation experience

to get started

Simulation : locale ou servie

Un environnement simulé peut être piloté de deux manières :

  • en tant qu'env batché (--env.*) : de nombreux environnements pour une même tâche, exécutés ensemble à chaque appel de step(). lerobot-eval et l'évaluation pendant l'entraînement l'utilisent.
  • en tant que robot simulé (--robot.type=sim) : un environnement derrière l'interface Robot, interchangeable avec du matériel réel. lerobot-rollout, lerobot-record, lerobot-teleoperate et lerobot-replay l'utilisent.

Elle s’exécute soit localement, via l’API d’environnement, soit en mode serveur via lerobot-env-server, généralement dans son propre conteneur Docker, afin que les dépendances du simulateur ne se croisent jamais avec celles de la politique. La définition d’un endpoint sélectionne l’exécution en mode serveur ; les deux chemins d’exposition offrent les mêmes observations canoniques (images HWC uint8, état float32 aplati), les mêmes fins d’épisode et les mêmes conventions de contrôle.

Le code maintient trois couches distinctes :

  • un env (lerobot.envs, --env.type) est ce qu'une commande LeRobot exécute, configuré par un EnvConfig. Tous les env ne sont pas des simulateurs : gym_manipulator pilote un robot réel.
  • Un sim (lerobot.sim) est le simulateur derrière un environnement simulé : un SimConfig qui nomme son intégration, exécuté par LocalVectorEnv, sans torch.
  • le serveur d’environnement (lerobot.env_server) sert une simulation ; RemoteVectorEnv le pilote avec la même API que LocalVectorEnv.

Évaluer un point de contrôle

Localement, avec le simulateur installé à côté de LeRobot (voir LIBERO) :

lerobot-eval \
  --policy.path=lerobot/smolvla_libero \
  --policy.pretrained_revision=a24f1f380461b665158d52acd140152c79e8b36d \
  --policy.device=cuda \
  --env.type=libero --env.task=libero_spatial --env.task_ids='[0]' \
  --rename_map='{"observation.images.image": "observation.images.camera1", "observation.images.image2": "observation.images.camera2"}' \
  --eval.n_episodes=1 --eval.batch_size=1 \
  --output_dir=outputs/eval_libero

Served : démarrez le serveur avec le même environnement (voir Servir un environnement) et ajoutez son point de terminaison :

lerobot-env-server --config_path=docker/sim/configs/libero.yaml --docker=true
lerobot-eval ... --env.server.endpoint=tcp/127.0.0.1:7448

Toutes les options du serveur se trouvent sous --env.server.* et aucune ne s’applique à une exécution locale. Le client demande le déploiement nommé d’après --env.type, tel que nommé par les configurations du serveur ; passez --env.server.deployment pour un autre. Un point de terminaison ou un déploiement incorrect échoue dans un délai de --env.server.handshake_timeout_s (10 s) et indique ce que le point de terminaison sert. Face à un serveur sécurisé par TLS, passez son fichier JSON5 Zenoh avec --env.server.zenoh_config_path, comme pour l’inférence distante. Le serveur doit exécuter l’environnement décrit par la commande : le même type, la même tâche, les mêmes conventions de contrôle et le même corps simulé (robot_type), sinon l’évaluation refuse de démarrer et liste les différences. Les autres options qui diffèrent (résolution, longueur d’épisode) sont journalisées en tant qu’avertissements.

Les noms des observations proviennent de l’environnement (observation.images.<camera>, observation.state). Si un point de contrôle a été entraîné avec d’autres noms de caméras, mappez-les à l’aide de --rename_map, comme pour n’importe quel robot, et conservez l’identité de chaque caméra même lorsque plusieurs partagent la même forme. Les caméras placeholders (empty_cameras) constituent un paramètre de politique enregistré avec le point de contrôle ; ne le remplacez par --policy.empty_cameras que si nécessaire.

Avant la première étape, chaque point de contrôle d’entrée doit exister dans l’environnement après le renommage, avec des dimensions d’état et d’action ainsi qu’un nombre de canaux RVB correspondants. La hauteur et la largeur des images peuvent différer : le prétraitement de la politique gère le redimensionnement. Les conventions du contrôleur (actions delta par rapport aux actions absolues, format de rotation) ne sont pas vérifiées ; utilisez un point de contrôle entraîné selon la convention de l’environnement.

Chaque step() fait avancer une fois chaque environnement non terminé du lot. Un environnement qui se termine conserve son observation terminale jusqu’au prochain réinitialisation ; le fait d’avancer les autres ne le redémarre jamais. Avec --eval.use_async_envs=true (par défaut), chaque environnement s’exécute dans son propre processus worker, en local ou sur le serveur, et le lot avance en parallèle. Un serveur accepte jusqu’à max_envs environnements par lot (32 par défaut). --env.server.encoding=jpeg (ou --robot.env.server.encoding=jpeg, avec --env.server.jpeg_quality, 90 par défaut) envoie les images de caméra servies au format JPEG : des réponses plus petites pour un serveur distant et des lots plus grands, au prix d’un temps d’encodage et d’images avec perte. En local, les images brutes sont plus rapides. Une réponse contient les images de tous les environnements du lot et doit tenir dans max_payload_bytes (32 Mio par défaut) aux deux extrémités, sinon le serveur refuse le lot à l’ouverture. Pour les grands lots ou les caméras haute résolution, augmentez cette valeur sur le serveur (max_payload_bytes dans la section zenoh du YAML, à côté de listen_endpoints) et sur le client (--env.server.max_payload_bytes, ou --robot.env.server.max_payload_bytes).

Exécuter un robot de simulation

Le même environnement qu'un environnement par lots et qu'un robot de simulation :

lerobot-eval    --env.type=libero --env.task=libero_spatial --env.task_ids='[0]' ...
lerobot-rollout --robot.type=sim --robot.env.type=libero --robot.env.task=libero_spatial --robot.task_id=0 ...

Par exemple :

lerobot-rollout \
  --robot.type=sim --robot.env.type=libero --robot.env.task=libero_spatial --robot.task_id=0 \
  --task="pick up the black bowl between the plate and the ramekin and place it on the plate" \
  --policy.path=lerobot/smolvla_libero \
  --policy.pretrained_revision=a24f1f380461b665158d52acd140152c79e8b36d \
  --rename_map='{"observation.images.image": "observation.images.camera1", "observation.images.image2": "observation.images.camera2"}' \
  --device=cuda --fps=20 --inference.type=sync \
  --display_data=true --display_mode=rerun \
  --return_to_initial_position=false --play_sounds=false
  • --robot.env.* prend les mêmes options que --env.* lors de l’évaluation. --robot.task_id sélectionne la tâche unique que le robot exécute, tandis que l’évaluation exécute toutes les tâches de la suite ou celles spécifiées dans --env.task_ids. Les environnements EnvHub sont --robot.env.type=envhub --robot.env.hub_path=<user/repo> --robot.env.trust_remote_code=true.
  • Certaines politiques nécessitent les processeurs de l’environnement (XVLA et Cosmos3 sur LIBERO, Isaac Lab Arena). lerobot-eval les applique, de même qu’un robot de simulation avec --inference.type=sync. L’inférence distante ne le fait pas et refuse donc un tel point de contrôle au démarrage.
  • --robot.env.server.endpoint=tcp/... pilote l’environnement sur un serveur d’environnement, de la même manière que --env.server.endpoint le fait pour un environnement par lots. Le robot vérifie que le serveur exécute cet environnement.
  • Chaque send_action() fait avancer l'environnement exactement une fois. La lecture des observations, l'inférence de la politique et l'attente n'avancent pas la simulation ; la boucle de contrôle existante gère le rythme en temps réel.
  • --fps doit être égal au taux de contrôle de l’environnement, divisé par --interpolation_multiplier lors de l’interpolation, car chaque commande fait avancer l’environnement d’un pas. Lors de l’enregistrement, --dataset.fps doit être égal à --fps. Le rollout refuse de démarrer dans le cas contraire.

Un robot de simulation est un robot : remplacez --robot.type=sim --robot.env.* par les paramètres --robot.* du suiveur réel, et le reste reste inchangé. Un téléopérateur le pilote de la même manière qu’il pilote le suiveur réel (--teleop.type=so101_leader pour un jumeau SO-101), lorsque l’environnement déclare les noms et les unités des actions du suiveur ; un désaccord est signalé à la première action. lerobot-record enregistre le corps déclaré par l’environnement en tant que robot_type du jeu de données (panda pour LIBERO), ou sim_robot s’il n’en déclare aucun.

Les épisodes enregistrés suivent ceux de l’environnement. lerobot-record et la stratégie de déploiement épisodique redémarrent l’environnement simulé au début de chaque épisode et le terminent lorsque l’épisode de l’environnement se termine (succès, terminaison ou limite d’étapes) ou lorsque sa durée est atteinte, selon ce qui survient en premier. Chaque épisode enregistré correspond donc à un épisode simulé, depuis son état initial. Aucun réinitialisation manuelle n’est nécessaire : passez la phase de réinitialisation entre les épisodes avec --dataset.reset_time_s=0, et, avec la stratégie de déploiement épisodique, passez également --strategy.reset_to_initial_position=false. Lorsqu’un épisode se termine, le robot s’arrête : il ignore les actions et conserve son état final, et latest conserve la récompense finale, la terminaison et le succès. La téléopération et la stratégie de déploiement de base démarrent alors un nouvel épisode (la stratégie réinitialise également la politique), et la lecture s’arrête. Les stratégies sentry, highlight et DAgger ne prennent pas encore en charge les robots simulés, car elles enregistrent par durée ou sur demande plutôt que par épisode ; utilisez la stratégie épisodique pour l’enregistrement. Les robots réels ne sont pas affectés : leurs épisodes sont chronométrés et leur scène est réinitialisée manuellement. Pour les taux de succès, évaluez avec lerobot-eval et un environnement par lots.

Les fonctionnalités de la caméra robotique utilisent les mêmes noms observation.images.<camera> que l’enregistrement sur matériel réel. Une caméra unique sans nom est observation.images.image. L’évaluation par lots conserve les clés propres à l’environnement, telles que observation.image pour une caméra unique ; lors du déploiement d’un point de contrôle portant ce nom via SimRobot, utilisez --rename_map='{"observation.images.image": "observation.image"}'.

Pour l'inférence à distance, conservez les mêmes options --robot.* et remplacez les options locales de politique et d'inférence par :

--inference.type=remote \
--inference.endpoint=tcp/127.0.0.1:7447 \
--inference.deployment=libero \
--inference.semantics=libero-delta-v1

Démarrer le serveur de politique séparément à l'aide de remote inference setup. Son schéma doit correspondre aux observations du robot après --rename_map. Omettre --policy.path de la commande de rollout car le serveur de politique charge le checkpoint. Pour RTC local, utiliser --inference.type=rtc avec les paramètres RTC de la politique.

Lorsque la politique est en retard, maintenir un robot de simulation n'avance pas la physique. Les pannes du simulateur se propagent jusqu'à l'arrêt du déroulement.

Servir un environnement

Depuis un checkout source de LeRobot (l’image est construite à partir de celui-ci), exécutez depuis la racine du dépôt :

lerobot-env-server --config_path=docker/sim/configs/libero.yaml --docker=true

--docker=true utilise docker/sim/compose.server.yaml, sélectionne l’image à partir de sim.type, monte le YAML effectif et exécute le conteneur sur le réseau hôte, de sorte que le serveur écoute sur localhost:7448 sauf si --zenoh.listen_endpoints indique le contraire. Remplacez le YAML pour sélectionner un autre simulateur. La fréquence de contrôle, la convention d’action, les noms des composants et le type de robot de chaque simulateur proviennent de conventions() de son intégration, de sorte qu’un YAML ne nomme que la tâche et les options du simulateur.

En ce qui concerne lerobot-policy-server, chaque champ YAML accepte une surcharge par ligne de commande imbriquée, et le fichier reste inchangé. Une valeur de dictionnaire telle que sim.kwargs est fusionnée dans celle du YAML :

lerobot-env-server --config_path=docker/sim/configs/libero.yaml --docker=true \
  --sim.task=libero_goal \
  --sim.kwargs='{gym_kwargs: {observation_height: 256, observation_width: 256}}'

La configuration effective est conservée sous $HF_LEROBOT_HOME/sim, de sorte qu’un conteneur redémarré la retrouve. Le changement de configuration recrée le serveur et met fin aux sessions actives. L’image est construite si elle est absente ; ajoutez --build=true pour la reconstruire après avoir modifié le simulateur ou le code source de LeRobot, ou --stop=true pour arrêter le serveur. Le conteneur nécessite l’accès GPU de Docker pour le rendu EGL. Les dépôts EnvHub sont servis avec --envhub=<user/repo> ; voir EnvHub et le serveur de simulateur.

Si un simulateur qui rend avec Vulkan (Isaac Sim, ou ManiSkill/SAPIEN comme dans RoboMME, dont l’image embarque son propre fichier Vulkan) échoue dans le conteneur avec vkCreateInstance failed ou ERROR_INCOMPATIBLE_DRIVER alors qu’il fonctionne hors de Docker, le conteneur possède les bibliothèques du pilote NVIDIA mais pas les fichiers de chargeur qui y pointent (/usr/share/vulkan/icd.d/nvidia_icd.json, /usr/share/glvnd/egl_vendor.d/10_nvidia.json). Le mode par défaut du NVIDIA Container Toolkit, utilisé par gpus: all, peut ne pas les monter ; son mode CDI, lui, le fait. Demandez le GPU via CDI (--device nvidia.com/gpu=all pour docker run, devices: [nvidia.com/gpu=all] à la place de gpus: all dans docker/sim/compose.server.yaml), ou ajoutez les deux fichiers à l’image.

Sans --docker=true, la même commande exécute le serveur dans l’environnement actuel : installez les dépendances natives du simulateur dans un environnement isolé, installez LeRobot avec --no-deps, puis installez docker/sim/requirements.txt. Dans les deux cas, le serveur écoute sur localhost ; pour accepter d’autres machines, passez l’adresse de l’interface réseau qu’elles utilisent, comme dans --zenoh.listen_endpoints='[tcp/192.168.1.20:7448]', et ajoutez le TLS ainsi que le contrôle d’accès via un zenoh.config_file dans le fichier YAML.

Les images d’exécution de LIBERO utilisent des fichiers d’état initial NumPy convertis. La construction de l’image convertit les ressources amont de confiance à l’aide de scripts/ci/convert_libero_init_states.py ; le serveur rejette les fichiers convertis manquants. RoboTwin et RoboMME nécessitent chacun leur propre torch pour la planification native et ManiSkill, respectivement ; leurs installations de torch sont isolées de l’environnement de la politique.

Les requêtes serveur ne sont jamais réessayées. Après un délai d’attente ambigu, le client échoue ; fermez-le et ouvrez une nouvelle session.

Ajouter un benchmark

Voir Ajouter un benchmark pour les modules de simulateur, les conventions, les images et l’intégration CI.

Update on GitHub