ROS tf : Ajout de Repères Coordonnés Supplémentaires

Ce tutoriel explique comment introduire des repères coordonnés supplémentaires et fixes dans le système tf de ROS.

Pourquoi ajouter des repères coordonnés ?

Dans de nombreux scénarios, il est plus intuitif de raisonner dans un référentiel local. Par exemple, une lecture de télémètre laser est plus facilement interprétable dans un système de coordonnées centré sur le capteur lui-même. Le système tf permet de définir un tel référentiel local pour chaque capteur, chaque maillon de chaîne cinématique, etc., tout en gérant automatiquement les transformations nécessaires entre tous ces référentiels.

Structure des Repères Coordonnés dans tf

tf organise les repères coordonnés sous forme d'arbre. Cela signfiie qu'un repère ne peut avoir qu'un seul parent, mais peut avoir plusieurs enfants. Dans notre exemple de base, nous avons les repères world, turtle1 et turtle2, où les deux tortues sont des enfants du repère world. Pour ajouter un nouveau repère, l'un des repères existants doit devenir son parent.

Implémentation de l'ajout de repères

Dans l'exemple des tortues, nous allons ajouter un nouveau repère nommé carrot1, dont le parent sera turtle1.

Créez un nouveau fichier nommé frame_tf_broadcaster.cpp dans le répertoire learning_tf/src :

$ roscd learning_tf
$ touch src/frame_tf_broadcaster.cpp
$ vim src/frame_tf_broadcaster.cpp

Voici le contenu du fichier :

#include <ros/ros.h>
#include <tf/transform_broadcaster.h>

int main(int argc, char** argv) {
    ros::init(argc, argv, "my_tf_broadcaster");
    ros::NodeHandle node;

    tf::TransformBroadcaster broadcaster;
    tf::Transform transform;

    ros::Rate loop_rate(10.0); // Fréquence de publication de 10 Hz

    while (node.ok()) {
        // Définir l'origine du nouveau repère par rapport à son parent ("turtle1")
        transform.setOrigin(tf::Vector3(0.0, 2.0, 0.0));
        // Définir la rotation (ici, aucune rotation initiale)
        transform.setRotation(tf::Quaternion(0, 0, 0, 1));

        // Diffuser la transformation : (transform, temps, parent, enfant)
        broadcaster.sendTransform(tf::StampedTransform(transform, ros::Time::now(), "turtle1", "carrot1"));

        loop_rate.sleep();
    }
    return 0;
}

Explication du code

  • transform.setOrigin(tf::Vector3(0.0, 2.0, 0.0)); : Définit la position du repère carrot1 à 2 unités sur l'axe Y par rapport à turtle1.
  • transform.setRotation(tf::Quaternion(0, 0, 0, 1)); : Définit l'orientation. Un quaternion (0,0,0,1) représente l'identité, c'est-à-dire aucune rotation.
  • broadcaster.sendTransform(...) : La fonction principale qui publie la transformation entre le repère parent turtle1 et le repère enfant carrot1.

Compilation et Exécution

Modifiez le fichier CMakeLists.txt du package learning_tf pour inclure le nouvel exécutable :

$ rosed learning_tf CMakeLists.txt

Ajoutez les lignes suivantes à la fin du fichier :

add_executable(frame_tf_broadcaster src/frame_tf_broadcaster.cpp)
target_link_libraries(frame_tf_broadcaster ${catkin_LIBRARIES})

Recompilez votre espace de travail Catkin :

$ cd ~/catkin_ws
$ catkin_make

Ajoutez le nouveau nœud au fichier de lancement start_demo.launch :

$ rosed learning_tf start_demo.launch

Insérez la ligne suivante dans la section <launch> :

<node pkg="learning_tf" type="frame_tf_broadcaster" name="broadcaster_frame" />

Lancez la démo :

$ roslaunch learning_tf start_demo.launch

Vérification et Adaptation du Listener

Si vous lancez la démo et déplacez turtle1, vous remarquerez que le comportement général n'a pas changé. Ceci est dû au fait que le listener (turtle_tf_listener.cpp) utilise toujours la transformation entre /turtle2 et /turtle1. Pour observer l'effet du nouveau repère, nous devons modifier le listener pour qu'il utilise /carrot1.

Modifiez les lignes 26-27 du fichier src/turtle_tf_listener.cpp pour remplacer /turtle1 par /carrot1 :

listener.lookupTransform("/turtle2", "/carrot1",
                           ros::Time(0), transform);

Recompilez et relancez la démo :

$ catkin_make
$ roslaunch learning_tf start_demo.launch

Vous devriez maintenant observer que turtle2 suit /carrot1 au lieu de directement turtle1.

Diffusion de Repères Coordonnés Mobiles

Jusqu'à présent, le repère carrot1 était fixe par rapport à turtle1. Pour créer un repère mobile, il suffit de modifier le calcul de sa position et de son orientation dans le temps. Modifions le fichier src/frame_tf_broadcaster.cpp pour que carrot1 bouge en cercle autour de turtle1.

Éditez le fichier src/frame_tf_broadcaster.cpp :

$ vim src/frame_tf_broadcaster.cpp

Remplacez la section définissant l'origine par le code suivant :

// Le repère se déplace en cercle autour de turtle1
double delta_x = 2.0 * sin(ros::Time::now().toSec());
double delta_y = 2.0 * cos(ros::Time::now().toSec());
transform.setOrigin(tf::Vector3(delta_x, delta_y, 0.0));
transform.setRotation(tf::Quaternion(0, 0, 0, 1));

Recompilez et relancez la démo pour observer le mouvement du repère carrot1 :

$ catkin_make
$ roslaunch learning_tf start_demo.launch

Étiquettes: ROS tf coordinate frames C++ broadcaster

Publié le 23 juillet à 20h35