Robótica

Clase 04

Semana 5 - 14/04/2025

Resumen Clase 03

Workspace y paquetes de ROS

Archivos mínimos

📂 src
  📁 nombre_paquete
      📁 nombre_paquete
          📄 __init__.py
          📄 nodo_A.py      ⬅️ Código
          ...                 
      📁 resource
          📄 nombre_paquete
      📄 package.xml
      📄 setup.cfg
      📄 setup.py

Resumen Clase 03

rclpy: Partes básicas del programa

  1. Inicialización

     rclpy.init(..)
  2. Creación de 1 o más nodos

     rclpy.create_node(..)
  3. Procesamiento de callbacks (spinning)

     rclpy.spin(..)
  4. Apagado / finalización (shutdown)

     rclpy.shutdown()

Resumen Clase 03

Gestión de nodos

  • Crear un publisher: node.create_publisher(..)
  • Crear un suscriber: node.create_subscription(..)
  • Timer: node.create_timer(..)
  • Log: node.get_logger(..)

Callbacks

Acción que se ejecuta automáticamente al ocurrir un evento

Función de callback

Función que se le da a un sistema para que ejecute al ocurrir un evento

Permite al programa:

  • No detenerse esperando al evento
  • Ejecute la acción solo cuando es necesario
  • Pueda ejecutar otras tareas

Analogía “compra online”

sequenceDiagram
    participant Cliente
    participant Tienda Online
    participant Repartidor

    Cliente->>Tienda Online: Hace un pedido 📦
    %% Cliente-->>Cliente: Sigue con su día
    Note left of Cliente: Sigue con su día
    Tienda Online->>Repartidor: Despacha el paquete
    Repartidor-->>Cliente: Notificación de entrega

Analogía “compra online”

sequenceDiagram
    participant Cliente
    participant Tienda Online
    participant Repartidor

    Cliente->>Tienda Online: Hace un pedido 📦
    %% Cliente-->>Cliente: Sigue con su día
    Note left of Cliente: Sigue con su día
    Tienda Online->>Repartidor: Despacha el paquete
    Repartidor-->>Cliente: Notificación de entrega

Cliente ➡️ Nodo que espera datos
Pedido en la tienda ➡️ Suscripción a un topic
El nodo sigue ejecutando tareas
Tienda despacha el paquete ➡️ Publicador envía un mensaje
Notificación y entrega ➡️ Se activa la función callback

Aplicación en ROS

Ejemplo de nodo publisher

Código de publisher

import rclpy
from std_msgs.msg import String

def main(args=None):
    # 1. Inicialización
    rclpy.init(args=args)

    # 2. Creación de nodo
    nodo = rclpy.create_node('publicador')

    # 2.1 Creación de publisher
    pub = nodo.create_publisher(String, 'chat', 10)

    # 2.2 Programación de función de callback
    def timer_callback():
        # Creación de mensaje
        msg = String()
        # Completar el campo 'data' del mensaje 
        msg.data = 'Mensaje de prueba'

        # Publicar el mensaje
        pub.publish(msg)

    # 2.3 Creación del timer
    timer = nodo.create_timer(1, timer_callback)

    # 3. Procesamiento de mensajes y callback
    rclpy.spin(nodo)

    # 4. Finalización 
    rclpy.shutdown()


if __name__ == '__main__':
    main()

Uso de nombres

Uso de nombres

Nombres para:

  • Paquete
  • Archivo
  • Ejecutable
  • Nodo

Uso de nombres

Paquete

📂 src
  📁 nombre_paquete
      📁 nombre_paquete
          📄 __init__.py
          📄 codigo.py
          ...                   
    📁 resource
        📄 nombre_paquete
    📄 package.xml
    📄 setup.cfg
    📄 setup.py

Uso de nombres

Archivo

📂 src
  📁 nombre_paquete
      📁 nombre_paquete
          📄 __init__.py
          📄 codigo.py
          ...                   
    📁 resource
        📄 nombre_paquete
    📄 package.xml
    📄 setup.cfg
    📄 setup.py

Uso de nombres

Paquete

package.xml
<package format="3">
    <name>{nombre_paquete}</name>
    <version>{version}</version>
    <description>
        {descripcion}
        ...
    </description>
    ...
</package>

Uso de nombres

Paquete

setup.cfg
[develop]
script_dir=$base/lib/{nombre_paquete}
[install]
install_scripts=$base/lib/{nombre_paquete}

Uso de nombres

Paquete

setup.py
from setuptools import setup

setup(
    name={nombre_paquete},
    version={version},
    description={descripción},
    ...
    packages=[{nombre_paquete}],
    data_files=[
        ('share/ament_index/resource_index/packages', ['resource/{nombre_paquete}’]),
        ('share/{nombre_paquete}’, ['package.xml']),
    ],
    ...
    entry_points={
        'console_scripts': [
            '{nombre_ejecutable} = {nombre_paquete}.{nombre_archivo}:main'
        ],
    },
)

Uso de nombres

Ejecutable, paquete, archivo

setup.py
from setuptools import setup

setup(
    name={nombre_paquete},
    version={version},
    description={descripción},
    ...
    packages=[{nombre_paquete}],
    data_files=[
        ('share/ament_index/resource_index/packages', ['resource/{nombre_paquete}’]),
        ('share/{nombre_paquete}’, ['package.xml']),
    ],
    ...
    entry_points={
        'console_scripts': [
            '{nombre_ejecutable} = {nombre_paquete}.{nombre_archivo}:main'
        ],
    },
)

Uso de nombres

Nodo

codigo.py
def main(args=None):
  # 1. Inicialización
  rclpy.init(args=args)

  # 2. Creación de nodo
  node = rclpy.create_node({nombre_nodo})

  # 3. Procesamiento de callback
  rclpy.spin(node)

  # 4. Finalización
  rclpy.shutdown()

if __name__ == '__main__':
  main()

Dependencias, ejecutables y compilación

Dependencias

Código fuente de un nodo

import rclpy
from std_msgs.msg import String


Se refleja en las dependencias en package.xml

...
    <exec_depend>rclpy</exec_depend>
    <exec_depend>std_msgs</exec_depend>
...

Dependencias

Tipos de dependencias:

  • <build_depend>: compilación
  • <exec_depend>: ejecución
  • <depend>: compilación y ejecución
  • <test_depend>: solo para pruebas

Administración via rosdep

    rosdep install -i --from-path src --rosdistro jazzy -y

Ejecutables y compilación

Añadir un ejecutable en setup.py

...
entry_points={
    'console_scripts': [
        '{nombre_ejecutable} = {nombre_paquete}.{nombre_archivo}:main',
    ],
},
...


Compilar

    colcon build [--symlink-install] [--packages-select <nombre_paquete>]

Laboratorio (parte 2)

  • Creación de paquetes
  • Programación y compilación de nodos