Fase 3: Movimiento avanzado
Objetivos de la Fase 3
En esta fase buscaré que el robot responda bien a comandos de velocidad más avanzados introduciendo un rango de velocidad lineal más amplio (de -1m/s a 1m/s) y una componente de velocidad angular (yaw) para que el robot aprenda a girar. Todo esto sin olvidar lo aprendido en fases anteriores.
Los objetivos por lo tanto serán:
Que el robot sea capaz de mantenerse en equilibrio estático cuando el comando de movimiento es cero.
Que el robot sea capaz de desplazarse recto a la velocidad lineal solicitada cuando el comando de velocidad no tiene componente angular.
Que el robot sea capaz de realizar movimientos curvilineos, adaptando su velocidad linear y angular a la solicitada cuando el comando tiene tanto componente lineal como angular.
Estrategia de entrenamiento
Al igual que en la fase anterior, vamos a tener que introducir nuevas observaciones para lograr los nuevos objetivos. El vector de acción se mantendrá igual, puesto que seguiremos actuando únicamente sobre la velocidad de cada una de las ruedas del robot.
Como ya vimos, cambiar el espacio de observaciones hace que la política entrenada anteriormente no pueda utilizarse para continuar el entrenamiento de esta nueva fase. Debido a esto, modificaremos las observaciones y entrenaremos de nuevo las fases 1 y 2, para así poder utilizar la política aprendida en la segunda fase para entrenar la tercera.
Cambios en el espacio de observaciones
Cambios en simplerobot_env.py
simplerobot_env.pyHe modificado la función _get_observations:
He cambiado el nombre de
lin_vel_bporvxpor conveniencia.He agregado
yaw_velal vector de observaciones, que representa la componente de la velocidad angular yaw (giro en el eje vertical del robot)He simplificado la observación de
angular_velocitypara que solo contenga los valores de las componentes pitch y roll, ya que la componente yaw la estoy observando conyaw_velHe modificado la observación del comando
cmd, ya que ahora tendrá dos componentes: la velocidad lineal y la angular.
Cambios en simplerobot_env_cfg.py
simplerobot_env_cfg.py Los cambios en el env, nos obligan a cambiar la dimensión de la variable observation_space :
Cambios en pesos y tasks
En las fases anteriores he estado modificando manualmente los pesos de las recompensas y penalizaciones y adaptándolas según la fase que estuviese entrenando. Eso funciona, pero hardcodear no suele ser una buena práctica, así que voy a tratar de parametrizar un poco el tema de las fases.
Migración de los pesos a simplerobot_env_cfg.py
simplerobot_env_cfg.pyLo primero, es pasar los pesos de las recompensas y penalizaciones al archivo simplerobot_env_cfg.py:
Ahora, podremos acceder a estos parámetros desde simplerobot_env.py utilizando robot.cfg.nombre_del_parametro. Entonces, en mi cálculo del reward puedo poner:
Ahora ya no hace falta tocar el archivo simplerobot_env.py para cambiar los pesos de las recompensas y penalizaciones entre fases. Para ello solamente tendremos que modificar el archivo simplerobot_env_cfg.py, ajustando los valores de los pesos según la fase en la que estemos.
Los valores positivos estarán asociados a recompensas y los valores negativos a las penalizaciones. Pondremos un valor de 0.0 para aquellas recompensas o penalizaciones que no queramos utilizar durante el entrenamiento de esa fase en concreto.
Creación de nuevas tasks
He movido los pesos al archivo de configuración, pero eso no evita que tenga que modificar manualmente los pesos entre los entrenamientos de las distintas fases. Además, me resulta un poco complicado recordar qué pesos había utilizado anteriormente y he terminado anotándolo todo en un bloc de notas un poco chapucero, así que voy a intentar hacerlo un poco mejor.
Investigando un poco, he visto que se pueden crear distintas tasks. Esto permite lanzar entrenamientos utilizando configuraciones concretas.
Lo primero es crear una configuración por cada una de las fases que va a tener el entrenamiento. Estas configuraciones van a heredar de la configuración base que ya teníamos definida anteriormente:
Como se puede ver, he asignado los pesos que quiero que tengan las recompensas y penalizaciones en cada una de las fases. Además he añadido la variable phase que me ayudará posteriormente a parametrizar el entrenamiento en el archivo del env.
Después de crear estas configuraciones, tenemos que crear las tareas. Para ello hay que modificar el archivo source/SimpleRobot/SimpleRobot/tasks/direct/simplerobot/__init__.py:
Por defecto solo hay una task registrada, la copiamos y pegamos tantas veces como fases tengamos.
Cada task debe tener un nombre diferente, así que yo he identificado a cada una de ellas con el número de la fase del entrenamiento que quiero que lancen.
Por último, en cada task hay que cambiar el parámetro de configuración env_cfg_entry_point para hacerlo coincidir con el nombre de la configuración de la fase creada en simplerobot_env_cfg.py
Una vez hecho esto, podrémos lanzar los entrenamientos de la siguiente forma:
Para lanzar el entrenamiento de la Fase 1 con sus pesos de las recompensas y penalizaciones:
~/IsaacLab/isaaclab.sh -p ~/SimpleRobot/scripts/rsl_rl/train.py --task=Template-Simplerobot-Direct-Phase1-v0
Para lanzar el entrenamiento de la Fase 2 con los pesos de las recompensas y penalizaciones de la segunda fase, cargando además la política de un checkpoint de la Fase 1:
~/IsaacLab/isaaclab.sh -p ~/SimpleRobot/scripts/rsl_rl/train_mod.py --task=Template-Simplerobot-Direct-Phase2-v0 --load_policy <path_del_checkpoint>
Entrenamiento
Cambios en el simplerobot_env.py
simplerobot_env.pyCambios en _get_observations
_get_observationsLos cambios realizados en esta función ya han sido comentados anteriormente.
Cambios en _get_rewards
_get_rewardsHe cambiado cómo se calcula la penalización por no moverse a la velocidad indicada por el comando cuando este impone un valor de velocidad lineal. Ahora acoto el valor de la penalización entre 0 y 1, esto hace que sea más sencillo ajustar los pesos de las penalizaciones después.
En el aprendizaje por refuerzo, solo debemos aplicar una penalización cuando el comportamiento sea inequívocamente incorrecto. Si puede ser correcto en otro contexto, debemos condicionarlo para no introducir señales de aprendizaje contradictorias.
De la misma manera, he cambiado el cómo se calcula la penalización por moverse cuando no se recibe un comando de movimiento.
He agregado una nueva penalización por no girar cuando existe el comando indica una velocidad angular.
Y por último he ajustado el cálculo del reward final.
Cambios en _reset_idx
_reset_idxHe utilizado el parámetro phase de la configuración para decidir cómo he de resetear los comandos en función de la fase del entrenamiento que se esté ejecutando.
En la primera fase, todos los robots reciben un comando de velocidad lineal y angular nulo.
En la segunda fase, el 30% de los robots reciben un comando de velocidad lineal y angular nulo. El 70% restante reciben un comando de velocidad lineal de 0.3m/s y una velocidad angular nula. He cambiado la manera de asignar los valores respecto al entrenamiento de la Fase 2. Antes no eran el 30% de los robots, si no el 30% de las iteraciones las que tenian comandos de velocidad nulos. Ahora utilizo máscaras para, en la misma iteración, mezclar robots con comandos de velocidad nulos y robots con comandos de velocidad de 0.3m/s.
En la tercera fase, el 20% de los robots reciben un comando de velocidad lineal y angular nulo. Otro 20% recibe un comando de velocidad lineal acotado entre -1m/s y 1m/s y velocidad angular nula. El 60% restante recibe un comando de velocidad lineal acotado entre -1m/s y 1m/s y una velocidad angular de entre -1rad/s y 1rad/s.
Cambios en simplerobot_env_cfg.py
simplerobot_env_cfg.pyAdemás de los cambios de las configuraciones que he mencionado anteriormente, he agregado la configuración para la fase 3. También he incluido los parámetros max_lin_vel y max_yaw_vel para normalizar las penalizaciones. Y, por último, en todas las configuraciones he ajustado los pesos de las recompensas y penalizaciones, así como he incluido el peso para la penalización de yaw_penalty
Cambios en __init__.py
__init__.pyHe registrado una nueva task llamada Template-Simplerobot-Direct-Phase3-v0 para lanzar el entrenamiento de la Fase 3 con su configuración.
Entrenamiento Fase 1: Estabilización
Ya estamos listos para comenzar con el entrenamiento. Al igual que hice anteriormente, voy a entrenar la Fase 1 desde cero. Además, voy a prescindir de la interfaz gráfica para que el entrenamiento sea más rápido utilizando la flag --headless:
~/IsaacLab/isaaclab.sh -p ~/SimpleRobot/scripts/rsl_rl/train.py --task=Template-Simplerobot-Direct-Phase1-v0 --headless
Utilizando la herramienta Tensorboard, analizo cómo ha sido la evolución de la política durante el entrenamiento (ver Interpretación de resultados del entrenamiento):
Run: 2026-01-24_21-05-26

En las gráficas se puede ver claramente que tras aproximadamente 200 iteraciones la política parece haber encontrado una solución óptima alcanzando un máximo en la media de recompensas y en la duración del episodio. Por la pinta que tiene la gráfica, todo apunta a que ha encontrado el máximo y no parece que vayamos a conseguir una mejor solución por mucho que aumentemos el número de iteraciones del entrenamiento.
Voy a echar un ojo a la política del checkpoint 200 para ver si está bien:
~/IsaacLab/isaaclab.sh -p ~/SimpleRobot/scripts/rsl_rl/play.py --task=Template-Simplerobot-Direct-Phase1-v0 --checkpoint /home/angellm/logs/rsl_rl/simplerobot_direct/2026-01-24_21-05-26/model_200.pt

Visualmente puedo comprobar que el robot ha aprendido a mantener el equilibrio y no se cae. Es cierto que o se mantiene quieto en el sitio, pero dado que no hay ninguna recompensa por hacerlo ni existe tampoco ninguna penalización por moverse, es un comportamiento esperable. El robot ha aprendido a mantener el equilibrio mientras se desplaza despacio en una dirección.
Como el objetivo de esta fase es que el robot aprendiese a estabilizarse, lo damos por bueno y pasamos a la siguiente fase.
Entrenamiento Fase 2: Movimiento básico
Para este entrenamiento utilizaré los pesos de la política del paso anterior:
~/IsaacLab/isaaclab.sh -p ~/SimpleRobot/scripts/rsl_rl/train_mod.py --task=Template-Simplerobot-Direct-Phase2-v0 --load_policy /home/angellm/logs/rsl_rl/simplerobot_direct/2026-01-24_21-05-26/model_200.pt --max_iterations 5000 --headless
En este caso utilicé 5000 iteraciones porque con 1000 no llegué a una solución válida.
Run: 2026-01-24_21-09-10

En la gráfica de Train/mean_episode_length se puede ver que hacia la iteración 1000 se maximiza la duración de los episodios, pero la gráfica de Train/mean_reward muestra que no es hasta unas iteraciones después (hacia la 1500 aproximadamente) que no se llega a un punto alto de recompensa media.
Como parece que el máximo de recompensa se alcanza sobre la iteración 2000, voy a echarle un ojo al comportamiento de la política en ese checkpoint:
~/IsaacLab/isaaclab.sh -p ~/SimpleRobot/scripts/rsl_rl/play.py --task=Template-Simplerobot-Direct-Phase2-v0 --checkpoint ~/logs/rsl_rl/simplerobot_direct/2026-01-24_21-09-10/model_2000.pt

Además de comprobar visualmente que el robot se mueve cuando debe y se queda quieto cuando se le pide, he introducido un comando para visualizar el valor del comando enviado al robot 0, así como su valor de velocidad lineal (en las X+ de la base) y su velocidad angular (yaw):
Como el comportamiento es el adecuado, paso a la siguiente fase del entrenamiento:
Entrenamiento Fase 3: Movimiento avanzado
Al igual que antes, ejecutaré la task correspondiente a esta fase de entrenamiento y cargaré los pesos de la política anterior:
~/IsaacLab/isaaclab.sh -p ~/SimpleRobot/scripts/rsl_rl/train_mod.py --task=Template-Simplerobot-Direct-Phase3-v0 --load_policy /home/angellm/logs/rsl_rl/simplerobot_direct/2026-01-24_21-09-10/model_2000.pt --max_iterations 10000 --headless
En este caso, utilicé 10000 iteraciones porque ni con 1000 ni con 5000 logré llegar a una solución adecuada.
Run: 2026-01-24_21-59-22

En las gráficas podemos ver que cerca de la iteración 5000 se llega al máximo en duración de los episodios, y que aproximadamente a las 6000 iteraciones la política parece converger en una solución y se estabiliza la gráfica de recompensa.
Me llama la atención la pinta que tienen las gráficas, parecen un poco ruidosas. No sé si con un mejor diseño de las recompensas y penalizaciones hubiésemos obtenido un entrenamiento más directo. En cualquier caso, voy a revisar el comportamiento del último checkpoint, que en la gráfica parece ser el que más recompensa media tiene. Como lo que quiero es cargar el último checkpoint disponible del entrenamiento de la fase 3, basta con ejecutar:
~/IsaacLab/isaaclab.sh -p ~/SimpleRobot/scripts/rsl_rl/play.py --task=Template-Simplerobot-Direct-Phase3-v0
En el output de la consola saldrá una linea que nos confirmará qué checkpoint se ha cargado:

En la simulación observo que existen:
Robots en equilibrio estático
Robots que se mueven en linea recta sin girar
Robots que se mueven realizando curvas
Además, el output de la consola me permite comprobar que los robots están cumpliendo con las velocidades lineales y angulares comandadas.
Evaluación
La política entrenada se comporta como se espera. Se cumplen todos los objetivos marcados para esta fase.
¡Fase 3 completada con éxito!
Last updated