Semana 31. Acercándonos a la meta
Las tareas de esta semana eran pocas, pero muy importantes, ya que casi estamos en la recta final del desarrollo de este proyecto, y éstas tareas son clave:
- Crear una función para parametrizar también el movimiento lateral (setL)
- Crear una función para parametrizar V y W al mismo tiempo, en lugar de en funciones separadas (setArc)
- Hacer que los movimientos de NAO sean totalmente fiables y demostrarlo cuantitativamente
- Crear el índice de la memoria del TFG e indicar qué quiero comentar en cada punto
- Pensar en la Aplicación GreenNao
Creación de la función setL
Comencé por la creación de esta función, ya que no era complicado, ólo era hacerlo igual que con setV y setW, pero con los ficheros dedicados a los movimeintos laterales, para que así, al pasar velocidad lateral positiva se desplazase hacia la derecha y si se le pasa negativa sea hacia la derecha.
Los valores límite en este caso con los mismos que para la velocidad lineal, ±0.35 y ±4.35:
Creación del índice de la memoria
Continué con esta tarea porque también era sencilla. Dejo a continuación lo que me gustaría contar resumidamente en cada punto de la memoria.
- Introducción: Comentar el auge de los robots humanoides y las dificultades que tienen para caminar (comparandolos con los robots con ruedas, el por qué son más utiles en algunas tareas, etc)
- Objetivos: En esta sección se comenta que queremos hacer una librería para hacer caminar a NAO en python, además de otras funciones para que el usuario no tenga que batallar con encontrar el modo de caminar y sea más fácil de usar el robot en general, además de poner un ejemplo de uso de esta librería para una aplicación en un invernadero
- Plataforma de desarrollo: Aquí se explicará que hemos utilizado ros2 humble, gazebo harmonic, python y todas las librerías y cosas necesarias para que el proyecto funcione
- GreenNao: Aquí se hace una breve introducción sobre todos los componentes que hay en juego (editor, intérprete, librería y aplicación final), para después explicarlos uno por uno en subsecciones, las cuales explican cómo se han hecho, cómo funcionan, etc.
- Conclusiones y trabajos futuros: Se explica si se han cumplido o no los objetivos, por qué, y se comentan posibles usos y mejoras a futuro del software del proyecto.
Este índice se basa en TFG’s de otros años.
En resumen, el índice quedaría más o menos de la siguiente forma:
1.Introducción
2.Objetivos
2.1. Problema
2.2. Soluciones planteadas
2.3. Objetivo final
3.Plataforma de desarrollo
3.1. Ros2 Humble Hawskbill
3.2. Gazebo Harmonic
3.3. Python
3.4. Github
3.4.1. Github pages
4.GreenNao
4.1. Editor de movimientos
4.2. Intérprete de movimientos
4.3. Librería GreenNaoLib
4.4. Aplicación GreenNao
5.Conclusiones y trabajos futuros
5.1. Conclusiones
5.2. Trabajos futuros
Cómo se puede ver, es bastante extenso y se abarcarán todas las cosas abordadas en este proyecto. Aunque, antes de llegar al índice, (sin contar la portada), sería bueno tener, al menos, una página de agradecimientos y otra que resuma el TFG íntegramente, pero sin llegar a detallar demasiado (eso es “trabajo” de la memoria cómo tal). También me gustaría poner tras la portada alguna frase célebre, ya que vi que varios compañeros de otros años en sus TFG’s lo hacían y me gustaba cómo quedaba.
Dejé escritos los agradecimientos y busqué la frase que quería poner para ahorrar ese tiempo en el futuro y pasé a la siguiente tarea:
Posibles aplicaciones para GreenNao
Esto también fue una tarea sencilla, ya que mi tutor mencionó que estaría bien que Nao levantase una caja, cosa que a mí me pareció una buena idea y sencilla para abordar con la librería, por lo que, en lugar de pensar aplicacines para GreenNao, detallaré posibles soluciones para esta tarea de llevar cajas.
Caja/Carrito
Para la caja, simplemente sería crear un cubo con adaptaciones para las manos de NAO, debido a que éste modelo en concreto no tiene dedos. Una buena solución para esto es una caja con pliegues o similar para que quede enganchada a las manos de NAO. También pensé, que para simplificar la aplicación, NAO empujase un carrito de frutas adaptado a su tamaño, cosa que comenté a mi tutor.
Al hacer la caja especial para NAO, no necesitaríamos visión para cogerla, pero sí para ver dónde está y llevarla a su destino, por lo que sería necesario ponerla de un color especial para detectarla por color y que sea más sencillo, lo mismo con la zona de destino.
Cómo la caja debe ser pequeña, habría que hacer que NAO se agache para cogerla y luego se levante con ella en las manos, cosa que me parecía algo complicada, por lo que pensé en dejarla sobre una pequeña mesa o similar para que sólo sea extender los brazos para cogerla, o, en el caso del carrito, sólo habría que colocarlo en algún sitio del mundo para que NAO lo empuje a su destino.
Este elemento del mundo sería fácilmente modelable en sdf directamente, ya que no tiene geometrías muy complicadas.
Idea Final: Caja
Al final, decidí decantarme por la caja por la simplicidad del diseño, ya que sólo era hacer cubos con links y joints directamente en el sdf del mundo, así que, me puse manos a la obra y conseguí la siguiente caja:
Que, cómo se puede ver, tiene la forma y el peso adecuados para que NAO la lleve, sin embargo, es necesario crear una funcion grab_box, para que nao la agarre con firmeza, de este modo, no se caerá cómo se ve en el video.
Para hacerlo cree un nuevo patrón para que la agarrase, una vez hecho esto, probé a hacer a NAO caminar con la caja en brazos
Movimientos fiables demostrados cuantitativamente
Para esto, lo primero que hice fue probar con el rozamiento conseguido la semana anterior, obteniendo los siguientes resultados en las gráficas de trayectoria recta:
Velocidad 0.5
Velocidad 1
Velocidad 2
Velocidad 4.35
Cómo se puede ver, el error respecto a la semana anterior es mejor, pero sigue sin ser del todo fiable, ya que las gráficas no tienen mucho sentido.
Por lo que decidí ver cómo andan otros NAO’s, más bien, cómo tienen colocados los brazos, ya que igual la raíz del problema es esta postura al caminar.
Repasandos vídeos que ya había visto, me di cuenta de que la mayoría de estos robots tenían los brazos hacia abajo, excepto los de la robocup, que mantenían sus brazon en la espalda.
Así que probé hacer que NAO andase con los brazos abajo, y obtuve lo siguiente:
Pero, como se puede ver, el resultado incluso empeora, así que decidí dejarlo como estaba al principio.
También proobé restablecer el peso original de lo spies, a ver si esque era problema de los pesos, pero me salía ell mismo resultado que de normal.
Así que probé incluir de nuevo el parámetro “min_depth”, mencionado en la entrada de blog anterior
Probé con un valor de 3, a ver qué tal funcionaba:
Cosa que mejoraba un poco el resultado, pero no demasiado.
Probé a subirlo a 10:
Cosa que mejoraba un poco los balanceos, pero se desviaba, como si se quedase enganchado en el suelo se forma extraña.
Por lo que probé bajarlo a 1:
Cosa que tampoco me convencía, por lo que decidí dejarlo sin este parámetro min_depth y continuar con otras pruebas.
La siguiente cosa que probé fue subir el rozamiento de los pies a 1.5 y dejar el del sueo a 1.0:
Cosa que funcionaba mejor que con el parametro depth, pero no era bueno
Así que probé a cambiarlo, el suelo a 1.5 y los pies a 1.0:
Cosa que era incluso peor.
Así que decidí probar a subir los rozamientos mucho, hasta 3.5:
Cosa que tampoco estaba bien, pero, decidí, por probar, en lugar de grabar la pantalla, grabarlo con mi teléfono, a ver si había alguna diferencia:
Dónde se ve mejoría, por lo que decidí garabar con el teléfono a partir de ahora, para que la grabación no consumiera recursos.
Probé a subir el rozamiento a 4.0 en pies y suelo:
Como se puede ver, el resultado ya está bastante bien. Por lo que procedí con la prueba de las gráficas de trayectoria:
Velocidad 1 (rozamiento 4)
Velocidad 0.5 (rozamiento 4)
Velocidad 2 (rozamiento 4)
Velocidad 4.35 (rozamiento 4)
Con lo que me quedé bastante satisfecha, ya que la desviación en y es mínima (0.09 la máxima) así que también decidí pasar a la siguiente tarea.
Creación de la función setArc
Para hacer esto, tenía que tener en cuenta la siguiente casuística:
- V != 0, W = 0: Caminaremos recto
- V != 0, W != 0: Caminaremos en arco
- V = 0, W != 0: Rotaremos en el sitio
Por lo que, con las funciones que tenía ya implementadas (setV, setW y turn), podría hacer la función setArc de la siguiente forma (en pseudocódigo):
if V != 0, W == 0:
setV(V, pasos)
elif V != 0, W != 0:
setW(W, pasos)
elif V == 0, W != 0:
for i in pasos:
turn(degrees)
elif v == 0 and w == 0:
stand_still()
else:
print("ERROR: Patrón de movimiento no válido")
sys.exit(1)
Así que, me puse manos a la obra, y, al terminar, obtuve el siguiente resultado:
Pero… nos faltaba algo. Y esto era la capacidad de poder hacer los arcos hacia atrás, al pasar un V negativa y una W distinta de 0.
También me di cuenta de que faltaba definir una velocidad para cuando girase en el sitio, ya que no la tenía parametrizada, así que me puse con ello también. Cuando lo conseguí, tuve lo siguiente:
Después, para la V negativa, tuve que crear un nuevo patrón, setNW, que se encargaba de esto de los arcos “negativos”, y, así, la función setArc la llamaría en su correspondiente caso (en pseudocódigo):
def setArc(v,w,steps = 10):
if v != 0, w == 0:
setV(v, steps)
elif v != 0, w != 0:
if v > 0:
setW(w, steps)
else:
setNW(w, steps)
elif v == 0, w != 0:
for i in steps/10:
if w < 0:
turn("L", 60)
else:
turn("R", 60)
elif v == 0 and w == 0:
stand_still()
else:
print("ERROR: Patrón de movimiento no válido")
sys.exit(1)
Para que se entienda mejor que trayectoria seguirá NAO dependiendo de los valores pasados a setArc, dejo el siguiente esquema aquí:
Una vez conseguido este nuevo patrón, obtuve el siguiente resultado (solo pongo este porque los otros movimientos ya se vieron en el anterior video):
Los arcos hacia atrás y a la derecha son algo inestables, pero cabe destacar que estaba grabando pantalla, cuando no se graba funciona correctamente.
EXTRA 1: Arreglando la abstracción de rclpy
Al intentar ejecutar una prueba, me dejó de funcionar lo que hice la semana anterior de rlcpy.init() y rclpy.shutdown(), por lo que, me informé un poco, y lo solucioné añadiendo estas 2 lineas de código al inicio de la librería GreenNaoLib:
import atexit
rclpy.init()
atexit.register(rclpy.shutdown)
Esto hace que se ejecute rclpy.init() al llamar a la librería y a rclpy.shutdown() al terminar el programa principal. Tras unas pruebas, funcionó correctamente
EXTRA 2: Abstrayendo el launcher de la simulación
Ya que tratabámos de abstraer al máximo ros2 para que el usuario no tenga que preocuparse por él, se me ocurrió encapsular también el lanzamiento del simulador en un script de bash, para que sólo sea ejecutarlo sin precuparse de escribir el comando:
#!/bin/bash
ros2 launch greennao launcher.launch.py
Parece un script tonto, pero ahorra tiempo al escribirlo, y es más sencillo para el usuario, ya que simplemente es escribir ruta_al_script/launch.sh y ya se lanza el simulador:
Como se puede ver, todo funciona con normalidad (exceptuando que NAO se ha caído, pero eso no importa para demostrar que el lanzador funciona)
EXTRA 3: Dando un formato a los logs
Para que los mesajes impresos por pantalla quedasen más limpios, les puse el siguiente formato:
[función] Mensaje
Así el usuario sabrá en todo momento qué funciones han tenido éxito y cuáles fallo, en lugar de utilizar el mensaje de get_logger, que me parecía menos estético y más compicado de manejar, ya que en la libreria hay muchas funciones que se llaman unas a otras, por lo que podían salir varios logs a la vez, por ejemplo, en los patrones fijos, salía el log del intérprete incluso varias veces, y eso no me gustaba. Simplemente una cuestión estética.
EXTRA 4: Actualizando README.md
Como ya había avanzado bastante y ahbí muchas cosas nuevas en el proyecto, actualicé el README.md al respecto para que estuviera al día.