- CoordMoves: Directorio dónde se encuentra todo el desarrollo del proyecto final
- docs: Directorio dónde se sostiene el blog del proyecto
- pruebas: Directorio dónde se han hecho pruebas y se ha preparado el proyecto antes de construirlo
- .gitignore: Fichero que indica a git qué otros ficheros no deben subirse al repositorio
- README.md: ¡Fichero que estás leyendo ahora mismo! Contiene un resumen de lo que trata el proyecto, cómo funciona, etc
Este trabajo de fin de grado consiste en construir una aplicación para convertir al robot NAO de Aldebaran Robotics en un robot de servicio. Para ello, ha sido necesario crear patrones de movimiento para que pueda operar correctamente, estos son:
- Caminar recto hacia adelante y hacia atrás
- Girar en el sitio ya sea a la derecha o la izquierda
- Desplazarse lateralmente hacia la izquierda o derecha
- Levantarse si se cae boca arriba
- Levantarse si se cae boca abajo
- Caminar en arco hacia la derecha y la izquierda
- Caminar en arco hacia atrás a derecha e izquierda
- Coger una caja
- Dejar uuna caja
Después, para la aplicación de servicios se ha decidido hacer que nuestro pequeño NAO eche una mano en un invernadero, el cual ha sido modelado por mí para funcionar en gazebo, además de un nuevo aspecto para el robot.
Para que este TFG funcione correctamente, se necesita:
- Ubuntu 22.04
- Ros2 humble
- Gazebo Harmonic (versión 8.9.0)
- Todas las dependencias necesarias para comunicar ros y gazebo
- ros-gz-sim
- ros-humble-ros-gz-bridge
- Todas las librerías necesarias para python
- Pybullet
- numpy
- sys
- csv
- json
- time
- atexit
- rclpy
- std_msgs
- sensor_msgs
Cómo ya se ha explicado en la introducción de este README.md, este trabajo de fin de grado se compone de 2 pilares, los cuáles se explicarán corta, pero detalladamente a continuación, aunque, si quieres una explicación totalmente detallada de este TFG, puedes leer la memoria asociada a él aquí:
El movimento del NAO se da de manera sencilla publicando posiciones en sus topics, cada uno un grado de libertad del propio robot, con un total de 24:
A continuación dejo un esquema dónde se ve claramente de qué movimiento se encarga cada topic:
Como se puede intuir, aunque el movimiento esté tan "controlado", es decir, que tengamos tantos grados de libertad para poder hacer los movimientos que veamos oportunos, no es sencillo publicar números a cada una de las articulaciones por separado y ver qué ocurre, por lo que para este proyecto se desarrolló un editor de movimientos, el cuál está basado en la siguiente demo de gazebo harmonic:
Esta demo simplemente es para que veamos cómo se mueve NAO, pero, como se puede ver, el robot está anclado en el aire, por lo que no podemos ver si los movimientos son efectivos o no. Es por eso que para este proyecto se ha desarrollado el editor de movimientos, nao_movement_pattern_creator.py, que hace lo mismo que la demo, pero, además de eso, el robot no está anclado al suelo, para que se pueda ver el impacto del movimiento a realizar y, además, da la opción de guardar patrones de movimiento en un fichero .json, diciendo: "quiero esta posicion en este tiempo". Adjunto un vídeo de su funcionamiento para que se entienda mejor, cabe destacar que el NAO cae para dar a entender que hay movimiento:
Pero, ¿qué tiene que ver esto con ROS2 y Gazebo? Nada.
Es por eso que además de este editor de movimentos ha sido necesario crear un nodo ROS2 capaz de interpretar esos ficheros .json, que tienen la secuencia dentro, para luego enviar esa secuencia al robot simulado en gazebo. Dejo aquí otro vídeo para que se vea el funcionamiento de este intérprete:
Una vez conseguido el intérprete, podíamos pasar a tareas más complejas, cómo la caminata, la cual se divide en varias partes:
- Caminata recta hacia adelante
- Caminata recta hacia atrás
- Caminata en arco hacia la derecha
- Caminata en arco hacia la izquierda
- Caminata lateral hacia la derecha
- Caminata lateral hacia la izquierda
Que, por suerte, todas, excepto la 3 y la 4 (las cuales fueron desarrolladas combinando distintos patrones), son proporcionadas por el simulador webots (enlace al final de este README.md), pero, en lugar de en formato json, cómo nosotros trabajamos, están en formato motion, un formato idéntico a csv, exceptuando la extensión, así que, una vez cambiados a csv, pueden ser interpretados por el intérprete, ya que no sólo es capaz de interpretar ficheros json, también puede interpretar ficheros csv.
Además de la caminata, es necesario que NAO esté preparado para posibles caídas, esto significa:
- Debe ser capaz de levantarse desde cúbito supino (boca arriba)
- Debe ser capaz de levantarse desde cúbito prono (boca abajo)
El punto 2 también nos lo da resuelto webots, sin embargo, el punto 1 tuvo que ser desarrollado a mano utilizando el editor de movimientos mencionado anteriormente, para ello, lo que hace es primero darse la vuelta, para poder llamar al patrón de webots, y así aprovechar el fichero para ambos movimientos.
Cabe destacar también que nuestro NAO cuenta con un sensor IMU, para así poder detectar si ha caído, y una cámara.
Cómo se ha leído en la sección anterior, nuestro NAO es capaz de hacer muchas cosas, pero, ¿qué es lo que necesita una aplicación robótica útil? Ser fácil de usar, por lo que todo el esquema de movimientos relacionado con ros2 (interpretar los patrones, leer sensores, etc.), es realizable desde un sencillo programa en python como el siguiente:
import CoordMovesLib
orientation = CoordMovesLib.get_face() # Gracias a lecturas de IMU, sabemos si hemos caído y de que forma
if orientation == "face normal":
CoordMovesLib.stand_still()
elif orientation == "face up":
CoordMovesLib.wakeup_face_up()
elif orientation == "face down":
CoordMovesLib.wakeup_face_down()
else:
print("ERROR: No puedo levantarme")
sys.exit(1)
Para hacer esto posible, ha sido necesario desarrollar la librería CoordMovesLib, la cual se encarga de todo lo mencionado anteriormente. Aunque, para poder usarla, es necesario tener todas las dependencias instaladas, y, obviamente, tener lanzada la simulación, además de configurado un paquete de ROS2 que contenga la librería, y respetar las rutas, ya que, al depender de ficheros, son muy importantes.
A continuación, dejo una lista con todas las funciones y clases de esta librería, junto a una breve explicación de cada una de ellas:
CLASES
- Interpreter_class(file): Llama al intérprete de movimientos mencionado anteriormente
- setV_class(linear_velocity, steps): Hace que NAO ande recto, a la velocidad indicada, los pasos indicados
- setW_class(angular_velocity, steps): Hace que NAO camine en arco, a la velocidad indicada, los pasos indicados
- setNW_class(angular_velocity, steps): Hace que NAO camine en arco hacia atrás, a la velocidad indicada, los pasos indicados
- setL_class(angular_velocity, steps): Hace que NAO camine lateralmente, a la velocidad indicada, los pasos indicados
- Read_IMU(): Devuelve la aceleración en z leyendo las mediciones del IMU
FUNCIONES
- get_face(): Devuelve si NAO esta boca arriba, boca abajo, de pie normal o error si no está de ninguna de esas formas
- wakeup_face_down(): Hace que Nao se levante desde cubito prono
- wakeup_face_up(): Hace que Nao se levante desde cubito supino
- stand_still(): Hace que Nao se quede en la posición estándar, de estar quieto
- say_hi(hand): Hace que Nao salude con la mano que se le pasa como argumento
- turn(side, degrees): Hace que Nao gire en el sentido que se le pasa como primer argumento, los grados que se le pasan como segundo argumento
- grab_box(): Hace que NAO recoja la caja
- release_box(): Hace que NAO suelte la caja
- setArc(linear_velocity, angular_velocity, steps): Combina las clases encargadas de las caminatas para que no haya que llamarlas por separado y hacer andar a NAO sea más sencillo.
- Interpreter(file): Llama a la clase del intérprete, para poder ejecutar correctamente el nodo ROS2
- setV(linear_velocity, steps): Llama a la clase de caminar recto, para poder ejecutar correctamente el nodo ROS2
- setW(angular_velocity, steps): Llama a la clase de caminar en arco, para poder ejecutar correctamente el nodo ROS2
- setNW(angular_velocity, steps): Llama a la clase de camniar en arco hacia atrás, para poder ejecutar correctamente el nodo ROS2
- setL(angular_velocity, steps): Llama a la clase de camimar lateralmente, para poder ejecutar correctamente el nodo ROS2
Además de ofrecer la encapsulación necesaria para poder mover a NAO de forma cómoda, disponemos también de los modos de caminar mencionados anteriormente, pero, con una particularidad: El movimiento de caminata recto y el de caminata en arco han sido parametrizados. Esto es, disponemos de V (velocidad lineal), W (velocidad angular), L (velocidad lateral) y una combinación de V y W para no tener que llamar a 2 clases por separado. Dependiendo de la clase, se tiene un número mínimo de 10 o 2 pasos, esto se indicará en este fichero README.md con un * en su nombre en caso de ser 10, y con un ^ en caso de ser 2.
La velocidad lineal puede ser positiva (andar hacia adelante), o negativa (andar hacia atrás) y tiene un valor mínimo (-0.35 ó 0.35) y un valor máximo (4.35 ó -4.35), de este modo, a mayor valor abosoluto, más rápido se moverá nuestro robot, siguiendo este esquema:
De igual modo que con la velocidad lineal, tenemos la angular, que puede ser positiva (giro a la derecha) o negativa (giro a la izquierda), y sus valores límite son 0.35 y -0.35 para el mínimo, y 1.9 y -1.9 para el máximo.
También tenemos setNW, que hace lo mismo, pero el arco es hacia atrás.
Esta clase es igual que la anterior, pero los arcos se describen hacia atrás.
De igual modo que con la velocidad lineal y la angular, tenemos la lateral, que puede ser positiva (hacia la derecha) o negativa (hacia la izquierda), y sus valores límite son los mismos que para la velocidad lineal.
Esta clase sirve para que NAO gire en el sitio, a izquierda (velocidad negativa) o derecha (velocidad positiva). Sus valores línme son los mismos que la clase setW.
Para encapsular las velocidades lineal y angular, está la clase setArc, para que llamar a la caminata sea más sencillo y directo. Se le pasan por argumento la velocidad lineal, la angular, y los pasos que queremos que NAO dé, y NAO seguirá el siguiente esquema dependiendo de qué valores le pasemos, adjunto un esquema para que se entienda mejor:
Ésta es la función que se debería usar para abordar todos los modos de caminar posibles de manera compacta, ya que dependiendo de los parámetros que se le pasan, llama a uno u otro.
Utilizando la librería explicada anteriormente, se ha desarrollado una aplicación para NAO que consiste en llevar una caja adaptada a él de un lugar del invernadero a otro.
Para hacerlo, primero se ha diseñado dicha caja, ya que el modelo del NAO utilizado para este proyecto no tiene dedos, y era necesario asegurar la caja de alguna forma, por lo que se ha optado por este diseño:
Ya que es un tamaño adecuado para el robot y hace que no precise de dedos, lo que es una ventaja porque el modelo utilizado tiene las manos sin dedos.
También cabe destacar que la misión de NAO es recoger la caja de una mesa azul (también adecuada a su tamaño) y llevarla hasta una mesa naranja (igual que la azul en cuanto a dimensiones) y dejarla allí.
Para cumplir esta tarea, existen en la librería las funciones grab_box y release_box, que son las encargadas de coger y dejar la caja, respectivamente.
Como se puede apreciar en la imagen del mundo, la tarea es sencilla, ya que NAO simplemente debe recoger la caja, darse la vuelta, ir hasta la mesa naranja y dejarla.
Para que se aprecie la potencia de la librería desarrollada, se adjunta a continuación el código de esta aplicación:
import CoordMovesLib
import time
time.sleep(5)
CoordMovesLib.grab_box()
time.sleep(3)
for i in range(3):
CoordMovesLib.turn("L", 60)
CoordMovesLib.turn("L", 40)
CoordMovesLib.setArc(1, 0)
time.sleep(3)
CoordMovesLib.release_box()
print("Terminado")
Gracias a la integración de ambas partes anteriormente explicadas, se ha conseguido el siguiente resultado:
Que, cómo se puede ver satisface el objetivo propuesto en la sección anterior.
Si te interesa saber cómo se ha ido desarrollando este proyecto, puedes visitar su blog en el que se describen los progresos del desarrollo por semanas, desde su inicio, hasta su fin.
Para poder llevar a cabo este proyecto se han visitado los siguientes enlaces:
- Modelo de NAO utilizado
- Creación de un paquete ros2 python
- Urdf de NAO
- Información sobre el plugin de movimiento de joints de gazebo
- Correspondencia de mensajes entre gazebo y ros2 humble
- Tutorial de ros-gz-bridge
- NAO real caminando
- NAO real levantándose si cae boca arriba
- NAO real levantándose si cae boca abajo
- Otro NAO real caminando
- Partido de fútbol con NAOS para la RoboCup 2018
- Tutorial para crear un mundo personalizado en gazebo
- Documentación sobre caminatas de Aldebaran
- Página oificial de NAO
- Enlace de descarga para el simulador Webots
- Ejemplo de publicador y suscriptor para ros2 humble en python
- Tutorial de como usar tus programas como librería para un nodo ros2
- Geogebra (usado para un par de gráficas)
- Parámetros físicos en Gazebo explicados
- Paper de Georgios Pierris y Michail G. Lagoudakis para el editor de movimientos
- Paper de 2011 IEEE International Conference on Control System, Computing and Engineering para el editor de movimientos
- Artículo sobre robots humanoides