Surveillance des changements de paramètres (C++)
Objectif : Apprendre à utiliser la classe ParameterEventHandler pour surveiller et réagir aux modifications de paramètres.
Niveau du didacticiel : Intermédiaire
Durée : 20 minutes
Contenu
Arrière-plan
Souvent, un nœud doit répondre aux modifications de ses propres paramètres ou des paramètres d’un autre nœud. La classe ParameterEventHandler facilite l’écoute des modifications de paramètres afin que votre code puisse y répondre. Ce didacticiel vous montrera comment utiliser la version C++ de la classe ParameterEventHandler pour surveiller les modifications apportées aux paramètres d’un nœud ainsi que les modifications apportées aux paramètres d’un autre nœud.
Conditions préalables
Avant de commencer ce didacticiel, vous devez d’abord suivre les didacticiels suivants :
Tâches
Dans ce didacticiel, vous allez créer un nouveau package contenant des exemples de code, écrire du code C++ pour utiliser la classe ParameterEventHandler et tester le code résultant.
1 Créer un package
Tout d’abord, 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. Alors, naviguez dans ros2_ws/src
puis créez-y un nouveau paquet :
ros2 pkg create --build-type ament_cmake cpp_parameter_event_handler --dependencies rclcpp
Votre terminal renverra un message vérifiant la création de votre package cpp_parameter_event_handler
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>C++ parameter events client tutorial</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>
2 Écrivez le nœud C++
Dans le répertoire ros2_ws/src/cpp_parameter_event_handler/src
, créez un nouveau fichier appelé parameter_event_handler.cpp
et collez le code suivant à l’intérieur :
#include <memory>
#include "rclcpp/rclcpp.hpp"
class SampleNodeWithParameters : public rclcpp::Node
{
public:
SampleNodeWithParameters()
: Node("node_with_parameters")
{
this->declare_parameter("an_int_param", 0);
// Create a parameter subscriber that can be used to monitor parameter changes
// (for this node's parameters as well as other nodes' parameters)
param_subscriber_ = std::make_shared<rclcpp::ParameterEventHandler>(this);
// Set a callback for this node's integer parameter, "an_int_param"
auto cb = [this](const rclcpp::Parameter & p) {
RCLCPP_INFO(
this->get_logger(), "cb: Received an update to parameter \"%s\" of type %s: \"%ld\"",
p.get_name().c_str(),
p.get_type_name().c_str(),
p.as_int());
};
cb_handle_ = param_subscriber_->add_parameter_callback("an_int_param", cb);
}
private:
std::shared_ptr<rclcpp::ParameterEventHandler> param_subscriber_;
std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle_;
};
int main(int argc, char ** argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<SampleNodeWithParameters>());
rclcpp::shutdown();
return 0;
}
2.1 Examiner le code
La première instruction, #include <memory>
est incluse afin que le code puisse utiliser le modèle std::make_shared. Le suivant, #include "rclcpp/rclcpp.hpp"
est inclus pour permettre au code de référencer les diverses fonctionnalités fournies par l’interface rclcpp, y compris la classe ParameterEventHandler.
Après la déclaration de classe, le code définit une classe, SampleNodeWithParameters
. Le constructeur de la classe déclare un paramètre entier an_int_param
, avec une valeur par défaut de 0. Ensuite, le code crée un ParameterEventHandler
qui sera utilisé pour surveiller les modifications apportées aux paramètres. Enfin, le code crée une fonction lambda et la définit comme rappel à invoquer chaque fois que an_int_param
est mis à jour.
Note
Il est très important de sauvegarder le handle renvoyé par add_parameter_callback
; sinon, le rappel ne sera pas correctement enregistré.
SampleNodeWithParameters()
: Node("node_with_parameters")
{
this->declare_parameter("an_int_param", 0);
// Create a parameter subscriber that can be used to monitor parameter changes
// (for this node's parameters as well as other nodes' parameters)
param_subscriber_ = std::make_shared<rclcpp::ParameterEventHandler>(this);
// Set a callback for this node's integer parameter, "an_int_param"
auto cb = [this](const rclcpp::Parameter & p) {
RCLCPP_INFO(
this->get_logger(), "cb: Received an update to parameter \"%s\" of type %s: \"%ld\"",
p.get_name().c_str(),
p.get_type_name().c_str(),
p.as_int());
};
cb_handle_ = param_subscriber_->add_parameter_callback("an_int_param", cb);
}
À la suite de SampleNodeWithParameters
se trouve une fonction main
typique qui initialise ROS, fait tourner le nœud échantillon afin qu’il puisse envoyer et recevoir des messages, puis s’arrête après que l’utilisateur ait saisi ^C sur la console.
int main(int argc, char ** argv)
{
rclcpp::init(argc, argv);
rclcpp::spin(std::make_shared<SampleNodeWithParameters>());
rclcpp::shutdown();
return 0;
}
2.2 Ajouter un exécutable
Pour construire ce code, ouvrez d’abord le fichier CMakeLists.txt
et ajoutez les lignes de code suivantes sous la dépendance find_package(rclcpp REQUIRED)
add_executable(parameter_event_handler src/parameter_event_handler.cpp)
ament_target_dependencies(parameter_event_handler rclcpp)
install(TARGETS
parameter_event_handler
DESTINATION lib/${PROJECT_NAME}
)
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 $ROS_DISTRO -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.
Revenez à la racine de votre espace de travail, ros2_ws
, et créez votre nouveau package :
colcon build --packages-select cpp_parameter_event_handler
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 :
ros2 run cpp_parameter_event_handler parameter_event_handler
Le nœud est maintenant actif et a un seul paramètre et imprimera un message chaque fois que ce paramètre est mis à jour. Pour tester cela, ouvrez un autre terminal et sourcez le fichier d’installation ROS comme avant (. install/setup.bash) et exécutez la commande suivante :
ros2 param set node_with_parameters an_int_param 43
Le terminal exécutant le nœud affichera un message semblable au suivant :
[INFO] [1606950498.422461764] [node_with_parameters]: cb: Received an update to parameter "an_int_param" of type integer: "43"
Le rappel que nous avons défini précédemment dans le nœud a été appelé et a affiché la nouvelle valeur mise à jour. Vous pouvez maintenant mettre fin à l’exemple de parameter_event_handler en cours d’exécution en utilisant ^C dans le terminal.
3.1 Surveiller les modifications apportées aux paramètres d’un autre nœud
Vous pouvez également utiliser le ParameterEventHandler pour surveiller les modifications de paramètres apportées aux paramètres d’un autre nœud. Mettons à jour la classe SampleNodeWithParameters pour surveiller également les modifications apportées à un paramètre dans un autre nœud. Nous utiliserons l’application de démonstration parameter_blackboard pour héberger un double paramètre que nous surveillerons pour les mises à jour.
Commencez par mettre à jour le constructeur pour ajouter le code suivant après le code existant :
// Now, add a callback to monitor any changes to the remote node's parameter. In this
// case, we supply the remote node name.
auto cb2 = [this](const rclcpp::Parameter & p) {
RCLCPP_INFO(
this->get_logger(), "cb2: Received an update to parameter \"%s\" of type: %s: \"%.02lf\"",
p.get_name().c_str(),
p.get_type_name().c_str(),
p.as_double());
};
auto remote_node_name = std::string("parameter_blackboard");
auto remote_param_name = std::string("a_double_param");
cb_handle2_ = param_subscriber_->add_parameter_callback(remote_param_name, cb2, remote_node_name);
Ajoutez ensuite une autre variable membre, cb_handle2
pour le handle de rappel supplémentaire :
private:
std::shared_ptr<rclcpp::ParameterEventHandler> param_subscriber_;
std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle_;
std::shared_ptr<rclcpp::ParameterCallbackHandle> cb_handle2_; // Add this
};
Dans un terminal, revenez à la racine de votre espace de travail, ros2_ws
, et construisez votre package mis à jour comme avant :
colcon build --packages-select cpp_parameter_event_handler
Ensuite, sourcez les fichiers d’installation :
. install/setup.bash
. install/setup.bash
call install/setup.bat
Maintenant, pour tester la surveillance des paramètres distants, exécutez d’abord le nouveau code parameter_event_handler :
ros2 run cpp_parameter_event_handler parameter_event_handler
Ensuite, à partir d’un autre terminal (avec ROS initialisé), exécutez l’application de démonstration parameter_blackboard, comme suit :
ros2 run demo_nodes_cpp parameter_blackboard
Enfin, depuis un troisième terminal (avec ROS initialisé), définissons un paramètre sur le nœud parameter_blackboard :
ros2 param set parameter_blackboard a_double_param 3.45
Lors de l’exécution de cette commande, vous devriez voir une sortie dans la fenêtre parameter_event_handler, indiquant que la fonction de rappel a été invoquée lors de la mise à jour du paramètre :
[INFO] [1606952588.237531933] [node_with_parameters]: cb2: Received an update to parameter "a_double_param" of type: double: "3.45"
Résumé
Vous avez créé un nœud avec un paramètre et utilisé la classe ParameterEventHandler pour définir un rappel afin de surveiller les modifications apportées à ce paramètre. Vous avez également utilisé la même classe pour surveiller les modifications apportées à un nœud distant. Le ParameterEventHandler est un moyen pratique de surveiller les modifications de paramètres afin que vous puissiez ensuite répondre aux valeurs mises à jour.