Guide de migration depuis ROS 1
Table des matières
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
parrosidl_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
parcatkin
et lesCOMPONENTS
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 avantament_package
:Au lieu de passer
CATKIN_DEPENDS ...
appelezament_export_dependencies(...)
avant.Au lieu de passer
INCLUDE_DIRS ...
appelezament_export_include_directories(...)
avant.Au lieu de passer
LIBRARIES ...
, appelezament_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
etgenerate_messages
parrosidl_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
estDEPENDENCIES
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
etDEPENDS
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 messagechanger 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
parrclcpp::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 fieldnanosec
Usages de ros :: Rate
Il existe un objet équivalent de type rclcpp::Rate
qui est essentiellement un remplacement de ros::Rate
.
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.
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
parstd::unique_lock<std::mutex>
Remplacez
boost::mutex
parstd::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
avecstd::unordered_map
fonction
Remplacer:
#include <boost/function.hpp>
avec#include <fonctionnel>
boost::fonction
avecstd::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.
Voir Document de conception de paramètres ROS 2 pour plus de détails sur le modèle de système.
Voir Utilisation de la CLI ROS 2 pour une meilleure compréhension du fonctionnement des outils CLI et de ses différences avec l’outillage ROS 1.
Voir Migration des fichiers de paramètres YAML de ROS 1 vers ROS 2 pour voir comment les fichiers de paramètres YAML sont analysés dans ROS 2 et leurs différences avec l’implémentation de 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
Migrateur de fichiers de lancement qui convertit un fichier de lancement XML ROS 1 en un fichier de lancement Python ROS 2 : https://github.com/aws-robotics/ros2-launch-file-migrator
Amazon a exposé ses outils de portage des robots ROS 1 vers ROS 2 https://github.com/awslabs/ros2-migration-tools/tree/master/porting_tools
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.