Semana 5 - Aerostack2 y pilotNet
Esta semana nos enfocamos en la simulación con Aerostack2 y en implementar nuestra primera red neuronal.
Index
Aerostack 2
Se cambió el launcher y en lugar de ejecutar todos los componentes de Aerostack2 en la misma terminal, se creó una sesión de Tmux para tener cada componente en una terminal por separado de una manera organizada. Sin embargo, al intentar lanzar todo con nuestra configuración previa del simulador, se notó que el drone no se conectaba.
Px4 autopilot
Investigando, descubrí que en el paquete de ejemplo se lanzaba el autopilot de px4 junto a Gazebo. Para probar si ese era el problema, creé un launcher que analizara los parámetros de world.json para que en “world” se especificara la ruta del mundo “ocean_simulation”, además de añadir el drone px4_dual_cam. Esto se ejecutaba mediante un script en la siguiente ubicación: ~/workspace/install/as2_gazebo_classic_assets/share/as2_gazebo_classic_assets/scripts. Sin embargo, el mundo se iniciaba vacío debido al siguiente error:
run_sitl.sh:
# Check if world file exist, else look for world
if [[ -f $world ]]; then
world_path="$world"
else
target="${world}.world"
world_path="$(get_path ${target} ${GAZEBO_RESOURCE_PATH})"
fi
# Check if world_path exist, else empty
if [[ -d $world_path ]]; then
world_path="${world_path}/${target}"
else
echo "empty world, setting empty.world as default"
world_path="${src_path}/Tools/simulation/gazebo-classic/sitl_gazebo/worlds/empty.world"
fi
Primero se verifica si $world es un archivo; si es así, se continúa con la parte del directorio. Sin embargo, al realizar la segunda comprobación con el parámetro -d, se verifica la existencia de un directorio. Dado que $world es un archivo, esta comprobación dará falso, lo que asignará la dirección a “empty.world” y resultará en el lanzamiento de un mundo vacío.
Si solo se proporciona el directorio, se añadirá solo “.world” a la ruta, lo cual será incorrecto.
Desde mi punto de vista, lo más sencillo es asegurarse de que se pase directamente el archivo “.world” al script, lo que simplificará la ejecución.
run_sitl.sh:
# Check if world file exist, else look for world
if [[ -f $world ]]; then
world_path="$world"
else
echo "empty world, setting empty.world as default"
world_path="${world_path}"
fi
Circuit launcher
Una vez resuelto esto, se logró lanzar la simulación del ejercicio “rescue people”, por lo que se preparó el lanzador para el circuito.
Problemas encontrados
-
No se consiguió pasar de formato LaunchConfiguration a String por lo que las constantes del launcher se declararon como globales.
-
El namespace de las cámaras del drone se cambiaba, esto era por que dependía de la variable de entorno $AEROSTACK2_SIMULATION_DRONE_ID por lo que se cambió en el executeProcess que lanza el simulador.
-
Al parsear las coordenadas de este mapa, el estado arm del dron tiende a fallar con mayor frecuencia, pero después de varios intentos automáticos, finalmente logra alcanzar el estado y comienza el despegue. La razón detrás de este comportamiento es desconocida.
Cerrar sesión tmux
Cada vez que realizaba una prueba, tenía que cerrar la sesión de Tmux ya que esta quedaba abierta. Intenté encontrar una forma de ejecutar comandos directos en el lanzador cuando se detectara Ctrl + C , pero no tuve éxito.
Sin embargo, encontré una forma de ejecutar un script de Python dentro del lanzador en el siguiente link. De esta manera, encontré una forma de llamar a un script al cerrar el simulador y así, cerrar todo el programa con un Ctrl+C. El script para cerrar la sesión se añadió a la carpeta “utils”.
Follow line launcher
Se creó un nodo que captura la imagen de la cámara frontal del dron y la filtra para detectar la línea. Luego, publica esta imagen en un topic. Posteriormente, el nodo de control del dron obtendrá esta imagen y comandará las velocidades, siguiendo un enfoque similar al ejercicio del coche. Sin embargo, la implementación de este último nodo se dejó pendiente para la semana siguiente.
PilotNet
Nuestro fue lograr entrenar el modelo PilotNet, el cual se estudió la semana pasada. Combinando la documentación de pytorch con el siguiente ejemplo de modelo, hicimos la primera implementación.
Redes convolucionales en pytorch:
Stride
Marca el desplazamiento del kernel.
Padding
Se añaden 0 al rededor del borde de la imagen.
Max poling
Reduce la cantidad de datos y preserva la información.
Stacking
Consiste en apilar imágenes después de la operación de convolución con varios filtros.
Función de activación ReLU
Función de activación no lineal donde la salida es 0 si la entrada es menor que 0 y si la entrada es mayor que cero se quedará su valor. g(x) = max(0, x)
Implementación con pyTorch
Modificando el código de ejemplo, logramos entrenar nuestra primera red neuronal. Además, debido a que el código estaba bien encapsulado, nos permitió realizar modificaciones de manera rápida. Dividimos el programa en una clase para los datos, otra para los modelos de red, una para el entrenamiento y otra para probar el funcionamiento o tests.
Train.py
- optim.SDG: Utiliza un algoritmo de descenso por gradiente estocástico. Los argumentos que recibe son:
- model.parameters: Donde se almacenan los pesos y sesgos de las capas de nuestra red neuronal.
- lr: Learning rate, determina cuanto se ajustan los pesos en cada iteración.
- momentum: Inercia del optimizador, ayuda acelerar la convergencia y suaviza el proceso de optimización.
- load_checkpoint: Nos permite cargar un modelo entrenado y continuar con su entrenamiento.
- MSELoss: Criterio de pérdida entre predicciones del modelo.
Model.py
Se realizaron cambios en las salidas de la red neuronal para que la última capa tuviera una dimensión de 2. Esto se hizo porque en el ejemplo que se usó (el del coche), se necesitan valores para la velocidad angular y la velocidad lineal. Además, se añadió la capa de normalización, para mejorar el entrenamiento y la estabilidad de la red.
Data.py
Obtenemos los datasets de las rosbags, como hicimos hace 2 semanas. Luego, aplicamos transformaciones a las imágenes y convertimos los datos en tensores para el entrenamiento.
Test.py
Se creó un programa básico para probar las predicciones. Debido a que el dataset era reducido y la mayoría de los ejemplos eran en línea recta, al examinar los valores de predicción se pudo observar que la red tenía dificultades cuando el robot tenía que girar. Esto se debía a que el dataset estaba desequilibrado, pero en última instancia, el dataset se utilizó únicamente para probar la red y no para una evaluación completa del rendimiento.
TensorBoard session
En la documentación de pytorch descubrí una herramienta que nos informa del estado del entrenamiento, aun no la investigué en profundidad pero podría ser una herramienta bastante útil.