Utiliser des paramètres dans une classe (Python)

Objectif : créer et exécuter une classe avec des paramètres ROS à l’aide de Python.

Niveau du tutoriel : Débutant

Durée : 20 minutes

Arrière-plan

Lorsque vous créez vos propres nodes, vous devrez parfois ajouter des paramètres pouvant être définis à partir du fichier de lancement.

Ce didacticiel vous montrera comment créer ces paramètres dans une classe Python et comment les définir dans un fichier de lancement.

Conditions préalables

Dans les tutoriels précédents, vous avez appris à créer un espace de travail et créer un package. Vous avez également découvert parameters et leur fonction dans un système ROS 2.

Tâches

1 Créer un package

Ouvrez un nouveau terminal et sourcez votre installation ROS 2 pour que les commandes ros2 fonctionnent.

Suivez ces instructions pour créer un nouvel espace de travail nommé ros2_ws.

Rappelez-vous que les packages doivent être créés dans le répertoire src, et non à la racine de l’espace de travail. Accédez à ros2_ws/src et créez un nouveau package :

ros2 pkg create --build-type ament_python python_parameters --dependencies rclpy

Votre terminal renverra un message vérifiant la création de votre package python_parameters et tous ses fichiers et dossiers nécessaires.

L’argument --dependencies ajoutera automatiquement les lignes de dépendance nécessaires à package.xml et CMakeLists.txt.

1.1 Mettre à jour package.xml

Comme vous avez utilisé l’option --dependencies lors de la création du package, vous n’avez pas besoin d’ajouter manuellement des dépendances à package.xml ou CMakeLists.txt.

Comme toujours, assurez-vous d’ajouter la description, l’adresse e-mail et le nom du responsable, ainsi que les informations de licence à package.xml.

<description>Python parameter tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>

2 Écrivez le nœud Python

Dans le répertoire ros2_ws/src/python_parameters/python_parameters, créez un nouveau fichier appelé python_parameters_node.py et collez le code suivant à l’intérieur :

import rclpy
import rclpy.node

class MinimalParam(rclpy.node.Node):
    def __init__(self):
        super().__init__('minimal_param_node')

        self.declare_parameter('my_parameter', 'world')

        self.timer = self.create_timer(1, self.timer_callback)

    def timer_callback(self):
        my_param = self.get_parameter('my_parameter').get_parameter_value().string_value

        self.get_logger().info('Hello %s!' % my_param)

        my_new_param = rclpy.parameter.Parameter(
            'my_parameter',
            rclpy.Parameter.Type.STRING,
            'world'
        )
        all_new_parameters = [my_new_param]
        self.set_parameters(all_new_parameters)

def main():
    rclpy.init()
    node = MinimalParam()
    rclpy.spin(node)

if __name__ == '__main__':
    main()

2.1 Examiner le code

Les instructions import en haut sont utilisées pour importer les dépendances du package.

Le morceau de code suivant crée la classe et le constructeur. La ligne self.declare_parameter('my_parameter', 'world') du constructeur crée un paramètre avec le nom my_parameter et une valeur par défaut de world. Le type de paramètre est déduit de la valeur par défaut, donc dans ce cas, il serait défini sur un type de chaîne. Ensuite, le timer est initialisé avec une période de 1, ce qui provoque l’exécution de la fonction timer_callback une fois par seconde.

class MinimalParam(rclpy.node.Node):
    def __init__(self):
        super().__init__('minimal_param_node')

        self.declare_parameter('my_parameter', 'world')

        self.timer = self.create_timer(1, self.timer_callback)

La première ligne de notre fonction timer_callback récupère le paramètre my_parameter du nœud et le stocke dans my_param. Ensuite, la fonction get_logger s’assure que le message est enregistré. La fonction set_parameters définit ensuite le paramètre my_parameter à la valeur de chaîne par défaut world. Dans le cas où l’utilisateur a modifié le paramètre de manière externe, cela garantit qu’il est toujours réinitialisé à l’original.

def timer_callback(self):
    my_param = self.get_parameter('my_parameter').get_parameter_value().string_value

    self.get_logger().info('Hello %s!' % my_param)

    my_new_param = rclpy.parameter.Parameter(
        'my_parameter',
        rclpy.Parameter.Type.STRING,
        'world'
    )
    all_new_parameters = [my_new_param]
    self.set_parameters(all_new_parameters)

Après le timer_callback se trouve notre main. Ici, ROS 2 est initialisé, une instance de la classe MinimalParam est construite et rclpy.spin commence à traiter les données du nœud.

def main():
    rclpy.init()
    node = MinimalParam()
    rclpy.spin(node)

if __name__ == '__main__':
    main()
2.1.1 (Facultatif) Ajouter un descripteur de paramètre

Vous pouvez éventuellement définir un descripteur pour le paramètre. Les descripteurs vous permettent de spécifier une description textuelle du paramètre et des contraintes de paramètres, comme le rendre en lecture seule, spécifier une plage, etc. Pour que cela fonctionne, le code __init__ doit être changé en :

# ...

class MinimalParam(rclpy.node.Node):
    def __init__(self):
        super().__init__('minimal_param_node')

        from rcl_interfaces.msg import ParameterDescriptor
        my_parameter_descriptor = ParameterDescriptor(description='This parameter is mine!')

        self.declare_parameter('my_parameter',
                               'world',
                               my_parameter_descriptor)

        self.timer = self.create_timer(1, self.timer_callback)

Le reste du code reste le même. Une fois que vous avez exécuté le nœud, vous pouvez alors exécuter ros2 param describe /minimal_param_node my_parameter pour voir le type et la description.

2.2 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='Python parameter tutorial',
license='Apache License 2.0',

Ajoutez la ligne suivante entre les parenthèses console_scripts du champ entry_points :

entry_points={
    'console_scripts': [
        'minimal_param_node = python_parameters.python_parameters_node:main',
    ],
},

N’oubliez pas de sauvegarder.

3 Construire et exécuter

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

Revenez à la racine de votre espace de travail, ros2_ws, et créez votre nouveau package :

colcon build --packages-select python_parameters

Ouvrez un nouveau terminal, accédez à ros2_ws et sourcez les fichiers d’installation :

. install/setup.bash

Exécutez maintenant le nœud :

ros2 run python_parameters minimal_param_node

Le terminal doit renvoyer le message suivant toutes les secondes :

[INFO] [parameter_node]: Hello world!

Vous pouvez maintenant voir la valeur par défaut de votre paramètre, mais vous souhaitez pouvoir la définir vous-même. Il existe deux façons d’y parvenir.

3.1 Modification via la console

Cette partie utilisera les connaissances que vous avez acquises grâce au tutoriel sur les paramètres et les appliquera au nœud que vous venez de créé.

Assurez-vous que le nœud est en cours d’exécution :

ros2 run python_parameters minimal_param_node

Ouvrez un autre terminal, sourcez à nouveau les fichiers d’installation depuis ros2_ws et entrez la ligne suivante :

ros2 param list

Vous y verrez le paramètre personnalisé my_parameter. Pour le changer, exécutez simplement la ligne suivante dans la console :

ros2 param set /minimal_param_node my_parameter earth

Vous savez que cela s’est bien passé si vous obtenez la sortie Set parameters réussi. Si vous regardez l’autre terminal, vous devriez voir la sortie changer en [INFO] [minimal_param_node] : Hello Earth !

Étant donné que le nœud a ensuite redéfini le paramètre sur world, d’autres sorties affichent [INFO] [minimal_param_node] : Hello world !

3.2 Modification via un fichier de lancement

Vous pouvez également définir des paramètres dans un fichier de lancement, mais vous devrez d’abord ajouter un répertoire de lancement. Dans le répertoire ros2_ws/src/python_parameters/, créez un nouveau répertoire appelé launch. Là, créez un nouveau fichier appelé python_parameters_launch.py

from launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='python_parameters',
            executable='minimal_param_node',
            name='custom_minimal_param_node',
            output='screen',
            emulate_tty=True,
            parameters=[
                {'my_parameter': 'earth'}
            ]
        )
    ])

Ici, vous pouvez voir que nous définissons my_parameter sur earth lorsque nous lançons notre nœud parameter_node. En ajoutant les deux lignes ci-dessous, nous nous assurons que notre sortie est imprimée dans notre console.

output="screen",
emulate_tty=True,

Ouvrez maintenant le fichier setup.py. Ajoutez les instructions import en haut du fichier et l’autre nouvelle instruction au paramètre data_files pour inclure tous les fichiers de lancement :

import os
from glob import glob
# ...

setup(
  # ...
  data_files=[
      # ...
      (os.path.join('share', package_name), glob('launch/*launch.[pxy][yma]*')),
    ]
  )

Ouvrez une console et accédez à la racine de votre espace de travail, ros2_ws, et créez votre nouveau package :

colcon build --packages-select python_parameters

Sourcez ensuite les fichiers de configuration dans un nouveau terminal :

. install/setup.bash

Exécutez maintenant le nœud en utilisant le fichier de lancement que nous venons de créer :

ros2 launch python_parameters python_parameters_launch.py

Le terminal doit renvoyer le message suivant toutes les secondes :

[INFO] [custom_minimal_param_node]: Hello earth!

Résumé

Vous avez créé un nœud avec un paramètre personnalisé, qui peut être défini à partir d’un fichier de lancement ou de la ligne de commande. Vous avez ajouté les dépendances, les exécutables et un fichier de lancement aux fichiers de configuration du package afin de pouvoir les générer et les exécuter, et voir le paramètre en action.

Prochaines étapes

Maintenant que vous disposez de certains packages et de vos propres systèmes ROS 2, le next tutorial vous montrera comment examiner les problèmes de votre environnement et de vos systèmes au cas où vous auriez des problèmes .