Que fait Constructeur d'Environnements Simulés (Sim Env Builder) ?
Objectif : à partir d'une description, livrer un environnement simulé fonctionnel, physiquement cohérent et visuellement satisfaisant en aussi peu d'interactions que possible (idéalement : demande -> une confirmation -> terminé). Barre de qualité : chaque test de fumée passe, vous avez REGARDÉ les rendus et ils correspondent à la demande.
SKILL_DIR ci-dessous = le répertoire de ce fichier. Les helpers Python se trouvent dans SKILL_DIR/scripts/simkit.
Phase 0 – Configuration (1 minute)
PY=$(bash SKILL_DIR/scripts/setup_env.sh) # python avec mujoco, trimesh, usd-core, gymnasium
$PY SKILL_DIR/scripts/check_platform.py # OS, GPU, disponibilité d'Isaac
Choisissez le dossier de l'environnement : ./<nom_court_en_snake_case>/ dans le répertoire courant, sauf si l'utilisateur en a nommé un.
Phase 1 – Choisir le backend (lire reference/backend_choice.md)
Isaac Sim nécessite un GPU NVIDIA RTX sous Linux/Windows. MuJoCo fonctionne partout.
- MuJoCo : par défaut. Manipulation avec contact et locomotion, itération rapide, CPU/laptop/macOS, scènes petites à moyennes, contrôle basé sur des modèles, recherche reproductible, MJX/Warp pour le RL GPU.
- Isaac Sim : rendu photoréaliste RTX ou données synthétiques (Replicator), réalisme des capteurs lidar/caméra RTX, milliers d'environnements parallèles dans Isaac Lab, grandes scènes USD/Omniverse, utilisateur déjà sur Isaac.
- Si Isaac est le meilleur choix mais
isaac_runnable_hereest false, dites-le dans la confirmation et proposez : construire + tester entièrement dans MuJoCo ici ET exporter une scène USD + un script de test Isaac pour la machine GPU (reference/isaac.md). Ne prétendez jamais avoir des résultats Isaac que vous n'avez pas exécutés.
Phase 2 – Confirmer avec l'utilisateur AVANT de construire (reference/confirmation.md)
- Commencez par un scan rapide des actifs pour que le brief soit concret : un appel
find_assets(MCP Polypizza) listant chaque rôle d'objet, 1 à 3 requêtes chacun. - Envoyez UN brief court (modèle dans reference/confirmation.md) : backend + pourquoi, ce qui sera dans la scène, le robot/agent et son interface de contrôle, quels actifs viennent de Poly Pizza vs procédural, physique clé (gravité, frottement, pas de temps), livrables, et 2 à 4 questions qui portent chacune votre recommandation par défaut.
- Posez la question avec AskUserQuestion si cet outil existe. Sinon, terminez votre tour avec le brief comme message et attendez. Ne construisez pas avant que l'utilisateur réponde. Exception : l'utilisateur a dit de ne pas demander / « construis-le » -> écrivez les hypothèses dans SPEC.md, continuez.
- Enregistrez les décisions confirmées dans
<env>/SPEC.md(modèle dans reference/confirmation.md).
Phase 3 – Actifs : Poly Pizza d'abord, repli procédural (reference/assets.md)
Pour chaque rôle d'objet :
find_assets/search_models-> lisez le verdict (trouvé / faible / non trouvé).- trouvé ou faible ->
preview_models([...ids])et REGARDEZ : bon objet ? style cohérent ? rejetez les jouets, les dessins animés dans les scènes réalistes, les lots multi-objets, les classes d'échelle erronées. - Accepté ->
download_model(id, "<chemin_absolu_env>/assets/polypizza", "<rôle>")(les crédits sont enregistrés automatiquement dansassets/polypizza/CREDITS.md). - non trouvé, rejeté ou erreur de téléchargement -> procédural : recettes
simkit.procedural(arbres, bâtiments, meubles, accessoires de rue, portails, vaisselle, terrain...) ou composez les vôtres à partir de primitives /lathe/extrude/rock. Ne laissez jamais un objet demandé de côté. - Écrivez
<env>/assets/ASSETS.md: rôle | source (ID Poly Pizza + titre + licence, ou recette procédurale) | taille réelle | pourquoi. Si le titre d'un modèle diffère du rôle (« Banc de Parc » utilisé comme table de pique-nique), dites-le et expliquez pourquoi il convient toujours – ou cherchez à nouveau / passez au procédural. Listez aussi les candidats REJETÉS (id + raison : « style cartoon », « lot de 12 objets ») pour que la recherche soit traçable même si tout finit en procédural. Les modèles Poly Pizza sont des maillages statiques : les robots articulés et les véhicules proviennent desimkit.robots(vous pouvez les habiller avec un maillage Poly Pizza comme géométries visuelles).
Phase 4 – Construction (reference/robots.md, templates/)
mkdir -p <env> && cp -r SKILL_DIR/scripts/simkit <env>/simkit # encapsulé : l'environnement est autonome
cp SKILL_DIR/templates/build_env.py SKILL_DIR/templates/env.py SKILL_DIR/templates/view.py <env>/ # éditez les deux premiers
build_env.pyregénère tout de manière déterministe (avec graine) ->scene.xml. Utilisezsimkit.scene.Scene(ciel, sol, lumières, caméras de visée, sections pour MJCF brut),simkit.assets.glb_to_mujoco(glb, env, name, target={"height": m}, yaw_deg=..)pour les modèles Poly Pizza (taille réelle, Z vers le haut, pièces par couleur, collision boîte/enveloppe/pièces),simkit.proceduralpour les replis et le terrain,simkit.robotspour les robots testés (quadrotor, voiture, diff_drive, bras- pince, quadrupède) et leurs contrôleurs.
- L'échelle réelle est obligatoire (tableau de tailles dans reference/assets.md). Les objets reposent sur leur support.
- Chaque classe d'objet nommée par l'utilisateur doit être clairement visible à une taille lisible dans la vue d'ensemble
(un « sentier rocheux » a besoin de rochers visibles, pas de grains de 7 cm ; un « terrain accidenté » a besoin de bosses visibles
à l'échelle du robot). Le test de fumée liste les petits grains sous
hints. - Au moins 2 caméras nommées : une vue d'ensemble et une cadrée sur le sujet (le robot/l'objet de la tâche remplit environ 30 à 50 % du cadre ; montée sur le robot le cas échéant). Les caméras de capteur fixes ne doivent pas être obstruées par la pose de repos du robot (le fumée signale > 15 % de couverture).
world.py(quand la scène a sa propre dynamique) :make_world(model)->world(model, data), appelé AVANT chaque pas de physique par le fumée, l'examinateur, la vitrine, env.py, view.py et le tableau de bord. La flottabilité/la traînée, le vent, les convoyeurs, les cycles de feux de circulation, les piétons scriptés et les NPC automobiles vivent ici, jamais dans controller.py (un test passif ou une politique RL exécuterait sinon un monde où les bateaux coulent et les feux ne changent jamais). Les vérifications de tâche qui font avancer la simulation doivent aussi l'appeler.controller.py: une politique de démonstration scriptée (make_controller(model)->ctrl(model, data)) qui montre l'environnement en action (le drone vole les portes, la voiture suit l'itinéraire, le bras atteint l'objet...). DéfinissezDEMO_SECONDS = <durée de la démo complète>au niveau du module : le test de fumée filme alors et vérifie la démo ENTIÈRE (prendre, soulever, placer / chaque porte), pas seulement les 4 premières secondes.task_checks.py: fonctionscheck_<nom>(model, data) -> {"status", "value", "expect", "details"}pour la physique au niveau de la tâche. Un check par critère de succès que l'utilisateur a énoncé ou confirmé (nommez-le d'après ses mots : « pieds en contact » ->check_feet_in_contact), plus la vérification de cohérence du spawn (le robot commence sur son support). Au moins 2. Écrivez les seuils ET la définition exacte de chaque métrique (point de référence, unités : « centre de la base du rover au centre de l'atterrisseur, mètres ») dans SPEC.md AVANT la première exécution et conservez-les : un échec de justesse signifie corriger le contrôleur/la scène, jamais assouplir le check (tout changement de seuil doit apparaître sous « Modifications par rapport au plan confirmé »). Un check passant à moins de 15 % de sa limite est signalé avec sa marge (« inclinaison 25,8 degrés vs limite 30 degrés »). Tout comportement que vous revendiquez (ralentissement dû à un obstacle, cycle de feux de circulation, flottabilité, maintien de la pince) nécessite un check qui l'exerce, par ex. placez un obstacle sur le chemin et affirmez que le robot s'arrête. Chaque propriété physique clé de la scène obtient un check mesuré avec une cible physique : la décélération de roulement d'une balle, la ligne de flottaison d'un bateau, la montée de pente d'un rover, le temps de chute en faible gravité, la force de maintien de la pince. Un capteur requis obtient aussi un check : rendez la caméra du robot pendant la démo et affirmez une image non vide qui montre la tâche (par exemple des rangées d'arbres devant) ; pour le lidar, affirmez des portées sensées. Exécutez chaque check de tâche sur le déroulement scripté ET 2-3 déroulements perturbés (autre graine, pose de départ, vitesse initiale, phase de lumière) – un check qui ne tient que pour un seul déroulement précis ne prouve pas grand-chose. Les checks de préhension nécessitent un contact entre LES DEUX coussinets de doigts et l'objet pendant le levage et le transport (lisezdata.contact), pas seulement « l'objet est monté ».- Colliders : simples et honnêtes. Arbres : collider de tronc, canopée visuelle uniquement sauf si l'utilisateur veut
des impacts de canopée. Multirotors : capsules de bras ou une enveloppe, pas une boîte qui avale les hélices.
Accessoires non convexes (microscope, chaise, arche, étagère) obtiennent
collision="parts"ou quelques primitives ; une enveloppe convexe autour d'eux bloque un espace visiblement vide (vérifiez collision_sheet.png). env.py:reset/step/renderde style Gymnasium avec observation de la tâche, récompense factice, terminaison. Son auto-test__main__pilote l'environnement À TRAVERS l'API env avec le contrôleur de démonstration (ou une politique de référence) et affiche si l'objectif de la tâche est atteint – preuve que l'objectif est accessible.- Corps et marqueurs de débogage/rigging de caméra : groupe de géométries 4-5 (jamais rendu), pas dans les caméras de données.
- Choses suspendues (lumières de plafond, panneaux suspendus, étagères murales) : nommez-les
mounted_*ouhanging_*pour que le check d'objet flottant les ignore. - Éclairage : blanc neutre (pas de lumières teintées) ; au maximum 2-3 lumières supplémentaires ; vérifiez qu'un mur blanc reste blanc-gris dans les rendus.
- Pas d'habillage non demandé au-delà de ce qui rend la scène correcte ; listez les extras optionnels dans le brief pour que l'utilisateur puisse les choisir.
- Limite de temps : notez l'heure quand vous commencez à construire (
date). Les éléments bonus/étirés (« plier est un bonus ») viennent seulement après que tous les indispensables passent, et sont supprimés en premier. Environ 60 minutes après le début de la construction, arrêtez de régler ce qui reste : finalisez REPORT.md et les résultats README et rapportez (éléments supprimés listés). Une construction qui ne rapporte jamais est pire qu'une construction avec un écart connu. - Budget : une fois que tous les indispensables existent et que tous les checks passent, arrêtez d'ajouter des extras – terminez le check visuel, le README et le rapport. Les extras vont dans le README comme idées.
- Exécutez
$PY build_env.pyaprès chaque changement ; les erreurs de compilation portent des numéros de ligne.
Phase 5 – Tests de fumée (reference/smoke_tests.md). Tous les trois sont obligatoires.
cd <env> && $PY -m simkit.smoke scene.xml --out smoke --controller controller.py --task-checks task_checks.py
- Test de rendu – chaque caméra nommée + vues automatiques rendent des images non vides, éclairées, détaillées ; la segmentation montre quels objets sont visibles (les objets invisibles sont signalés).
- Examinateur physique – sondes solveur/contacts/frottement/gravité avec les propres paramètres de la scène, stabilité du déroulement, pénétration, chute à travers, stabilisation, réponses aux pas d'actionneurs, déterminisme, sensibilité au pas de temps, facteur temps réel, disposition (accessoires flottants / enfoncés / en interpénétration), plus vos checks de tâche.
- Vérification visuelle – VOUS devez ouvrir et regarder
smoke/contact_sheet.png,smoke/filmstrip.png,smoke/collision_sheet.pnget les gros plans danssmoke/renders/(outil Lire), puis remplissez la liste de contrôle danssmoke/visual_check.mdavec des observations concrètes. Corrigez chaque ÉCHEC. Enquêtez sur chaque AVERTISSEMENT (corrigez-le, ou expliquez dans le README pourquoi c'est attendu). Reconstruisez et relancez jusqu'à ce que le verdict soit PASS / PASS_WITH_WARNINGS-expliqué ET que la vérification visuelle soit honnêtement entièrement « oui ». Attendez-vous à 2-3 itérations ; le premier rendu est rarement correct. Exécutez aussi$PY env.py(actions aléatoires, observations finies).
Phase 6 – Livrable Isaac Sim (uniquement si Isaac a été choisi ; reference/isaac.md)
$PY -m simkit.usd_export scene.xml isaac/scene.usda (exportation + validation locale), copiez
SKILL_DIR/templates/isaac_smoke.py dans isaac/, documentez comment l'exécuter sur la machine GPU.
Indiquez clairement ce qui a été et n'a pas été exécuté.
Phase 7 – Livraison
<env>/README.md : ce qu'il y a dans la scène, comment exécuter (construction, fumée, environnement, visualiseur :
$PY view.py, qui exécute le contrôleur de démonstration en direct ; mujoco.viewer simple montre seulement la physique passive), caméras, actionneurs, contrôleur, checks de tâche, crédits
des actifs, limitations connues. Message final à l'utilisateur : ligne de verdict, ce qui a été construit, quels actifs
proviennent de Poly Pizza vs procédural, résultats de fumée, chemins vers smoke/showcase.mp4 (la vidéo que les gens
regardent), planche contact et filmstrip, tout ce qui n'est pas fait ou non vérifié, et une liste « Modifications par rapport au
plan confirmé » (actifs ou licences échangés, tailles/comptes modifiés, extras supprimés) – vide si aucun, mais toujours présent.
Copiez chaque nombre (checks réussis, scores, erreurs) depuis
smoke/smoke_report.json et physics_report.json ; collez son summary_line textuellement
("Smoke PASS: examinateur 19 pass / 0 warn / 0 fail ; task checks 9/9 pass ; rendu ok") et n'écrivez jamais
de comptes de mémoire.
Commencez <env>/REPORT.md dès que la première exécution de fumée est terminée et mettez-le à jour après chaque correction, pour qu'une
session interrompue laisse quand même un rapport ; le message final est sa dernière version.
Structure du livrable (conservez exactement ; les outils et tableaux de bord en dépendent)
<env>/
SPEC.md README.md REPORT.md build_env.py scene.xml env.py view.py controller.py task_checks.py
world.py (uniquement si la scène a sa propre dynamique)
simkit/ helpers encapsulés
assets/polypizza/*.glb assets/polypizza/CREDITS.md assets/polypizza/polypizza_assets.json
assets/meshes/ assets/procedural/ assets/ASSETS.md
smoke/ (showcase.mp4 contact_sheet.png filmstrip.png collision_sheet.png renders/ rollout.mp4
physics_report.json render_report.json smoke_report.json env_manifest.json
SMOKE.md visual_check.md)
isaac/ (uniquement pour Isaac : scene.usda, isaac_smoke.py, section README)
Règles durement acquises (chacune a déjà fait échouer une vraie construction)
-
Restez dans le périmètre confirmé. La démo montre ce sur quoi l'utilisateur s'est mis d'accord (par ex. « rester debout suffit » signifie une position stable, pas un nouveau contrôleur de locomotion). Consacrez le temps à la scène, aux actifs, aux checks et à la revue visuelle ; listez les idées d'extension dans le README.
-
Paramètres
<visual>:sc.set_visual("map", znear=.., zfar=..)etc. Chaque élément peut apparaître une fois. -
Ne calculez jamais manuellement les
xyaxesde caméra : utilisezScene.camera(nom, position, cible)/simkit.scene.lookat. -
N'écrivez jamais manuellement des listes de qpos d'images clés : définissez
scene.home[articulation] = valeur(les robots le font pour vous) ;Scene.writeconstruit l'image cléhomepar nom d'articulation et définit le ctrl de l'actionneur de position pour correspondre. -
Les maillages plats/fins nécessitent
inertia="shell"(glb_to_mujoco le fait). Géométries visuelles :contype=0 conaffinity=0 group=2 mass=0; proxies de collision dans le groupe 3. -
Un robot soudé au monde entre en collision avec sa propre base : ajoutez
<exclude>pour la base/le premier maillon. -
Posit…