Implementación de Comunicación por Servicios ROS en Python

Comunicación por Servicios en ROS - Implementación Práctica con Python

ROS proporciona tres mecanismos principais de comunicación: comunicación por temas (topics), comunicación por servicios (services) y el servidor de parámetros (paramter server). Este artículo se centra específicamente en la implementación práctica del mecanismo de comunicación por servicios utilizando Python.

Requisitos Previos

Antes de implementar la comunicación por servicios, es necesario haber preparado el formato de datos srv personalizado. Para más información sobre cómo crear y configurar archivos srv personalizados, consulte la documentación sobre srv personalizados en ROS.

En la implementación del modelo de servicio, el ROS Master no requiere implementación explícita, ya que el establecimiento de conexiones está encapsulado. Los elementos fundamentales que debemos gestionar son:

  • Proveedor de servicio (Server): Procesa las solicitudes y genera respuestas
  • Solicitante de servicio (Client): Envía solicitudes y procesa respuestas
  • Datos: Estructura definida por el archivo srv

Fases de Implementación

La implementación del mecanismo de comunicación por servicios en ROS sigue estos cinco pasos:

  1. Configuración del entorno de desarrollo
  2. Desarrollo del proveedor de servicio
  3. Desarrollo del solicitante de servicio
  4. Configuración de archivos de compilación
  5. Compilación y ejecución

Configuración del Entorno

Para mejorar la experiencia de desarrollo y obtener autocompletado de código, es necesario configurar el archivo settings.json de VSCode incluyendo la ruta donde se generan los archivos Python del paquete srv personalizado.

Implementación del Proveedor de Servicio

Flujo de Trabajo

El proveedor de servicio sigue este patrón de implementación:

  1. Importación de paquetes necesarios
  2. Inicialización del nodo ROS
  3. Creación del objeto servidor
  4. Definición de la lógica de procesamiento (función de callback)
  5. Ejecución del bucle principal con spin()

Código de Implementación

#! /usr/bin/env python3

import rospy
from mi_paquete_servicio.srv import OperacionMatematica, OperacionMatematicaRequest, OperacionMatematicaResponse

"""
Proveedor de servicio que procesa solicitudes y genera respuestas.
    1. Importar paquetes necesarios
    2. Inicializar el nodo ROS
    3. Crear el objeto servidor
    4. Definir lógica de procesamiento (callback)
    5. Ejecutar spin()
"""

def procesar_solicitud(peticion):
    """Funcióncallback que procesa la solicitud del cliente"""
    valor_a = peticion.valor_a
    valor_b = peticion.valor_b
    
    # Lógica de procesamiento: suma de dos números
    resultado = valor_a + valor_b
    
    # Crear y configurar la respuesta
    respuesta = OperacionMatematicaResponse()
    respuesta.resultado = resultado
    
    rospy.loginfo("Servidor接受了请求: valor_a = %d, valor_b = %d, 结果 = %d", 
                  valor_a, valor_b, resultado)
    return respuesta


if __name__ == "__main__":
    # Inicializar el nodo ROS con un nombre único
    rospy.init_node("servidor_operaciones")
    
    # Crear el objeto servidor
    # Parámetro 1: nombre del servicio
    # Parámetro 2: tipo de mensaje del servicio
    # Parámetro 3: función callback
    servidor = rospy.Service("operacion_matematica", OperacionMatematica, procesar_solicitud)
    
    rospy.loginfo("El servidor de servicio ha iniciado correctamente")
    
    # Mantener el servidor en ejecución
    rospy.spin()

Configuración de Permisos de Ejecución

Es necesario otorgar permisos de ejecución al archivo del servidor. Desde el directorio scripts, ejecute en la terminal:

chmod +x demo_server.py

Configuración CMakeLists.txt

Modifique el archivo CMakeLists.txt del paquete para configurrar la instalación de scripts Python. Localice la sección catkin_install_python y configúrela según sea necesario.

Verificación del Servidor

Para verificar el funcionamiento correcto:

  1. Ejecute roscore en una terminal
  2. En otra terminal, ejecute source ./devel/setup.bash y luego rosrun mi_paquete_servicio demo_server.py
  3. En una tercera terminal, pruebe el servicio con: rosservice call operacion_matematica "valor_a: 5 valor_b: 3"

Implementación del Solicitante de Servicio

Flujo de Trabajo

El solicitante de servicio sigue este patrón:

  1. Importación de paquetes necesarios
  2. Inicialización del nodo ROS
  3. Creación del objeto cliente
  4. Preparación y envío de datos de solicitud
  5. Procesamiento de la respuesta

Código de Implementación

#! /usr/bin/env python3

import rospy
from mi_paquete_servicio.srv import OperacionMatematica, OperacionMatematicaRequest, OperacionMatematicaResponse

"""
Solicitante de servicio que envía solicitudes y procesa respuestas.
    1. Importar paquetes necesarios
    2. Inicializar el nodo ROS
    3. Crear el objeto cliente
    4. Preparar datos de solicitud y enviarlos
    5. Procesar la respuesta
"""

if __name__ == "__main__":
    # Inicializar el nodo ROS
    rospy.init_node("cliente_operaciones")
    
    # Crear el objeto cliente para llamar al servicio
    # Parámetro 1: nombre del servicio
    # Parámetro 2: tipo de mensaje del servicio
    cliente = rospy.ServiceProxy("operacion_matematica", OperacionMatematica)
    
    # Preparar datos de solicitud
    numero_x = 25
    numero_y = 17
    
    # Enviar solicitud y obtener respuesta
    respuesta = cliente.call(numero_x, numero_y)
    
    # Procesar y mostrar la respuesta
    rospy.loginfo("La respuesta recibida es: %d", respuesta.resultado)

Configuración de Permisos

Otorgue permisos de ejecución al archivo del cliente:

chmod +x demo_client.py

Compilación y Ejecución

Proceso de Compilación

Utilice el atajo de teclado Ctrl + Shift + B para compilar el proyecto.

Ejecución de los Componentes

Para ejecutar la aplicación completa:

  1. Paso 1: Inicie roscore en una terminal
  2. Paso 2: En una nueva terminal, ejecute el servidor: rosrun mi_paquete_servicio demo_server.py
  3. Paso 3: En otra terminal, ejecute el cliente: rosrun mi_paquete_servicio demo_client.py

Mejoras y Optimizaciones

Parámetros Dinámicos

Para permitir la entrada dinámica de parámetros desde la línea de comandos, modifique el código del cliente:

#! /usr/bin/env python3

import rospy
from mi_paquete_servicio.srv import OperacionMatematica, OperacionMatematicaRequest, OperacionMatematicaResponse
import sys

"""
Cliente con soporte para parámetros dinámicos desde línea de comandos.
Formato: rosrun paquete cliente valor_a valor_b
"""

if __name__ == "__main__":
    # Validar número de argumentos recibidos
    if len(sys.argv) != 3:
        rospy.loginfo("Número incorrecto de argumentos. Uso: valor_a valor_b")
        sys.exit(1)
    
    # Inicializar el nodo ROS
    rospy.init_node("cliente_operaciones")
    
    # Crear objeto cliente
    cliente = rospy.ServiceProxy("operacion_matematica", OperacionMatematica)
    
    # Parsear argumentos de línea de comandos
    argumento_1 = int(sys.argv[1])
    argumento_2 = int(sys.argv[2])
    
    # Enviar solicitud con parámetros dinámicos
    respuesta = cliente.call(argumento_1, argumento_2)
    
    # Mostrar resultado
    rospy.loginfo("El resultado de %d + %d es: %d", 
                  argumento_1, argumento_2, respuesta.resultado)

Después de compilar, ejecute:

rosrun mi_paquete_servicio demo_client.py 10 20

Manejo de Inicio Anticipado del Cliente

Si el cliente se inicia antes que el servidor, se producirá una excepción. Para manejar esta situación, podemos implementar una espera activa utilizando las funciones integradas de ROS:

#! /usr/bin/env python3

import rospy
from mi_paquete_servicio.srv import OperacionMatematica, OperacionMatematicaRequest, OperacionMatematicaResponse
import sys

"""
Cliente con espera activa del servidor.
Si el servidor no está disponible, el cliente espera hasta que esté disponible.
"""

if __name__ == "__main__":
    # Validar argumentos
    if len(sys.argv) != 3:
        rospy.loginfo("Argumentos inválidos. Uso: valor_a valor_b")
        sys.exit(1)
    
    # Inicializar nodo
    rospy.init_node("cliente_operaciones")
    
    # Crear cliente
    cliente = rospy.ServiceProxy("operacion_matematica", OperacionMatematica)
    rospy.loginfo("Cliente iniciado, esperando servidor...")
    
    # Parsear argumentos
    parametro_x = int(sys.argv[1])
    parametro_y = int(sys.argv[2])
    
    # Esperar a que el servicio esté disponible
    # Método 1: cliente.wait_for_service()
    # Método 2: rospy.wait_for_service("nombre_servicio")
    rospy.wait_for_service("operacion_matematica")
    
    # Enviar solicitud
    respuesta = cliente.call(parametro_x, parametro_y)
    
    # Procesar respuesta
    rospy.loginfo("Resultado recibido: %d", respuesta.resultado)

Con esta implementación, el cliente permanecerá en estado de espera hasta que el servidor esté disponible, evitando así excepciones por conexión fallida.

Resumen

La comunicación por servicios en ROS proporciona un mecanismo de solicitud-respuesta síncrono ideal para operaciones que requieren confirmación inmediata. Las implementaciones mostradas demuestran cómo crear proveedores y solicitantes de servicio en Python, incluyendo características avanzadas como parámetros dinámicos y manejo de escenarios donde el cliente se ejecuta antes que el servidor.

Etiquetas: ROS Python robótica Service Communication rospy

Publicado el 7-20 00:47