Upstream: https://github.com/pollen-robotics/microduck_rl Upstream-Commit: d424a0c899f6b33cbd3daeb279913134349c0b63 Upstream-Branch: develop
6.3 KiB
Mode pente — roller_slope (descente passive équilibrée)
Date : 2026-07-22 Statut : design validé, prêt pour le plan d'implémentation.
Objectif
Entraîner une politique dédiée où microduck (sur rollers) démarre sur du plat avec une petite impulsion vers l'avant, roule jusqu'à une rampe descendante, et se laisse glisser jusqu'en bas en restant debout et équilibré. Aucun pilotage pendant la descente : le seul objectif de la politique est de ne pas tomber.
La politique doit gérer des rampes de raideur croissante (~2° → ~20°) grâce à un curriculum de difficulté.
Décisions cadrées (brainstorming)
| Sujet | Décision |
|---|---|
| Comportement | Descente passive équilibrée (la gravité fait avancer, pas de pédalage imposé) |
| Pilotage | Aucun — équilibre pur, commande twist forcée à zéro |
| Approche | A — tâche dédiée, isolée (comme roller_crouch) |
| Forme du terrain | Rampe simple : plat de départ + rampe descendante (pas de pyramide) |
| Scénario épisode | Spawn sur le plat → vitesse d'impulsion vers l'avant → glisse sur la rampe |
| Raideur | Curriculum 0/2° → 20° |
| Déploiement | Flag --slope <onnx> + touche Y dans infer_policy.py (Y est libre) |
Architecture
1. Nouvelle tâche
Fichier : src/mjlab_microduck/tasks/microduck_roller_slope_env_cfg.py, cloné de
microduck_velocity_rollers_env_cfg.py.
- Même robot rollers (
MICRODUCK_WALK_ROLLERS_ROBOT_CFG), même physique, même domain randomization / bruit / délais. - Même observation 61D (twist + head/body en zéro-padding) → la politique
charge par le chemin
--new-cmd-obsdu runtime et reste interchangeable avec les autres politiques rollers. - Enregistrement dans
src/mjlab_microduck/tasks/__init__.pyviaregister_mjlab_task, avec une config PPOMicroduckRollerSlopeRlCfg(experiment_name/run_name=roller_slope).
2. Terrain « plat + rampe » (custom)
Les terrains inclinés fournis par mjlab sont des pyramides ; on écrit donc un
SubTerrainCfg dédié (p. ex. FlatRampTerrainCfg) dont la méthode
function(difficulty, spec, rng) construit :
- une zone plate de départ (longueur ~1–2 m) où le robot spawne ;
- une rampe descendante à la suite, dont l'angle est
interpolé par
difficultysur[~2°, ~20°].
Le terrain est monté via TerrainEntityCfg(terrain_type="generator", ...) avec un
TerrainGeneratorCfg qui génère plusieurs niveaux de difficulté (donc plusieurs
angles de rampe). L'origine de chaque environnement doit tomber sur la zone
plate, la rampe devant lui.
Risque d'implémentation à traiter dans le plan : positionnement de l'origine de spawn sur le plat (pas au centre de la tuile), et orientation de la rampe pour que « devant » = « vers le bas ».
3. Commande = aucune
Slot twist neutralisé : rel_standing_envs = 1.0, ranges de vitesse à 0,
rel_heading_envs = 0.0. Head/body restent en zéro-padding. La politique ne
reçoit aucune consigne de déplacement.
4. Reset & vitesse d'impulsion
reset_base: spawn au repos sur le plat, hauteurznominale rollers (~0.1335–0.1435, comme le roller env).- Vitesse d'entrée injectée via le
velocity_rangedereset_root_state_uniform(état propre + range), pas viapush_by_setting_velocity(qui s'additionne à l'état courant et peut faire diverger le free-joint → NaN — leçon déjà apprise surroller_crouch) :x ≈ (0.2, 0.5) m/svers l'avant. - Pushs aléatoires légers conservés pendant l'épisode (robustesse), comme le roller env.
5. Récompenses
Cœur « rester droit + posture naturelle », anti-optimum-paresseux (éviter qu'il s'écrase au sol pour maximiser la stabilité) :
upright(tronc vertical) — principalealive(bonus de survie par pas)- pose debout nominale : récompense vers la pose HOME (mécanique
d'interpolation de pose reprise de
roller_crouch, mais cible fixe = debout), pour garder une stance rollers normale plutôt qu'un accroupi défensif feet_flat(rollers à plat au sol)body_ang_vel,angular_momentum(pas de tremblement / vrille)action_rate_l2,neck_action_rate_l2,joint_torques_l2,self_collisions(douceur + sim2real)
Pas de récompense de vitesse/frein : la descente est passive. On ne récompense pas « aller vite », seulement « rester droit en descendant ».
6. Terminaisons
- Chute :
bad_orientation(tronc trop incliné). - Bas atteint :
out_of_terrain_bounds(le robot est arrivé en bas de la rampe → reset). nan_state, time-out.
7. Curriculum de difficulté (raideur)
Progression doux → raide : commencer sur des rampes quasi plates, augmenter l'angle vers 20° au fur et à mesure des réussites.
Risque d'implémentation : le curriculum standard
terrain_levels_velpromeut selon la distance parcourue par rapport à la vitesse commandée. Ici la commande est nulle, donc il faut un critère de promotion custom : promouvoir si le robot a survécu / atteint le bas sans tomber, rétrograder s'il chute tôt.
8. Déploiement — bouton Y
Dans scripts/infer_policy.py :
- nouveau flag
--slope <onnx>chargeant la politique pente comme session supplémentaire (même schéma que--walking/--standing/--ground-pick) ; GLFW_KEY_Y = 89(aujourd'hui libre — la tête est surH) qui bascule la session active vers/depuis la politique pente ;- ligne d'aide clavier ajoutée.
Aucun contrôle existant n'est cassé (contrairement à un partage de la touche H
du contrôle de la tête).
Ce qui n'est PAS dans le périmètre (YAGNI)
- Pas de pilotage gauche/droite ni de freinage en descente.
- Pas de montée de pente ni de traversée.
- Pas de pyramide ni de terrains multi-directions.
- Pas de fine-tuning depuis les poids roller existants (entraînement from scratch).
Livrables
microduck_roller_slope_env_cfg.py(env +FlatRampTerrainCfg+ PPO cfg).- Enregistrement de la tâche dans
tasks/__init__.py. - Récompenses/curriculum custom nécessaires dans
tasks/mdp.py(pose-debout, promotion de niveau). - Branchement
--slope+ toucheYdansscripts/infer_policy.py. - Tests unitaires pour les fonctions pures (angle de rampe par difficulté, éventuel critère de promotion).