Écrire un simple éditeur et abonné (Python)
Objectif : Créer et exécuter un nœud d’éditeur et d’abonné à l’aide de Python
Niveau du tutoriel : Débutant
Durée : 20 minutes
Contenu
Arrière-plan
Dans ce didacticiel, vous allez créer des nodes qui se transmettent des informations sous forme de messages de chaîne via un : doc:sujet. L’exemple utilisé ici est un simple système « locuteur » et « auditeur » ; un nœud publie des données et l’autre s’abonne au sujet afin de pouvoir recevoir ces données.
Le code utilisé dans ces exemples peut être trouvé ici.
Conditions préalables
Dans les tutoriels précédents, vous avez appris à créer un espace de travail et créer un package.
Une compréhension de base de Python est recommandée, mais pas entièrement nécessaire.
Tâches
1 Créer un package
Ouvrez un nouveau terminal et sourcez votre installation ROS 2 pour que les commandes ros2
fonctionnent.
Naviguez dans le répertoire ros2_ws
créé dans un tutoriel précédent.
Rappelez-vous que les packages doivent être créés dans le répertoire src
, et non à la racine de l’espace de travail. Alors, naviguez dans ros2_ws/src
et exécutez la commande de création de package :
ros2 pkg create --build-type ament_python py_pubsub
Votre terminal renverra un message vérifiant la création de votre package py_pubsub
et tous ses fichiers et dossiers nécessaires.
2 Écrivez le nœud de l’éditeur
Accédez à ros2_ws/src/py_pubsub/py_pubsub
. Rappelez-vous que ce répertoire est un package Python avec le même nom que le package ROS 2 dans lequel il est imbriqué.
Téléchargez l’exemple de code Talker en saisissant la commande suivante :
wget https://raw.githubusercontent.com/ros2/examples/rolling/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py
wget https://raw.githubusercontent.com/ros2/examples/rolling/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py
Dans une invite de ligne de commande Windows :
curl -sk https://raw.githubusercontent.com/ros2/examples/rolling/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py -o publisher_member_function.py
Ou en powershell :
curl https://raw.githubusercontent.com/ros2/examples/rolling/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py -o publisher_member_function.py
Il y aura maintenant un nouveau fichier nommé publisher_member_function.py
adjacent à __init__.py
.
Ouvrez le fichier à l’aide de votre éditeur de texte préféré.
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalPublisher(Node):
def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
def timer_callback(self):
msg = String()
msg.data = 'Hello World: %d' % self.i
self.publisher_.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
self.i += 1
def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
# Destroy the node explicitly
# (optional - otherwise it will be done automatically
# when the garbage collector destroys the node object)
minimal_publisher.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
2.1 Examiner le code
Les premières lignes de code après les commentaires importent rclpy
afin que sa classe Node
puisse être utilisée.
import rclpy
from rclpy.node import Node
L’instruction suivante importe le type de message de chaîne intégré que le nœud utilise pour structurer les données qu’il transmet sur le sujet.
from std_msgs.msg import String
Ces lignes représentent les dépendances du nœud. Rappelez-vous que les dépendances doivent être ajoutées à package.xml
, ce que vous ferez dans la section suivante.
Ensuite, la classe MinimalPublisher
est créée, qui hérite de (ou est une sous-classe de) Node
.
class MinimalPublisher(Node):
Voici la définition du constructeur de la classe. super().__init__
appelle le constructeur de la classe Node
et lui donne le nom de votre nœud, dans ce cas minimal_publisher
.
create_publisher
déclare que le nœud publie des messages de type String
(importés du module std_msgs.msg
), sur un sujet nommé topic
, et que la « taille de la file d’attente » est 10. La taille de la file d’attente est un paramètre QoS (qualité de service) requis qui limite la quantité de messages en file d’attente si un abonné ne les reçoit pas assez rapidement.
Ensuite, une minuterie est créée avec un rappel à exécuter toutes les 0,5 secondes. self.i
est un compteur utilisé dans le rappel.
def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
timer_callback
crée un message avec la valeur du compteur ajoutée et le publie sur la console avec get_logger().info
.
def timer_callback(self):
msg = String()
msg.data = 'Hello World: %d' % self.i
self.publisher_.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
self.i += 1
Enfin, la fonction principale est définie.
def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
# Destroy the node explicitly
# (optional - otherwise it will be done automatically
# when the garbage collector destroys the node object)
minimal_publisher.destroy_node()
rclpy.shutdown()
La bibliothèque rclpy
est d’abord initialisée, puis le nœud est créé, puis il « fait tourner » le nœud pour que ses rappels soient appelés.
2.2 Ajouter des dépendances
Naviguez d’un niveau vers le répertoire ros2_ws/src/py_pubsub
, où les fichiers setup.py
, setup.cfg
et package.xml
ont été créés pour vous.
Ouvrez package.xml
avec votre éditeur de texte.
Comme mentionné dans le tutoriel précédent, assurez-vous de remplir les champs <description>
, <maintainer>
et < licence>
balises :
<description>Examples of minimal publisher/subscriber using rclpy</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>
Après les lignes ci-dessus, ajoutez les dépendances suivantes correspondant aux instructions d’importation de votre nœud :
<exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>
Cela déclare que le paquet a besoin de rclpy
et std_msgs
lorsque son code est exécuté.
Assurez-vous de sauvegarder le fichier.
2.3 Ajouter un point d’entrée
Ouvrez le fichier setup.py
. Encore une fois, faites correspondre les champs maintainer
, maintainer_email
, description
et license
à votre package.xml
:
maintainer='YourName',
maintainer_email='you@email.com',
description='Examples of minimal publisher/subscriber using rclpy',
license='Apache License 2.0',
Ajoutez la ligne suivante entre les parenthèses console_scripts
du champ entry_points
:
entry_points={
'console_scripts': [
'talker = py_pubsub.publisher_member_function:main',
],
},
N’oubliez pas de sauvegarder.
2.4 Vérifier setup.cfg
Le contenu du fichier setup.cfg
doit être correctement rempli automatiquement, comme ceci :
[develop]
script_dir=$base/lib/py_pubsub
[install]
install_scripts=$base/lib/py_pubsub
Cela indique simplement à setuptools de mettre vos exécutables dans lib
, car ros2 run
les cherchera là-bas.
Vous pouvez créer votre package maintenant, sourcer les fichiers d’installation locaux et l’exécuter, mais créons d’abord le nœud d’abonné afin que vous puissiez voir le système complet au travail.
3 Écrivez le nœud de l’abonné
Retournez à ros2_ws/src/py_pubsub/py_pubsub
pour créer le nœud suivant. Entrez le code suivant dans votre terminal :
wget https://raw.githubusercontent.com/ros2/examples/rolling/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py
wget https://raw.githubusercontent.com/ros2/examples/rolling/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py
Dans une invite de ligne de commande Windows :
curl -sk https://raw.githubusercontent.com/ros2/examples/rolling/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py -o subscriber_member_function.py
Ou en powershell :
curl https://raw.githubusercontent.com/ros2/examples/rolling/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py -o subscriber_member_function.py
Maintenant, le répertoire devrait contenir ces fichiers :
__init__.py publisher_member_function.py subscriber_member_function.py
3.1 Examiner le code
Ouvrez le subscriber_member_function.py
avec votre éditeur de texte.
import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalSubscriber(Node):
def __init__(self):
super().__init__('minimal_subscriber')
self.subscription = self.create_subscription(
String,
'topic',
self.listener_callback,
10)
self.subscription # prevent unused variable warning
def listener_callback(self, msg):
self.get_logger().info('I heard: "%s"' % msg.data)
def main(args=None):
rclpy.init(args=args)
minimal_subscriber = MinimalSubscriber()
rclpy.spin(minimal_subscriber)
# Destroy the node explicitly
# (optional - otherwise it will be done automatically
# when the garbage collector destroys the node object)
minimal_subscriber.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
Le code du nœud d’abonné est presque identique à celui de l’éditeur. Le constructeur crée un abonné avec les mêmes arguments que l’éditeur. Rappelez-vous du tutoriel topics que le nom du sujet et le type de message utilisés par l’éditeur et l’abonné doivent correspondre pour leur permettre communiquer.
self.subscription = self.create_subscription(
String,
'topic',
self.listener_callback,
10)
Le constructeur et le rappel de l’abonné n’incluent aucune définition de minuterie, car il n’en a pas besoin. Son rappel est appelé dès qu’il reçoit un message.
La définition de rappel imprime simplement un message d’information sur la console, ainsi que les données qu’elle a reçues. Rappelons que l’éditeur définit msg.data = 'Hello World: %d' % self.i
def listener_callback(self, msg):
self.get_logger().info('I heard: "%s"' % msg.data)
La définition principale
est presque exactement la même, remplaçant la création et la rotation de l’éditeur par l’abonné.
minimal_subscriber = MinimalSubscriber()
rclpy.spin(minimal_subscriber)
Étant donné que ce nœud a les mêmes dépendances que l’éditeur, il n’y a rien de nouveau à ajouter à package.xml
. Le fichier setup.cfg
peut également rester intact.
3.2 Ajouter un point d’entrée
Rouvrez setup.py
et ajoutez le point d’entrée du nœud d’abonné sous le point d’entrée de l’éditeur. Le champ entry_points
devrait maintenant ressembler à ceci :
entry_points={
'console_scripts': [
'talker = py_pubsub.publisher_member_function:main',
'listener = py_pubsub.subscriber_member_function:main',
],
},
Assurez-vous d’enregistrer le fichier, puis votre système pub/sub devrait être prêt à l’emploi.
4 Construire et exécuter
Vous avez probablement déjà les packages rclpy
et std_msgs
installés dans le cadre de votre système ROS 2. Il est recommandé d’exécuter rosdep
à la racine de votre espace de travail (ros2_ws
) pour vérifier les dépendances manquantes avant de compiler :
rosdep install -i --from-path src --rosdistro rolling -y
rosdep ne fonctionne que sous Linux, vous pouvez donc passer à l’étape suivante.
rosdep ne fonctionne que sous Linux, vous pouvez donc passer à l’étape suivante.
Toujours à la racine de votre espace de travail, ros2_ws
, construisez votre nouveau package :
colcon build --packages-select py_pubsub
colcon build --packages-select py_pubsub
colcon build --merge-install --packages-select py_pubsub
Ouvrez un nouveau terminal, accédez à ros2_ws
et sourcez les fichiers d’installation :
. install/setup.bash
. install/setup.bash
call install/setup.bat
Exécutez maintenant le nœud Talker :
ros2 run py_pubsub talker
Le terminal devrait commencer à publier des messages d’information toutes les 0,5 seconde, comme ceci :
[INFO] [minimal_publisher]: Publishing: "Hello World: 0"
[INFO] [minimal_publisher]: Publishing: "Hello World: 1"
[INFO] [minimal_publisher]: Publishing: "Hello World: 2"
[INFO] [minimal_publisher]: Publishing: "Hello World: 3"
[INFO] [minimal_publisher]: Publishing: "Hello World: 4"
...
Ouvrez un autre terminal, sourcez à nouveau les fichiers de configuration depuis ros2_ws
, puis démarrez le nœud d’écoute :
ros2 run py_pubsub listener
L’écouteur commencera à imprimer des messages sur la console, à partir du nombre de messages sur lequel l’éditeur se trouve à ce moment-là, comme ceci :
[INFO] [minimal_subscriber]: I heard: "Hello World: 10"
[INFO] [minimal_subscriber]: I heard: "Hello World: 11"
[INFO] [minimal_subscriber]: I heard: "Hello World: 12"
[INFO] [minimal_subscriber]: I heard: "Hello World: 13"
[INFO] [minimal_subscriber]: I heard: "Hello World: 14"
Entrez Ctrl+C
dans chaque terminal pour empêcher les nœuds de tourner.
Résumé
Vous avez créé deux nœuds pour publier et vous abonner à des données sur une rubrique. Avant de les exécuter, vous avez ajouté leurs dépendances et leurs points d’entrée aux fichiers de configuration du package.
Prochaines étapes
Ensuite, vous allez créer un autre package ROS 2 simple en utilisant le modèle service/client. Encore une fois, vous pouvez choisir de l’écrire en C++ ou Python.