Guide de migration depuis ROS 1

Il existe deux types différents de migrations de packages :

  • Migrer le code source d’un package existant de ROS 1 vers ROS 2 avec l’intention qu’une partie importante du code source reste identique ou au moins similaire. Un exemple pour cela pourrait être pluginlib où le code source est conservé dans différentes branches au sein du même référentiel et généralement des correctifs peuvent être portés entre ces branches si nécessaire.

  • Implémentation de la même fonctionnalité ou d’une fonctionnalité similaire d’un package ROS 1 pour ROS 2, mais en supposant que le code source sera significativement différent. Un exemple pour cela pourrait être roscpp dans ROS 1 et rclcpp dans ROS 2 qui sont des référentiels séparés et ne partagent aucun code.

Cet article se concentre sur le premier cas et décrit les étapes de haut niveau pour migrer un package ROS 1 vers ROS 2. Il ne vise pas à être une instruction de migration étape par étape et n’est pas considéré comme la « solution » * finale *. Les futures versions viseront à rendre la migration plus fluide et moins d’effort jusqu’au point de maintenir un seul paquet de la même branche pour ROS 1 ainsi que ROS 2.

Conditions préalables

Avant de pouvoir migrer un package ROS 1 vers ROS 2, toutes ses dépendances doivent être disponibles dans ROS 2.

Étapes de migration

Manifestes de package

ROS 2 ne prend pas en charge le format 1 de la spécification du package, mais uniquement les versions de format plus récentes (2 et supérieures). Par conséquent, le fichier package.xml doit être mis à jour au moins au format 2 s’il utilise le format 1. Étant donné que ROS 1 prend en charge tous les formats, il est sûr d’effectuer cette conversion dans le package ROS 1.

Certains packages peuvent avoir des noms différents dans ROS 2, il peut donc être nécessaire de mettre à jour les dépendances en conséquence.

Métapaquets

ROS 2 n’a pas de type de package spécial pour les métapackages. Les métapackages peuvent toujours exister en tant que packages réguliers qui ne contiennent que des dépendances d’exécution. Lors de la migration de métapaquets depuis ROS 1, supprimez simplement la balise <metapackage /> dans le manifeste de votre paquet.

Définitions des messages, des services et des actions

Les fichiers de messages doivent se terminer par .msg et doivent être situés dans le sous-dossier msg. Les fichiers de service doivent se terminer par .srv et doivent être situés dans le sous-dossier srv. Les fichiers d’actions doivent se terminer par .action et doivent être situés dans le sous-dossier action.

Ces fichiers devront peut-être être mis à jour pour se conformer à la définition de l’interface ROS. Certains types primitifs ont été supprimés et les types duration et time qui étaient des types intégrés dans ROS 1 ont été remplacés par des définitions de message normales et doivent être utilisés à partir des builtin_interfaces package. De plus, certaines conventions de nommage sont plus strictes que dans ROS 1.

Dans votre package.xml :

  • Ajoutez <buildtool_depend>rosidl_default_generators</buildtool_depend>.

  • Ajoutez <exec_depend>rosidl_default_runtime</exec_depend>.

  • Pour chaque package de message dépendant, ajoutez <depend>message_package</depend>.

Dans votre CMakeLists.txt :

  • Commencez par activer C++14

set(CMAKE_CXX_STANDARD 14)
  • Ajouter find_package(rosidl_default_generators OBLIGATOIRE)

  • Pour chaque paquet de message dépendant, ajoutez find_package(message_package REQUIRED) et remplacez l’appel de la fonction CMake à generate_messages par rosidl_generate_interfaces.

Cela remplacera la liste add_message_files et add_service_files de tous les fichiers de messages et de services, qui peuvent être supprimés.

Système de construction

Le système de construction dans ROS 2 s’appelle ament et l’outil de construction est colcon. Ament est construit sur CMake : ament_cmake fournit des fonctions CMake pour faciliter l’écriture des fichiers CMakeLists.txt.

Outil de construction

Au lieu d’utiliser catkin_make, catkin_make_isolated ou catkin build ROS 2 utilise l’outil de ligne de commande colcon pour construire et installer un ensemble de packages.

Paquet Python pur

Si le package ROS 1 utilise CMake uniquement pour appeler le fichier setup.py et ne contient rien à côté du code Python (par exemple, aucun message, service, etc.), il doit être converti en un package Python pur dans ROS 2 :

  • Mettez à jour ou ajoutez le type de build dans le fichier package.xml :

    <export>
      <build_type>ament_python</build_type>
    </export>
    
  • Supprimez le fichier CMakeLists.txt

  • Mettez à jour le fichier setup.py pour qu’il devienne un script d’installation Python standard

ROS 2 ne prend en charge que Python 3. Bien que chaque package puisse choisir de prendre également en charge Python 2, il doit appeler des exécutables avec Python 3 s’il utilise une API fournie par d’autres packages ROS 2.

Mettez à jour le CMakeLists.txt pour utiliser ament_cmake

Appliquez les modifications suivantes pour utiliser ament_cmake au lieu de catkin :

  • Définissez le type de construction dans la section d’exportation du fichier package.xml :

    <export>
      <build_type>ament_cmake</build_type>
    </export>
    
  • Remplacez l’invocation find_package par catkin et les COMPONENTS par :

    find_package(ament_cmake REQUIRED)
    find_package(component1 REQUIRED)
    # ...
    find_package(componentN REQUIRED)
    
  • Déplacez et mettez à jour l’invocation catkin_package avec :

    • Invoquez ament_package à la place, mais après que toutes les cibles aient été enregistrées.

    • Le seul argument valide pour ament_package est CONFIG_EXTRAS. Tous les autres arguments sont couverts par des fonctions séparées qui doivent toutes être invoquées avant ament_package :

      • Au lieu de passer CATKIN_DEPENDS ... appelez ament_export_dependencies(...) avant.

      • Au lieu de passer INCLUDE_DIRS ... appelez ament_export_include_directories(...) avant.

      • Au lieu de passer LIBRARIES ..., appelez ament_export_libraries(...) avant.

    • TODO document ament_export_targets (``ament_export_interfaces`` dans Eloquent et versions antérieures) ?

  • Remplacez l’invocation de add_message_files, add_service_files et generate_messages par rosidl_generate_interfaces __.

    • Le premier argument est le target_name. Si vous construisez une seule bibliothèque, c’est ${PROJECT_NAME}

    • Suivi de la liste des noms de fichiers de messages, par rapport à la racine du package.

      • Si vous utilisez la liste des noms de fichiers plusieurs fois, il est recommandé de composer une liste de fichiers de messages et de transmettre la liste à la fonction pour plus de clarté.

    • L’argument final du mot-clé à valeurs multiples fpr generate_messages est DEPENDENCIES qui nécessite la liste des packages de messages dépendants.

      rosidl_generate_interfaces(${PROJECT_NAME}
        ${msg_files}
        DEPENDENCIES std_msgs
      )
      
  • Supprimez toutes les occurrences de l”espace de développement. Les variables CMake associées comme CATKIN_DEVEL_PREFIX n’existent plus.

    • Les arguments CATKIN_DEPENDS et DEPENDS sont passés à la nouvelle fonction ament_export_dependencies.

    • CATKIN_GLOBAL_BIN_DESTINATION : bin

    • CATKIN_GLOBAL_INCLUDE_DESTINATION : inclure

    • CATKIN_GLOBAL_LIB_DESTINATION : lib

    • CATKIN_GLOBAL_LIBEXEC_DESTINATION : lib

    • CATKIN_GLOBAL_SHARE_DESTINATION : partager

    • CATKIN_PACKAGE_BIN_DESTINATION : lib/${PROJECT_NAME}

    • CATKIN_PACKAGE_INCLUDE_DESTINATION : include/${PROJECT_NAME}

    • CATKIN_PACKAGE_LIB_DESTINATION : lib

    • CATKIN_PACKAGE_SHARE_DESTINATION : partager/${PROJECT_NAME}

Tests unitaires

Si vous utilisez gtest :

Remplacez CATKIN_ENABLE_TESTING par BUILD_TESTING. Remplacez catkin_add_gtest par ament_add_gtest.

-   if (CATKIN_ENABLE_TESTING)
-     find_package(GTest REQUIRED)  # or rostest
-     include_directories(${GTEST_INCLUDE_DIRS})
-     catkin_add_gtest(${PROJECT_NAME}-some-test src/test/some_test.cpp)
-     target_link_libraries(${PROJECT_NAME}-some-test
-       ${PROJECT_NAME}_some_dependency
-       ${catkin_LIBRARIES}
-       ${GTEST_LIBRARIES})
-   endif()
+   if (BUILD_TESTING)
+     find_package(ament_cmake_gtest REQUIRED)
+     ament_add_gtest(${PROJECT_NAME}-some-test src/test/test_something.cpp)
+     ament_target_dependencies(${PROJECT_NAME)-some-test
+       "rclcpp"
+       "std_msgs")
+     target_link_libraries(${PROJECT_NAME}-some-test
+       ${PROJECT_NAME}_some_dependency)
+   endif()

Ajoutez <test_depend>ament_cmake_gtest</test_depend> à votre package.xml.

-   <test_depend>rostest</test_depend>
+   <test_depend>ament_cmake_gtest</test_depend>

Linters

Dans ROS 2, nous travaillons pour maintenir un code propre en utilisant des linters. Les styles pour les différentes langues sont définis dans notre Guide du développeur.

Si vous démarrez un projet à partir de zéro, il est recommandé de suivre le guide de style et d’activer les tests unitaires automatiques de linter en ajoutant ces lignes juste en dessous de if(BUILD_TESTING) (jusqu’à l’alpha 5, c’était AMENT_ENABLE_TESTING) .

find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()

Vous devrez également ajouter les dépendances suivantes à votre package.xml :

<test_depend>ament_lint_auto</test_depend>
<test_depend>ament_lint_common</test_depend>

Continuez à utiliser catkin dans CMake

ROS 2 utilise ament comme système de construction mais pour la rétrocompatibilité, ROS 2 a un paquet appelé catkin qui fournit presque la même API que catkin dans ROS 1. Afin d’utiliser cette API de rétrocompatibilité, le CMakeLists.txt` ` ne doit être mis à jour que pour appeler la fonction ``catkin_ament_package() après toutes les cibles.

REMARQUE : Ceci n’a pas encore été implémenté et n’est qu’une idée pour le moment. En raison du nombre de modifications liées aux dépendances, il n’a pas encore été décidé si cette API de compatibilité est suffisamment utile pour justifier l’effort.

Mettre à jour le code source

Messages, services et actions

L’espace de noms des messages, services et actions ROS 2 utilise un sous-espace de noms (msg, srv ou action, respectivement) après le nom du package. Par conséquent, une inclusion ressemble à : #include <my_interfaces/msg/my_message.hpp>. Le type C++ est alors nommé : my_interfaces::msg::MyMessage.

Les types de pointeurs partagés sont fournis en tant que typedefs dans les structures de message : my_interfaces::msg::MyMessage::SharedPtr ainsi que my_interfaces::msg::MyMessage::ConstSharedPtr.

Pour plus de détails, veuillez consulter l’article sur les interfaces C++ générées.

La migration nécessite la modification d’includes par :

  • insertion du sous-dossier msg entre le nom du package et le type de données du message

  • changer le nom de fichier inclus de CamelCase pour souligner la séparation

  • passage de *.h à *.hpp

// ROS 1 style is in comments, ROS 2 follows, uncommented.
// # include <geometry_msgs/PointStamped.h>
#include <geometry_msgs/msg/point_stamped.hpp>

// geometry_msgs::PointStamped point_stamped;
geometry_msgs::msg::PointStamped point_stamped;

La migration nécessite du code pour insérer l’espace de noms msg dans toutes les instances.

Utilisation des objets de service

Les rappels de service dans ROS 2 n’ont pas de valeurs de retour booléennes. Au lieu de renvoyer false en cas d’échec, il est recommandé de lever des exceptions.

// ROS 1 style is in comments, ROS 2 follows, uncommented.
// #include "nav_msgs/GetMap.h"
#include "nav_msgs/srv/get_map.hpp"

// bool service_callback(
//   nav_msgs::GetMap::Request & request,
//   nav_msgs::GetMap::Response & response)
void service_callback(
  const std::shared_ptr<nav_msgs::srv::GetMap::Request> request,
  std::shared_ptr<nav_msgs::srv::GetMap::Response> response)
{
  // ...
  // return true;  // or false for failure
}

Usages de ros::Time

Pour les utilisations de ros::Time :

  • Remplacez toutes les instances de ros::Time par rclcpp::Time

  • Si vos messages ou votre code utilisent std_msgs::Time :

    • Convertir toutes les instances de std_msgs::Time en builtin_interfaces::msg::Time

    • Convertissez tous les #include "std_msgs/time.h en #include "builtin_interfaces/msg/time.hpp"

    • Convertissez toutes les instances utilisant le champ std_msgs::Time nsec en builtin_interfaces::msg::Time field nanosec

Usages de ros :: Rate

Il existe un objet équivalent de type rclcpp::Rate qui est essentiellement un remplacement de ros::Rate.

bibliothèque cliente ROS

REMARQUE : Autres à écrire

Augmenter

Une grande partie des fonctionnalités précédemment fournies par Boost ont été intégrées dans la bibliothèque standard C++. En tant que tel, nous aimerions tirer parti des nouvelles fonctionnalités de base et éviter la dépendance au boost dans la mesure du possible.

Pointeurs partagés

Pour basculer les pointeurs partagés de boost vers le C++ standard, remplacez les instances de :

  • #include <boost/shared_ptr.hpp> avec #include <mémoire>

  • boost::shared_ptr avec std::shared_ptr

Il peut également y avoir des variantes telles que weak_ptr que vous souhaitez également convertir.

Il est également recommandé d’utiliser using au lieu de typedef. using a la capacité de mieux fonctionner dans la logique basée sur des modèles. Pour plus de détails voir ici

Thread/Mutex

Une autre partie courante de boost utilisée dans les bases de code ROS sont les mutex dans boost::thread.

  • Remplacez boost::mutex::scoped_lock par std::unique_lock<std::mutex>

  • Remplacez boost::mutex par std::mutex

  • Remplacez #include <boost/thread/mutex.hpp> par #include <mutex>

Carte non ordonnée

Remplacer:

  • #include <boost/unordered_map.hpp> avec #include <unordered_map>

  • boost::unordered_map avec std::unordered_map

fonction

Remplacer:

  • #include <boost/function.hpp> avec #include <fonctionnel>

  • boost::fonction avec std::fonction

Paramètres

Dans ROS 1, les paramètres sont associés à un serveur central qui permettait de récupérer les paramètres au moment de l’exécution grâce à l’utilisation des API réseau. Dans ROS 2, les paramètres sont associés par nœud et sont configurables lors de l’exécution avec les services ROS.

Lancer des fichiers

Alors que les fichiers de lancement dans ROS 1 sont toujours spécifiés à l’aide de fichiers .xml, ROS 2 prend en charge les scripts Python pour permettre plus de flexibilité (voir package de lancement) ainsi que des fichiers XML et YAML. Voir tutoriel séparé sur la migration des fichiers de lancement de ROS 1 vers ROS 2.

Exemple : conversion d’un package ROS 1 existant pour utiliser ROS 2

Disons que nous avons un package ROS 1 simple appelé talker qui utilise roscpp dans un nœud, appelé talker. Ce paquet se trouve dans un espace de travail catkin, situé dans ~/ros1_talker.

Le code ROS 1

Voici la disposition du répertoire de notre espace de travail catkin :

$ cd ~/ros1_talker
$ find .
.
./src
./src/talker
./src/talker/package.xml
./src/talker/CMakeLists.txt
./src/talker/talker.cpp

Voici le contenu de ces trois fichiers :

src/talker/paquet.xml :

<package>
  <name>talker</name>
  <version>0.0.0</version>
  <description>talker</description>
  <maintainer email="gerkey@osrfoundation.org">Brian Gerkey</maintainer>
  <license>Apache 2.0</license>
  <buildtool_depend>catkin</buildtool_depend>
  <build_depend>roscpp</build_depend>
  <build_depend>std_msgs</build_depend>
  <run_depend>roscpp</run_depend>
  <run_depend>std_msgs</run_depend>
</package>

src/talker/CMakeLists.txt :

cmake_minimum_required(VERSION 2.8.3)
project(talker)
find_package(catkin REQUIRED COMPONENTS roscpp std_msgs)
catkin_package()
include_directories(${catkin_INCLUDE_DIRS})
add_executable(talker talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
install(TARGETS talker
  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})

src/talker/talker.cpp :

#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc, char **argv)
{
  ros::init(argc, argv, "talker");
  ros::NodeHandle n;
  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
  ros::Rate loop_rate(10);
  int count = 0;
  std_msgs::String msg;
  while (ros::ok())
  {
    std::stringstream ss;
    ss << "hello world " << count++;
    msg.data = ss.str();
    ROS_INFO("%s", msg.data.c_str());
    chatter_pub.publish(msg);
    ros::spinOnce();
    loop_rate.sleep();
  }
  return 0;
}

Construire le code ROS 1

Nous créons un fichier de configuration d’environnement (dans ce cas pour Jade en utilisant bash), puis nous construisons notre paquet en utilisant catkin_make install :

. /opt/ros/jade/setup.bash
cd ~/ros1_talker
catkin_make install

Exécution du nœud ROS 1

S’il n’y en a pas déjà un en cours d’exécution, nous lançons un roscore, en commençant par rechercher le fichier de configuration à partir de notre arbre d’installation catkin (le fichier de configuration du système à /opt/ros/jade/setup.bash fonctionnerait aussi ici):

. ~/ros1_talker/install/setup.bash
roscore

Dans un autre shell, nous exécutons le nœud à partir de l’espace d’installation catkin en utilisant rosrun, en recherchant d’abord le fichier de configuration (dans ce cas, il doit s’agir de celui de notre espace de travail) :

. ~/ros1_talker/install/setup.bash
rosrun talker talker

Migration vers ROS 2

Commençons par créer un nouvel espace de travail dans lequel travailler :

mkdir ~/ros2_talker
cd ~/ros2_talker

Nous allons copier l’arborescence source de notre package ROS 1 dans cet espace de travail, où nous pourrons le modifier :

mkdir src
cp -a ~/ros1_talker/src/talker src

Nous allons maintenant modifier le code C++ dans le nœud. La bibliothèque ROS 2 C++, appelée rclcpp, fournit une API différente de celle fournie par roscpp. Les concepts sont très similaires entre les deux bibliothèques, ce qui rend les modifications raisonnablement simples à effectuer.

En-têtes inclus

Au lieu de ros/ros.h, qui nous a donné accès à l’API de la bibliothèque roscpp, nous devons inclure rclcpp/rclcpp.hpp, qui nous donne accès à la ``rclcpp `` API de la bibliothèque :

//#include "ros/ros.h"
#include "rclcpp/rclcpp.hpp"

Pour obtenir la définition de message std_msgs/String, à la place de std_msgs/String.h, nous devons inclure std_msgs/msg/string.hpp :

//#include "std_msgs/String.h"
#include "std_msgs/msg/string.hpp"

Modification des appels de bibliothèque C++

Au lieu de passer le nom du nœud à l’appel d’initialisation de la bibliothèque, nous effectuons l’initialisation, puis passons le nom du nœud à la création de l’objet nœud (nous pouvons utiliser le mot-clé auto car nous avons maintenant besoin d’un C++ 14 compilateur):

//  ros::init(argc, argv, "talker");
//  ros::NodeHandle n;
    rclcpp::init(argc, argv);
    auto node = rclcpp::Node::make_shared("talker");

La création des objets d’éditeur et de taux semble assez similaire, avec quelques changements dans les noms de l’espace de noms et des méthodes.

//  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
//  ros::Rate loop_rate(10);
  auto chatter_pub = node->create_publisher<std_msgs::msg::String>("chatter",
    1000);
  rclcpp::Rate loop_rate(10);

Pour mieux contrôler la manière dont la livraison des messages est gérée, un profil de qualité de service (QoS) peut être transmis. Le profil par défaut est rmw_qos_profile_default. Pour plus de détails, consultez le document de conception et la vue d'ensemble du concept.

La création du message sortant est différente dans l’espace de noms :

//  std_msgs::String msg;
  std_msgs::msg::String msg;

Au lieu de ros::ok(), nous appelons rclcpp::ok() :

//  while (ros::ok())
  while (rclcpp::ok())

Dans la boucle de publication, nous accédons au champ data comme précédemment :

msg.data = ss.str();

Pour imprimer un message console, au lieu d’utiliser ROS_INFO(), nous utilisons RCLCPP_INFO() et ses différents cousins. La principale différence est que RCLCPP_INFO() prend un objet Logger comme premier argument.

//    ROS_INFO("%s", msg.data.c_str());
    RCLCPP_INFO(node->get_logger(), "%s\n", msg.data.c_str());

La publication du message est la même qu’avant :

chatter_pub->publish(msg);

La rotation (c’est-à-dire laisser le système de communication traiter tous les messages entrants/sortants en attente) est différente en ce sens que l’appel prend désormais le nœud comme argument :

//    ros::spinOnce();
    rclcpp::spin_some(node);

Dormir à l’aide de l’objet tarif reste inchangé.

En mettant tout cela ensemble, le nouveau talker.cpp ressemble à ceci :

#include <sstream>
// #include "ros/ros.h"
#include "rclcpp/rclcpp.hpp"
// #include "std_msgs/String.h"
#include "std_msgs/msg/string.hpp"
int main(int argc, char **argv)
{
//  ros::init(argc, argv, "talker");
//  ros::NodeHandle n;
  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("talker");
//  ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
//  ros::Rate loop_rate(10);
  auto chatter_pub = node->create_publisher<std_msgs::msg::String>("chatter", 1000);
  rclcpp::Rate loop_rate(10);
  int count = 0;
//  std_msgs::String msg;
  std_msgs::msg::String msg;
//  while (ros::ok())
  while (rclcpp::ok())
  {
    std::stringstream ss;
    ss << "hello world " << count++;
    msg.data = ss.str();
//    ROS_INFO("%s", msg.data.c_str());
    RCLCPP_INFO(node->get_logger(), "%s\n", msg.data.c_str());
    chatter_pub->publish(msg);
//    ros::spinOnce();
    rclcpp::spin_some(node);
    loop_rate.sleep();
  }
  return 0;
}

Changer le package.xml

ROS 2 ne prend pas en charge le format 1 de la spécification du package, mais uniquement les versions de format plus récentes (2 et supérieures). Nous commençons par spécifier la version du format dans la balise package :

<!-- <package> -->
<package format="2">

ROS 2 utilise une version plus récente de catkin, appelée ament_cmake, que nous spécifions dans la balise buildtool_depend :

<!--  <buildtool_depend>catkin</buildtool_depend> -->
  <buildtool_depend>ament_cmake</buildtool_depend>

Dans nos dépendances de construction, au lieu de roscpp, nous utilisons rclcpp, qui fournit l’API C++ que nous utilisons.

<!--  <build_depend>roscpp</build_depend> -->
  <build_depend>rclcpp</build_depend>

Nous faisons le même ajout dans les dépendances d’exécution et mettons également à jour la balise run_depend vers la balise exec_depend (partie de la mise à niveau vers la version 2 du format de package) :

<!--  <run_depend>roscpp</run_depend> -->
  <exec_depend>rclcpp</exec_depend>
<!--  <run_depend>std_msgs</run_depend> -->
  <exec_depend>std_msgs</exec_depend>

Dans ROS 1, nous utilisons <depend> pour simplifier la spécification des dépendances à la fois pour la compilation et l’exécution. Nous pouvons faire la même chose dans ROS 2 :

<depend>rclcpp</depend>
<depend>std_msgs</depend>

Nous devons également dire à l’outil de construction quel type de paquet nous sommes, afin qu’il sache comment nous construire. Parce que nous utilisons ament et CMake, nous ajoutons les lignes suivantes pour déclarer notre type de construction comme étant ament_cmake :

<export>
  <build_type>ament_cmake</build_type>
</export>

En mettant tout cela ensemble, notre package.xml ressemble maintenant à ceci :

<!-- <package> -->
<package format="2">
  <name>talker</name>
  <version>0.0.0</version>
  <description>talker</description>
  <maintainer email="gerkey@osrfoundation.org">Brian Gerkey</maintainer>
  <license>Apache License 2.0</license>
<!--  <buildtool_depend>catkin</buildtool_depend> -->
  <buildtool_depend>ament_cmake</buildtool_depend>
<!--  <build_depend>roscpp</build_depend> -->
<!--  <run_depend>roscpp</run_depend> -->
<!--  <run_depend>std_msgs</run_depend> -->
  <depend>rclcpp</depend>
  <depend>std_msgs</depend>
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

TODO : affiche une version plus simple de ce fichier en utilisant simplement la balise ``<depend>``, qui est activée par la version 2 du format de package (également prise en charge dans ``catkin`` donc, à proprement parler, orthogonale à ROS 2 ).

Changer le code CMake

ROS 2 s’appuie sur une version supérieure de CMake :

#cmake_minimum_required(VERSION 2.8.3)
cmake_minimum_required(VERSION 3.5)

ROS 2 s’appuie sur la norme C++14. Selon le compilateur que vous utilisez, la prise en charge de C++14 peut ne pas être activée par défaut. En utilisant gcc 5.3 (ce qui est utilisé sur Ubuntu Xenial), nous devons l’activer explicitement, ce que nous faisons en ajoutant cette ligne en haut du fichier :

set(CMAKE_CXX_STANDARD 14)

La façon préférée de travailler sur toutes les plateformes est la suivante :

if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

En utilisant catkin, nous spécifions les packages avec lesquels nous voulons construire en les passant comme arguments COMPONENTS lors de la recherche initiale de catkin lui-même. Avec ament_cmake, nous trouvons chaque paquet individuellement, en commençant par ament_cmake :

#find_package(catkin REQUIRED COMPONENTS roscpp std_msgs)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

Les dépendances du système peuvent être trouvées comme avant :

find_package(Boost REQUIRED COMPONENTS system filesystem thread)

Nous appelons catkin_package() pour générer automatiquement des choses comme les fichiers de configuration CMake pour d’autres packages qui utilisent notre package. Alors que cet appel se produit avant de spécifier les cibles à construire, nous appelons maintenant l’analogue ament_package() après les cibles :

# catkin_package()
# At the bottom of the file:
ament_package()

Les seuls répertoires qui doivent être inclus manuellement sont les répertoires locaux et les dépendances qui ne sont pas des packages d’ament :

#include_directories(${catkin_INCLUDE_DIRS})
include_directories(include ${Boost_INCLUDE_DIRS})

Une meilleure alternative consiste à spécifier les répertoires d’inclusion pour chaque cible individuellement, plutôt que d’inclure tous les répertoires pour toutes les cibles :

target_include_directories(target PUBLIC include ${Boost_INCLUDE_DIRS})

De la même manière que nous avons trouvé chaque package dépendant séparément, nous devons lier chacun à la cible de construction. Pour créer un lien avec des packages dépendants qui sont des packages ament, au lieu d’utiliser target_link_libraries(), ament_target_dependencies() est une manière plus concise et plus approfondie de gérer les drapeaux de construction. Il gère automatiquement à la fois les répertoires d’inclusion définis dans _INCLUDE_DIRS et les bibliothèques de liens définies dans _LIBRARIES.

#target_link_libraries(talker ${catkin_LIBRARIES})
ament_target_dependencies(talker
  rclcpp
  std_msgs)

Pour créer un lien avec des packages qui ne sont pas des packages ament, tels que des dépendances système comme Boost, ou une bibliothèque construite dans le même CMakeLists.txt, utilisez target_link_libraries() :

target_link_libraries(target ${Boost_LIBRARIES})

Pour l’installation, catkin définit des variables comme CATKIN_PACKAGE_BIN_DESTINATION. Avec ament_cmake, on donne juste un chemin relatif à la racine d’installation, comme bin pour les exécutables :

#install(TARGETS talker
#  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
install(TARGETS talker
  DESTINATION lib/${PROJECT_NAME})

En option, nous pouvons installer et exporter les répertoires inclus pour les packages en aval :

install(DIRECTORY include/
  DESTINATION include)
ament_export_include_directories(include)

En option, nous pouvons exporter les dépendances pour les packages en aval :

ament_export_dependencies(std_msgs)

En mettant tout cela ensemble, le nouveau CMakeLists.txt ressemble à ceci :

#cmake_minimum_required(VERSION 2.8.3)
cmake_minimum_required(VERSION 3.5)
project(talker)
if(NOT CMAKE_CXX_STANDARD)
  set(CMAKE_CXX_STANDARD 14)
endif()
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()
#find_package(catkin REQUIRED COMPONENTS roscpp std_msgs)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
#catkin_package()
#include_directories(${catkin_INCLUDE_DIRS})
include_directories(include)
add_executable(talker talker.cpp)
#target_link_libraries(talker ${catkin_LIBRARIES})
ament_target_dependencies(talker
  rclcpp
  std_msgs)
#install(TARGETS talker
#  RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
install(TARGETS talker
  DESTINATION lib/${PROJECT_NAME})
install(DIRECTORY include/
  DESTINATION include)
ament_export_include_directories(include)
ament_export_dependencies(std_msgs)
ament_package()

TODO : Montrez à quoi cela ressemblerait avec ``ament_auto``.

Construire le code ROS 2

Nous créons un fichier de configuration d’environnement (dans ce cas, celui généré en suivant le tutoriel d’installation de ROS 2, qui se construit dans ~/ros2_ws, puis nous construisons notre paquet en utilisant colcon build :

. ~/ros2_ws/install/setup.bash
cd ~/ros2_talker
colcon build

Exécution du nœud ROS 2

Parce que nous avons installé l’exécutable talker dans bin, après avoir récupéré le fichier d’installation, à partir de notre arbre d’installation, nous pouvons l’invoquer directement par son nom (de plus, il n’y a pas encore d’équivalent ROS 2 pour ``rosrun ``):

. ~/ros2_ws/install/setup.bash
talker

Mettre à jour les scripts

Arguments de la CLI ROS

Depuis ROS Eloquent, les arguments ROS doivent être définis avec --ros-args et un -- final (le double tiret final peut être élidé si aucun argument ne le suit).

Le remappage des noms est similaire à ROS 1, prenant la forme from:=to, sauf qu’il doit être précédé d’un drapeau --remap (ou -r). Par exemple:

ros2 run some_package some_ros_executable --ros-args -r foo:=bar

Nous utilisons une syntaxe similaire pour les paramètres, en utilisant le drapeau --param (ou -p) :

ros2 run some_package some_ros_executable --ros-args -p my_param:=value

Notez que ceci est différent de l’utilisation d’un trait de soulignement initial dans ROS 1.

Pour changer un nom de nœud, utilisez __node (l’équivalent ROS 1 est __name) :

ros2 run some_package some_ros_executable --ros-args -r __node:=new_node_name

Notez l’utilisation du drapeau -r. Le même drapeau de remappage est nécessaire pour changer l’espace de noms __ns :

ros2 run some_package some_ros_executable --ros-args -r __ns:=/new/namespace

Il n’y a pas d’équivalent dans ROS 2 pour les clés ROS 1 suivantes :

  • __log (mais --log-config-file peut être utilisé pour fournir un fichier de configuration de l’enregistreur)

  • __ip

  • __hostname

  • __maître

Pour plus d’informations, consultez le document de conception.

Référence rapide

Fonctionnalité

RSO 1

RSO 2

remappage

toto:=bar

-r toto:=bar

paramètres

_foo :=barre

-p toto:=bar

nom du nœud

__name:=foo

-r __node:=foo

espace de noms

__ns:=foo

-r __ns:=foo

Plus d’exemples et d’outils

Licence

Dans ROS 2, notre licence recommandée est la Licence Apache 2.0. Dans ROS 1, notre licence recommandée était la 3-Clause BSD License.

Pour tout nouveau projet, nous vous recommandons d’utiliser la licence Apache 2.0, que ce soit ROS 1 ou ROS 2.

Cependant, lors de la migration du code de ROS 1 vers ROS 2, nous ne pouvons pas simplement changer la licence. La licence existante doit être conservée pour toute contribution préexistante.

À cette fin, si un package est en cours de migration, nous vous recommandons de conserver la licence existante et de continuer à contribuer à ce package sous la licence OSI existante, qui devrait être la licence BSD pour les éléments principaux.

Cela gardera les choses claires et faciles à comprendre.

Modification de la licence

Il est possible de modifier la licence, mais vous devrez contacter tous les contributeurs et obtenir leur autorisation. Pour la plupart des packages, cela représente probablement un effort important et ne vaut pas la peine d’être pris en compte. Si le paquet a un petit ensemble de contributeurs, cela peut être faisable.