Comunicación principal de ROS2

06 Nodo

06 Nodos

6.1 Resumen de los nodos

6.1.1 Qué es un nodo

Un nodo es la unidad de cálculo más básica en ROS 2. Un nodo es un proceso que utiliza la API de ROS 2 para comunicarse con otros nodos. Cada nodo es normalmente responsable de funciones específicas, como leer datos de sensores, procesar datos, controlar implementadores, etc.

6.1.2 Características de los nodos

CaracterísticasAnotaciones
LigeroUn ejecutable puede contener múltiples nodos
DistribuciónEl nodo puede ejecutarse en diferentes máquinas.
DesacopladoComunicaciones entre nodos a través de interfaz, no directamente dependientes
AgrupableMúltiples nodos para ejecutar funciones complejas
Ciclo de vida independienteIniciar y cerrar cada nodo de forma independiente

6.1.3 Reglas de nomenclatura de nodos

El nombre de nodo debe ser único (en el mismo espacio de nombres)

Solo pueden incluirse letras, números y guiones bajos

Distingue entre mayúsculas y minúsculas

Uso recomendado de nombre descriptivo

Ejemplo de nombre:

Nombre del nodoEvaluación
Camera_driverExcelente.
path_plannerExcelente.
Node1No recomendado (sin descripción)
Oh, my-node.Inválido (con guion)

6.2 Caso de nodo Hello World

6.2.1 Crear paquete python

workspace reemplaza la ruta real del workspace

bash
cd workspace/src
ros2 pkg create pkg_helloworld_py --build-type ament_python --dependencies rclpy --node-name helloworld

6.2.2 Preparación de códigos

bash
import rclpy  # ROS 2 Python client library
from rclpy.node import Node  # ROS 2 node class
import time

class HelloWorldNode(Node):
  def __init__(self, name):
  super().__init__(name)
  while rclpy.ok():
  self.get_logger().info("Hello World")
  time.sleep(0.5)

def main(args=None):
  rclpy.init(args=args)
  node = HelloWorldNode("helloworld")
  rclpy.spin(node)
  node.destroy_node()
  rclpy.shutdown()
bash
colcon build --packages-select pkg_helloworld_py
source install/setup.bash
ros2 run pkg_helloworld_py helloworld

6.3 Próximos pasos

1.07 Comunicación de tópicos

2.08 Comunicaciones de servicios

07 Comunicación de tópicos

07 Comunicación de tópicos (Topics)

7.1 Resumen de las comunicaciones de tópicos

7.1.1 ¿Qué es la comunicación de tópicos?

El tópico (Topic) es el mecanismo para la comunicación asincrónica entre los nodos de ROS 2, utilizando el modo de publicación/suscripción (Pub/Sub). El nodo emisor emite noticias al tópico, y el nodo suscriptor recibe información del tópico, y ninguno necesita conocer al otro.

7.1.2 Características de las comunicaciones de tópicos

CaracterísticasDescripciónAplicar escena
Comunicaciones asíncronasEl emisor no espera la respuesta del suscriptorFlujo de datos del sensor
Múltiples a múltiplesMúltiples publicadores y suscriptoresDifusión de datos
Acoplamiento débilDesacoplamientoDiseño modular
Transferencia de flujoFlujos de datos en cursoMonitoreo continuo

7.1.3 Reglas de nomenclatura de tópicos

ReglaAnotaciones
Debe comenzar (espacio de nombres global) o nombre relativo
Use letras minúsculas, números y guiones bajos
Use / para separar niveles de espacio de nombres
Evite retener nombres

Ejemplo de nombre:

Nombre del sujetoEvaluación
/cmd_velEstándares, recomendado
/camera/image_rawNivel claro. Recomendado.
/sensor/front_camera/imageEspacio de nombres, recomendado.
/MyTopicNo recomendado (mayúsculas)
add_velNombre relativo (espacio de nombres del nodo agregado)

7.2 Casos de comunicación

7.2.1 Nuevo paquete funcional

bash
cd ~/workspaces/src
ros2 pkg create pkg_topic --build-type ament_python --dependencies rclpy --node-name publisher_demo

7.2.2 El autor logra

bash
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class Topic_Pub(Node):
  def __init__(self,name):
  super().__init__(name)
  self.pub = self.create_publisher(String,"/topic_demo",1)
  self.timer = self.create_timer(1,self.pub_msg)
  def pub_msg(self):
  msg = String()
  msg.data = "Hi,I send a message."
  self.pub.publish(msg)

def main():
  rclpy.init()
  pub_demo = Topic_Pub("publisher_node")
  rclpy.spin(pub_demo)
  pub_demo.destroy_node()
  rclpy.shutdown()

7.2.3 Editar archivos de configuración

7.2.4 Compilador del paquete funcional

bash
cd ~/workspace
colcon build --packages-select pkg_topic
source install/setup.bash

7.2.5 Ejecutar nodo de publicación

bash
ros2 run pkg_topic publisher_demo
ros2 topic list
ros2 topic echo /topic_demo

7.2.6 Crear un suscriptor

bash
import rclpy
from rclpy.node import Node
from std_msgs.msg import String

class Topic_Sub(Node):
  def __init__(self,name):
  super().__init__(name)
  self.sub = self.create_subscription(String,"/topic_demo",self.sub_callback,1)
  def sub_callback(self,msg):
  self.get_logger().info(msg.data)

def main():
  rclpy.init()
  sub_demo = Topic_Sub("subscriber_node")
  rclpy.spin(sub_demo)
  sub_demo.destroy_node()
  rclpy.shutdown()

7.2.7 Editar archivos de configuración

7.2.8 Compilador del paquete funcional

bash
cd ~/workspace
colcon build --packages-select pkg_topic
source install/setup.bash

7.2.9 Nodos operativos

bash
ros2 run pkg_topic publisher_demo
ros2 run pkg_topic subscriber_demo

7.3 Próximos pasos

1.08 Comunicaciones de servicio

2.09 Comunicaciones de acción

08 Comunicaciones de servicio

08 Comunicaciones de servicio (Services)

8.1 Descripción general de las comunicaciones de servicios

8.1.1 Qué es la comunicación de servicios

El servicio (Service) es el mecanismo para la comunicación sincronizada entre los nodos en ROS 2, utilizando el modelo cliente/servidor (Client/Server). El cliente envía la solicitud, el servicio la maneja y devuelve la respuesta.

8.1.2 Servicios vs tópicos

CaracterísticaServiciosTópicos
Modo de comunicaciónSincrónico (solicitud-respuesta)Asincrónico (publicación-suscripción)
ConexiónUno a uno.Múltiple a múltiple.
Aplicar escenaConsulta de operaciones cortasFlujos de datos en curso
BloqueoCliente bloquea esperando.Sin bloqueo.
Valor de retornoDebemos devolver la respuesta.Sin respuesta

8.1.3 Definición del tipo de servicio

bash
# File: example interfaces/srv/AddTwoInts.srv
int64 a
int64 b
---
int64 sum

8.2 Ejemplos de comunicaciones de servicios

8.2.1 Nuevo paquete funcional

bash
ros2 pkg create pkg_service --build-type ament_python --dependencies rclpy --node-name server_demo

8.2.2 Crear un extremo de servicio

bash
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

class Service_Server(Node):
  def __init__(self,name):
  super().__init__(name)
  self.srv = self.create_service(AddTwoInts, '/add_two_ints', self.Add2Ints_callback)
  def Add2Ints_callback(self,request,response):
  response.sum = request.a + request.b
  print("response.sum = ",response.sum)
  return response
def main():
  rclpy.init()
  server_demo = Service_Server("publisher_node")
  rclpy.spin(server_demo)
  server_demo.destroy_node()
  rclpy.shutdown()
bash
ros2 interface show example_interfaces/srv/AddTwoInts

8.2.3 Editar archivos de configuración

bash
'server_demo = pkg_service.server_demo:main',

8.2.4 Compilador del paquete funcional

bash
colcon build --packages-select pkg_service
source install/setup.bash
ros2 run pkg_service server_demo
bash
ros2 service list
ros2 service call /add_two_ints example_interfaces/srv/AddTwoInts "{a: 1,b: 4}"

8.2.5 Crear cliente

bash
import rclpy
from rclpy.node import Node
from example_interfaces.srv import AddTwoInts

class Service_Client(Node):
  def __init__(self,name):
  super().__init__(name)
  self.client = self.create_client(AddTwoInts,'/add_two_ints')
  while not self.client.wait_for_service(timeout_sec=1.0):
  print("service not available, waiting again...")
  self.request = AddTwoInts.Request()

  def send_request(self):
  self.request.a = 10
  self.request.b = 90
  self.future = self.client.call_async(self.request)

def main():
  rclpy.init()
  service_client = Service_Client("client_node")
  service_client.send_request()
  while rclpy.ok():
  rclpy.spin_once(service_client)
  if service_client.future.done():
  try:
  response = service_client.future.result()
  print("Result = ",response.sum)
  except Exception as e:
  service_client.get_logger().info('Service call failed %r' % (e,))
  break
  service_client.destroy_node()
  rclpy.shutdown()

8.2.6 Editar archivos de configuración

bash
'client_demo = pkg_service.client_demo:main'

8.2.7 Compilador del paquete funcional

bash
cd ~/workspace
colcon build --packages-select pkg_service
source install/setup.bash
ros2 run pkg_service server_demo
bash
source install/setup.bash
ros2 run pkg_service client_demo

8.3 Próximos pasos

1.09 Comunicaciones de acción - Aprender comunicaciones de acción (tarea larga)

  1. 10 Transformación de coordenadas TF2 - Crear tipo de servicio personalizado

09 Comunicaciones de acción

09 Comunicaciones de acción (Actions)

9.1 Resumen de las comunicaciones de acción

9.1.1 ¿Qué es la comunicación de movimiento?

La acción es el mecanismo de comunicación utilizado en ROS 2 para manejar asignaciones largas. Similar a los servicios, las acciones son un modo cliente-servidor, pero soportan:

  • Retroalimentación en tiempo real durante la ejecución del mandato

  • El cliente puede cancelar una asignación activa.

  • Adapta para manejar operaciones que pueden tomar segundos a minutos.

9.1.2 Acción vs servicios

CaracterísticaServicioAcción
Duración de la aplicaciónOperación corta (ms-s)Misiones largas (segundos-minutos)
RetroalimentaciónSin retroalimentación en tiempo realEnviar retroalimentación de forma continua
CancelarNo soportadoPero cancelar.
BloqueoBloqueo del clienteDeshabilitar
Aplicar escenaConsulta, operaciones simplesNavegación, captura

9.2 Casos de comunicaciones de acción

9.2.1 Nuevo kit funcional

bash
ros2 pkg create --build-type ament_cmake pkg_interfaces
bash
int64 num
---
int64 sum
---
float64 progress
bash
<buildtool_depend>rosidl_default_generators</buildtool_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<depend>action_msgs</depend>
<member_of_group>rosidl_interface_packages</member_of_group>
bash
find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
  "action/Progress.action")
bash
cd ~/workspace
colcon build --packages-select pkg_interfaces
bash
ros2 interface show pkg_interfaces/action/Progress
bash
ros2 pkg create pkg_action --build-type ament_python --dependencies rclpy pkg_interfaces --node-name action_server_demo

4. Realización del extremo del servicio

4.1 Crear un proveedor de servicios

bash
import time
import rclpy
from rclpy.action import ActionServer
from rclpy.node import Node

from pkg_interfaces.action import Progress

class Action_Server(Node):
  def __init__(self):
  super().__init__('progress_action_server')
  self._action_server = ActionServer(
  self,
  Progress,
  'get_sum',
  self.execute_callback)
  self.get_logger().info('The action server has started!')

  def execute_callback(self, goal_handle):
  self.get_logger().info('Starting task execution...')
  feedback_msg = Progress.Feedback()
  total = 0
  for i in range(1, goal_handle.request.num + 1):
  total += i
  feedback_msg.progress = i / goal_handle.request.num
  self.get_logger().info('Continuous feedback: %.2f' % feedback_msg.progress)
  goal_handle.publish_feedback(feedback_msg)
  time.sleep(1)

  goal_handle.succeed()
  result = Progress.Result()
  result.sum = total
  self.get_logger().info('Task completed!')
  return result

def main(args=None):
  rclpy.init(args=args)
  Progress_action_server = Action_Server()
  rclpy.spin(Progress_action_server)
  Progress_action_server.destroy_node()
  rclpy.shutdown()

4.2 Editar archivos de configuración

bash
'action_server_demo = pkg_action.action_server_demo:main',

4.3 Compilador del paquete funcional

bash
cd ~/workspace
colcon build --packages-select pkg_action
source install/setup.bash
ros2 run pkg_action action_server_demo
bash
ros2 action list
ros2 action send_goal /get_sum pkg_interfaces/action/Progress "{num: 10}"

5. Cliente logrado

5.1 Crear cliente