Communication principale de ROS2

06 Nœud

06 Nœuds

6.1 Résumé des nœuds

6.1.1 Qu'est-ce qu'un nœud

Un nœud est l'unité de calcul la plus basique dans ROS 2. Un nœud est un processus utilisant l'API ROS 2 pour communiquer avec d'autres nœuds. Chaque nœud est normalement responsable de fonctions spécifiques, telles que la lecture de données de capteurs, le traitement de données, le contrôle des implémentateurs, etc.

6.1.2 Caractéristiques des nœuds

CaractéristiquesAnnotations
LégerUn exécutable peut contenir plusieurs nœuds
DistributionLe nœud peut s'exécuter sur différentes machines.
DécoupléCommunications entre les nœuds via interface, ne dépendent pas directement
GroupablePlusieurs nœuds pour effectuer des fonctions complexes
Cycle de vie indépendantDémarrer et fermer chaque nœud indépendamment

6.1.3 Règles de nommage des nœuds

Le nom du nœud doit être unique (dans le même espace de noms)

Seules les lettres, les chiffres et les soulignements peuvent être inclus

Sensible à la casse

Utilisation recommandée d'un nom descriptif

Exemple de nom :

Nom du nœudÉvaluation
Camera_driverExcellent.
path_plannerExcellent.
Node1Non recommandé (non descriptif)
Oh, my-node.Invalide (avec trait d'union)

6.2 Cas du nœud Hello World

6.2.1 Créer un kit python

workspace remplace le chemin réel de l'espace de travail

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

6.2.2 Préparation des codes

bash
import rclpy
from rclpy.node import Node
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 Étapes suivantes

1.07 Communications de topics

2.08 Communications de service

07 Communication de topic

07 Bulletin d'information sur les topics (Topics)

7.1 Résumé des communications topiques

7.1.1 Qu'est-ce qu'une communication de topic ?

Le topic est le mécanisme de communication asynchrone entre les nœuds ROS 2, utilisant le mode de publication/abonnement (Pub/Sub). Le nœud émetteur émet des nouvelles au topic, et le nœud abonné reçoit les informations du topic, et aucun ne doit connaître l'autre.

7.1.2 Caractéristiques des communications topiques

CaractéristiquesDescriptionAppliquer la scène
Communications asynchronesL'expéditeur n'attend pas la réponse de l'abonnéFlux de données du capteur
Multiple à multiplePlusieurs éditeurs et abonnésDiffusion de données
Couplage faibleDécouplageConception modulaire
Transfert en fluxFlux de données en coursSurveillance continue

7.1.3 Règles de nommage des topics

RègleAnnotations
Doit commencer (espace de noms global) ou nom relatif
Utilisez des lettres minuscules, des chiffres et des soulignements
Utilisez / pour séparer les niveaux d'espace de noms
Évitez de conserver les noms

Exemple de nom :

Nom du sujetÉvaluation
/cmd_velStandards, recommandé
/camera/image_rawNiveau clair. Recommandé.
/sensor/front_camera/imageEspace de noms, recommandé.
/MyTopicNon recommandé (capitalisé)
add_velNom relatif (espace de nommage du nœud ajouté)

7.2 Cas de communication

7.2.1 Nouveau paquet de fonctionnalités

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

7.2.2 Réalisation de l'auteur

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 Modifier les fichiers de configuration

7.2.4 Compilateur du paquet fonctionnel

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

7.2.5 Exécuter les nœuds de publication

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

7.2.6 Créer un abonné

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 Modifier les fichiers de configuration

7.2.8 Compilateur du paquet fonctionnel

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

7.2.9 Nœuds opérationnels

bash
ros2 run pkg_topic publisher_demo
ros2 run pkg_topic subscriber_demo

7.3 Étapes suivantes

1.08 Communications de service

2.09 Communications d'action

08 Communications de service

08 Communications de service (Services)

8.1 Vue d'ensemble des communications de service

8.1.1 Qu'est-ce que la communication de service

Le service est le mécanisme de communication synchronisée entre les nœuds dans ROS 2, en utilisant le modèle client/serveur. Le client envoie la demande, le service la traite et retourne la réponse.

8.1.2 Services vs topics

CaractéristiqueServicesTopics
Mode de communicationSynchrone (requête-réponse)Asynchrone (publication-abonnement)
ConnexionUn à un.Multiple à multiple.
Appliquer la scèneRequête d'opération courteFlux de données en cours
BlocClient en attente de blocage.Pas de blocage.
Valeur de retourNous devons retourner la réponse.Pas de réponse

8.1.3 Définition du type de service

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

8.2 Exemples de communications de service

8.2.1 Nouveau paquet de fonctionnalités

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

8.2.2 Créer une extrémité de service

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 Modifier les fichiers de configuration

bash
'server_demo = pkg_service.server_demo:main',

8.2.4 Compilateur du paquet fonctionnel

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 Créer un client

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 Modifier les fichiers de configuration

bash
'client_demo = pkg_service.client_demo:main'

8.2.7 Compilateur du paquet fonctionnel

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 Étapes suivantes

1.09 Communications d'action - Apprendre les communications d'action (longue mission)

  1. 10 Transformation de coordonnées TF2 - Créer un type de service personnalisé

09 Communications d'action

09 Communications d'action (Actions)

9.1 Résumé des communications d'action

9.1.1 Qu'est-ce que la communication de mouvement ?

L'action est le mécanisme de communication utilisé dans ROS 2 pour gérer les longues affectations. Semblable aux services, les actions sont un mode client-serveur, mais prennent en charge :

  • Retour en temps réel pendant la mise en œuvre du mandat

  • Le client peut annuler une affectation active.

  • Convient au traitement des opérations qui peuvent prendre des secondes à des minutes.

9.1.2 Action vs services

CaractéristiqueServiceAction
Durée de l'applicationCourte opération (ms-s)Longues missions (secondes-minutes)
RetourAucun retour en temps réelEnvoyer des retours sur une base continue
AnnulerNon pris en chargeMais annuler.
BlocBloc clientDésactiver
Appliquer la scèneRequête, opérations simplesNavigation, capture

9.2 Cas de communications d'action

9.2.1 Nouveau kit fonctionnel

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. Réalisation côté service

4.1 Créer un fournisseur de services

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 Modifier les fichiers de configuration

bash
'action_server_demo = pkg_action.action_server_demo:main',

4.3 Compilateur du paquet fonctionnel

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. Client réalisé

5.1 Créer un client